/* L'ACCUEIL (`/`, pages/accueil.html.erb) — trois choix, un par porte :
   L'ART en majesté au centre, ses dessins en grappes le long des bords du
   haut ; LE DESIGN, son nom sous le mot, ses projets en grandes cartes le long
   des bords du bas (les deux : envol_controller) ; LES RECHERCHES, un petit
   lien en bas de l'écran. La page tient en UN écran. */

.accueil {
  display: flex;
  flex-direction: column;
  /* La fenêtre entière : l'accueil annule les gouttières du <body>
     (application.css), les dessins couvrent le haut et les côtés jusqu'aux
     bords de l'écran — pas un liseré de fond. */
  margin: calc(-1 * var(--page-gutter));
  height: 100dvh;
  /* Les feuilles arrivent du dehors et débordent : rien ne doit allonger la
     page. */
  overflow: clip;
}

/* ── L'art ──────────────────────────────────────────────────────────────── */
.accueil-art {
  position: relative;
  /* Les dessins s'y rangent entre eux (z-index jusqu'à ~100) sans jamais
     passer devant la pastille du menu. */
  isolation: isolate;
  flex: 1 1 auto;
  display: grid;
  place-items: center;
}

/* Au centre : la galerie, la signature, le studio. La signature est SOUS les
   feuilles (`.accueil-art__mot`, z-index 1) ; la galerie et le studio sont
   AU-DESSUS (« il ne faut pas que les images recouvrent l'un ou l'autre ») —
   des feuilles posées comme de celles qui volent (`EN_L_AIR`, ~1 000), sous le
   seul dessin qu'on ouvre (`OUVERTE_RANG`, 5 000 : ils s'effacent alors). D'où
   un centre SANS z-index : il ne ferme pas de contexte d'empilement, chacun y
   prend son rang parmi les feuilles. */
.accueil-art__centre {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.8rem;
}

/* LES LETTRES DES TITRES VOLENT (1er oct. 2026 : « les lettres se détachent une
   à une pour aller se mettre en haut ; il faut qu'elles gardent leur taille,
   sinon c'est illisible » ; envol_controller#_titrer) : chaque lettre est une
   boîte (`lettres`, AccueilHelper) qui fait le même trajet — `--lettre-x`
   `--lettre-y`, posés sur le mot — à son tour (`--i`), à sa taille, comme une
   feuille (la durée de son voyage, VOYAGE_MS). Le mot, lui, garde sa boîte au
   centre : son z-index (2 000, ci-dessus) tient ses lettres au-dessus des
   feuilles où qu'elles soient. `sans-vol` : un saut (un retour, une fenêtre qui
   change). `--i` : le rang de la lettre DEPUIS LE CENTRE DU MOT (5 oct. 2026 :
   « que l'animation parte plutôt du centre finalement » — la veille, c'était des
   extrémités vers le centre) — le milieu part d'abord, les deux bouts en dernier,
   ensemble.
   ET LES TITRES SUIVENT UN ARC DE CERCLE sur un grand écran (2 oct. 2026 : « je
   veux que 'la galerie' soit écrit par rapport à un arc de cercle : le centre du
   cercle au milieu du côté bas de l'écran, le rayon va jusqu'au premier tiers ;
   pour le studio, le centre au milieu du côté haut, le rayon jusqu'au deuxième
   tiers ; sur mobile, pas de cercle ») : chaque lettre reçoit son décalage et sa
   pente depuis sa place dans le mot (`--arc-x` `--arc-y` `--arc-r`,
   envol_controller#_arquer) ; en vol (en haut, en bas de l'écran), le mot se
   redresse — en ligne, au même espacement —, et reprend l'arc en revenant. */
.lettre {
  /* LA DURÉE DU VOL D'UNE LETTRE, et le pas entre deux lettres : c'est ICI qu'on
     les change — le smear du glyphe (plus bas) les reprend. */
  --lettre-duree: 450ms;
  --lettre-pas: 5ms;
  display: inline-block;
  /* La lettre ne fait que se DÉPLACER : son vol, sa place sur l'arc. Sa PENTE sur
     l'arc (`--arc-r`) est sur le glyphe, dedans — l'étirement du smear, entre les
     deux, reste ainsi en repère écran (cf. « Le smear »). */
  transform: translate(var(--lettre-x, 0px), var(--lettre-y, 0px)) translate(var(--arc-x, 0px), var(--arc-y, 0px));
  /* … et CHANGE DE CORPS en transition aussi (5 oct. 2026 : « une animation des
     titres du passage au x-large si sélectionné » — le titre courant de la série,
     plus bas) : le corps est hérité du mot, chaque lettre grandit à son tour. */
  /* (L'opacité aussi : à l'ouverture, elles partent INVISIBLES du centre de l'écran —
     envol_controller#_arquer.) */
  transition: transform var(--lettre-duree) cubic-bezier(0.55, 0, 0.2, 1), font-size var(--lettre-duree) cubic-bezier(0.55, 0, 0.2, 1), opacity var(--lettre-duree) cubic-bezier(0.5, 0, 0.6, 1);
  transition-delay: calc(var(--i, 0) * var(--lettre-pas));
}

/* (Les petites FLÈCHES entre les tirets — 5 oct. 2026, au corps des lettres, qui se
   retournaient quand leur figure était active — sont RETIRÉES le 12 oct. 2026 : « puisque
   les dessins et les projets sont mélangés, ça n'a plus vraiment de sens ».) */
.sans-vol .lettre {
  transition: none;
}

/* LE SMEAR (5 oct. 2026 : « c'est possible de simuler un smear ? » — « go
   étirement pour voir ») : comme en dessin animé, une lettre qui vole S'ÉTIRE dans
   le sens de sa course au milieu du trajet, puis reprend sa forme en arrivant.
   TROIS BOÎTES EMBOÎTÉES (AccueilHelper) : la LETTRE se déplace (sa transition),
   LE SMEAR (`.lettre__smear`, entre les deux) s'étire, LE GLYPHE (`.lettre__glyphe`)
   penche avec l'arc — « le smear n'est pas totalement bon à cause de la rotation,
   la ligne de base étant en arc et non en ligne » : la pente appliquée au-dessus de
   l'étirement l'inclinait en vol ; mise DESSOUS, l'étirement reste en repère écran,
   dans l'axe exact de la course. Le contrôleur donne à chaque départ le CAP de la
   course, en repère écran (`--cap`), et la FORCE de l'étirement selon la distance
   (`--etire`, 0 à 1 — envol_controller#_smear), puis relance l'animation, qui a la
   durée et le délai de la transition (`--i`). Au repos, `--etire` est à 0 : rien ne
   bouge. `--etire-long` : ce qu'il s'allonge à pleine force — faible, pour que
   le mot reste lisible. `--etire-large` — ce qu'il s'AMINCISSAIT en travers — est
   À ZÉRO (5 oct. 2026 : « il y a comme un effet bouncy sur les sous-titres ; je ne
   veux pas cet effet ; les déformations anamorphiques doivent se faire seulement
   s'il y a un mouvement et dans le sens du mouvement » : sur une colonne de
   lettres qui arrivait de côté, l'amincissement en travers, vertical, faisait
   respirer toute la colonne en hauteur — un rebond ; il ne reste que
   l'allongement dans l'axe de la course, et le contrôleur ne relance l'animation
   que si la lettre bouge vraiment, `SMEAR_MIN`). */
.lettre__smear {
  --etire-long: 0.8;
  --etire-large: 0;
  display: inline-block;
  transform-origin: 50% 50%;
  /* La durée et le délai de la lettre (`--lettre-duree`, `--lettre-pas`, hérités). */
  animation: lettre-smear var(--lettre-duree, 700ms) cubic-bezier(0.4, 0, 0.6, 1) both;
  animation-delay: calc(var(--i, 0) * var(--lettre-pas, 55ms));
}

/* Le glyphe penche avec l'arc (`--arc-r`, posé sur la lettre par le contrôleur),
   dans la même transition que le déplacement. */
.lettre__glyphe {
  display: inline-block;
  transform-origin: 50% 50%;
  transform: rotate(var(--arc-r, 0deg));
  transition: transform var(--lettre-duree, 700ms) cubic-bezier(0.55, 0, 0.2, 1);
  transition-delay: calc(var(--i, 0) * var(--lettre-pas, 55ms)), 0s;
}

@keyframes lettre-smear {

  0%,
  100% {
    transform: rotate(var(--cap, 0deg)) scale(1, 1) rotate(calc(-1 * var(--cap, 0deg)));
  }

  /* Le plus vite, c'est vers le milieu de la course (la transition va vite au
     début, se pose doucement) : l'étirement y culmine. */
  42% {
    transform: rotate(var(--cap, 0deg)) scale(calc(1 + var(--etire, 0) * var(--etire-long)), calc(1 - var(--etire, 0) * var(--etire-large))) rotate(calc(-1 * var(--cap, 0deg)));
  }
}

/* (Pas de `animation: none` sur le smear sous `sans-vol` : le retrait de la
   classe RELANÇAIT l'animation, avec la force de la dernière course — les lettres
   s'étiraient sur place, sans bouger, à chaque saut (5 oct. 2026, « il y a encore
   cet effet bouncy »). Un saut éteint le smear autrement : `--etire` à 0,
   envol_controller#_figer.) */

.sans-vol .lettre__glyphe {
  transition: none;
}

@media (prefers-reduced-motion: reduce) {

  .lettre,
  .lettre__glyphe {
    transition: none;
  }

  .lettre__smear {
    animation: none;
  }
}

/* Les titres passent SOUS les feuilles (5 oct. 2026 : « il faut que les titres
   passent dessous les dessins et les diapos et pas par dessus » — ils étaient
   au-dessus, z-index 2 000, depuis le 30 sept.) : au rang de la signature. Rangés,
   la grille et la planche leur laissent leur ligne (envol_controller, `this.titre`). */
.accueil-art__galerie,
.accueil-art__design {
  position: relative;
  z-index: 1;
}

.accueil-art__galerie {
  display: flex;
  align-items: baseline;
  gap: 0.5em;
  margin: 0;
  font-weight: bold;
  font-size: x-large;
  color: var(--ink-muted);
}

/* « Le Studio » : l'allure de « La galerie », au-dessus de la signature. */
.accueil-art__design {
  font-size: x-large;
  font-weight: bold;
  color: var(--ink-muted);
  letter-spacing: 0.2em;
  /* comme « La galerie » : le départ de l'ouverture (cf. plus bas) */
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}

.accueil-art__design:hover,
.accueil-art__design:focus-visible {
  color: var(--blue);
  outline: none;
}

.accueil-art__mot {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  color: var(--ink);
  text-decoration: none;
}

.accueil-art__mot svg {
  display: block;
  width: min(52vw, 62dvh);
  height: auto;
  overflow: visible;
}

.accueil-art__mot text {
  fill: currentColor;
  font-weight: 700;
  letter-spacing: -2px;
}

/* La signature (signature_controller) : la forme — le <svg>, le masque de la
   signature, noir — ne tient que la place, JAMAIS MONTRÉE (« il ne faut pas
   afficher l'image en noir » : ni avant que le JS démarre, ni quand le motif ne
   peut pas se peindre) ; seule la toile posée dessus (WebGL) montre le motif,
   aux bords nets, sur du vide : la page se voit au travers. */
.accueil-art__signature {
  position: relative;
  display: block;
}

.accueil-art__signature canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.accueil-art__signature svg {
  visibility: hidden;
}

/* (LA TABLE LUMINEUSE DU STUDIO — une lumière blanche qui s'allumait sous les
   diapositives rangées, le film éclairci, un halo autour du cadre ; 1er oct.
   2026, « le studio, un univers plus lumière, diapo et photos » — est RETIRÉE le
   5 oct. 2026 : « je veux qu'on revienne sur le côté 'art/galerie' et
   'diapo/photo' ; je ne veux pas ce fond ». Git la garde.) */

/* Le focus au clavier : la signature ne change pas de couleur, elle est
   cernée. */
.accueil-art__mot.a-motif:focus-visible .accueil-art__signature {
  outline: 2px solid var(--blue);
  outline-offset: 0.8rem;
  border-radius: 0.5rem;
}

/* L'admin tire une image au-dessus de la page : la signature est cernée — la
   lâcher la remplace. Son état (l'envoi, un refus) s'écrit dessous. */
.accueil-art__mot.is-depot .accueil-art__signature {
  outline: 2px dashed var(--blue);
  outline-offset: 0.8rem;
  border-radius: 0.5rem;
}

.accueil-art__depot {
  font-size: small;
  color: var(--ink-muted);
}

.accueil-art__depot:empty {
  display: none;
}

.accueil-art__depot.is-erreur {
  color: var(--red);
}

/* L'espacement des lettres, ICI, est celui du DÉPART de l'ouverture (2 oct. 2026 :
   « augmente l'espacement entre les lettres », puis « il y a un décrochage à
   l'affichage des mots ; une animation d'ouverture pour que ça ne flashe pas : les
   mots partent d'une ligne droite avec un letter-spacing basique et finissent en
   courbe avec le nouveau letter-spacing ») : la page peint les mots droits, à cet
   espacement ; sur un grand écran, envol_controller#_arquer les porte sur leur arc
   ET les espace à `ARC_ESPACEMENT` par le transform de chaque lettre — une
   transition, lettre après lettre : rien ne saute. Sur un écran étroit, pas d'arc :
   l'espacement large est donné ici (plus bas, dans la règle de l'écran étroit). */
.accueil-art__porte {
  color: var(--ink-muted);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  /* cinq tirets de chaque côté : le mot ne se plie pas sur un petit écran */
}

/* La figure où l'on est : son libellé à l'encre pleine. */
.accueil-art__porte[aria-current],
.accueil-art__design[aria-current] {
  color: var(--ink);
}

.accueil-art__mot:hover,
.accueil-art__mot:focus-visible,
.accueil-art__porte:hover,
.accueil-art__porte:focus-visible {
  color: var(--blue);
  outline: none;
}

/* Un dessin : posé au centre de la scène, déplacé par le contrôleur.
   `--vol` (0 posé, 1 au départ de l'envol) : son ombre s'éloigne et s'étale.
   Très grands (« grossis encore les images… tant pis si on ne voit pas
   vraiment les dessins ») : ils sortent du cadre, couvrent le haut et les
   côtés, et passent PAR-DESSUS le mot — le contrôleur ne règle que leur ordre
   entre eux. */
.accueil-art__dessin {
  --vol: 0;
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 2;
  display: block;
  will-change: transform;
}

.accueil-art__dessin {
  /* On la tire (envol_controller) : le doigt ne fait pas défiler la page, et
     le lien ne part pas en glisser-déposer natif (Chrome le tentait malgré
     `draggable="false"`). */
  touch-action: none;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  -webkit-user-drag: none;
}

.accueil-art__dessin.is-tenu {
  cursor: grabbing;
}

/* LA BARRE DES REPÈRES (l'admin) : « Mobile » — en bas à gauche, fixe. (Le HORS-CHAMP
   — la scène qui glissait à la molette, ses deux cadres en pointillé, « Recentrer » —
   est RETIRÉ le 14 oct. 2026 : « retire le fait de pouvoir avoir le hors-champ » ;
   git le garde.) */
/* LE DESSIN DU FOND (lot 21, #74 : « il sera possible de dessiner directement sur le
   fond ») : un canevas tendu sur la scène, AU RANG 0 — sous la signature, les titres et
   toutes les feuilles (controllers/fond, envol « Le fond ») ; il ne prend pas le
   pointeur. EN DESSIN (l'admin, `is-fond`), IL RESTE À SA PLACE et les feuilles restent
   nettes — la mise en page telle qu'elle sera (15 oct. 2026 : « quand j'écris sur le
   fond, je veux voir la mise en page des différents éléments » ; un voile clair les
   pâlissait, le dessin passé au-dessus, git le garde) : seul le calque du trait en
   cours (`--vif`), transparent, passe AU-DESSUS DE TOUT et prend le pointeur — la
   table du dessin ; le trait s'y voit pendant qu'on le tire, puis se pose dessous. */
.accueil-fond {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.accueil-art.is-fond .accueil-fond--vif {
  z-index: 9000;
  pointer-events: auto;
  touch-action: none;
  cursor: crosshair;
}

.accueil-art.is-fond.is-gomme .accueil-fond--vif {
  cursor: cell;
}

/* EN DESSIN — le boîtier comme le fond —, LA MÊME PALETTE AU MÊME ENDROIT (15 oct.
   2026 : « parfois le feutre n'est pas au même endroit, le fond non plus » — celle du
   boîtier suivait la feuille, celle du fond restait au bas de la scène) : le cartouche ne
   porte qu'elle, FIXÉ en bas au milieu de l'écran (envol#_cartoucheOutils) ; sa ligne (la
   taille écrite, les liens) se tait ; en dessin du fond, la couleur du boîtier n'a pas
   lieu d'être. */
.accueil-echelle--outils {
  position: fixed;
  left: 50%;
  top: auto;
  bottom: 12px;
  z-index: 9600;
}

.accueil-echelle--outils>.accueil-echelle__ligne {
  display: none;
}

.accueil-art.is-fond .accueil-feutre__nuancier,
.accueil-art.is-fond [data-feutre="cadre-blanc"],
.accueil-art.is-fond .accueil-feutre__ligne:last-child .accueil-feutre__blanc {
  display: none;
}

.accueil-reperes {
  position: fixed;
  left: 12px;
  bottom: 12px;
  z-index: 9500;
  display: flex;
  gap: 0.5rem;
}

.accueil-reperes button {
  padding: 0.35em 0.9em;
  border: 0;
  border-radius: 999px;
  background: var(--bg-card);
  box-shadow: 0 0.1em 0.6em rgba(18, 24, 44, 0.2), 0 0 0 1px rgb(200 72 52 / 0.4);
  font: inherit;
  font-size: small;
  color: var(--ink);
  cursor: pointer;
}

/* L'APERÇU MOBILE (envol_controller, `_ouvrirMobile`) : la page en cours dans un téléphone
   de 390 × 844, sur un voile, son nom au-dessus ; réduit s'il ne tient pas. */
.accueil-mobile {
  position: fixed;
  inset: 0;
  z-index: 100000;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 0.6rem;
  background: rgb(20 24 34 / 0.55);
  backdrop-filter: blur(2px);
}

.accueil-mobile__tete {
  display: flex;
  align-items: baseline;
  gap: 0.8rem;
  font-size: small;
  color: #f4f2ec;
}

.accueil-mobile__nom {
  font-weight: 600;
  letter-spacing: 0.08em;
}

.accueil-mobile__aide {
  opacity: 0.75;
}

.accueil-mobile__fermer {
  padding: 0.3em 0.9em;
  border: 0;
  border-radius: 999px;
  background: var(--bg-card);
  font: inherit;
  color: var(--ink);
  cursor: pointer;
}

.accueil-mobile__ecran {
  overflow: hidden;
  border-radius: 18px;
  box-shadow: 0 0 0 6px #1b1b1f, 0 1.2rem 3rem rgb(0 0 0 / 0.4);
  background: var(--bg);
}

.accueil-mobile__ecran iframe {
  display: block;
  border: 0;
  transform-origin: 0 0;
}

/* LA POIGNÉE QUI TOURNE UNE FEUILLE (l'admin ; 9 oct. 2026 : « je veux pouvoir décider de
   la rotation d'un objet » — envol_controller, « Tourner une feuille ») : un petit rond
   au coin haut droit de la feuille survolée, au-dessus de tout ; tiré, il la tourne. */
.accueil-poignee {
  position: absolute;
  z-index: 9000;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  translate: -50% -50%;
  background: var(--bg-card);
  box-shadow: 0 0.1em 0.6em rgba(18, 24, 44, 0.25), 0 0 0 1px rgb(0 0 0 / 0.08);
  font-size: medium;
  line-height: 1;
  color: var(--ink);
  cursor: grab;
  touch-action: none;
}

.accueil-tourne.is-tenue {
  cursor: grabbing;
}

/* « Passer par-dessus », « par-dessous » (9 oct. 2026), à gauche de la poignée. */
.accueil-dessus,
.accueil-dessous {
  cursor: pointer;
}

.accueil-poignee[hidden] {
  display: none;
}

/* LE VISITEUR NE TIRE RIEN (9 oct. 2026 : « si je suis en admin, j'ai la possibilité de
   choisir la place des objets ; sinon il est impossible de drag & drop » —
   envol_controller, « Les places ») : un lien qu'on clique, et le doigt fait défiler la
   page (une feuille au centre, sa page dessous). */
.accueil-art:not([data-envol-admin-value="true"]) :is(.accueil-art__dessin, .accueil-carte) {
  touch-action: auto;
  cursor: pointer;
}

/* JETÉE (l'admin, sur l'index — 2 oct. 2026 : « pour supprimer l'image, il faut
   drag & drop l'image de l'index vers le bas, en hors champ, avec au moins 50 % de
   l'objet, puis une boîte de confirmation » ; envol_controller, `_jetee`) : tirée à
   moitié sous le bas de l'écran, la feuille pâlit, le temps qu'on confirme. */
.accueil-art__dessin.is-jetee,
.accueil-carte.is-jetee {
  filter: grayscale(0.7);
  opacity: 0.55;
}

/* REMONTÉE (au tas : tirée à moitié au-dessus du haut de l'écran, elle repart
   dans les douze — « comme pour delete mais vers le haut » ; envol_controller,
   `_montee`) : elle s'éclaire un rien. */
.accueil-art__dessin.is-montee,
.accueil-carte.is-montee {
  filter: brightness(1.08) saturate(1.1);
}

/* PLUS DE DIAPOSITIVES BLANCHES (7 oct. 2026 : « il faut retirer l'idée des diapos
   blanches si elles ne sont plus sur la home ») : un projet qui n'est pas à la une
   (archivé, ou sans couverture) a le cadre graphite de tous ; c'est la GOMMETTE
   BLEUE, sur ceux qui le sont, qui fait la différence (plus bas, « Les gommettes »).
   Le cadre de plastique blanc cassé a vécu ce jour-là ; git le garde. */

/* L'ADMIN DÉPOSE DES DESSINS sur l'index (2 oct. 2026 : « pour uploader des
   images, il faut drag & drop une image dans l'index » ; envol_controller) :
   pendant le glisser, un cadre sur tout l'écran dit ce qui va arriver — au-dessus
   des feuilles et des titres ; le temps de l'envoi, le curseur attend. */
.accueil-art.is-depot::after {
  content: "Déposer : de nouveaux dessins de l'année";
  position: fixed;
  inset: 0.6rem;
  z-index: 6000;
  display: grid;
  place-content: start center;
  padding-top: 0.7rem;
  border: 1.5px dashed var(--ink);
  border-radius: 10px;
  font-size: x-small;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
  pointer-events: none;
}

.accueil-art.is-tas.is-depot::after {
  content: "Déposer : de nouveaux dessins, dans les autres";
}

.accueil-art.is-envoi {
  cursor: progress;
}

/* LA TAILLE D'UN TIRAGE 13 × 18 (8 oct. 2026 : « j'aimerais que les dessins soient
   plus grands ; qu'ils aient la taille de 13 cm / 18 cm » — ils faisaient 75 % de la
   hauteur de l'écran) : chaque dessin dans un cadre de 13 × 18 cm, à son format (un
   portrait plus étroit garde ses 18 cm de haut, un carré fait 13 × 13) ; un paysage,
   18 × 13 (`is-paysage`, posée par envol_controller quand son fichier arrive). En cm
   CSS, comme les 5 cm des diapositives. LA TAILLE EST ÉCRITE, pas laissée au
   fichier : `--a`, le format du fichier (largeur / hauteur, posé par
   envol_controller#_format quand il arrive ; 13 / 18 en attendant) — sans quoi une
   image pas encore arrivée n'avait pas de taille, et la feuille se mesurait vide.
   Jamais plus large que 75 % de l'écran. Sur un écran étroit, la hauteur que le
   serpentin choisit (plus bas). */
.accueil-art__dessin img {
  --a: 0.7222;
  --hauteur: min(18cm, calc(13cm / var(--a)), calc(75vw / var(--a)));
  display: block;
  width: calc(var(--hauteur) * var(--a));
  height: var(--hauteur);
  object-fit: contain;
}

.accueil-art__dessin.is-paysage img {
  --hauteur: min(13cm, calc(18cm / var(--a)), calc(75vw / var(--a)));
}

/* Le focus au clavier : sur le lien — l'image, masquée par le bord du papier,
   perdrait son contour. */
.accueil-art__dessin:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 4px;
}

/* ── Les calques ────────────────────────────────────────────────────────
   Les CALQUES d'un dessin (cf. `Image#base`), comme sur le mur — la soie les
   peint en papier calque (soie_supports.js, `CALQUE` et `PILE` ; soie.md, « Les
   couches ») ; ici, les mêmes lois en CSS, pour les dessins de l'accueil ET la
   copie du passage (controllers/passage) :
     · le DÉPOLI : sous un calque, le dessin du dessous se lit flou (`diffus`,
       2,5 mm ≈ 0,6 % de la hauteur de la feuille : `.sous-calque`) ;
     · le VOILE : la feuille de calque blanchit ce qu'elle couvre (`voile` 0,34
       au contact, sa teinte [0,985 ; 0,985 ; 0,975] : `.calque-voile`) ;
     · l'OMBRE DU TRAIT sur le dessous : décalée dans l'axe des ombres, floue,
       pâle (`PILE.ombre` 0,3 : `.calque-ombre`) ;
     · le TRAIT se multiplie (le POINT BLANC d'un calque scanné, `PILE.blanc`
       0,9 : ce qui est plus clair compte pour du papier nu — `brightness`).
   Tous dans la boîte du dessin, au même cadrage (aucun recalage), du bas vers le
   haut ; la feuille est une couche à part (son z-index) : ils ne se mêlent qu'à
   leur dessin. */
.accueil-art__dessin img.sous-calque,
.passage-copie img.sous-calque {
  filter: blur(calc(var(--h, 675px) * 0.006));
}

.calque-voile,
.accueil-art__dessin img.calque-ombre,
.accueil-art__dessin img.calque-trait,
.passage-copie .calque-voile,
.passage-copie img.calque-ombre,
.passage-copie img.calque-trait {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: contain;
  pointer-events: none;
}

/* LA PLACE D'UN CALQUE (`--ux` `--uy`, Image#place — l'admin l'a tiré sur le mur,
   calque_controller, 2 oct. 2026) : le voile, l'ombre et le trait se décalent
   ensemble, en parts de la feuille — comme sur le mur, à toute taille. */
.calque-voile {
  display: block;
  background: rgb(251 251 249);
  opacity: 0.34;
  transform: translate(calc(var(--ux, 0) * 100%), calc(var(--uy, 0) * 100%));
}

.accueil-art__dessin img.calque-ombre,
.passage-copie img.calque-ombre {
  mix-blend-mode: multiply;
  opacity: 0.3;
  transform: translate(calc(var(--ux, 0) * 100%), calc(var(--uy, 0) * 100%)) translate(1px, 1.3px);
  filter: brightness(1.11) blur(1.2px);
}

.accueil-art__dessin img.calque-trait,
.passage-copie img.calque-trait {
  mix-blend-mode: multiply;
  filter: brightness(1.11);
  transform: translate(calc(var(--ux, 0) * 100%), calc(var(--uy, 0) * 100%));
}

/* ── Ombres et lumières ─────────────────────────────────────────────────
   La LUMIÈRE est celle de la zone Art (la soie, soie_gl.js) : elle vient d'en
   haut à gauche, chaude (`CHAUD`).
   Les OMBRES sont celles d'une vraie feuille sur une table (« plus réalistes » :
   deux ombres, qui suivent la hauteur, moins colorées) — elles tombent en bas à
   droite, et `--vol` est la hauteur de la feuille (0 posée ; soulevée, en vol) :
     · l'ombre de CONTACT, au ras de la feuille : L'ÉPAISSEUR DU PAPIER — un
       filet, un demi-pixel, net (« des ombres cohérentes avec l'épaisseur des
       feuilles ; aujourd'hui trop grossières ») — qui s'efface dès que la
       feuille quitte la table ;
     · l'ombre DIFFUSE : posée, presque rien (une feuille à plat ne projette
       pas d'ombre : 2,5 px à peine) ; soulevée, elle s'éloigne, s'étale, se
       fonce un peu, puis pâlit quand la feuille est loin.
   Un gris à peine bleuté, sans la couleur du dessin. Portées par la feuille
   elle-même (`box-shadow`). Ce sont celles d'un PAPIER : les diapositives, un
   objet de 2 mm, ont les leurs (« Le design : les cartes », plus bas). */
.feuille {
  --v: var(--vol, 0);
  box-shadow:
    calc(0.35px + var(--v) * 5px) calc(0.5px + var(--v) * 7px) calc(0.6px + var(--v) * 7px) rgb(22 27 38 / calc(0.3 * (1 - min(1, var(--v) * 2.5)))),
    calc(0.6px + var(--v) * 34px) calc(0.9px + var(--v) * 42px) calc(2.5px + var(--v) * 44px) rgb(22 27 38 / calc(0.08 + 0.1 * min(1, var(--v) * 3) * (1 - var(--v) * 0.6)));
}

/* La lumière chaude, d'en haut à gauche (`::after`), et le bord (`::before`). */
.feuille::after,
.feuille::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
}

.feuille::after {
  background: linear-gradient(140deg, rgb(255 247 224 / 0.16), rgb(255 247 224 / 0) 45%, rgb(40 90 170 / 0.05));
}

/* LE BORD DU PAPIER (les dessins, et la copie du passage) : celui du show — la
   FRANGE du papier aquarelle (les barbes qui mangent le bord : `--bord`, un
   masque, sur l'image, ses calques et sa lumière) et sa TRANCHE (l'épaisseur,
   claire du côté de la lumière : `--tranche`, une image posée dessus), calculés
   par controllers/bord_papier aux formules de la soie. Les ombres restent sur
   la feuille même, hors du masque. */
.papier img,
.papier .calque-voile,
.papier::after {
  -webkit-mask: var(--bord, none) 0 0 / 100% 100% no-repeat;
  mask: var(--bord, none) 0 0 / 100% 100% no-repeat;
}

.papier::before {
  z-index: 1;
  background: var(--tranche, none) 0 0 / 100% 100% no-repeat;
}

/* ── Vers le show d'un dessin, et retour (envol_controller#_partir, _regagner)
   Il voyage au milieu, droit, à la taille de l'image seule du mur ; le reste
   s'efface — puis on est sur son permalien. Au retour, l'inverse. */
/* D'UN SHOW VERS UNE FIGURE (envol#_vue, `is-revient`) : ce qui est à l'écran le reste le
   temps que la figure pose ses classes — une règle de figure, appliquée entre les deux,
   l'aurait effacé puis fait revenir en fondu. */
.accueil-art .is-revient {
  opacity: 1 !important;
}

/* Le fondu, SEULEMENT le temps d'ouvrir et de refermer (`is-fondu`, posée par
   le contrôleur) — PIÈGE : toujours là, il faisait fondre au démarrage les
   feuilles que le contrôleur cache en attendant leur envol, le « flash ». */
.accueil-art.is-fondu .accueil-art__dessin,
.accueil-art.is-fondu .accueil-carte,
.accueil-art.is-fondu .accueil-art__design,
.accueil-art.is-fondu .accueil-art__galerie,
.accueil-art.is-fondu .accueil-serie {
  transition: opacity 450ms ease;
}

/* Le TITRE « Art » reste au centre dans toutes les figures (« pas besoin de le
   faire disparaître ») : seul le lien du design s'efface, avec les
   diapositives — sauf dans la leur (`is-diapos`, l'index des projets), où ce
   sont les dessins qui s'effacent. */
.accueil-art.is-show .accueil-art__dessin:not(.is-ouverte),
.accueil-art.is-show .accueil-carte,
.accueil-art.is-range .accueil-carte,
.accueil-art:not(.is-tas) .accueil-art__autre:not(.is-exposee):not(.is-autour):not(.is-sur-figure):not(.is-sur-home),
.accueil-art:is(.is-range, .is-diapos) .accueil-art__autre.is-sur-home:not(.is-exposee):not(.is-autour):not(.is-sur-figure),
/* LA HOME A SES DESSINS (#86, 15 oct. 2026 : « la sélection de la galerie n'est pas
   forcément celle sur la home ») : en vrac, seuls ceux de sa liste (`is-sur-home`,
   envol#_surHome) — les douze restent à l'index. */
.accueil-art:not(.is-range):not(.is-tas):not(.is-diapos):not(.is-choix):not(.is-projet) .accueil-art__dessin:not(.is-sur-home):not(.is-exposee):not(.is-sur-figure),
.accueil-art.is-tas .accueil-carte,
.accueil-art.is-diapos .accueil-art__dessin:not(.accueil-art__autre):not(.is-sur-figure),
.accueil-art:not(.is-diapos) .accueil-carte--vide,
.accueil-art:not(.is-diapos) .accueil-carte--archive:not(.is-autour):not(.is-exposee):not(.is-choisie),
/* (au centre, il se voit — 15 oct. 2026 : un projet archivé a son show lui aussi) */
.accueil-art.is-show .accueil-art__galerie,
.accueil-art.is-show .accueil-art__design,
.accueil-art:not(.is-range):not(.is-tas) .accueil-serie--galerie,
.accueil-art.is-show .accueil-serie,
.accueil-art:not(.is-diapos) .accueil-studio {
  opacity: 0;
  pointer-events: none;
}

/* L'ENTOURAGE CHOISI (lot 14, 14 oct. 2026 : « il faut que je puisse choisir ce qui
   va aller autour de l'image au centre » — #60 à #62) : une feuille au centre, SEULS
   les objets collés pour ce show se voient autour (`is-autour`, envol#_entourer) ;
   sans choix, le centre est seul. Les autres et les archivées choisies se montrent
   (le `:not(.is-autour)` du bloc du dessus). EN MODE CHOIX (lot 17, #67) : le centre,
   cerné, ET LES CHOISIS — on les place (2026-10-14 au soir : « quand je suis en
   entourage, je veux pouvoir placer les éléments choisis » ; le centre-seul du
   lot 17, git le garde) — le reste est en vignettes dans la boîte. SUR LA HOME AUSSI
   (15 oct. 2026 : « l'entourage sur la home doit se comporter comme le reste ») : ce
   qui y est — à la une, collé — reste à sa place (`is-choisie`, envol#_marquerChoisies). */
.accueil-art.is-projet .accueil-art__dessin:not(.is-exposee):not(.is-autour),
.accueil-art.is-projet .accueil-carte:not(.is-exposee):not(.is-autour),
.accueil-art.is-choix .accueil-art__dessin:not(.is-exposee):not(.is-autour):not(.is-choisie),
.accueil-art.is-choix .accueil-carte:not(.is-exposee):not(.is-autour):not(.is-choisie) {
  opacity: 0;
  pointer-events: none;
}

/* Un projet SANS COUVERTURE (l'admin), sur la planche seule : l'écran éteint, et son
   titre sur le menton — sans image, rien d'autre ne le reconnaît. */
.accueil-carte--vide .accueil-carte__image {
  background: var(--papier-eink);
}

/* « DÉMARRER UN PROJET » (7 oct. 2026 : « des diapos vides pour que les lecteurs
   viennent cliquer dessus et démarrer un projet en ouvrant une correspondance ») :
   UN PICPAK DONT L'ÉCRAN L'ÉCRIT (8 oct. 2026, #31) — « Démarrer un projet » en
   grand, à l'encre e-ink sur le gris papier de l'écran, comme un message de
   l'appareil ; la gommette orange sur le menton. (Polaroid, c'était une photo pas
   développée ; diapositive, un cadre sans film — git les garde.) */
.accueil-carte--amorce .accueil-carte__image {
  display: grid;
  place-items: center;
  background: var(--papier-eink);
}

/* SON IMAGE, à la place du message (8 oct. 2026 : « mettre une autre image que
   Démarrer un projet » ; `accueil-carte--ecran`, Amorce#image) ; et, un fichier tiré
   au-dessus de lui (l'admin), il se cerne. */
.accueil-carte--ecran .accueil-carte__message {
  display: none;
}

.accueil-carte--amorce.is-depot {
  outline: 2px dashed color-mix(in lab, var(--ink) 55%, transparent);
  outline-offset: 4px;
}

.accueil-carte--amorce .accueil-carte__titre {
  max-width: 80%;
  margin: 0;
  font-size: large;
  font-weight: 800;
  letter-spacing: 0.06em;
  line-height: 1.15;
  white-space: normal;
  color: #262624;
  text-shadow: 0 0 0.4px rgb(38 38 36 / 0.6);
}

/* LA GOMMETTE (7 oct. 2026 : « je ne veux qu'une seule diapo démarrer un projet et
   je veux qu'elle ait une petite gommette rouge sur elle » ; puis « la gommette est
   laide, je veux qu'elle soit plus réaliste et d'un orange fluo plutôt ») : une
   PASTILLE DE PAPIER FLUO de `--gommette` (6 mm), collée au coin bas gauche du cadre
   — là où l'on repère une vraie diapo. Du papier, pas un bouton : MAT (aucun
   reflet), une couleur pleine (`--fluo`), un GRAIN de papier très fin (un bruit
   SVG, en points sombres), le BORD COUPÉ du papier qui prend la lumière en haut à
   gauche et s'ombre en bas à droite (la lumière du cadre), l'OMBRE de son épaisseur
   — un dixième de millimètre : courte, serrée — et, parce que le papier est
   fluorescent, un léger HALO de sa propre couleur sur le cadre. (Une première
   gommette rouge, bombée d'un reflet, a vécu une heure.) */
.accueil-carte__gommette,
.accueil-art__gommette,
.accueil-carte__une,
.accueil-gommettes__point,
.accueil-vignette__gommette,
.gommette-vol {
  --gommette: calc(6 * var(--mm));
  --fluo: #ff6a13;
  /* l'orange fluo du papier */
  --halo: rgb(255 106 19 / 0.28);
  /* le halo de sa couleur : un papier fluorescent */
  position: absolute;
  left: calc(3.5 * var(--mm));
  bottom: calc(3.5 * var(--mm));
  z-index: 1;
  width: var(--gommette);
  height: var(--gommette);
  border-radius: 50%;
  background:
    url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSc0OCcgaGVpZ2h0PSc0OCc+PGZpbHRlciBpZD0nZyc+PGZlVHVyYnVsZW5jZSB0eXBlPSdmcmFjdGFsTm9pc2UnIGJhc2VGcmVxdWVuY3k9JzEuMScgbnVtT2N0YXZlcz0nMicgc2VlZD0nMycgc3RpdGNoVGlsZXM9J3N0aXRjaCcvPjxmZUNvbG9yTWF0cml4IHZhbHVlcz0nMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMC4wOSAwIDAgMCAwJy8+PC9maWx0ZXI+PHJlY3Qgd2lkdGg9JzQ4JyBoZWlnaHQ9JzQ4JyBmaWx0ZXI9J3VybCgjZyknLz48L3N2Zz4=") 0 0 / 48px 48px repeat,
    var(--fluo);
  box-shadow:
    inset calc(0.12 * var(--mm)) calc(0.12 * var(--mm)) calc(0.1 * var(--mm)) rgb(255 255 255 / 0.35),
    inset calc(-0.12 * var(--mm)) calc(-0.12 * var(--mm)) calc(0.1 * var(--mm)) rgb(0 0 0 / 0.2),
    calc(0.08 * var(--mm)) calc(0.15 * var(--mm)) calc(0.25 * var(--mm)) rgb(0 0 0 / 0.32),
    0 0 calc(0.9 * var(--mm)) var(--halo);
  pointer-events: none;
}

/* LES GOMMETTES BLEUES : « À LA UNE » (7 oct. 2026 : « je veux avoir une gommette
   bleue sur les dessins de la home quand on affiche tous les dessins », puis « même
   système de gommettes pour les projets ; je veux pouvoir drag & drop une gommette
   sur une diapo ou sur un dessin pour décider si c'est ce dessin à la une sur mon
   site ou non ») : la même pastille de papier que l'orange, BLEUE (le bleu de la
   charte) et mate — pas fluo, donc sans halo —, au coin bas gauche, par-dessus le
   papier (hors du masque de son bord). Là où l'on voit TOUT — « Voir les X
   dessins » (`is-tas`), la planche du studio (`is-diapos`) —, sur ce qui est à la
   une seulement : les douze (pas `.accueil-art__autre`), les projets pas archivés.
   À 6 mm À L'ÉCRAN, quelle que soit l'échelle de la feuille (`--g`, posée par
   envol_controller). */
.accueil-art__gommette,
.accueil-carte__une,
.accueil-gommettes__point,
.accueil-vignette__gommette,
.gommette-vol {
  --fluo: var(--blue);
  --halo: transparent;
}

.accueil-art__gommette,
.accueil-carte__une {
  --mm: calc(1mm / var(--g, 1));
  z-index: 3;
  opacity: 0;
  transition: opacity 0.3s ease;
}

.accueil-art.is-tas .accueil-art__dessin:not(.accueil-art__autre) .accueil-art__gommette,
.accueil-art.is-diapos .accueil-carte:not(.accueil-carte--archive) .accueil-carte__une {
  opacity: 1;
}

/* LES OBJETS (lot 18, 14 oct. 2026, #70/#71 : « les notes en deviennent un, les
   croquis aussi ») : des feuilles de la scène comme les autres — cachées d'office,
   montrées par les ENTOURAGES (celui de la home, celui d'un show : envol les
   découvre, `_visibleEn` / `is-autour`). Le CROQUIS : son image, au bord de papier
   des dessins (envol#_border), à une taille d'étude (plus petit qu'un dessin) ;
   le PAPIER : la feuille à petits carreaux de 82 × 128 mm du cahier (ses règles,
   re-scopées `:is(.cahier-scene, .accueil-objet)` dans cahier.css), paginée
   (papier_objet_controller). */
.accueil-objet {
  --vol: 0;
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 2;
  display: block;
  opacity: 0;
  pointer-events: none;
  will-change: transform;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-user-drag: none;
}

/* Collé (sur la home : son entourage, `is-colle` — envol#_collerObjets ; dans un
   show : `is-autour`), il se voit — et l'admin le tire (le visiteur, lui, tourne
   les pages d'un papier). EN MODE CHOIX AUSSI (2026-10-14 au soir : on y place
   les choisis) : les `:not(.is-choix)` sont tombés. */
.accueil-art.is-projet .accueil-objet.is-autour,
.accueil-art:not(.is-projet) .accueil-objet.is-sur-figure,
/* (posé sur une figure, lot 23) */
.accueil-art:not(.is-projet):not(.is-range):not(.is-tas):not(.is-diapos) .accueil-objet.is-colle {
  opacity: 1;
  pointer-events: auto;
}

.accueil-art[data-envol-admin-value="true"] .accueil-objet {
  cursor: grab;
}

/* L'ADMIN ÉCRIT SUR LE PAPIER (14 oct. 2026 : « comment je fais pour éditer une
   note ? ») : le champ prend le curseur du texte — on tire la feuille par ses
   marges ; ✕ au coin, au survol seulement (il couvrirait une voisine). */
.accueil-objet .cahier__champ--texte {
  display: block;
  /* (en ligne, l'espace sous la ligne de base faussait les pages de 5 px) */
  width: 100%;
  border: 0;
  background: transparent;
  resize: none;
  cursor: text;
}

.accueil-objet__retirer-form {
  position: absolute;
  top: 0.3em;
  right: 0.3em;
  z-index: 1;
  margin: 0;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.accueil-objet:hover .accueil-objet__retirer-form,
.accueil-objet:focus-within .accueil-objet__retirer-form {
  opacity: 1;
}

.accueil-objet__retirer {
  background: color-mix(in lab, var(--bg-card) 80%, transparent);
}

/* LE STICKER-LIEN (15 oct. 2026 : « un sticker qui permet d'aller directement à
   l'accueil » ; 18 oct. : « … sur mon CV ») : la pastille « Lien », au coin haut gauche
   du sticker (l'admin y choisit sa destination — choisie, à l'encre) ; un sticker qui a
   un lien (`data-lien`) se clique, pour tout le monde. */
.accueil-objet[data-lien] {
  cursor: pointer;
}

.accueil-objet__lien {
  position: absolute;
  top: 0.3em;
  left: 0.3em;
  z-index: 1;
  padding: 0.1em 0.45em;
  border: 0;
  border-radius: 999px;
  background: color-mix(in lab, var(--bg-card) 80%, transparent);
  font: inherit;
  font-size: small;
  color: var(--ink-muted);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.accueil-objet:hover .accueil-objet__lien,
.accueil-objet:focus-within .accueil-objet__lien,
.accueil-objet__lien[data-choisi="true"] {
  opacity: 1;
}

.accueil-objet__lien {
  max-width: calc(100% - 0.6em);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* LE MENU DES LIENS (pages/accueil/_liens, controllers/menu_liens) : le plan du site
   (site_menu.css) — ses tiroirs un peu plus larges, les titres des dessins et des projets
   y tiennent sur une ligne de plus. */
.menu-liens .site-menu__sub {
  max-width: 18rem;
}

.accueil-objet__lien[data-choisi="true"] {
  background: var(--ink);
  color: var(--bg-card);
}

.accueil-objet[data-lien] {
  cursor: pointer;
}

.accueil-objet[data-lien] img {
  cursor: pointer;
}

/* LA BANDE D'UN SHOW DU STUDIO (15 oct. 2026 : « une bande avec la photo de cover tramée
   qui prend toute la largeur, dans le but d'inciter le lecteur à scroller vers le bas » ;
   envol#_poserBandeau) : la couverture du projet en TRAME de Bayer (eink#tramer : des
   points AUX COULEURS de la couverture, le fond de la page au travers, nets), pleine
   largeur ; posée, elle S'AFFICHE EN E-INK (16 oct. ; `is-eink` le temps de la série).
   AU DÉFILEMENT, ELLE PREND TOUT L'ÉCRAN ET S'Y ARRÊTE (18 oct. 2026 : « au scroll, la
   trame doit prendre toute la hauteur de l'écran et s'arrêter une fois que l'écran est
   couvert ») : HORS DE LA SCÈNE, dans `main.accueil`, juste après elle — haute d'un
   écran, remontée de `--bande-champ` (2 cm dans le premier écran) ; en descendant elle
   monte, puis COLLE en haut (`sticky`) jusqu'au bout de la page. LES PICPAK PASSENT
   DESSOUS (18 oct. 2026 : « les PicPak, quand ils arrivent et partent, doivent passer
   sous le titre et la trame ») — elle est après la scène, positionnée : devant elle ;
   la page du projet, elle, passe par-dessus (plus bas, « La page du projet passe
   par-dessus la bande »). ELLE CHANGE AVEC SON PICPAK, en balayant de haut en bas
   (envol#_balayerBandeau, eink#balayer). (Elle a été, du 15 au 16 oct., un bloc de 1 à
   20 cm dans la scène.) Rien pendant un mode (le choix, un dessin en cours). */
.accueil.a-bandeau {
  --bande-champ: 2cm;
  --bande-suite: 3cm;
  /* la page du projet commence 3 cm sous le bord du premier écran */
  --entete-h: 6.5rem;
  /* le bandeau blanc du nom */
  /* (La bande ne colle QUE DANS `main` : il lui faut sa hauteur et un écran de plus —
     PIÈGE, mesuré : un projet court, une image, finissait la page avant le bas de la
     bande, qui ne collait jamais.) */
  min-height: calc(300dvh - var(--bande-champ));
}

.accueil-bandeau {
  position: sticky;
  top: 0;
  z-index: 1;
  flex: none;
  display: block;
  width: 100%;
  height: 100dvh;
  margin-top: 0;
  /* (le bandeau du nom, juste avant, remonte les deux au bas du premier écran) */
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.accueil-bandeau__trame {
  display: block;
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
  opacity: 0.85;
}

.accueil:has(> .accueil-art:is(.is-choix, .is-crayon, .is-fond))>.accueil-bandeau {
  opacity: 0;
  pointer-events: none;
}

/* SON NOM, DANS UN BANDEAU BLANC (18 oct. 2026 : « le titre reste en haut dans un bandeau
   blanc et les éléments viennent scroller dessous » — « pleine largeur, nom et fiche » ;
   puis « au départ après les PicPak, et sticky en haut quand on scroll ») : dans le flux,
   juste après la scène, REMONTÉ au bas du premier écran (sa hauteur et la part visible
   de la bande : il est juste au-dessus d'elle) ; en descendant, il COLLE en haut
   (`sticky`), au-dessus de la scène et de la page (qui passe dessous) ; sous la pastille
   Menu de l'admin. Le nom en e-ink, la fiche dessous (envol#_poserBandeau ; les règles
   de `.accueil-projet__titre` et `__fiche`). Les PicPak passent DESSOUS (pleine largeur,
   compté dans le centre libre, il en faisait tout l'écran : les feuilles autour sortaient
   de l'écran). Un dessin, lui, garde son nom en bas. */
.accueil-entete {
  position: sticky;
  top: 0;
  z-index: 50;
  flex: none;
  box-sizing: border-box;
  height: var(--entete-h);
  margin-top: calc(-1 * (var(--entete-h) + var(--bande-champ)));
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.2rem;
  padding: 0 1rem;
  overflow: hidden;
  /* (« le blanc est trop blanc », puis « trop foncé », 18 oct. 2026 — `--bg-card`, un
     blanc pur, puis le gris papier e-ink, #e7e6e0) : le fond de la page. */
  background: var(--bg);
  pointer-events: none;
}

/* LES STICKERS (lot 19, #72 : « une image à toi, détourée ») : une feuille LÉGÈRE —
   l'image telle quelle, sans bord de papier aquarelle ni ombre de feuille ; le
   LISERÉ BLANC d'un autocollant découpé (quatre ombres pleines, sans flou, qui
   suivent la forme détourée) et une ombre COURTE, collée à la table — soulevée
   (tenue), elle s'éloigne un peu. À une taille d'autocollant : 7 cm au plus. */
.accueil-objet--sticker img {
  display: block;
  max-width: 7cm;
  max-height: 7cm;
  width: auto;
  height: auto;
  filter:
    drop-shadow(1.5px 0 0 #fff) drop-shadow(-1.5px 0 0 #fff) drop-shadow(0 1.5px 0 #fff) drop-shadow(0 -1.5px 0 #fff) drop-shadow(0 1px 1.2px rgb(18 24 44 / 0.28));
  transition: filter 0.2s ease;
}

.accueil-objet--sticker.is-tenu img {
  filter:
    drop-shadow(1.5px 0 0 #fff) drop-shadow(-1.5px 0 0 #fff) drop-shadow(0 1.5px 0 #fff) drop-shadow(0 -1.5px 0 #fff) drop-shadow(0 6px 8px rgb(18 24 44 / 0.22));
}

.accueil-objet--croquis img {
  display: block;
  max-width: 10cm;
  max-height: 14cm;
  width: auto;
  height: auto;
}

/* LE MODE CHOIX DE L'ENTOURAGE (lot 17, #67 à #69 : « un écran plus simple avec d'un
   côté les images et de l'autre les projets ; plus tard il y aura d'autres catégories ;
   il est possible de scroller dans les différentes catégories ; le même système que
   quand je mets des gommettes pour la home ») : le centre reste au milieu, cerné
   (`data-centre`) ; UNE SEULE BOÎTE DE VIGNETTES À ONGLETS sur le flanc gauche
   (2026-10-14 au soir : « est-ce que tu peux mettre tous les panneaux dans une seule
   boîte avec des tabs ? » — les panneaux par flanc du lot 17, git les garde) :
   `.accueil-categorie`, envol#_ouvrirCategories — un onglet par catégorie, un seul
   panneau montré, une planche contact qui défile —, la gommette bleue sur les
   vignettes de l'entourage (`data-choisie`), et LA RÉSERVE de la home en haut à
   gauche : on tire, on pose. (La grille mêlée du lot 14, où le clic collait, a vécu
   la journée ; git la garde.) */
.accueil-art.is-choix [data-centre] {
  outline: 2px dashed color-mix(in lab, var(--ink) 55%, transparent);
  outline-offset: 4px;
}

.accueil-categories {
  position: fixed;
  inset: 0;
  z-index: 2050;
  display: flex;
  justify-content: flex-start;
  padding: 104px 16px 88px;
  pointer-events: none;
}

.accueil-categorie {
  display: flex;
  flex-direction: column;
  width: clamp(160px, 20vw, 280px);
  max-height: 100%;
  border-radius: 8px;
  background: color-mix(in lab, var(--bg-card) 92%, transparent);
  backdrop-filter: blur(6px);
  box-shadow: 0 0.15em 0.9em rgba(18, 24, 44, 0.16), inset 0 0 0 1px rgb(0 0 0 / 0.05);
  pointer-events: auto;
}

.accueil-categorie__onglets {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: 8px 10px 6px;
}

.accueil-categorie__onglet {
  border: 0;
  border-radius: 0.35em;
  padding: 0.3em 0.7em;
  background: none;
  color: var(--ink-muted);
  font-size: x-small;
  font-weight: 600;
  letter-spacing: 0.06em;
  cursor: pointer;
}

.accueil-categorie__onglet[aria-selected="true"] {
  background: rgb(0 0 0 / 0.06);
  color: var(--ink);
}

.accueil-categorie__defile {
  overflow-y: auto;
  overscroll-behavior: contain;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(58px, 1fr));
  gap: 8px;
  padding: 0 10px 10px;
}

/* LE PANNEAU DE DROITE (lot 22, #79 : les objets contextuels — « Ce show », « La
   home ») : en face de la boîte, la même allure ; « + Note », « + Croquis »,
   « + Sticker » (#81) ; chaque vignette a son ✕ (#80), au survol. */
.accueil-categorie--contexte {
  margin-left: auto;
}

.accueil-categorie__titre {
  margin: 0;
  padding: 0.7em 1em 0.2em;
  font-size: x-small;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--ink);
}

.accueil-categorie__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2em 0.8em;
  padding: 0.3em 1em 0.6em;
}

.accueil-categorie__action {
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-muted);
  font: inherit;
  font-size: x-small;
  letter-spacing: 0.06em;
  cursor: pointer;
}

.accueil-categorie__action:hover {
  color: var(--ink);
}

.accueil-vignette__retirer {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 1.4em;
  height: 1.4em;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: color-mix(in lab, var(--bg-card) 85%, transparent);
  color: var(--ink-muted);
  font-size: x-small;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.accueil-vignette:hover .accueil-vignette__retirer,
.accueil-vignette__retirer:focus-visible {
  opacity: 1;
}

.accueil-categorie__defile[hidden] {
  display: none;
  /* (le `display: grid` du dessus l'emporterait sur `hidden`) */
}

.accueil-vignette {
  --mm: 0.7mm;
  position: relative;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  padding: 4px;
  border-radius: 6px;
  background: rgb(0 0 0 / 0.04);
}

.accueil-vignette img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.accueil-vignette__nom {
  font-size: xx-small;
  text-align: center;
  color: var(--ink-muted);
  overflow: hidden;
}

.accueil-vignette__gommette {
  left: calc(1.5 * var(--mm));
  bottom: calc(1.5 * var(--mm));
  opacity: 0;
  transition: opacity 0.3s ease;
}

/* La pastille bleue ne fait plus que DIRE « il y est » (15 oct. 2026 : on tire la
   vignette elle-même, plus la gommette) — elle ne prend pas le pointeur. */
.accueil-vignette[data-choisie] .accueil-vignette__gommette {
  opacity: 1;
  pointer-events: none;
}

/* LA VIGNETTE SE TIRE SUR LA SCÈNE (15 oct. 2026 : « est-ce que je peux juste drag & drop
   depuis le panneau ? » — envol#_prendreVignette) : sa copie suit la main
   (`.vignette-vol`) ; au-dessus de la boîte, elle pâlit (relâchée là : rien). Un objet
   de la scène ramené SUR la boîte la cerne (`is-cible-retour`) : lâché, il sort. */
.accueil-vignette[data-ref] {
  cursor: grab;
  touch-action: none;
}

.vignette-vol {
  position: fixed;
  z-index: 9800;
  pointer-events: none;
  translate: -50% -50%;
  rotate: -3deg;
  background: var(--bg-card);
  box-shadow: 0 0.6em 1.4em rgba(18, 24, 44, 0.22);
  transition: opacity 0.12s ease;
}

.vignette-vol.is-dans-boite {
  opacity: 0.45;
}

.accueil-categorie.is-cible-retour {
  outline: 2px dashed color-mix(in lab, var(--ink) 55%, transparent);
  outline-offset: 4px;
}

.accueil-vignette.sans-gommette .accueil-vignette__gommette {
  opacity: 0;
  transition: none;
}

/* La case « + » des stickers (lot 19, #76) : on y dépose (un clic ouvre le choix
   des fichiers). */
.accueil-vignette--depot {
  border: 1px dashed color-mix(in lab, var(--ink) 35%, transparent);
  background: none;
  cursor: pointer;
}

.accueil-vignette--depot:hover {
  border-color: color-mix(in lab, var(--ink) 65%, transparent);
}

.accueil-vignette__plus {
  font-size: x-large;
  line-height: 1;
  color: var(--ink-muted);
}

.accueil-vignette.is-cible-gommette {
  outline: 2px solid rgb(19 112 237 / 0.7);
  outline-offset: 1px;
}

/* La barre du mode : un mot d'aide et « Terminer », en bas à droite, sobres —
   au-dessus des feuilles, sous la loupe. */
.accueil-choix {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 2100;
  display: flex;
  align-items: center;
  gap: 1em;
  max-width: min(46ch, calc(100vw - 32px));
  padding: 0.6em 1em;
  border-radius: 8px;
  background: color-mix(in lab, var(--bg-card) 92%, transparent);
  backdrop-filter: blur(6px);
  box-shadow: 0 0.15em 0.9em rgba(18, 24, 44, 0.16), inset 0 0 0 1px rgb(0 0 0 / 0.05);
  color: var(--ink);
  font-size: small;
}

/* Ce qu'on compose, nommé (envol#_barreChoix : « Entourage — Wassim », « — la home »). */
.accueil-choix__texte {
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--ink);
}

.accueil-choix__terminer {
  border: 1px solid var(--input-border);
  border-radius: 0.35em;
  padding: 0.25em 0.8em;
  background: none;
  color: var(--ink);
  font-size: small;
  cursor: pointer;
}

.accueil-choix__terminer:hover {
  border-color: color-mix(in lab, var(--ink) 55%, transparent);
}

/* L'ADMIN LES DÉCOLLE (envol_controller, « Les gommettes ») : elles se prennent ; et
   celle qu'il tient a quitté sa feuille (`sans-gommette`). */
.accueil-art.is-tas[data-envol-admin-value="true"] .accueil-art__dessin:not(.accueil-art__autre) .accueil-art__gommette,
.accueil-art.is-diapos[data-envol-admin-value="true"] .accueil-carte:not(.accueil-carte--archive) .accueil-carte__une {
  pointer-events: auto;
  touch-action: none;
  cursor: grab;
}

.accueil-art .sans-gommette .accueil-art__gommette,
.accueil-art .sans-gommette .accueil-carte__une {
  opacity: 0;
  transition: none;
}

/* LA PLANCHE DE GOMMETTES de l'admin, en haut à gauche, là où l'on voit tout : une
   bande de papier siliconé, brillant, où elles attendent — pour les douze, autant
   que de places libres (les prises : leur trace en creux), pour les projets, une
   réserve. On en prend une, on la colle sur une feuille. */
.accueil-gommettes {
  --mm: 1mm;
  display: none;
  align-items: center;
  gap: calc(1.6 * var(--mm));
  padding: calc(1.6 * var(--mm)) calc(2.2 * var(--mm));
  border-radius: calc(1 * var(--mm));
  background: linear-gradient(170deg, #ffffff, #eef0f2);
  box-shadow: 0 0.15em 0.9em rgba(18, 24, 44, 0.16), inset 0 0 0 1px rgb(0 0 0 / 0.05);
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
}

.accueil-art.is-tas .accueil-gommettes,
.accueil-art.is-diapos .accueil-gommettes {
  display: flex;
}

/* (L'écran de choix d'une figure — lot 23 — n'a pas de gommettes : on y tire les vignettes.) */
.accueil-art.is-choix-figure .accueil-gommettes {
  display: none;
}

.accueil-gommettes__point {
  position: static;
  flex: none;
  pointer-events: auto;
  cursor: grab;
}

.accueil-gommettes__point.is-prise {
  background: none;
  box-shadow: inset 0 0 0 1px rgb(19 112 237 / 0.25);
  pointer-events: none;
}

/* Celle qu'on tient : soulevée — plus grande d'un rien, son ombre plus loin. */
.gommette-vol {
  --mm: 1mm;
  position: fixed;
  left: 0;
  top: 0;
  bottom: auto;
  z-index: 99999;
  translate: -50% -50%;
  scale: 1.08;
  box-shadow:
    inset calc(0.12 * var(--mm)) calc(0.12 * var(--mm)) calc(0.1 * var(--mm)) rgb(255 255 255 / 0.35),
    inset calc(-0.12 * var(--mm)) calc(-0.12 * var(--mm)) calc(0.1 * var(--mm)) rgb(0 0 0 / 0.2),
    calc(0.8 * var(--mm)) calc(1.4 * var(--mm)) calc(1.6 * var(--mm)) rgb(0 0 0 / 0.28);
  pointer-events: none;
  transition: left 0.25s ease, top 0.25s ease, opacity 0.25s ease;
}

.gommette-vol.is-tenue {
  transition: none;
}

/* La feuille où elle va se coller : un liseré de son bleu. */
.accueil-art__dessin.is-cible-gommette,
.accueil-carte.is-cible-gommette {
  outline: 2px solid rgb(19 112 237 / 0.7);
  outline-offset: 2px;
}

/* « LE STUDIO », EN BAS DANS LA GALERIE, EST DISCRET (7 oct. 2026 : « il devrait
   rester en bas en ligne et être plus discret ») : sur l'index et le tas, la porte
   d'à côté — en retrait, à demi effacée, mais là, pour y aller d'un clic. ET « LA
   GALERIE », EN HAUT DANS LE STUDIO, DE MÊME (« il faut le menu galerie en haut
   aussi ») : sur la planche des projets. */
.accueil-art.is-range .accueil-art__design,
.accueil-art.is-tas .accueil-art__design,
.accueil-art.is-diapos .accueil-art__galerie {
  opacity: 0.55;
}

/* EN HAUT À GAUCHE, pour l'admin : ses deux boutons de l'index des projets. (Le
   bouton RANGER / ÉPARPILLER est retiré, 1er oct. 2026 ; « les douze · autres »,
   qui s'écrivaient ici, sont EN BAS AU CENTRE depuis le même jour : la série.) */
.accueil-outils {
  position: fixed;
  top: 0.55rem;
  left: max(0.5rem, var(--page-gutter));
  z-index: 9000;
  display: flex;
  flex-wrap: wrap;
  /* le feutre pris, sa palette s'ajoute : sur un écran étroit, à la ligne */
  align-items: flex-start;
  /* la palette du feutre, dessous son bouton, allonge la rangée */
  gap: 1rem;
  max-width: calc(100vw - 7rem);
  /* la pastille « Menu » est en haut à droite */
  /* PIÈGE : sa boîte va jusqu'aux derniers outils, même effacés — par-dessus le Polaroid
     qu'on dessine ; seuls les outils prennent le pointeur. */
  pointer-events: none;
}

.accueil-outils>* {
  pointer-events: auto;
}

.accueil-art.is-show .accueil-outils {
  opacity: 0;
  pointer-events: none;
}

/* Les boutons de l'admin : la matière de la pastille « Menu » (menu.css). */
.accueil-ranger {
  padding: 0.45em 1em;
  border: 0;
  border-radius: 999px;
  background: color-mix(in lab, var(--bg-card) 86%, transparent);
  backdrop-filter: blur(1.5mm);
  box-shadow: 0 0.2em 1.2em rgba(18, 24, 44, 0.14);
  font: inherit;
  font-size: small;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}

.accueil-ranger:hover,
.accueil-ranger:focus-visible {
  background: var(--bg-card);
  outline: none;
}

.accueil-ranger:focus-visible {
  box-shadow: 0 0 0 2px var(--blue), 0 0.2em 1.2em rgba(18, 24, 44, 0.14);
}

/* L'index des projets, pour l'admin : « + Nouveau projet », « Ordonner ». */
.accueil-studio {
  display: flex;
  gap: 0.5rem;
}

.accueil-studio__form {
  display: flex;
  max-width: none;
  margin: 0;
}

a.accueil-ranger {
  text-decoration: none;
}

/* LA SÉRIE, EN BAS AU CENTRE (1er oct. 2026 : « je veux en bas le titre de la
   série en cours, et une petite flèche à droite ou à gauche s'il y a d'autres
   galeries ; à la place de Recherches ») : sur l'index, « Les douze » ou « Les
   autres » — celui de la figure où l'on est (`is-range` / `is-tas`) — et la
   FLÈCHE vers l'autre (› les autres, ‹ les douze). Au-dessus des feuilles, comme
   la galerie et le studio (2 000) ; effacée ailleurs (plus haut). Là où était
   « Les recherches » : « Le Studio » s'y pose quand les diapositives se rangent
   (envol_controller#_titrer). */
/* LA SÉRIE SOUS « LA GALERIE » (7 oct. 2026 : « mets les sous-titres sous
   galerie » — du 5 au 7 oct., VERTICAUX SUR LES FLANCS, couchés sur des arcs de
   cercle, le courant en grand : « je n'aime pas du tout le rendu », retiré, git le
   garde ; avant, en bas au centre) : ses deux titres l'un sous l'autre, au milieu,
   juste sous les lettres envolées de « La galerie » (`--serie-y`, posé par
   envol_controller#_titrer), SOUS LES FEUILLES comme les grands titres (z-index 1 ;
   un clic sur une feuille qui couvre une lettre va au titre, `_titreSous`) ;
   effacée hors de l'index et du tas (plus haut, avec les figures). */
.accueil-serie {
  position: fixed;
  left: 50%;
  top: var(--serie-y, 5rem);
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35em;
  margin: 0;
  transform: translateX(-50%);
  font-size: small;
  white-space: nowrap;
}

/* UN TITRE EN LETTRES (« –↑–↑–↑–↑– Les douze –↑–↑–↑–↑– » comme « La galerie »,
   « →–→–Les autres–←–← », les flèches vers le mot) : l'espacement de départ ici,
   l'espacement large et le smear par le contrôleur (`_arquer`, forme `droit` ;
   `_ouvrirSerie` quand la série paraît). Le titre de la figure où l'on est à
   l'encre pleine ; l'autre, en retrait. */
.accueil-serie__titre {
  display: block;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-muted);
  transition: color 150ms;
}

.accueil-serie__titre[aria-current] {
  color: var(--ink);
}

.accueil-serie__titre:hover,
.accueil-serie__titre:focus-visible {
  color: var(--blue);
  outline: none;
}

.accueil-art__dessin.is-ouverte {
  cursor: default;
}

/* Avant que le contrôleur les place : rien (sinon, un instant, tous au centre). */
/* La série aussi attend le contrôleur (5 oct. 2026 : au rafraîchissement, ses
   lettres paraissaient à leur place, puis sautaient hors champ pour arriver en
   volant — « cette mauvaise animation ») : rien ne se voit avant qu'il les lance. */
.avant-envol .accueil-serie {
  opacity: 0;
}

.avant-envol .accueil-art__dessin {
  visibility: hidden;
}

/* « La galerie » et « Le Studio » aussi (15 oct. 2026 : « il ne faut pas afficher La
   galerie et Le Studio sur les premières images ; il y a comme un flash au démarrage »)
   : la page les peint droits, au centre, avant que le contrôleur démarre — puis il les
   faisait partir, invisibles, du milieu de l'écran. (`visibility` : leur place se mesure
   quand même.) */
.avant-envol .accueil-art__galerie,
.avant-envol .accueil-art__design {
  visibility: hidden;
}

/* ── Le studio : les cartes, des PICPAK ─────────────────────────────────
   Des feuilles comme les dessins (envol_controller : posées au centre de la scène
   et déplacées par le contrôleur, `--vol` pour l'ombre, qu'on tire). DES PICPAK
   (8 oct. 2026 : « plutôt que des Polaroids, je veux des formats PicPak ; on
   pourrait voir les images changer toutes les minutes, avec des effets de
   changement d'image en mode e-ink ») : le petit cadre photo à écran e-ink couleur,
   À SA VRAIE TAILLE (#28) — 99 × 91 mm, en unités PHYSIQUES (`--mm`), sur un
   téléphone aussi —, l'écran de 4,2 pouces en paysage (85 × 64 mm) en haut, le
   MENTON en bas (20 mm), VIDE (« rien d'imprimé » : l'admin y dessine ; le titre
   reste dans la page pour les lecteurs d'écran — visible seulement sur un projet
   sans couverture). L'image change toutes les minutes, en e-ink (controllers/eink,
   envol_controller « Les PicPak »). (Ont précédé, le même jour et la veille : des
   Polaroids classiques, des diapositives — git les garde.)
     · LE BOÎTIER : un plastique MAT, de la couleur choisie (`--cadre`, le nuancier
       de la palette ; d'origine, un blanc cassé), un grain fin, à peine modelé vers
       la lumière (d'en haut à gauche, chaude : celle de la zone Art) ; ses arêtes
       arrondies, claires du côté de la lumière (`::before`) — RIEN DE BRILLANT
       (« sans effets glosés, je trouve ça immonde ») ;
     · SES OMBRES, celles d'un objet de 6 mm (`--epaisseur`) : l'occlusion au pied,
       l'ombre portée de l'épaisseur, une pénombre ; en vol, les distances des
       feuilles (`--vol`) ;
     · L'ÉCRAN (`.accueil-carte__fenetre`, le nom d'avant) : en retrait sous le
       boîtier, son bord inactif autour (`--bord-eink`), et la surface MATE d'un papier
       e-ink — l'image TELLE QUELLE, à peine ternie (#29 : ses vraies couleurs, un
       blanc de papier, un contraste plus doux), aucun reflet.
   Les réglages sont les variables de `.accueil-carte`, à l'auteur. */
.accueil-carte {
  --vol: 0;
  --v: var(--vol, 0);
  --mm: 1mm;
  --epaisseur: calc(6 * var(--mm));
  /* le boîtier : 6 mm */
  --ombre: 22 27 38;
  /* la couleur des ombres : le gris à peine bleuté des feuilles */
  --chaud: 255 250 236;
  /* la lumière : CHAUD, celle de la soie */
  --papier-eink: #e7e6e0;
  /* le gris papier d'un écran e-ink, éteint */
  --bord-eink: #cfcec7;
  /* le bord inactif de l'écran */
  --cadre: #f3f2ee;
  /* LA COULEUR DU BOÎTIER (8 oct. 2026 : « je veux pouvoir choisir une couleur
     spéciale pour les polas ») : un blanc cassé, ou celle que l'admin a choisie pour
     ce projet (`style`, Product#cadre ; envol_controller#cadre, en direct) — le modelé
     s'en déduit, plus clair vers la lumière, plus sombre de l'autre côté. */
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: calc(99 * var(--mm));
  height: calc(91 * var(--mm));
  padding: calc(7 * var(--mm)) calc(7 * var(--mm)) 0;
  border-radius: calc(4.5 * var(--mm));
  background:
    url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSc0OCcgaGVpZ2h0PSc0OCc+PGZpbHRlciBpZD0nZyc+PGZlVHVyYnVsZW5jZSB0eXBlPSdmcmFjdGFsTm9pc2UnIGJhc2VGcmVxdWVuY3k9JzEuMScgbnVtT2N0YXZlcz0nMicgc2VlZD0nMycgc3RpdGNoVGlsZXM9J3N0aXRjaCcvPjxmZUNvbG9yTWF0cml4IHZhbHVlcz0nMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMC4wOSAwIDAgMCAwJy8+PC9maWx0ZXI+PHJlY3Qgd2lkdGg9JzQ4JyBoZWlnaHQ9JzQ4JyBmaWx0ZXI9J3VybCgjZyknLz48L3N2Zz4=") 0 0 / 48px 48px repeat,
    linear-gradient(145deg, color-mix(in oklab, var(--cadre) 86%, white), color-mix(in oklab, var(--cadre) 92%, black));
  color: rgb(28 28 34 / 0.82);
  text-decoration: none;
  will-change: transform;
  touch-action: none;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  box-shadow:
    0 0 calc(0.5 * var(--mm)) calc(0.1 * var(--mm)) rgb(var(--ombre) / calc(0.3 * (1 - min(1, var(--v) * 2.5)))),
    calc(0.12 * var(--epaisseur) + var(--v) * 6px) calc(0.16 * var(--epaisseur) + var(--v) * 8px) calc(0.15 * var(--epaisseur) + var(--v) * 8px) rgb(var(--ombre) / calc(0.26 * (1 - var(--v) * 0.55))),
    calc(0.25 * var(--epaisseur) + var(--v) * 34px) calc(0.35 * var(--epaisseur) + var(--v) * 42px) calc(0.6 * var(--epaisseur) + var(--v) * 44px) rgb(var(--ombre) / calc(0.11 + 0.08 * min(1, var(--v) * 3) * (1 - var(--v) * 0.6)));
}

/* Ses ARÊTES arrondies : claires en haut et à gauche (vers la lumière), plus sombres
   en bas et à droite — un modelé, pas un reflet. */
.accueil-carte::before {
  box-shadow:
    inset calc(0.35 * var(--mm)) calc(0.35 * var(--mm)) calc(0.3 * var(--mm)) rgb(255 255 255 / 0.55),
    inset calc(-0.35 * var(--mm)) calc(-0.35 * var(--mm)) calc(0.4 * var(--mm)) rgb(0 0 0 / 0.1);
}

/* UN BOÎTIER SOMBRE (`accueil-carte--sombre`, Product#cadre_sombre?) : ce qui s'écrit
   dessus passe en clair, et ses arêtes s'éclairent moins. */
.accueil-carte--sombre {
  color: rgb(255 255 255 / 0.85);
}

.accueil-carte--sombre::before {
  box-shadow:
    inset calc(0.35 * var(--mm)) calc(0.35 * var(--mm)) calc(0.3 * var(--mm)) rgb(255 255 255 / 0.16),
    inset calc(-0.35 * var(--mm)) calc(-0.35 * var(--mm)) calc(0.4 * var(--mm)) rgb(0 0 0 / 0.32);
}

/* SA LUMIÈRE, celle d'un plastique mat : le modelé seul — chaud vers la lumière, un
   rien de bleu dans l'ombre, comme la soie. */
.accueil-carte::after {
  background: linear-gradient(140deg, rgb(var(--chaud) / 0.07), rgb(var(--chaud) / 0) 50%, rgb(40 90 170 / 0.05));
}

.accueil-carte.is-tenu {
  cursor: grabbing;
}

/* L'ÉCRAN : 85 × 64 mm, son bord inactif (1,2 mm) autour de l'image. */
.accueil-carte__fenetre {
  position: relative;
  display: block;
  flex: none;
  width: calc(85 * var(--mm));
  height: calc(64 * var(--mm));
  padding: calc(1.2 * var(--mm));
  border-radius: calc(1 * var(--mm));
  background: var(--bord-eink);
  pointer-events: none;
}

/* L'IMAGE SUR LE PAPIER E-INK (#29, « telle quelle ») : ses couleurs, à peine
   ternies — le blanc d'un papier, un contraste plus doux. */
.accueil-carte__image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: calc(0.3 * var(--mm));
  background: var(--papier-eink);
  filter: saturate(0.82) contrast(0.9) brightness(0.97) sepia(0.06);
}

/* L'écran en retrait sous le boîtier : l'ombre de son bord, en haut et à gauche ; et
   le grain du papier e-ink, mat. Pas de reflet. */
.accueil-carte__fenetre::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
  pointer-events: none;
  background:
    url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPSc0OCcgaGVpZ2h0PSc0OCc+PGZpbHRlciBpZD0nZyc+PGZlVHVyYnVsZW5jZSB0eXBlPSdmcmFjdGFsTm9pc2UnIGJhc2VGcmVxdWVuY3k9JzEuMScgbnVtT2N0YXZlcz0nMicgc2VlZD0nMycgc3RpdGNoVGlsZXM9J3N0aXRjaCcvPjxmZUNvbG9yTWF0cml4IHZhbHVlcz0nMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMCAwIDAgMC4wOSAwIDAgMCAwJy8+PC9maWx0ZXI+PHJlY3Qgd2lkdGg9JzQ4JyBoZWlnaHQ9JzQ4JyBmaWx0ZXI9J3VybCgjZyknLz48L3N2Zz4=") 0 0 / 32px 32px repeat,
    linear-gradient(to bottom, rgb(0 0 0 / 0.22), rgb(0 0 0 / 0) calc(0.6 * var(--mm))),
    linear-gradient(to right, rgb(0 0 0 / 0.16), rgb(0 0 0 / 0) calc(0.5 * var(--mm)));
  box-shadow: inset 0 0 0 calc(0.1 * var(--mm)) rgb(0 0 0 / 0.18);
}

/* SUR LA SIGNATURE, À SA TAILLE RÉELLE (envol_controller, « Sur la signature ») : la
   signature se cerne quand une feuille tirée passe dessus ; la feuille posée là a sa
   TAILLE RÉELLE écrite dessous (« 99 × 91 mm », « 21 × 29,7 cm · 1:1,4 »), discrète. */
.accueil-art__mot.is-expo .accueil-art__signature {
  outline: 1px dashed color-mix(in lab, var(--ink) 45%, transparent);
  outline-offset: 10px;
  border-radius: 6px;
}

/* SOUS LA FEUILLE (`echelle`, pages/accueil) : sa TAILLE RÉELLE écrite (« 99 × 91 mm »,
   « ≈ » sans étalon), « Calibrer l'écran », et pour l'admin « Feutre » — ses réglages
   dessous (plus bas, « Le feutre »). Discret : petit, à l'encre pâle, les liens
   soulignés ; seuls les liens et les réglages prennent le pointeur. */
.accueil-echelle {
  position: absolute;
  /* dans la scène : il défile avec elle (le projet au centre, plus bas) */
  z-index: 9000;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
  translate: -50% 0;
  font-size: x-small;
  letter-spacing: 0.08em;
  color: var(--ink-muted);
  pointer-events: none;
}

.accueil-echelle[hidden] {
  display: none;
}

.accueil-echelle__ligne {
  display: flex;
  align-items: baseline;
  margin: 0;
  white-space: nowrap;
}

/* Les liens : « Calibrer l'écran » (controllers/etalon : sans étalon, le mm du
   navigateur, « à peu près »), « Feutre » — un point médian devant chacun. */
.accueil-echelle__lien {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  letter-spacing: inherit;
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  cursor: pointer;
  pointer-events: auto;
}

.accueil-echelle__lien::before {
  content: "·";
  display: inline-block;
  margin: 0 0.6em;
  color: var(--ink-muted);
  text-decoration: none;
}

.accueil-echelle__lien[hidden] {
  display: none;
}

.accueil-echelle__feutre[aria-pressed="true"] {
  font-weight: 700;
}

.accueil-echelle__lien:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

/* ── LE PROJET AU CENTRE (envol_controller, « Le projet au centre » ; 8 oct. 2026 :
   « quand un PicPak est au centre, les autres objets vont se mettre au-dessus, le titre
   apparaît au niveau de la ligne de champ basse ; en scrollant, le projet s'affiche ») :
   les autres feuilles en FRISE en haut (le contrôleur), « La galerie » et « Le Studio »
   effacés, SON NOM sur la ligne du bas à l'allure de « Le Studio » (ses flèches vers le
   bas : on descend), sa fiche dessous ; et la home DÉFILE — la scène garde l'écran, le
   projet (sa page) se déroule dessous (`.accueil-suite`). */
.accueil.is-projet {
  height: auto;
  overflow: visible;
  overflow-x: clip;
}

.accueil.is-projet .accueil-art {
  flex: none;
  height: 100dvh;
}

.accueil-art.is-projet .accueil-art__galerie,
.accueil-art.is-projet .accueil-art__design,
.accueil-art.is-projet .accueil-serie {
  opacity: 0;
  pointer-events: none;
}

.accueil-projet {
  position: absolute;
  left: 50%;
  bottom: 28px;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  translate: -50% 0;
  pointer-events: none;
  animation: accueil-projet 0.5s ease both;
}

.accueil-projet[hidden] {
  display: none;
}

@keyframes accueil-projet {
  from {
    opacity: 0;
    translate: -50% 6px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .accueil-projet {
    animation: none;
  }
}

.accueil-projet__titre {
  margin: 0;
  padding-inline: 0.8em;
  font-size: x-large;
  font-weight: bold;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--ink);
}

.accueil-projet__fiche {
  margin: 0;
  max-width: min(36rem, calc(100vw - 32px));
  font-size: x-small;
  letter-spacing: 0.08em;
  line-height: 1.5;
  text-align: center;
  color: var(--ink-muted);
}

/* (Une description passe à la ligne, entre deux mots — eink#ecrire les fait insécables.) */
.accueil-projet__fiche.eink-texte {
  white-space: normal;
}

.accueil-projet__fiche .eink-lettre {
  padding-block: 0.1em;
}

.accueil-projet__fiche:empty {
  display: none;
}

/* LE TITRE S'ÉCRIT EN E-INK, DU CENTRE VERS LES BOUTS (9 oct. 2026 : « je veux que les
   titres apparaissent en e-ink », puis « certains caractères ne sont pas bien placés ; il
   faut plus de padding autour du titre ; un effet e-ink qui part du centre du titre en
   cascade » — controllers/eink#ecrire) : chaque lettre est le VRAI TEXTE (une toile peinte
   par-dessus, le premier jour, plaçait mal certains caractères), qui passe par ce que fait
   un écran e-ink — flash noir, papier, noir, le négatif, puis la trame qui se resserre
   (Bayer 4 × 4 : 4, 8, 12 points sur 16, en masques — base64, cf. les pièges de
   CLAUDE.md), et la lettre ; à son tour, `--i` étant son rang depuis le milieu du titre
   (`--eink-pas` entre deux rangs). Chaque case a de l'air autour (`padding-block`). Avant
   son tour, rien. Sans mouvement : le texte, simplement (le contrôleur ne découpe pas). */
.eink-texte {
  --eink-encre: #232320;
  --eink-papier: #e7e6e0;
  --eink-pas: 40ms;
  --eink-duree: 1.25s;
  white-space: nowrap;
}

.eink-mot {
  white-space: nowrap;
}

.eink-lettre {
  display: inline-block;
  padding-block: 0.3em;
  white-space: pre;
  animation: eink-lettre var(--eink-duree) steps(1, end) backwards;
  animation-delay: calc(var(--i, 0) * var(--eink-pas));
}

.eink-lu {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@keyframes eink-lettre {
  0% {
    background: transparent;
    color: transparent;
  }

  2% {
    background: var(--eink-encre);
    color: transparent;
  }

  10% {
    background: var(--eink-papier);
    color: transparent;
  }

  18% {
    background: var(--eink-encre);
    color: transparent;
  }

  26% {
    background: var(--eink-encre);
    color: var(--eink-papier);
  }

  37% {
    background: var(--eink-papier);
    color: transparent;
  }

  45% {
    background: transparent;
    color: var(--eink-encre);
    -webkit-mask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjYiIHZpZXdCb3g9IjAgMCA0IDQiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyI+PGcgZmlsbD0iIzAwMCI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjIiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIwIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMiIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjwvZz48L3N2Zz4=") 0 0 / 6px 6px;
    mask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjYiIHZpZXdCb3g9IjAgMCA0IDQiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyI+PGcgZmlsbD0iIzAwMCI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjIiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIwIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMiIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjwvZz48L3N2Zz4=") 0 0 / 6px 6px;
  }

  57% {
    background: transparent;
    color: var(--eink-encre);
    -webkit-mask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjYiIHZpZXdCb3g9IjAgMCA0IDQiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyI+PGcgZmlsbD0iIzAwMCI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjIiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIxIiB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMyIgeT0iMSIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjAiIHk9IjIiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMSIgeT0iMyIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjMiIHk9IjMiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48L2c+PC9zdmc+") 0 0 / 6px 6px;
    mask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjYiIHZpZXdCb3g9IjAgMCA0IDQiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyI+PGcgZmlsbD0iIzAwMCI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjIiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIxIiB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMyIgeT0iMSIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjAiIHk9IjIiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMSIgeT0iMyIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjMiIHk9IjMiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48L2c+PC9zdmc+") 0 0 / 6px 6px;
  }

  69% {
    background: transparent;
    color: var(--eink-encre);
    -webkit-mask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjYiIHZpZXdCb3g9IjAgMCA0IDQiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyI+PGcgZmlsbD0iIzAwMCI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMyIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjEiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIzIiB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMCIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjIiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMyIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjMiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIzIiB5PSIzIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PC9nPjwvc3ZnPg==") 0 0 / 6px 6px;
    mask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2IiBoZWlnaHQ9IjYiIHZpZXdCb3g9IjAgMCA0IDQiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyI+PGcgZmlsbD0iIzAwMCI+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjAiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMyIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjEiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIzIiB5PSIxIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMCIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjIiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIyIiB5PSIyIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PHJlY3QgeD0iMyIgeT0iMiIgd2lkdGg9IjEiIGhlaWdodD0iMSIvPjxyZWN0IHg9IjEiIHk9IjMiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiLz48cmVjdCB4PSIzIiB5PSIzIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIi8+PC9nPjwvc3ZnPg==") 0 0 / 6px 6px;
  }

  81% {
    background: transparent;
    color: var(--eink-encre);
  }

  100% {
    background: transparent;
  }
}

@media (prefers-reduced-motion: reduce) {
  .eink-lettre {
    animation: none;
  }
}

/* Le projet, dessous : sa page, telle quelle. */
.accueil-suite {
  padding-inline: var(--page-gutter);
  padding-block: 2.5rem 4rem;
}

/* LA PAGE DU PROJET PASSE PAR-DESSUS LA BANDE (16 oct. 2026 : « les images qui arrivent
   ensuite doivent commencer à 5 cm du bandeau, soit 3 cm après le hors-champ ; ainsi le
   bloc passe par-dessus le bandeau ») : son bloc commence `--bande-suite` sous le bord
   du premier écran — la bande, haute d'un écran, est dans le flux juste avant : la page
   remonte d'autant (son padding de 2,5rem compté ; le bandeau du nom, avant elle, ne
   compte pas : il remonte de sa propre hauteur) — et défile au-dessus d'elle,
   DIRECTEMENT SUR LA TRAME (18 oct. 2026 : « directement sur la trame » — un fond de page
   la cachait sous le bloc, le 16), sous le bandeau blanc du nom. */
.accueil.a-bandeau .accueil-suite {
  position: relative;
  z-index: 3;
  margin-top: calc(var(--bande-suite) + var(--bande-champ) - 2.5rem - 100dvh);
}

/* UN DESSIN AU CENTRE, SA PAGE (pages/accueil/_page_dessin ; 8 oct. 2026 : « je ne veux
   plus de show spécifiques ; les éléments de notes sont disponibles au scroll » — #45 à
   #48) : sa description en tête, au milieu, puis la table de son cahier (cahier.css,
   « La table »). Pour l'admin, les champs ont l'allure du texte (le titre, la
   description, le format du papier), ses calques et leur ✕. PIÈGE : form.scss.css borne
   et centre tout <form>, habille tout <input> et grandit tout <textarea> — repris ici. */
.dessin-page {
  display: flex;
  flex-direction: column;
  gap: 2.5rem;
}

.dessin-page__tete {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.8rem;
  width: 100%;
  max-width: 40em;
  margin-inline: auto;
  text-align: center;
}

.dessin-page__fiche {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  width: 100%;
  max-width: none;
  margin: 0;
}

.dessin-page__description {
  margin: 0;
  font-size: medium;
  line-height: 1.55;
  white-space: pre-line;
  color: var(--ink);
}

.dessin-page__fiche .dessin-page__champ {
  width: 100%;
  padding: 0.15em 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  font-family: inherit;
  text-align: center;
  color: var(--ink);
}

.dessin-page__fiche .dessin-page__champ:focus {
  outline: 1px dashed var(--ink-10);
  outline-offset: 4px;
}

.dessin-page__fiche .dessin-page__champ::placeholder {
  color: var(--ink-muted);
  opacity: 0.6;
}

.dessin-page__fiche .dessin-page__titre {
  font-size: large;
  font-weight: bold;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

.dessin-page__fiche textarea.dessin-page__description {
  height: auto;
  min-height: 2.6em;
  field-sizing: content;
  resize: none;
}

.dessin-page__format {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5em;
  font-size: x-small;
  letter-spacing: 0.08em;
  color: var(--ink-muted);
}

.dessin-page__fiche .dessin-page__format .dessin-page__champ {
  width: 9em;
  font-size: x-small;
  text-align: left;
}

.dessin-page__statut,
.dessin-page__aide {
  margin: 0;
  min-height: 1em;
  font-size: x-small;
  color: var(--ink-muted);
}

.dessin-page__calques {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
}

.dessin-page__etiquette {
  font-size: x-small;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.dessin-page__liste {
  display: flex;
  gap: 0.6rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.dessin-page__calque {
  position: relative;
}

.dessin-page__vignette {
  display: block;
  width: auto;
  height: 56px;
  border-radius: 2px;
  box-shadow: 0 0 0 1px var(--ink-10);
}

.dessin-page__supprimer-form {
  position: absolute;
  top: -0.6em;
  right: -0.6em;
  max-width: none;
  margin: 0;
}

.dessin-page__supprimer {
  width: 1.6em;
  height: 1.6em;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--bg-card);
  box-shadow: 0 0 0 1px var(--ink-10);
  font-size: x-small;
  color: var(--ink);
  cursor: pointer;
}

/* Un fichier tiré au-dessus (l'admin) : sur le dessin, un calque ; ailleurs sur la
   page, un croquis (envol_controller, « Un dessin au centre »). */
.accueil-art__dessin.is-depot {
  outline: 2px dashed var(--blue);
  outline-offset: 6px;
}

.accueil-suite.is-depot {
  outline: 2px dashed var(--blue);
  outline-offset: -12px;
}

/* LE RAFRAÎCHISSEMENT E-INK (controllers/eink) : un canevas posé sur l'image le temps
   du changement — en basse résolution, ses pixels nets, comme ceux d'un e-ink. */
.eink {
  position: absolute;
  border-radius: calc(0.3 * var(--mm));
  image-rendering: pixelated;
  pointer-events: none;
}

/* LE TITRE : rien d'imprimé sur le menton (#18) — il reste pour les lecteurs
   d'écran ; écrit, au milieu du menton, sur un projet sans couverture (et, sur
   « Démarrer un projet », à l'écran : plus haut). */
.accueil-carte__titre {
  max-width: 100%;
  margin-block: auto;
  font-size: xx-small;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 1.2;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.accueil-carte:not(.accueil-carte--vide):not(.accueil-carte--amorce) .accueil-carte__titre {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
}

.avant-envol .accueil-carte {
  visibility: hidden;
}

/* ── LE FEUTRE : le boîtier dessiné d'un projet ─────────────────────────────
   (8 oct. 2026 : « j'aimerais qu'on développe de quoi dessiner autour du cadre
   des diapos, pour que je puisse décorer les zones autour de l'image ») : des
   traits de BROSSE, peints pas à pas sur un canevas par controllers/feutre (le
   crayon, le pinceau sec — « comme Photoshop, avec les pressions »), SANS LUSTRE
   (« sans effets glosés, je trouve ça immonde » : le Posca d'une heure, son filtre
   et son ombre, sont retirés). CHAQUE TRAIT EST SUR SON SUPPORT (« sur le support
   sur lequel il doit aller ») : UN canevas APRÈS l'écran (`feutre--cadre`), au rang 0
   — par-dessus l'image, mais sous le bord de l'écran et son grain (son `::after`, au
   rang 1) ; et, par-dessus, le trait en cours (`feutre--vif`). */
.feutre {
  position: absolute;
  z-index: 0;
  inset: 0;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  pointer-events: none;
}

/* LE CONTOUR DE LA BROSSE (envol_controller#_curseur), comme dans Photoshop : un rond
   de sa taille qui suit le pointeur sur le boîtier ouvert — un filet clair et un
   filet sombre, lisible sur toutes les encres ; un point au milieu. */
.feutre-curseur {
  position: fixed;
  z-index: 99999;
  translate: -50% -50%;
  min-width: 4px;
  min-height: 4px;
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgb(255 255 255 / 0.9), 0 0 0 2px rgb(0 0 0 / 0.55);
  pointer-events: none;
}

.feutre-curseur::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 2px;
  height: 2px;
  translate: -50% -50%;
  border-radius: 50%;
  background: rgb(0 0 0 / 0.6);
}

/* LES RÉGLAGES DU FEUTRE, sous la feuille posée sur la signature (« en cliquant sur
   le lien "feutre", il faut que les paramètres s'affichent dessous de manière simple et
   sobre ») : trois lignes de texte — les brosses, la gomme, « Annuler », « Terminer » ;
   les pointes ; les encres (des pastilles), la pipette, la couleur du boîtier. Le choix
   en cours à l'encre pleine, souligné ; le reste pâle. Pas de pastilles ni de fond :
   des mots. (Une palette en panneau, en haut à gauche, a précédé le même jour.) */
.accueil-feutre {
  display: none;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  pointer-events: auto;
}

.accueil-art.is-feutre .accueil-feutre {
  display: flex;
}

.accueil-feutre__ligne {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.15rem 0.5rem;
  max-width: min(32rem, calc(100vw - 2rem));
}

.accueil-feutre__outil,
.accueil-feutre__pointe {
  padding: 0.1em 0.15em;
  border: 0;
  background: none;
  font: inherit;
  letter-spacing: inherit;
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
  cursor: pointer;
}

.accueil-feutre__outil[aria-pressed="true"],
.accueil-feutre__pointe[aria-pressed="true"] {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

.accueil-feutre__outil:hover,
.accueil-feutre__pointe:hover {
  color: var(--ink);
}

/* Terminer : la sortie, à l'encre pleine — on la trouve. */
.accueil-feutre__terminer {
  font-weight: 700;
  color: var(--ink);
}

/* Un blanc entre deux groupes, et l'unité des pointes. */
.accueil-feutre__blanc {
  width: 0.8em;
}

.accueil-feutre__unite {
  color: var(--ink-muted);
}

/* UNE ENCRE : une pastille (`--encre`, Product::DECOR_ENCRES) ; la prise, cernée. */
.accueil-feutre__couleur {
  flex: none;
  width: 0.85rem;
  height: 0.85rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--encre, var(--bg-card));
  cursor: pointer;
}

.accueil-feutre__couleur[aria-pressed="true"] {
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 3px var(--ink);
}

/* LA PIPETTE : un mot ; l'encre qu'elle a prise, en pastille devant. */
.accueil-feutre__pipette[style*="--encre"]::before {
  content: "";
  display: inline-block;
  width: 0.7em;
  height: 0.7em;
  margin-right: 0.35em;
  border-radius: 50%;
  vertical-align: -0.05em;
  background: var(--encre);
}

/* Le nuancier du système, ouvert par la pipette là où le navigateur n'en a pas :
   présent, pas montré. */
.accueil-feutre__libre {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* LA COULEUR DU BOÎTIER : un mot, et sa pastille de nuancier, petite. */
.accueil-feutre__nuancier {
  display: flex;
  align-items: center;
  gap: 0.35em;
  color: var(--ink-muted);
}

.accueil-feutre__nuancier input {
  width: 1.3rem;
  height: 0.95rem;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.accueil-feutre__couleur:focus-visible,
.accueil-feutre__outil:focus-visible,
.accueil-feutre__pointe:focus-visible,
.accueil-feutre__nuancier input:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

/* EN DESSIN (`is-crayon`, envol_controller) : le boîtier sur la signature, à sa taille
   réelle (`is-ouverte`) ; le reste s'efface (`is-fondu` le temps d'y aller et d'en
   revenir). */
.accueil-art.is-crayon .accueil-art__dessin,
.accueil-art.is-crayon .accueil-carte:not(.is-ouverte),
.accueil-art.is-crayon .accueil-art__galerie,
.accueil-art.is-crayon .accueil-art__design,
.accueil-art.is-crayon .accueil-serie,
.accueil-art.is-crayon .accueil-studio,
.accueil-art.is-crayon .accueil-gommettes,
.accueil-art.is-crayon .accueil-carte__une {
  opacity: 0;
  pointer-events: none;
}

/* Le contour de la brosse remplace le pointeur sur le boîtier ouvert. */
.accueil-carte.is-crayon {
  cursor: none;
}

/* UN ÉCRAN ÉTROIT (en portrait, ou moins de 40rem — le même seuil que
   envol_controller, `ETROIT`) : « les dessins en haut, pour qu'on voie bien la
   signature au centre » — LE HAUT AUX DESSINS (un serpentin de rangées, du haut
   de l'écran à « La galerie », le centre compris : envol_controller), LE BAS AUX
   DIAPOSITIVES (des rangées sous le studio, jusqu'au bas), et entre les deux LA SIGNATURE, LA
   GALERIE ET LE STUDIO AU PREMIER TIERS EN PARTANT DU BAS (1er oct. 2026 : « mets
   la signature avec la galerie et le studio au niveau du 1er tiers en partant du
   bas ») : la scène en trois rangées égales, le centre dans les deux du bas — son
   milieu est aux deux tiers de la hauteur. Les DESSINS PRENNENT LA PLACE (« plus
   de place en haut et en bas ») : leur hauteur est calculée par le contrôleur
   (`--dessin-h` sur la scène, envol_controller#_remplirBandes), celle-ci ne sert
   qu'avant qu'il démarre. Les DIAPOSITIVES, NON : leur vraie taille, 5 cm
   (`--mm`, plus haut). */
@media (orientation: portrait),
(max-width: 40rem) {
  .accueil-art {
    grid-template-rows: repeat(3, 1fr);
  }

  /* LE TEXTE TIENT EN LARGEUR (7 oct. 2026 : « sur mobile, le texte ne passe pas en
     largeur » — trente lettres au corps x-large, espacées de 0,45em, faisaient
     ~800 px) : l'espacement reste celui de la page (0,2em — le large était pour
     l'arc, qu'il n'y a pas sur un écran étroit ; du 2 au 7 oct., 0,45em ici), et
     des cinq tirets de chaque côté, SEULS LES TROIS CONTRE LE MOT restent —
     « ––– La galerie ––– » — (`data-orne`, AccueilHelper : leur rang depuis le mot ;
     des flèches les séparaient jusqu'au 12 oct. 2026). */
  .accueil-art__porte,
  .accueil-art__design {
    letter-spacing: 0.2em;
  }

  .accueil-art__porte .lettre--orne:not([data-orne="1"]):not([data-orne="2"]):not([data-orne="3"]),
  .accueil-art__design .lettre--orne:not([data-orne="1"]):not([data-orne="2"]):not([data-orne="3"]) {
    display: none;
  }

  /* LA SIGNATURE AU CENTRE (5 oct. 2026 : « abandonner sur mobile le 1er tiers du
     bas et remettre la signature au centre » — du 1er au 5 oct., le centre
     occupait les deux rangées du bas, `grid-row: 2 / 4`, la signature au premier
     tiers en partant du bas) : le centre prend les trois rangées, la signature est
     à mi-hauteur ; les dessins remontent jusqu'au-dessus de « La galerie », les
     diapositives suivent « Le Studio » (envol_controller, `_serpentin`, `_dedans`). */
  .accueil-art__centre {
    grid-row: 1 / 4;
  }

  .accueil-art__mot svg {
    width: min(64vw, 50dvh);
  }

  /* SUR TÉLÉPHONE, LES DESSINS PLUS GRANDS, LES PICPAK PLUS PETITS (9 oct. 2026 : « sur
     mobile, que les dessins soient plus grands et les PicPak plus petits » — #52) : les
     dessins à 1,4 fois la hauteur que le contrôleur leur donne (`--dessin-h`), un peu
     plus larges que l'écran au plus ; les PicPak à la moitié de leur vraie taille (le mm
     du boîtier, `--mm` — posé sur la signature, il reprend sa taille réelle). */
  .accueil-art__dessin img,
  .accueil-art__dessin.is-paysage img {
    --hauteur: min(calc(1.4 * var(--dessin-h, clamp(7rem, 20dvh, 16rem))), calc(98vw / var(--a)));
  }

  .accueil-carte {
    --mm: 0.5mm;
  }
}

/* ── Les réglages du motif de la signature ─────────────────────────────────
   Le panneau de la touche L (l'admin, sur l'accueil : signature_reglages.js),
   en bas à droite, par-dessus tout ; la matière de la pastille « Menu ». */
.signature-reglages {
  position: fixed;
  right: max(0.75rem, var(--page-gutter));
  bottom: 0.75rem;
  z-index: 9500;
  width: min(20rem, calc(100vw - 1.5rem));
  max-height: calc(100dvh - 1.5rem);
  overflow: auto;
  padding: 0.8rem 1rem 1rem;
  border-radius: 0.9rem;
  background: color-mix(in lab, var(--bg-card) 92%, transparent);
  backdrop-filter: blur(2mm);
  box-shadow: 0 0.4em 2em rgba(18, 24, 44, 0.18);
  font-size: small;
  color: var(--ink);
}

.signature-reglages[hidden] {
  display: none;
}

.signature-reglages__tete {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.signature-reglages h2 {
  margin: 0;
  font-size: small;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.signature-reglages kbd {
  margin-left: 0.3em;
  padding: 0 0.35em;
  border: 1px solid var(--ink-faint);
  border-radius: 0.25rem;
  font: inherit;
  font-weight: 400;
  color: var(--ink-muted);
}

.signature-reglages fieldset {
  margin: 0.8rem 0 0;
  padding: 0;
  border: 0;
}

.signature-reglages legend {
  margin-bottom: 0.2rem;
  padding: 0;
  font-size: x-small;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.signature-reglages__champ {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0 0.5rem;
  margin: 0.3rem 0;
}

.signature-reglages__champ input {
  grid-column: 1 / -1;
  width: 100%;
  margin: 0.15rem 0 0;
  accent-color: var(--ink);
}

.signature-reglages output {
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
}

.signature-reglages__couleur {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 0.3rem 0;
}

.signature-reglages input[type="color"] {
  width: 2.4rem;
  height: 1.5rem;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.signature-reglages__connus,
.signature-reglages__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.6rem;
}

.signature-reglages button {
  padding: 0.35em 0.8em;
  border: 0;
  border-radius: 999px;
  background: var(--ink-10);
  font: inherit;
  color: var(--ink);
  cursor: pointer;
}

.signature-reglages__tete button {
  padding: 0.2em 0.5em;
  background: none;
}

.signature-reglages button:hover,
.signature-reglages button:focus-visible,
.signature-reglages__actions .signature-reglages__enregistrer {
  background: var(--ink);
  color: var(--bg-card);
  outline: none;
}

.signature-reglages__etat {
  min-height: 1.3em;
  margin: 0.5rem 0 0;
  color: var(--ink-muted);
}

.signature-reglages__etat.is-erreur {
  color: var(--red);
}
/* ── Zone Art : produit à la une ─────────────────────────────────────────────── */
.art-zone {
  /* Pleine largeur (annule la gouttière du <body>, quelle qu'elle soit : sur
     petit écran elle vaut zéro, et cette marge aussi — sans quoi la zone
     dépasserait de l'écran) et hauteur bornée à la fenêtre pour interdire tout
     scroll vertical de la page : la zone occupe l'écran moins la gouttière basse
     (--bottom-clearance, cf. application.css). La navigation, elle, ne prend
     plus de place — elle s'ouvre au clic droit (cf. site_menu.css). */
  --art-chrome: var(--bottom-clearance);
  margin-inline: calc(-1 * var(--page-gutter));
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 0.75rem 0;
  /* La zone monte jusqu'au BORD HAUT de l'écran : elle annule aussi la gouttière
     haute du <body>, la reprend en marge intérieure et s'allonge d'autant
     (`border-box` : sans ça le contenu perdrait cette hauteur). Le contenu ne
     bouge donc pas d'un pixel, mais ce que la zone rogne (`overflow: hidden`)
     commence maintenant tout en haut : le mur (soie_controller) et l'ombre d'une
     feuille en vol vont jusqu'au bord de l'écran. */
  margin-top: calc(-1 * var(--page-gutter));
  padding-top: calc(0.75rem + var(--page-gutter));
  /* … et jusqu'au BORD BAS, de la même façon. L'ombre d'une feuille tombe vers le
     bas : elle était COUPÉE net au bas de la zone, à une gouttière du bord de l'écran
     (l'auteur : « l'ombre est coupée en bas ») — il n'y a plus rien sous les dessins
     pour l'accueillir. `--art-bas` : ce qui restait d'air sous la zone (la gouttière basse, moins celle
     du <body>), repris en marge intérieure ; la marge négative rend au <body> la
     hauteur qu'il avait — la page ne défile toujours pas. Le contenu ne bouge pas. */
  --art-bas: calc(var(--art-chrome) - var(--page-gutter));
  margin-bottom: calc(-1 * var(--art-bas));
  padding-bottom: calc(0.75rem + var(--art-bas));
  height: 100dvh;
}

.art-featured {
  flex: 1;
  min-height: 0;
  /* Repère de ce qui s'y pose en absolu (le canevas de la soie, le formulaire
     caché du dépôt de fichiers). */
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

/* Le nom du groupe s'affiche sur la grande platine de navigation, peinte dans un
   SVG `aria-hidden` : ce titre reste donc le seul en-tête de la page, présent
   pour les lecteurs d'écran mais jamais peint. */
.art-featured__name {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ── LE MUR ─────────────────────────────────────────────────────────────────────
   DOUZE DESSINS, UN PAR MOIS, TOUS À L'ÉCRAN (demande de l'auteur), ENTIERS, AU
   FORMAT DE LEUR DESSIN, séparés du même écart partout, et alignés sur LA DROITE DU
   CENTRE (28 sept. 2026 : « des images sur des pages avec le bon ratio et des gaps
   cohérents ; pour les alignements, utiliser la droite du centre — en paysage elle
   est verticale, en portrait horizontale »). Des BANDES de quatre dessins : en
   paysage, des rangées de même HAUTEUR, chacune centrée sur l'axe vertical de la
   fenêtre ; en portrait, des colonnes de même LARGEUR, chacune centrée sur l'axe
   horizontal — l'écart `--art-ecart` dans une bande, entre les bandes, et pour les
   marges. C'est art_carousel_controller qui POSE chaque figure (`_tailler` : `left`,
   `top`, `width`, `height`, en px, dans `.art-mur` ; le calcul ne tient pas en
   CSS). Les dessins s'y suivent dans l'ordre des collections (une section
   `.art-group` par collection, sa piste : des boîtes SANS BOÎTE, `display:
   contents`). `.art-groups` est la FENÊTRE du mur (la hauteur restante, tout ce qui
   dépasse est masqué — l'image seule y vole, cf. plus bas). Rien ne défile, rien ne
   glisse. Le doigt est au contrôleur (un glissement franc est un pas), sauf le
   pincement. ESSAYÉS ET RETIRÉS le même jour (git les garde) : des rangées par
   collection qui glissaient, puis une grille de cellules égales aux dessins
   recadrés (« les aspects ratios ne sont pas bons »). */
.art-groups {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  touch-action: pinch-zoom;
}

.art-mur {
  position: relative;
  height: 100%;
}

/* Une collection et sa piste ne font pas de boîte : leurs figures sont posées
   directement dans le mur. */
.art-group,
.art-featured__images {
  display: contents;
}

/* Image seule : les autres dessins s'effacent, et ne prennent plus de geste. Seule
   l'opacité bouge — les places, elles, ne changent pas. */
.art-mur.is-focused .art-featured__figure:not(.is-focus) {
  opacity: 0;
  pointer-events: none;
}

/* (`is-focused` reste posée sur la piste du dessin ouvert : la soie la lit pour
   effacer les voisines ; le CSS, lui, efface depuis le mur, ci-dessus.) */

/* ── Image seule : titre, texte, loupe ──────────────────────────────────────── */
/* Le panneau se tient à DROITE de l'image, en dehors d'elle : rien ne recouvre
   plus l'œuvre. En image seule, l'image n'est plus à sa place dans la grille (elle
   a volé au milieu de la fenêtre, par un `transform`) : c'est son rectangle
   d'arrivée que le contrôleur écrit sur la figure (`--img-*`), et c'est là que le
   panneau se pose — le texte en haut de l'image, le cartel en bas. */
.art-figure__info {
  position: absolute;
  /* À droite de l'image, LÀ OÙ ELLE EST : `--img-x` `--img-y` `--img-w` `--img-h`,
     le rectangle de l'image dans la figure, posé par art_carousel_controller
     (`_measure`) — celui de l'image agrandie, en image seule. */
  left: calc(var(--img-x, 0px) + var(--img-w, 0px) + 1.5rem);
  top: var(--img-y, 0px);
  height: var(--img-h, 100%);
  /* Bornée en `vw` : entre l'image (centrée) et le bord de l'écran, la place
     dépend de la largeur de la fenêtre. */
  width: min(30ch, 27vw);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  text-align: left;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.35s ease, visibility 0.35s;
}

.art-featured__figure.is-focus .art-figure__info {
  opacity: 1;
  visibility: visible;
}

/* Le bandeau et le cahier défilent pour eux-mêmes, au doigt aussi : le mur
   (`.art-groups`, `touch-action: pinch-zoom`) ne les prend pas — le contrôleur
   ignore les gestes qui partent d'eux. */
.art-figure__info,
.art-cahier {
  touch-action: pan-y;
}

/* Le bandeau porte les réglages de l'admin (en haut) et le cartel (en bas) : s'il
   dépasse la hauteur de l'oeuvre, il défile. */
@media (min-width: 781px) {
  .art-figure__info {
    overflow-y: auto;
    scrollbar-width: none;
    padding: 0 1rem 1rem 0;
    box-sizing: content-box;
  }

  .art-figure__info::-webkit-scrollbar {
    display: none;
  }
}

.art-figure__title {
  margin: 0;
  font-size: small;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink);
}

.art-figure__text {
  margin: 0;
  max-width: 52ch;
  font-size: x-small;
  line-height: 1.5;
  color: var(--ink-muted);
}

/* Édition en ligne (admin) : les champs prennent EXACTEMENT l'allure des textes
   qu'ils remplacent — même taille, même casse, même couleur — et ne se révèlent
   qu'au survol ou à la saisie, par un simple filet. Le bandeau garde donc la
   même tenue, qu'on soit connecté ou non. */
.art-figure__form {
  display: contents;
}

.art-figure__field {
  width: 100%;
  max-width: 52ch;
  /* `form.scss.css` habille TOUS les champs d'un <form> (bordure, fond, et pour
     les textareas `height: 100%` + `min-height: 48rem`) : ici on veut l'inverse,
     un champ qui se fait passer pour du texte et qui tient à la hauteur de son
     contenu (autogrow s'occupe du reste). */
  height: auto;
  min-height: 0;
  padding: 0.15rem 0.3rem;
  /* La famille seulement : la TAILLE reste celle de `.art-figure__title` /
     `.art-figure__text`, que le champ porte aussi — un `font: inherit` les
     écraserait et le texte changerait de corps en passant en édition. */
  font-family: inherit;
  font-weight: inherit;
  text-align: inherit;
  color: inherit;
  background: transparent;
  border: 0;
  border-bottom: 1px solid transparent;
  border-radius: 3px;
  resize: none;
  transition: background 0.2s, border-color 0.2s;
}

.art-figure__field::placeholder {
  color: var(--ink-10);
}

.art-figure__field:hover {
  border-bottom-color: var(--ink-10);
}

.art-figure__field:focus {
  outline: none;
  background: color-mix(in lab, var(--bg-card) 70%, transparent);
  border-bottom-color: var(--ink-muted);
}

/* Le témoin d'enregistrement (« … », « ✓ ») : discret, et il ne pousse rien
   puisqu'il ne prend pas de place dans le flux. */
.art-figure__status {
  height: 0;
  margin-top: -0.2rem;
  font-size: x-small;
  color: var(--ink-muted);
  line-height: 1;
  pointer-events: none;
}

/* Image seule : sur l'oeuvre, le pointeur reste le pointeur. RETIRÉS (l'auteur,
   28 sept. 2026 : « retire le curseur bulle quand on est sur une image ») : le
   `cursor: zoom-in` et, par-dessus, la GOUTTE de la loupe en curseur
   (`image-set(var(--loupe-icon) 2x) 18 18`, la miniature que loupe_controller
   dessine et pose en `--loupe-icon` / `has-loupe-icon`) — ils promettaient une
   loupe au clic, que le clic ne pose plus depuis que seule la touche L l'invoque.
   La miniature reste dessinée (loupe_controller), plus rien ne la porte ici. */









/* Écran étroit : LE MÊME DESSIN QU'EN GRAND (1er oct. 2026 : « en mobile le cartel
   est différent, ce n'est pas bon ; je veux qu'il reste comme il est en desktop,
   pas avec un nouveau layout ») — le cartel, un papier à droite de l'oeuvre, qu'on
   tire. (Un pied de vignette sur le bas de l'image, centré, sur un voile clair, a
   été le dessin étroit jusque-là ; git le garde.) */

.art-featured__figure {
  margin: 0;
  /* POSÉE par le contrôleur, au format de son dessin (`left` `top` `width`
     `height`) ; l'image la remplit. (Le repli sans contrôleur — des figures en
     rang, `is-pose` — est RETIRÉ le 1er oct. 2026 : « art-mur is-pose existe
     encore, il faut le supprimer » ; git le garde.) */
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  /* La figure, elle, ne bouge JAMAIS : c'est son image qui vole (`transform`,
     ci-dessous). `position: absolute` en fait le repère du bandeau, de la planche
     et du cadre ; `contain: layout` isole le calcul de mise en page de chaque
     figure (pas de `paint`, qui rognerait l'ombre et l'image envolée). */
  contain: layout;
  transition: opacity 0.35s ease;
}

/* L'image seule passe devant ses voisines. */
.art-featured__figure.is-focus {
  z-index: 2;
}

/* L'IMAGE : entière dans sa cellule (les deux bornes ensemble, format gardé) — et,
   en image seule, ELLE VOLE jusqu'au milieu de la fenêtre : `--zx` `--zy` (la translation) et `--zkx` `--zky`
   (l'échelle), posées sur la figure par art_carousel_controller (`_measure`), et une
   TRANSITION de `transform` fait le vol — la soie suit l'image où qu'elle soit. Sur
   le mur, le transform est l'identité. Le `transform` vaut aussi couche composite. */
.art-featured__img {
  display: block;
  /* Le vol : une translation et une échelle (`--zkx` = `--zky`, la figure a le
     format du dessin) — l'image glisse et grandit jusqu'au milieu de la fenêtre. */
  transform: translate(var(--zx, 0px), var(--zy, 0px)) scale(var(--zkx, 1), var(--zky, 1));
  transform-origin: 0 0;
  transition: transform 0.38s cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: transform;
  /* Sans ça, glisser une image la ferait partir en drag-and-drop natif (image
     fantôme). */
  -webkit-user-drag: none;
  user-select: none;
  /* Elle remplit sa figure, qui a exactement son format (posée par le contrôleur
     d'après `naturalWidth` / `naturalHeight`) : rien n'est recadré. `contain`, pour
     le repli sans contrôleur. */
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 6px;
  box-shadow: 0 2px 24px color-mix(in lab, var(--ink) 12%, transparent);
}



@media (prefers-reduced-motion: reduce) {
  .art-featured__img,
  .art-featured__couche {
    transition: none;
  }
}

/* Les COUCHES d'un dessin (cf. `Image#base`) : des feuilles posées sur l'image de
   base — un trait sur calque par-dessus un aplat de couleur. Hors du flux, dans la
   boîte même de la base : mêmes bornes qu'elle, même accroche (en haut, au
   milieu), même décalage — deux fichiers au même cadrage tombent donc l'un sur
   l'autre. Elles se MULTIPLIENT sur ce qu'elles couvrent : le blanc du calque
   disparaît, son trait reste, la couleur du dessous se voit au travers. Sur le
   mur, aucun geste ne s'y arrête : tout va à l'image de base, dessous ; EN IMAGE
   SEULE, ON LES TIRE (calque_controller, 2 oct. 2026 : « les calques doivent
   pouvoir être déplacés eux aussi ») — leur place, `--ux` `--uy`, en largeurs et
   hauteurs de l'image (Image#place, pages/art/_pile), vaut à toute taille. (La
   soie, quand elle est allumée, les repeint en feuilles de calque, là où elles
   sont, et les rend transparentes, comme la base — cf. soie.css.) */
.art-featured__couche {
  position: absolute;
  inset: 0;
  display: block;
  /* La boîte de la base — la figure, au format du dessin —, et même vol qu'elle
     (`--zx` `--zy` `--zkx` `--zky`) depuis le même coin : deux fichiers au même
     cadrage restent l'un sur l'autre, envolés ou non — puis SA PLACE (`--ux`
     `--uy`, des parts de sa propre boîte, avant l'échelle : le décalage grandit
     avec l'image). */
  transform: translate(var(--zx, 0px), var(--zy, 0px)) scale(var(--zkx, 1), var(--zky, 1))
    translate(calc(var(--ux, 0) * 100%), calc(var(--uy, 0) * 100%));
  transform-origin: 0 0;
  transition: transform 0.38s cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: transform;
  width: 100%;
  height: 100%;
  object-fit: contain;
  border-radius: 6px;
  mix-blend-mode: multiply;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}

/* En image seule, un calque se prend (calque_controller) : il reçoit le pointeur,
   le doigt ne fait pas défiler ; tenu, il suit la main sans transition. */
.art-featured__figure.is-focus .art-featured__couche {
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
}

.art-featured__couche.is-tenu {
  transition: none;
  cursor: grabbing;
}

/* Leur boîte n'existe que pour être remplacée d'un bloc (Turbo Stream, quand
   l'admin pose ou détache une couche) : elle ne fait pas de boîte — les couches
   restent posées par rapport à la FIGURE. */
.art-featured__pile {
  display: contents;
}

/* Titre de l'image courante, centré EN HAUT de la zone ; son contenu change
   selon l'image au centre (art_carousel_controller). Texte simple : la zone Art
   n'utilise plus les tuiles à volets. */
/* RETIRÉ DE L'ÉCRAN à la demande de l'auteur (« il faut retirer le titre
   art-featured__caption ») : le titre se lit sur le CARTON du dessin, en « image
   seule ». L'élément reste dans la page, jamais peint et sans place, pour les
   lecteurs d'écran — c'est lui (`aria-live`) qui leur annonce l'image qui passe
   au centre ; art_carousel_controller le tient toujours à jour. */
.art-featured__caption {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.art-featured--empty {
  justify-content: center;
  align-items: center;
  text-align: center;
  color: var(--ink-muted);
  padding: 4rem 1rem;
}

/* ── L'année ────────────────────────────────────────────────────────────────────
   L'année du mur (pages/art/_featured), en haut à gauche, écrite À MÊME LE MUR
   comme le cartel (même encre, même opacité : la lumière du mur passe au travers).
   La date se clique : un `<details>` natif déplie les autres années — des liens,
   un mur est une page (`/art/<année>`). Au-dessus du mur, sous la pastille
   « Menu » (à droite). Demande de l'auteur : « on peut passer d'une année à
   l'autre en cliquant sur la date ». */
/* L'année n'est pas rendue sur un SHOW (le permalien d'un dessin : pages/art/_featured,
   `show`) — 1er oct. 2026, « il faut retirer art-annee des show art » — et s'efface
   dès qu'un dessin s'ouvre en image seule sur un autre mur. */
.art-featured:has(.art-mur.is-focused) .art-annee {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.35s ease;
}

.art-annee {
  position: absolute;
  top: 0.25rem;
  /* Au ras du mur : la marge de gauche des dessins (`--art-ecart`, posée par le
     contrôleur sur `.art-featured`). */
  left: var(--art-ecart, max(1rem, var(--page-gutter)));
  z-index: 3;
  color: var(--ink);
  opacity: 0.86;
}

.art-annee__date {
  margin: 0;
  font-size: x-large;
  letter-spacing: 0.12em;
  line-height: 1.2;
  list-style: none;
  user-select: none;
}

.art-annee__date::-webkit-details-marker {
  display: none;
}

.art-annee__choix .art-annee__date {
  cursor: pointer;
}

/* Le signe qu'elle se déplie : un chevron fin après la date, qui bascule. */
.art-annee__choix .art-annee__date::after {
  content: "";
  display: inline-block;
  width: 0.4em;
  height: 0.4em;
  margin-left: 0.5em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-0.2em) rotate(45deg);
  opacity: 0.6;
  transition: transform 0.2s ease;
}

.art-annee__choix[open] .art-annee__date::after {
  transform: translateY(0.05em) rotate(-135deg);
}

.art-annee__liste {
  list-style: none;
  margin: 0.4rem 0 0 0.1em;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.art-annee__lien {
  font-size: medium;
  letter-spacing: 0.1em;
  color: var(--ink-muted);
  text-decoration: none;
  transition: color 0.2s ease;
}

.art-annee__lien:hover,
.art-annee__lien:focus-visible {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.25em;
  outline: none;
}

.art-annee__lien[aria-current="page"] {
  color: var(--ink);
}

/* Les DOUZE et les AUTRES (pages/art/_featured) : à côté de la date, deux mots — le
   mur où l'on est en encre pleine, l'autre en lien. */
.art-annee__ligne {
  display: flex;
  align-items: baseline;
  gap: 1em;
}

.art-annee__murs {
  display: flex;
  gap: 0.5em;
  margin: 0;
  font-size: small;
  letter-spacing: 0.1em;
  color: var(--ink-muted);
  white-space: nowrap;
}

.art-annee__mur {
  color: inherit;
  text-decoration: none;
  transition: color 0.2s ease;
}

.art-annee__mur:hover,
.art-annee__mur:focus-visible {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.25em;
  outline: none;
}

.art-annee__mur[aria-current="page"] {
  color: var(--ink);
}

@media (max-width: 780px) {
  .art-annee__date {
    font-size: large;
  }

  .art-annee__murs {
    font-size: x-small;
  }
}

/* ── Le cartel ──────────────────────────────────────────────────────────────────
   Le cartel du dessin (pages/art/_cartel), en bas à droite de l'oeuvre en mode
   « image seule » : son titre, puis sa description (7 oct. 2026 : « finalement juste
   un titre et une description » — la ligne du signe, de la date, de la technique et
   des dimensions est retirée). Il est écrit À MÊME LE MUR, comme un lettrage peint dans un musée
   (demande de l'auteur : « le cartel doit être écrit directement sur le mur, comme si
   c'était de la peinture murale ») : ni carton, ni fond, ni ombre — une première
   version en était un, posé sur le mur. Une peinture mate laisse deviner le mur
   dessous : l'encre n'est pas tout à fait opaque (la lumière du mur, peinte dans le
   canevas de la soie, passe au travers). Pour l'admin, les mêmes lignes sont des
   champs (`.art-figure__field`) qui se font passer pour du texte.
   Il est EN BAS À DROITE de l'oeuvre (demande de l'auteur) : le bandeau a la hauteur
   de l'oeuvre, et le cartel, dernier du bandeau, est poussé tout en bas — son bas
   tombe sur celui de l'oeuvre, pour l'admin comme pour le visiteur. (Une marge
   `auto` et non `justify-content: flex-end` : si le bandeau de l'admin déborde et
   défile, son haut reste atteignable. PIÈGE PAYÉ : la marge était posée sur le
   PREMIER enfant du bandeau — or pour l'admin c'était un <form> en `display:
   contents`, qui ne fait pas de boîte : rien n'était poussé, son cartel restait en
   haut. L'auteur : « l'alignement n'est pas bon ».)
   Son CORPS est un cran au-dessus du reste du bandeau (« je veux une typo plus grande
   pour le texte ») — titre `medium`, description `small` (c'était `small` et
   `x-small`) —, pour le rendu comme pour le formulaire, qui portent les mêmes
   classes. `position: relative` : pour le témoin d'enregistrement, hors du flux. */
.art-cartel {
  position: relative;
  width: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  margin-top: auto;
}

/* LE CARTEL EST UN PAPIER (1er oct. 2026 : « le cartel doit lui aussi être un
   papier, mais un papier affiché dès le début ») : le même petit papier crème
   que les notes du cahier (cahier.css, « Le papier »), tapé à la machine — là dès
   que l'image s'ouvre, à sa place à droite de l'oeuvre, un peu de travers ; les
   ombres d'une feuille posée (`.feuille`, accueil.css). Les champs de l'admin
   héritent la machine. */
.art-cartel {
  --vol: 0;
  padding: 1.1em 1.25em 1.4em;
  background:
    linear-gradient(180deg, rgb(255 255 255 / 0.4), rgb(255 255 255 / 0) 35%),
    linear-gradient(100deg, rgb(120 95 50 / 0.05), rgb(120 95 50 / 0) 40%, rgb(120 95 50 / 0.06)),
    #f3ecd9;
  color: #2b2621;
  font-family: var(--police-machine, monospace);
  letter-spacing: 0.02em;
  /* Un peu de travers — et là où on l'a tiré (`--cartel-x` `--cartel-y`,
     cahier_controller : « le cartel doit être déplaçable »). */
  transform: translate(var(--cartel-x, 0px), var(--cartel-y, 0px)) rotate(-1.2deg);
  touch-action: none;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  /* Ses ombres : les deux de la soie, les mêmes que les feuilles du cahier
     (cahier.css, « L'ombre de la soie » ; cahier_controller, `_ombrerCartel`). */
}

/* Tenu : il se soulève (ses ombres filent, cahier_controller), et suit sans traîner. */
.art-cartel.is-tenu {
  cursor: grabbing;
  transition: none;
}

/* Le bandeau ne rogne plus : le cartel, tiré, peut en sortir (il ne défile plus —
   un cartel long déborde, en papier). */
.art-featured__figure .art-figure__info {
  overflow: visible;
}

.art-cartel .art-figure__title,
.art-cartel .art-figure__text,
.art-cartel .art-cartel__champ {
  font-family: inherit;
  color: inherit;
}

.art-cartel .art-figure__text {
  color: #5e5346;
}

.art-cartel .art-figure__text {
  line-height: 1.55;
}

/* LE CARTEL OUVRE LES PAPIERS (1er oct. 2026 : « pas besoin du mot 'cahier',
   ce sera au clic sur le cartel que les papiers apparaîtront ») : quand le dessin
   a des notes (`data-papiers`, posé par cahier_controller), il se clique — il se
   soulève un rien au survol ; ouvert (`aria-expanded`), il reste soulevé. Pour
   l'admin, ses champs restent des champs (un clic dedans n'ouvre rien). */
.art-cartel:not([data-papiers="0"])[data-papiers] {
  cursor: pointer;
}

.art-cartel .art-cartel__champ {
  cursor: text;
}

.art-cartel .art-figure__title {
  font-size: medium;
}

.art-cartel .art-figure__text {
  font-size: small;
}

/* Dans le cartel, le témoin d'enregistrement ne prend AUCUNE place (hors du flux) :
   en ligne, il ajoutait un écart sous la description — le texte de l'admin finissait
   plus haut que celui du visiteur. */
.art-cartel .art-figure__status {
  position: absolute;
  right: 0;
  top: -1.1em;
  height: auto;
  margin: 0;
}

/* ── Le cartel en ÉDITION (admin) : le dessin du rendu final ────────────────────
   « Je veux que mon formulaire d'édition ait le même design que le rendu final » :
   dans le cartel, un champ n'a NI marge NI bordure NI fond, il a l'interligne du
   texte qu'il remplace, et il est de la largeur de ce qu'il contient
   (`field-sizing: content` — sans lui, une largeur de repli). Le seul signe d'un
   champ est un filet SOUS lui au survol et à la saisie — une ombre, pas une
   bordure : elle ne prend pas de place. */
.art-cartel .art-cartel__champ {
  display: block;
  width: auto;
  max-width: 100%;
  min-width: 3ch;
  field-sizing: content;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  line-height: inherit;
  letter-spacing: inherit;
  box-shadow: none;
  transition: box-shadow 0.2s;
}

/* LE FORMAT DU PAPIER (l'admin seul, 8 oct. 2026) : une ligne discrète sous la
   description, à la machine comme le reste — on la lit à peine. */
.art-cartel .art-cartel__format {
  margin-top: 0.5em;
  font-size: x-small;
  letter-spacing: 0.04em;
  color: #8a7f72;
}

/* Le titre et la description tiennent la largeur du cartel, comme leurs lignes. */
.art-cartel .art-figure__title.art-cartel__champ,
.art-cartel .art-figure__text.art-cartel__champ {
  width: 100%;
  field-sizing: fixed;
}

.art-cartel .art-figure__title.art-cartel__champ {
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.art-cartel .art-figure__text.art-cartel__champ {
  line-height: 1.5;
  overflow: hidden;
}

/* La description prend la hauteur de ce qu'elle MONTRE — son texte, ou son repli
   (la description du groupe) quand elle est vide : `autogrow` ne sait mesurer que
   le texte saisi, et couperait le repli à une ligne. Là où `field-sizing` existe,
   c'est lui qui décide (la hauteur en ligne d'`autogrow` est ignorée). */
@supports (field-sizing: content) {
  .art-cartel .art-figure__text.art-cartel__champ {
    field-sizing: content;
    height: auto !important;
  }
}

.art-cartel .art-cartel__champ:hover {
  box-shadow: 0 1px 0 var(--ink-10);
}

.art-cartel .art-cartel__champ:focus {
  background: transparent;
  box-shadow: 0 1px 0 var(--ink-muted);
}

/* Un champ vide dont le visiteur verrait le REPLI (le nom du groupe pour le titre,
   la description du groupe pour la description) le montre tel qu'il sera vu. */
.art-cartel .art-cartel__champ--repli::placeholder {
  color: inherit;
  opacity: 1;
}

/* (« Le cartel s'écrit » — les lettres qui paraissaient une à une, les champs de
   l'admin découverts par crans — est RETIRÉ le 1er oct. 2026 : « retire les
   animations du texte sur les cartels » ; git le garde.) */

/* ── Les calques (admin) : en haut du bandeau ───────────────────────────────────
   Le panneau `pages/art/_couches` (2 oct. 2026 : plus d'établi — il est là,
   directement, quand l'image est seule) : « Calques », une vignette par calque et
   son ✕ au coin ; caché sans calque. Le champ du dépôt (un fichier lâché SUR
   l'image, art_depot_controller) est dans un formulaire caché. */
.art-couches {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.5rem;
  margin: 0;
}

.art-couches[hidden] {
  display: none;
}

.art-couches__titre {
  font-size: xx-small;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.art-couches__liste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.art-couches__feuille {
  position: relative;
  width: 3.2rem;
}

.art-couches__vignette {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--ink-10);
  background: #fff;
}

/* PIÈGE : form.scss.css centre et borne tout <form> — ceux d'ici reprennent leur place. */
.art-couches__form {
  display: inline;
  max-width: none;
  margin: 0;
}

.art-couches__supprimer {
  position: absolute;
  top: -0.4rem;
  right: -0.4rem;
  width: 1.3rem;
  height: 1.3rem;
  padding: 0;
  border: 1px solid var(--ink-10);
  border-radius: 50%;
  background: color-mix(in lab, var(--bg-card) 90%, transparent);
  font: inherit;
  font-size: xx-small;
  line-height: 1;
  color: var(--ink-muted);
  cursor: pointer;
}

.art-couches__supprimer:hover,
.art-couches__supprimer:focus-visible {
  color: var(--red);
  border-color: var(--red);
  outline: none;
}

/* ── Le cahier de recherches ────────────────────────────────────────────────────
   LE CAHIER d'un dessin (notes/_cahier ; cahier.css pour sa matière) : en mode
   « image seule », À GAUCHE de l'oeuvre, en haut — rien pour le visiteur (c'est le
   cartel qui ouvre), « + Note » pour l'admin. Ouvert, le cahier S'ÉTALE sur tout
   l'écran (cahier_controller : la scène, posée sur le <body>, hors d'ici) ; la
   liste des notes, elle, n'est jamais montrée ici. Même repère que le bandeau
   (`--img-*`), même fondu. */
.art-cahier {
  position: absolute;
  /* À gauche de l'image, là où elle est (`--img-*`, cf. le bandeau). */
  right: calc(100% - var(--img-x, 0px) + 1.5rem);
  top: var(--img-y, 0px);
  width: min(16ch, 26vw);
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.6rem;
  text-align: right;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.35s ease, visibility 0.35s;
}

.art-cahier .cahier__tete {
  flex-direction: column;
  align-items: flex-end;
  gap: 0.6rem;
}

.art-cahier .cahier__ajouts {
  justify-content: flex-end;
}

.art-cahier[hidden] {
  display: none;
}

.art-featured__figure.is-focus .art-cahier {
  opacity: 1;
  visibility: visible;
}

/* LA FIGURE OUVERTE AU-DESSUS DU PASSAGE (controllers/passage ; 7 oct. 2026 :
   « depuis la home, la transition place le cartel par dessous alors qu'il devrait
   être par dessus ») : de l'accueil à son show, et retour, le voile et la copie du
   dessin (1000 et 1001, passage.css) sont RANGÉS dans le mur, et la figure passe
   au-dessus d'eux — son image est transparente sous la soie ; son cartel, ses
   ombres et son cahier couvrent la copie comme ils couvriront le dessin
   (art_carousel_controller, `_surPassage`). `passage-cache` les efface d'un coup —
   retirée aussitôt, ils paraissent en fondu avec la page ; `passage-part` les
   efface au rythme du voile qui monte (`--passage-ms`). */
.art-featured__figure.sur-passage {
  z-index: 1002;
}

.art-featured__figure.sur-passage .cartel-ombres {
  transition: opacity 0.35s ease;
}

.art-featured__figure.passage-cache .art-figure__info,
.art-featured__figure.passage-cache .art-cahier,
.art-featured__figure.passage-cache .cartel-ombres {
  opacity: 0;
  transition: none;
}

.art-featured__figure.passage-part .art-figure__info,
.art-featured__figure.passage-part .art-cahier,
.art-featured__figure.passage-part .cartel-ombres {
  opacity: 0;
  transition: opacity var(--passage-ms, 240ms) ease;
}

/* Écran étroit : plus de marge à gauche de l'oeuvre non plus. Le bouton se pose
   au coin de l'image, en haut à gauche ; la scène, elle, prend l'écran. */
@media (max-width: 780px) {
  .art-cahier {
    left: calc(var(--img-x, 0px) + 0.6rem);
    right: auto;
    top: calc(var(--img-y, 0px) + 0.6rem);
    width: auto;
    align-items: flex-start;
    text-align: left;
  }

  .art-cahier .cahier__tete {
    align-items: flex-start;
  }

  .art-cahier .cahier__vide {
    display: none;
  }
}

/* VENU DE L'ACCUEIL (art_carousel_controller, `sans-vol`) : le dessin cliqué sur
   l'accueil y a déjà glissé jusqu'au milieu — ici il est ouvert D'EMBLÉE, sans
   voler depuis sa place du mur, les autres déjà effacés. Jusqu'à ce que le passage
   se pose (`_accueillir`) : un fichier qui arrive sous le voile remet tout d'un
   coup, rien ne glisse. */
.art-featured.sans-vol,
.art-featured.sans-vol * {
  transition: none !important;
}
.chladni-bento {
  position: relative;
  aspect-ratio: 1 / 1;
  padding: 0;
  overflow: hidden;
}

.chladni-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  cursor: crosshair;
  touch-action: none;
}

.chladni-kicker {
  position: absolute;
  top: 1em;
  left: 1em;
  padding: 0.2em 0.6em;
  border-radius: 999px;
  background: color-mix(in lab, var(--bg) 70%, transparent);
  backdrop-filter: blur(4px);
}

.chladni-toolbar {
  position: absolute;
  top: 1em;
  right: 1em;
  display: flex;
  gap: 0.4em;
}

.chladni-icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.8em;
  height: 1.8em;
  border: none;
  border-radius: 999px;
  background: color-mix(in lab, var(--bg) 70%, transparent);
  backdrop-filter: blur(4px);
  color: var(--ink);
  cursor: pointer;
  font-size: x-small;

  &:hover {
    background: color-mix(in lab, var(--bg) 90%, transparent);
  }
}

.chladni-swatch {
  -webkit-appearance: none;
  appearance: none;
  width: 1em;
  height: 1em;
  padding: 0;
  border: 2px solid;
  border-radius: 50%;
  background: none;
  cursor: pointer;

  &::-webkit-color-swatch-wrapper {
    padding: 0;
    border-radius: 50%;
  }

  &::-webkit-color-swatch {
    border: none;
    border-radius: 50%;
  }

  &::-moz-color-swatch {
    border: none;
    border-radius: 50%;
  }
}

.chladni-swatch--bg {
  border-color: var(--ink);
}

.chladni-swatch--ink {
  border-color: var(--bg);
}

.chladni-readout {
  position: absolute;
  bottom: 1em;
  left: 1em;
  padding: 0.2em 0.6em;
  border-radius: 999px;
  font-family: monospace;
  font-size: x-small;
  background: color-mix(in lab, var(--bg) 70%, transparent);
  backdrop-filter: blur(4px);
  color: var(--ink);
}
.contact-bento {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 1.25rem;
  background:
    linear-gradient(160deg, color-mix(in lab, var(--blue) 12%, transparent), transparent 55%),
    var(--white--true);
  color: var(--ink);
}

.contact-bento .bento-copy i {
  color: var(--ink);
  margin-right: 0.4ch;
}
.experiences * {
  box-shadow: none;
}

/* Admin : lien « + Ajouter » en pied des bentos expériences/formations */
.experience-add {
  display: inline-block;
  margin-top: 0.4rem;
  font-size: x-small;
  color: var(--gray);
  text-decoration: none;
}

.experience-add:hover {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.formations * {
  box-shadow: none;
}
.globe-bento {
  display: flex;
  flex-direction: column;
}

.globe-bento .globe-host {
  flex: 1 0 auto;
}
.identity-bento {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 1.5rem;
}

.identity-top,
.identity-meta {
  display: flex;
  flex-direction: column;
}

.identity-top {
  gap: 0;
}

.identity-divider {
  margin: 1rem 0rem;
  border: none;
  border-top: 1px solid var(--ink-10);
}

.identity-name {
  color: var(--ink);
  font-size: large;
  font-weight: bold;
  line-height: 1;
}

.identity-name--last {
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.identity-meta {
  gap: 0.3rem;
  color: var(--grey);
}

.identity-job {
  color: var(--ink);
  font-size: large;
}
/* ── Formulaire d'offre « WYSIWYG » (admin, /admin/offers) ─────────────────────
   La carte éditable garde les proportions, tokens et tailles typographiques de
   l'ancienne carte publique (l'ex-.oc-card, partie avec la vitrine des offres le
   12 oct. 2026 — git la garde). Chaque input est posé là où l'élément apparaissait
   sur la carte. Le type d'offre masque les zones absentes (cf. offer_form_controller). */
.offer-form__form {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
  max-width: unset;
}

.offer-form {
  --oc-ink: var(--ink);
  --oc-soft: var(--ink-muted);
  --oc-hair: var(--ink-10);
  --oc-page: var(--bg-card);

  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
  width: 100%;
}

/* Type d'offre : segmented control (pilote l'eyebrow + la visibilité des zones) */
.offer-form__kinds {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  border: 1px solid var(--oc-hair);
  border-radius: 999px;
  background: color-mix(in srgb, var(--oc-hair) 30%, transparent);
}

.offer-form__kind {
  cursor: pointer;
}

.offer-form__kind input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.offer-form__kind span {
  display: block;
  padding: 0.4rem 1rem;
  border-radius: 999px;
  font-size: xx-small;
  font-weight: 600;
  color: var(--oc-soft);
  transition: background 120ms, color 120ms;
}

.offer-form__kind input:checked+span {
  background: var(--oc-page);
  color: var(--oc-ink);
  box-shadow: 0 1px 4px -1px rgba(15, 20, 30, 0.35);
}

/* La carte éditable — mêmes dimensions que .oc-card */
.offer-form-card {
  width: 460px;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  padding: clamp(20px, 4vw, 30px);
  border-radius: 20px;
  background: var(--oc-page);
  border: 1px solid var(--oc-hair);
  box-shadow: 0 30px 70px -50px rgba(15, 20, 30, 0.5);
}

.offer-form-card__eyebrow {
  margin: 0 0 clamp(10px, 2.5vw, 14px);
  font-size: x-small;
  font-weight: 600;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: var(--oc-soft);
}

.offer-form-card__rule {
  border: none;
  border-top: 1px solid var(--oc-hair);
  margin: 0 0 clamp(12px, 3vw, 18px);
}

/* Chaque champ = un bloc avec micro-libellé au-dessus de l'input */
.offer-field {
  display: block;
  margin-bottom: clamp(12px, 3vw, 18px);
}

.offer-field[hidden] {
  display: none;
}

.offer-field__hint {
  display: block;
  margin-bottom: 4px;
  font-size: xx-small;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--oc-soft);
  opacity: 0.7;
}

/* Inputs « transparents » : prennent l'allure du texte rendu, soulignés au repos,
   surlignés au focus pour rester manifestement éditables. */
.offer-input {
  font: inherit;
  color: var(--oc-ink);
  width: 100%;
  box-sizing: border-box;
  border: none;
  border-bottom: 1px dashed var(--oc-hair);
  background: transparent;
  padding: 2px 2px 4px;
  border-radius: 3px 3px 0 0;
  transition: background 120ms, border-color 120ms;
}

.offer-input:hover {
  border-bottom-color: var(--oc-soft);
}

.offer-input:focus {
  outline: none;
  border-bottom-color: var(--oc-ink);
  background: color-mix(in srgb, var(--oc-hair) 35%, transparent);
}

.offer-input::placeholder {
  color: var(--oc-soft);
  opacity: 0.5;
}

.offer-input--name {
  font-size: x-large;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.offer-input--desc {
  resize: vertical;
  min-height: 5lh;
  line-height: 1.4;
  font-size: small;
  font-weight: 500;
  border: 1px solid var(--oc-hair);
  border-radius: 10px;
  padding: 0.6rem 0.7rem;
}

.offer-input--desc:focus {
  border-color: var(--oc-ink);
}

/* Délai : pill du libellé + valeur, comme .oc-delay */
.offer-field--delay {
  display: flex;
  gap: 12px;
  align-items: flex-end;
  flex-wrap: wrap;
}

.offer-delay-edit__key,
.offer-delay-edit__val {
  display: block;
}

.offer-input--delay-key {
  width: 8ch;
  font-size: x-small;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-align: center;
  border: 1px solid var(--oc-hair);
  border-radius: 999px;
  padding: 4px 10px;
  color: var(--oc-soft);
}

.offer-input--delay {
  width: 16ch;
  font-size: medium;
  font-weight: 600;
}

/* Prix : préfixe · montant · € · suffixe, aligné comme .oc-priceline */
.offer-field--price {
  display: flex;
  gap: 14px;
  align-items: flex-end;
  flex-wrap: wrap;
  margin-bottom: 0;
}

.offer-price-edit__part {
  display: block;
}

.offer-price-edit__amount {
  flex: 0 0 auto;
}

.offer-price-edit__wrap {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
}

.offer-input--price {
  width: 6ch;
  font-size: x-large;
  font-weight: 700;
  text-align: right;
}

.offer-price-edit__euro {
  font-size: large;
  font-weight: 700;
  color: var(--oc-ink);
}

.offer-input--affix {
  width: 11ch;
  font-size: x-small;
  font-weight: 500;
  color: var(--oc-soft);
}

/* Média : grille de vignettes de groupes, sélection UNIQUE (= mini-slider rendu) */
.offer-products__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 8px;
}

.offer-product-chip {
  position: relative;
  display: flex;
  flex-direction: column;
  cursor: pointer;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--oc-hair);
  background: var(--light-grey);
  transition: border-color 120ms, box-shadow 120ms;
}

.offer-product-chip__input {
  position: absolute;
  top: 6px;
  left: 6px;
  z-index: 2;
  accent-color: var(--oc-ink);
}

.offer-product-chip__thumb {
  display: block;
  aspect-ratio: 4 / 3;
  background: var(--light-grey);
}

.offer-product-chip__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  filter: grayscale(0.4);
  transition: filter 120ms;
}

.offer-product-chip__thumb--empty {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: medium;
  color: var(--oc-soft);
}

.offer-product-chip__name {
  padding: 5px 7px 2px;
  font-size: xx-small;
  color: var(--oc-soft);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.offer-product-chip__deck {
  padding: 0 7px 5px;
  font-size: xx-small;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--oc-soft);
  opacity: 0.65;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.offer-product-chip:has(.offer-product-chip__input:checked) {
  border-color: var(--oc-ink);
  box-shadow: 0 0 0 2px var(--oc-ink);
}

.offer-product-chip:has(.offer-product-chip__input:checked) .offer-product-chip__thumb img {
  filter: grayscale(0);
}

.offer-product-chip:has(.offer-product-chip__input:checked) .offer-product-chip__name {
  color: var(--oc-ink);
  font-weight: 600;
}

/* Réglage hors-carte : ordre d'affichage (n'apparaît pas sur la carte) */
.offer-form__meta {
  width: 460px;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.offer-form__position {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.offer-form__position input {
  width: 8ch;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--input-border);
  border-radius: 0.4rem;
  font: inherit;
}

/* Bouton d'envoi : centré sous la carte, dans l'esprit du bento */
.offer-form__form>input[type="submit"] {
  padding: 0.6rem 1.6rem;
  font: inherit;
  font-weight: 600;
  color: var(--bg-card);
  background: var(--ink);
  border: none;
  border-radius: 999px;
  cursor: pointer;
  transition: opacity 120ms;
}

.offer-form__form>input[type="submit"]:hover {
  opacity: 0.85;
}
.skills {
  display: grid;
  grid-template: auto auto / 1fr 1fr;
  color: var(--grey);

  span {
    display: inline-flex;
    align-items: center;
    gap: 0.5ch;
  }

  img {
    height: 1.25lh;
    aspect-ratio: 1;
  }

  .header {
    margin-bottom: 0.5lh;
    grid-column: span 2;
  }

  .title {
    color: var(--ink);
    font-weight: bold;
  }

  .design .title,
  .code .title {
    font-size: small;
    margin-bottom: 0.5lh;
  }

  .design,
  .code {
    padding-right: 1lh;
  }
}
.atout {
  margin-bottom: 0.5lh;
}

.atouts,
.langues,
.passions {
  padding-bottom: 0.5lh;

  .header {
    margin-bottom: 0.5lh;
    color: var(--ink);
  }

  div {
    display: flex;
    justify-content: space-between;
    color: var(--grey);

    i {
      color: var(--ink);
    }
  }
}
.timeline-bento {
  display: flex;
  flex-direction: column;
}

.timeline-bento .timeline-section {
  flex: 1;
}

.timeline-empty {
  margin: 0.5rem 0 0;
  color: var(--white);
  font-style: italic;
}

/* ── Admin : événements ponctuels (naissances, ...) ───────────────────── */
.timeline-events-admin {
  position: relative;
  margin-left: auto;
}

.timeline-events-admin summary {
  list-style: none;
  cursor: pointer;
  width: 1.4rem;
  height: 1.4rem;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--gray);
  border: 1px solid var(--calendar-border);
  border-radius: 4px;
  line-height: 1;
}

.timeline-events-admin summary::-webkit-details-marker {
  display: none;
}

.timeline-events-admin__panel {
  position: absolute;
  right: 0;
  top: calc(100% + 0.35rem);
  z-index: 10;
  min-width: 16rem;
  padding: 0.6rem;
  background: var(--white--true);
  border: 1px solid var(--calendar-border);
  border-radius: 6px;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--ink) 15%, transparent);
}

.timeline-events-admin__form {
  display: flex;
  gap: 0.3rem;
}

.timeline-events-admin__form input {
  min-width: 0;
  font-size: x-small;
}

.timeline-events-admin__form input[type='text'] {
  flex: 1;
}

.timeline-events-admin__list {
  margin: 0.5rem 0 0;
  padding: 0;
  list-style: none;
  font-size: x-small;
  color: var(--gray);
}

.timeline-events-admin__list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.15rem 0;
}

.timeline-events-admin__delete {
  background: none;
  border: none;
  color: var(--gray);
  cursor: pointer;
  padding: 0 0.2rem;
}

.timeline-events-admin__delete:hover {
  color: var(--red);
}
/* Les couleurs du MOTIF (blanc et gris clair, dans turing_controller) vont au
   GPU, jamais sur `--bg`/`--ink` : celles-là restent celles de la charte, qui
   habillent la barre et le panneau. Le motif ne doit pas emporter le
   formulaire avec lui. */
.turing-bento {
  /* La couche des réglages : au-dessus de la loupe du site (cf.
     `.turing-pointe-curseur`). */
  --turing-couche-reglages: 42;
  position: relative;
  aspect-ratio: 1 / 1;
  padding: 0;
  overflow: hidden;
}

.turing-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  cursor: crosshair;
  touch-action: none;
}

/* L'APERÇU DU CURSEUR : posé une fois pour toutes en (0, 0), déplacé par
   `transform` (cf. `_majPointeCurseur`) — jamais par `left`/`top`, qui
   forceraient une mise en page à chaque déplacement de souris.
   L'ORDRE DES COUCHES, avec la loupe du site (`.art-loupe` à 40 et sa tache
   à 39, posées sur le <body>, cf. loupe.css — rien entre la pièce et le
   <body> ne fait de pile à part, les deux ordres se comparent donc) : le
   motif, ce rond, puis la tache et le VERRE, puis les réglages
   (`--turing-couche-reglages`). Le rond est là tout le temps, loupe posée
   comprise, mais SOUS le verre : là où le verre le couvre, il en montre sa
   propre version, grossie et déformée (la pièce la peint dans ce qu'elle lui
   rend, cf. `_zonePointe`) ; au-delà, c'est ce rond-ci qu'on voit. */
.turing-pointe-curseur {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  pointer-events: none;
  overflow: visible;
}

/* PIÈGE : c'est un <svg>, et la règle `[hidden]` du navigateur ne vise que les
   éléments HTML — sans celle-ci l'attribut ne cache rien, et le rond reste
   figé à sa dernière place (sous la loupe, hors du canevas). */
.turing-pointe-curseur[hidden] {
  display: none;
}

/* Deux rôles, deux classes (et non un sélecteur `*` qui les confondrait) : la
   ZONE est l'aire que le geste couvre — un contour, plus un remplissage très
   pâle qui la donne à voir sans masquer le motif dessous ; les GRAINS sont la
   matière elle-même, donc pleins. Pour la pointe pleine il n'y a que la zone,
   et c'est juste : tout le disque reçoit de la matière.
   Le trait et l'aplat de la zone sont repris par le contrôleur pour la
   peindre dans le verre de la loupe (POINTE_TRAIT_PX, POINTE_APLAT dans
   turing_controller.js) : si l'un bouge, l'autre suit. */
.turing-pointe__zone {
  fill: currentColor;
  fill-opacity: 0.16;
  stroke: currentColor;
  stroke-width: 1.5px;
}

/* Le nom, en tête de la colonne de gauche. */
.turing-bar {
  display: flex;
  align-items: center;
  gap: 0.4em;
}

.turing-kicker {
  padding: 0.2em 0.6em;
  margin-right: 0.2em;
  border-radius: 999px;
  background: color-mix(in lab, var(--bg-card) 80%, transparent);
  backdrop-filter: blur(4px);
}

.turing-icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.8em;
  height: 1.8em;
  border: none;
  border-radius: 999px;
  background: color-mix(in lab, var(--bg-card) 80%, transparent);
  backdrop-filter: blur(4px);
  color: var(--ink);
  cursor: pointer;
  font-size: x-small;

  &:hover {
    background: var(--bg-card);
  }
}

/* ── La colonne de gauche ────────────────────────────────────────────────────
   De haut en bas : le nom, les populations, le panneau de la population
   armée. La colonne descend jusqu'en bas pour que son corps ait une hauteur
   à remplir, et le corps (`__defile`) défile d'un bloc quand il la dépasse —
   le nom, lui, reste : il porte le bouton du mode épuré. Ni la colonne ni son
   corps n'interceptent rien eux-mêmes, sinon ils avaleraient les clics
   destinés au motif (même remède que pour `.turing-bas`) : seuls leurs
   contenus reçoivent le pointeur. La molette sur un contenu fait tout de
   même défiler le corps — `pointer-events` ne décide que de la cible, pas de
   qui défile. */
.turing-gauche {
  position: absolute;
  top: 1em;
  left: 1em;
  bottom: 1em;
  z-index: var(--turing-couche-reglages);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.6em;
  pointer-events: none;
}

.turing-gauche>.turing-bar {
  flex: none;
  pointer-events: auto;
}

/* Le filet de 2 px garde visible le cerne de la population armée (et la
   poignée au focus), que le défilement rognerait. */
.turing-gauche__defile {
  flex: 0 1 auto;
  min-height: 0;
  /* Une barre de défilement classique (hors macOS) prend de la largeur : la
     réserver d'avance évite qu'elle rogne la colonne en paraissant. */
  overflow-x: hidden;
  overflow-y: auto;
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  padding: 2px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1em;
  pointer-events: none;
  height: 100%;
}

.turing-gauche__defile>* {
  pointer-events: auto;
}

/* ── Le panneau de réglages généraux (admin) ────────────────────────────────
   Seul en haut à droite. Repliable NATIVEMENT via `<details>` : le triangle de
   `<summary>` fait tout le travail, rien à écrire pour ça. C'est un outil de
   mise au point et non une pièce publique : il peut se permettre d'être haut
   (beaucoup de réglages) et de défiler plutôt que de tout montrer d'un
   coup. */
.turing-reglages {
  position: absolute;
  /* Sous la pastille du menu (--menu-h, menu.css), qui occupe ce coin. */
  top: calc(1em + var(--menu-h, 0px));
  right: 1em;
  z-index: var(--turing-couche-reglages);
  max-height: calc(100% - 4em);
  overflow-y: auto;
  padding: 0.5em 0.8em;
  border: 1px solid var(--input-border);
  border-radius: 0.8em;
  background: color-mix(in lab, var(--bg-card) 92%, transparent);
  backdrop-filter: blur(6px);
  color: var(--ink);
  font-size: medium;
}

.turing-reglages__titre {
  cursor: pointer;
  font-weight: 600;

  &:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
  }
}

.turing-reglages__reset {
  display: block;
  margin: 0.5em 0 0.3em;
  padding: 0.2em 0;
  border: none;
  background: none;
  color: var(--ink-muted);
  text-decoration: underline;
  cursor: pointer;
  font: inherit;

  &:hover {
    color: var(--ink);
  }
}

.turing-reglages__groupe {
  padding: 0;
  margin: 0.6em 0 0;
  border: none;
  border-top: 1px solid var(--input-border);

  legend {
    padding: 0 0 0.2em;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-muted);
  }
}

.turing-reglage {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6em;
  padding: 0.15em 0;

  span {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  input {
    width: 6em;
    padding: 0 0.3em;
    border: none;
    border-bottom: 1px dashed color-mix(in lab, var(--ink) 35%, transparent);
    background: none;
    color: inherit;
    font: inherit;
    font-variant-numeric: tabular-nums;
    text-align: right;
    appearance: textfield;

    &::-webkit-outer-spin-button,
    &::-webkit-inner-spin-button {
      appearance: none;
      margin: 0;
    }

    &:focus-visible {
      outline: none;
      border-bottom-color: var(--ink);
    }
  }
}

/* ── Le mode ÉPURÉ ────────────────────────────────────────────────────────────
   Masque TOUT ce qui règle la pièce — `.turing-bas` (vitesse, cadrage), le
   corps de la colonne de gauche (les populations et leur panneau, pointe
   comprise) et le panneau admin — pour ne garder que le motif. `.turing-bar`
   (nom + bouton qui bascule ce mode) n'est JAMAIS visé : sans lui, rien ne
   pourrait plus rétablir les barres. */
.turing-bento--epure .turing-bas,
.turing-bento--epure .turing-gauche__defile,
.turing-bento--epure .turing-reglages {
  display: none;
}

/* ── Le bas de l'écran ───────────────────────────────────────────────────────
   La barre des réglages, centrée. Le bloc traverse toute la largeur : il ne doit donc RIEN
   intercepter, sinon il avalerait les clics destinés au motif (même remède
   que pour `.nav`). */
.turing-bas {
  position: absolute;
  bottom: 1em;
  /* Centré par les deux ancrages et des marges automatiques, et non par
     `left: 50%` : un élément absolu n'a pour largeur disponible que ce qui
     reste à droite de son ancrage, si bien qu'à `50 %` la barre se repliait
     sur deux lignes alors que la place ne manquait pas. */
  left: 1em;
  right: 1em;
  width: fit-content;
  margin-inline: auto;
  z-index: var(--turing-couche-reglages);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5em;
  pointer-events: none;
}

.turing-bas>* {
  pointer-events: auto;
}

/* Les populations, en COLONNE : une pastille par population — la poignée, sa
   couleur, puis la part qu'elle TIENT (un seul chiffre, qu'on clique pour
   fixer celle qu'elle VISE) — et le bouton d'ajout en bas.
   Elles gardent l'ordre qu'on leur a donné à la poignée, posé par `order` :
   ce sont des cibles de clic, elles ne doivent pas se glisser toutes seules
   sous le doigt qui les vise. Elles ont TOUTES la même taille
   (`--part-largeur`/`--part-hauteur`), quel que soit le chiffre qu'elles
   portent — le tri compte d'ailleurs là-dessus pour trouver la case visée.
   Trop nombreuses pour l'écran, c'est le corps de la colonne qui défile. */
.turing-parts {
  /* Un em de plus depuis la flèche de tendance, pour que « 100 » tienne
     toujours dans le chiffre, et encore un pour la poignée. */
  --part-largeur: 8.8em;
  --part-hauteur: 1.9em;
  flex: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.3em;
  font-size: small;
  justify-content: center;
  font-variant-numeric: tabular-nums;
  width: 25rem;
  margin-top: auto;
}

.turing-part {
  box-sizing: border-box;
  flex: none;
  display: flex;
  align-items: center;
  gap: 0.3em;
  width: var(--part-largeur);
  height: var(--part-hauteur);
  padding: 0 0.35em 0 0.3em;
  border: 1px solid transparent;
  border-radius: 999px;
  /* Le même fond que la barre : un fond plus transparent laissait le motif
     traverser le chiffre. */
  background: color-mix(in lab, var(--bg-card) 92%, transparent);
  backdrop-filter: blur(6px);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  transition: border-color 150ms, box-shadow 150ms;

  &:hover {
    border-color: color-mix(in lab, var(--ink) 45%, transparent);
  }
}

/* La région armée : cernée de SA couleur, pour qu'on sache de quoi le stylo
   est chargé sans avoir à relire la légende. */
.turing-part--choisie {
  border-color: var(--part-teinte, var(--ink));
  box-shadow: 0 0 0 1px var(--part-teinte, var(--ink));
}

/* LA POIGNÉE du tri : discrète au repos, comme la croix — elle ne doit pas
   peser autant que la part elle-même. `touch-action: none` : au doigt, le
   glissé la déplace au lieu de faire défiler la colonne. */
.turing-part__poignee {
  flex: none;
  display: grid;
  place-items: center;
  padding: 0 0.1em;
  border: none;
  background: none;
  color: inherit;
  cursor: grab;
  font-size: x-small;
  line-height: 1;
  opacity: 0.35;
  touch-action: none;
  transition: opacity 150ms;

  &:hover,
  &:focus-visible {
    opacity: 1;
  }

  &:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
  }
}

/* La pastille qu'on TIRE : au-dessus des autres, soulevée d'une ombre, et
   sans transition sur `transform` — elle suit le pointeur sans retard. */
.turing-part--tiree {
  z-index: 1;
  box-shadow: 0 0.3em 0.8em color-mix(in lab, var(--ink) 25%, transparent);

  .turing-part__poignee {
    cursor: grabbing;
    opacity: 1;
  }
}

.turing-part--tiree.turing-part--choisie {
  box-shadow: 0 0 0 1px var(--part-teinte, var(--ink)),
    0 0.3em 0.8em color-mix(in lab, var(--ink) 25%, transparent);
}

/* La pastille de couleur : c'est un BOUTON, et c'est là son vrai rôle —
   cliquer ARME LE STYLO de cette région, recliquer le désarme (le geste anime
   alors sans semer). Un disque de la couleur de la
   population, cerné de son FOND (`--part-fond`, le sol qu'elle tient :
   blanc → couleur → noir) ; un filet extérieur garde le cerne lisible quand
   ce fond est aussi clair que la pastille qui le porte. */
.turing-part__nourrir {
  box-sizing: border-box;
  flex: none;
  width: 1.5em;
  height: 1.5em;
  padding: 0;
  border: 0.5em solid var(--part-fond, var(--bg-card));
  border-radius: 50%;
  background: var(--part-teinte, var(--ink));
  box-shadow: 0 0 0 1px var(--input-border);
  cursor: pointer;

  &:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
  }
}

/* Le bouton d'AJOUT ferme la rangée, à la même taille que les pastilles. C'est
   lui qui crée les populations depuis qu'un coup de stylo n'en ouvre plus : le
   geste était ambigu, on ne savait plus si l'on nourrissait ou si l'on
   fondait. */
.turing-part--ajout {
  order: 999;
  justify-content: center;
  padding: 0;
  cursor: pointer;
  color: var(--ink);
  font: inherit;
  line-height: 1;
}

/* La croix qui retire une population. Discrète au repos — elle ne doit pas
   peser autant que la part elle-même — franche au survol. */
.turing-part__oter {
  flex: none;
  padding: 0 0.1em;
  border: none;
  background: none;
  color: inherit;
  cursor: pointer;
  font: inherit;
  line-height: 1;
  opacity: 0.35;
  transition: opacity 150ms;

  &:hover,
  &:focus-visible {
    opacity: 1;
  }
}

.turing-part__unite {
  flex: none;
  opacity: 0.45;
}

/* LA TENDANCE : la population augmente ou diminue. Les deux flèches occupent
   la MÊME case de grille, toutes deux cachées par `visibility` (et non
   `display`) : leur place reste réservée, le chiffre ne se décale pas quand
   l'une paraît. Stable, aucune ne se montre. */
.turing-part__tendance {
  flex: none;
  display: grid;
  font-size: x-small;
  line-height: 1;
  opacity: 0.7;

  >span {
    grid-area: 1 / 1;
    visibility: hidden;
  }

  &[data-sens="hausse"]>.turing-part__hausse,
  &[data-sens="baisse"]>.turing-part__baisse {
    visibility: visible;
  }
}

/* LE CHIFFRE : la part tenue, qu'on clique pour la changer en part VISÉE.
   Rien ne le souligne au repos — c'est d'abord un relevé ; le survol et le
   focus disent qu'il s'édite. Une part visée FIXÉE se signale par un trait
   plein sous le chiffre (et son titre la donne). */
.turing-part__chiffre {
  flex: 1;
  min-width: 0;
  padding: 0;
  border: none;
  border-bottom: 1px solid transparent;
  background: none;
  color: inherit;
  font: inherit;
  font-variant-numeric: tabular-nums;
  text-align: right;
  cursor: text;
  transition: border-color 150ms;

  &:hover {
    border-bottom-color: color-mix(in lab, var(--ink) 35%, transparent);
    border-bottom-style: dashed;
  }

  &::placeholder {
    opacity: 0.45;
  }

  &:focus-visible {
    outline: none;
    border-bottom-style: solid;
    border-bottom-color: var(--ink);
  }
}

.turing-part--visee .turing-part__chiffre {
  border-bottom-color: var(--part-teinte, var(--ink));
}

/* Sans WebGPU, il n'y a pas de pièce : la barre, les populations et le
   panneau admin n'ont plus rien à commander, et le nom reste seul au-dessus
   d'un mot qui dit ce qui manque. */
.turing-bento[data-backend="aucun"] .turing-bas,
.turing-bento[data-backend="aucun"] .turing-gauche__defile,
.turing-bento[data-backend="aucun"] .turing-reglages {
  display: none;
}

.turing-absente {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  margin: 0;
  padding: 2em;
  color: var(--ink-muted);
  text-align: center;
  text-wrap: balance;
}

/* ── Le panneau de la population ────────────────────────────────────────────
   Ce qui appartient à UNE population : son motif, et le droit qu'elle a de
   mordre chacune des autres. Il ne paraît que lorsqu'une population est
   sélectionnée, et se cerne de SA couleur pour qu'on sache de qui l'on parle
   sans avoir à relire la rangée des parts. */
.turing-population {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  align-self: end;
  gap: 1em;
  /* La largeur de la colonne : jamais sous 18em, et la carte ronde l'élargit
     quand une grosse pointe la fait grandir. Les autres champs ne comptent
     pas (`contain: inline-size`, plus bas) : les dix régimes, posés sur une
     seule ligne, l'étireraient sinon sur tout l'écran — ils prennent la
     largeur donnée et passent à la ligne. */
  min-width: 18em;
  border-radius: 0.8em;
  /* backdrop-filter: blur(4px); */
  color: var(--ink);
  background: color-mix(in lab, var(--white) 60%, transparent);
  font-size: x-small;
  width: 25rem;
  margin-top: auto;
}

/* `display: flex` l'emporte sur le `display: none` que le navigateur attache à
   l'attribut `hidden` : sans cette ligne, le panneau ne se masque JAMAIS. Le
   symptôme est discret — il occupe sa place en permanence — et il a faussé deux
   mesures avant d'être vu. */
.turing-population[hidden] {
  display: none;
}

.turing-population>.turing-champ:not(.turing-champ--couleurs) {
  contain: inline-size;
}

/* Un jeton par AUTRE population : sa couleur, et l'état du droit. Permis, il
   est plein ; interdit, il n'est plus qu'un cerne barré — la couleur reste
   lisible dans les deux cas, c'est elle qui dit DE QUI l'on parle. */
.turing-morsures {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35em;
}

.turing-morsure {
  position: relative;
  width: 1.3em;
  height: 1.3em;
  border: 1px solid var(--part-teinte, var(--ink));
  border-radius: 50%;
  background: var(--part-teinte, var(--ink));
  cursor: pointer;
  transition: background 150ms;

  &:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
  }
}

.turing-morsure--interdite {
  background: transparent;

  /* La barre oblique : elle dit l'interdit sans dépendre de la couleur, qui
     sert déjà à désigner la population. */
  &::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(to bottom right,
        transparent calc(50% - 0.5px), var(--part-teinte, var(--ink)) calc(50% - 0.5px),
        var(--part-teinte, var(--ink)) calc(50% + 0.5px), transparent calc(50% + 0.5px));
  }
}

/* La FUSION : l'INVERSE visuel de la morsure, plutôt que la même paire
   plein/barré — le défaut y est « pas de fusion » (creux), l'exception
   « fusionne » (plein) est donc celle qui doit sauter aux yeux, pas
   l'inverse. Pas de barre oblique : il n'y a rien à INTERDIRE ici, seulement
   à demander. */
.turing-fusions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35em;
}

.turing-fusion {
  width: 1.3em;
  height: 1.3em;
  border: 1px solid var(--part-teinte, var(--ink));
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  transition: background 150ms;

  &:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
  }
}

.turing-fusion--active {
  background: var(--part-teinte, var(--ink));
}

/* ── La barre des réglages ───────────────────────────────────────────────────
   Posée en bas au centre, TOUJOURS visible : la pièce n'a plus de panneau à
   ouvrir. Elle flotte au-dessus du motif comme la barre du haut, et se replie
   d'elle-même sur les écrans étroits. */
.turing-barre {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.4em 0.9em;
  padding: 0.4em 0.7em;
  border: 1px solid var(--input-border);
  border-radius: 0.8em;
  /* Le motif est pâle : sans fond franc ni cerne, la barre flotterait sans
     bord lisible par-dessus. */
  background: color-mix(in lab, var(--bg-card) 92%, transparent);
  backdrop-filter: blur(6px);
  color: var(--ink);
  font-size: x-small;
}

/* ── Les raccourcis de régimes ──────────────────────────────────────────────
   Dix puces vers les régimes nommés (MOTIFS), en point de DÉPART pour les
   curseurs F/k juste en dessous — pas un mode à part, donc pas de bordure
   « choisi » qui persisterait après qu'on ait touché aux curseurs : cliquer
   ne fait que POSER la valeur, comme si on avait glissé les deux curseurs. Dix
   noms ne tiennent pas sur une ligne de la colonne : la rangée en prend toute
   la largeur et passe à la ligne. */
.turing-champ--motifs {
  justify-content: center;
}

.turing-motifs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.3em;
}

.turing-motif {
  padding: 0.2em 0.55em;
  border: 1px solid var(--input-border);
  border-radius: 999px;
  background: color-mix(in lab, var(--white) 80%, transparent);
  color: var(--ink-muted);
  cursor: pointer;
  font: inherit;
  transition: border-color 150ms, color 150ms;

  &:hover {
    border-color: color-mix(in lab, var(--ink) 55%, transparent);
    color: var(--ink);
  }

  &:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
  }
}

/* La puce dont F/k valent EXACTEMENT ceux de la population armée : dès qu'un
   curseur en dévie d'un cran, `_syncInputs` la relâche — aucune puce n'est
   alors enfoncée, F et k ayant quitté tout régime nommé. */
.turing-motif--actif {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--bg-card);

  &:hover {
    border-color: var(--ink);
    color: var(--bg-card);
  }
}

/* ── La palette ──────────────────────────────────────────────────────────────
   Une carte RONDE : l'échantillon au centre, en disque, et autour de lui un
   ANNEAU qui en suit le contour — les dix pastilles de la palette sur l'arc du
   haut (la couleur libre s'ouvre en recliquant la pastille active), le curseur du fond sur l'arc du bas.
   Tout se place en coordonnées polaires depuis le centre de la carte : un
   élément est posé au centre, puis `rotate(angle) translateX(rayon)` —
   0deg à droite, sens horaire, donc 270deg en haut et 90deg en bas.
   `--disque` et `--anneau` décident de tout le reste.
   LE DISQUE EST LA POINTE : son diamètre est celui du stylo (`--stylo-d`,
   posé en direct par le contrôleur — un mécanisme, pas un choix de design),
   et la carte grandit et rétrécit avec lui. */
.turing-champ--couleurs {
  --disque: var(--stylo-d, 10em);
  --anneau: 2.1em;
  /* Le rayon du milieu de l'anneau : là que courent pastilles et piste. Il
     ne descend pas sous 6em, quelle que soit la pointe : dix pastilles de
     1.4em sur un arc de 160deg s'y écartent de 1.85em (corde 0.309 × rayon),
     et se chevaucheraient plus près. Une petite pointe laisse donc un vide
     entre le disque et l'anneau. */
  --rayon: max(calc(var(--disque) / 2 + var(--anneau) / 2), 6em);
  position: relative;
  /* `isolation` fait de la carte une PILE À ELLE : les `z-index` posés
     ci-dessous ne parlent qu'entre eux. */
  isolation: isolate;
  flex: none;
  display: grid;
  place-items: center;
  /* Le temps d'une rafale de molette, la carte garde sa plus grande largeur
     (`--stylo-tenue`, cf. `_tiensStylo`) : le disque, centré, rétrécit sous
     le pointeur au lieu de s'en dérober. */
  width: max(calc(2 * var(--rayon) + var(--anneau)), var(--stylo-tenue, 0px));
  aspect-ratio: 1 / 1;
  align-self: center;
  justify-content: center;
  /* Le pointeur qui tombe dans l'anneau hors des pastilles arrive ICI : c'est
     la carte qui lit le geste de l'arc (`fondArcStart`), et le doigt ne doit
     pas faire défiler la page en le glissant. */
  touch-action: none;
  margin-top: 4rem;
}

/* LE FOND DE LA CARTE : un ÉCHANTILLON de la population armée (une VRAIE
   seconde simulation Turing WebGPU, `_startCouleursFond`/`_majEchantillon`
   dans turing_controller.js), en DISQUE. Il est le PLANCHER de la pile
   (`z-index` 0) : pastilles et arc passent au-dessus. Un `border-radius`
   rogne aussi la zone de frappe — les coins de sa boîte ne sont pas à lui, et
   le pointeur y atteint l'anneau. `object-fit: cover` ne sert qu'aux toutes
   premières images : le contrôleur (`_cadreEchantillon`) accorde ensuite la
   résolution du canevas à sa boîte réelle. */
.turing-champ--couleurs__fond {
  position: relative;
  z-index: 0;
  box-sizing: border-box;
  width: var(--disque);
  height: auto;
  aspect-ratio: 1 / 1;
  border: 1px solid var(--input-border);
  border-radius: 50%;
  object-fit: cover;
  /* Le stylo y sème comme sur la pièce : même curseur, et le geste ne doit
     pas faire défiler la page sous le doigt. */
  cursor: crosshair;
  touch-action: none;
}

/* LA TRAME DES GRAINS, posée sur le disque le temps d'un réglage du grain
   (`_montreGrain`) : deux grilles de points décalées d'une demi-maille, à la
   taille réelle des grains (`--stylo-grain`, `--stylo-maille`, posés en
   direct par le contrôleur). Des points BLANCS en `difference` : ils
   s'inversent sur ce qu'ils couvrent et se lisent donc sur n'importe quel
   motif et n'importe quel fond — la carte isole déjà la pile (`isolation`),
   le mélange ne va pas chercher plus loin que l'échantillon. */
.turing-champ--couleurs__grain {
  --point: radial-gradient(circle,
      white calc(var(--stylo-grain, 2px) - 0.4px),
      transparent calc(var(--stylo-grain, 2px) + 0.4px));
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 0;
  width: var(--disque);
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  translate: -50% -50%;
  background:
    var(--point) center / var(--stylo-maille, 8px) var(--stylo-maille, 8px),
    var(--point) calc(50% + var(--stylo-maille, 8px) / 2) calc(50% + var(--stylo-maille, 8px) / 2) / var(--stylo-maille, 8px) var(--stylo-maille, 8px);
  mix-blend-mode: difference;
  opacity: 0;
  pointer-events: none;
  transition: opacity 250ms;
}

.turing-champ--couleurs__grain--visible {
  opacity: 1;
  transition-duration: 60ms;
}

/* Les deux curseurs RÉELS de la pointe (diamètre, grain), masqués à l'œil
   mais pas au clavier ni aux lecteurs d'écran : ce sont eux que lisent
   `changePen` et `changeGrain`, et eux qui bornent les valeurs. Le focus
   cerne le disque, qui est la pointe. */
.turing-champ--couleurs__pointe {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  opacity: 0;
}

.turing-champ--couleurs:has(.turing-champ--couleurs__pointe:focus-visible) .turing-champ--couleurs__fond {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

/* L'arc des pastilles : du haut-gauche (`--debut`) au haut-droit, un pas de
   `--pas` par pastille (`--i`, posé en ERB). Le conteneur couvre toute la
   carte sans rien intercepter — seules les pastilles reçoivent le pointeur. */
.turing-couleurs {
  --debut: 190deg;
  /* Dix pastilles de 190deg à 350deg : neuf pas. */
  --pas: 17.8deg;
  --pastille: 1.4em;
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;

  >* {
    position: absolute;
    top: 50%;
    left: 50%;
    margin: calc(var(--pastille) / -2);
    transform: rotate(calc(var(--debut) + var(--i) * var(--pas))) translateX(var(--rayon));
    pointer-events: auto;
  }
}

.turing-couleur {
  box-sizing: border-box;
  width: var(--pastille);
  height: var(--pastille);
  padding: 0;
  border: 1px solid var(--input-border);
  border-radius: 50%;
  /* À 80 % : les pastilles restent dans la même famille que la couleur
     réellement peinte, sans la crier. */
  background: color-mix(in lab, var(--part-teinte, var(--ink)) 80%, transparent);
  cursor: pointer;
  transition: border-color 150ms;

  &:hover {
    border-color: color-mix(in lab, var(--ink) 55%, transparent);
  }

  &:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
  }
}

/* La pastille dont la teinte vaut EXACTEMENT celle de la population armée :
   un cerne suffit à la distinguer des neuf autres. Elle porte la couleur
   LIBRE si la population en a une, et la recliquer ouvre le sélecteur. */
.turing-couleur--actif {
  border-color: var(--ink);
  border-width: 2px;
}

/* LA COULEUR LIBRE : aucun élément visible — recliquer la pastille active
   ouvre ce sélecteur natif (`_ouvreCouleurLibre`), qui prend alors la place
   de cette pastille sur l'arc (`--i`) pour que la fenêtre du navigateur s'y
   ancre. Invisible, et jamais sous le pointeur. */
.turing-couleurs>.turing-couleurs__libre {
  width: var(--pastille);
  height: var(--pastille);
  padding: 0;
  border: none;
  opacity: 0;
  pointer-events: none;
}

/* L'ARC DU FOND, sous le disque. Une piste courbe ne s'obtient pas d'un
   <input type="range"> : c'est un dégradé CONIQUE (blanc → couleur de la
   population → noir, comme le shader) masqué en anneau fin, et une poignée
   placée par `--fond-t`. Ses bouts (`--arc-blanc`, `--arc-course`) viennent du
   contrôleur (FOND_ARC) ; les valeurs ci-dessous n'en sont que le repli.
   Le conique compte depuis le HAUT (0deg) quand la carte compte depuis la
   DROITE, d'où le quart de tour d'écart. Il tourne dans le sens horaire :
   il part donc du bout noir et finit au blanc.
   Rien n'y intercepte le pointeur — c'est la carte qui lit le geste. */
.turing-arc-fond {
  --arc-blanc: 165deg;
  --arc-course: 150deg;
  --piste: 0.34em;
  --fond-t: 0;
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;

  &::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: conic-gradient(in lab from calc(var(--arc-blanc) - var(--arc-course) + 90deg),
        black 0deg,
        var(--part-teinte, var(--ink)) calc(var(--arc-course) / 2),
        white var(--arc-course),
        transparent var(--arc-course));
    mask: radial-gradient(circle closest-side,
        transparent calc(var(--rayon) - var(--piste) / 2 - 0.5px),
        #000 calc(var(--rayon) - var(--piste) / 2 + 0.5px),
        #000 calc(var(--rayon) + var(--piste) / 2 - 0.5px),
        transparent calc(var(--rayon) + var(--piste) / 2 + 0.5px));
    /* Un filet pour que le bout blanc se lise sur un motif clair. */
    filter: drop-shadow(0 0 0.5px color-mix(in lab, var(--ink) 60%, transparent));
  }
}

/* La poignée : posée au centre puis tournée à sa place sur l'arc. Même
   silhouette que celle des curseurs droits (`.turing-curseur__glisse`). */
.turing-arc-fond__poignee {
  --poignee: 1.2em;
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--poignee);
  height: var(--poignee);
  margin: calc(var(--poignee) / -2);
  border-radius: 50%;
  background: var(--ink);
  box-shadow: 0 0 0 3px color-mix(in lab, var(--bg-card) 92%, transparent);
  transform: rotate(calc(var(--arc-blanc) - var(--fond-t) * var(--arc-course))) translateX(var(--rayon));
  transition: scale 150ms;
}

.turing-arc-fond--actif .turing-arc-fond__poignee {
  scale: 1.15;
}

.turing-arc-fond:has(.turing-arc-fond__input:focus-visible) .turing-arc-fond__poignee {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

/* Le curseur RÉEL, masqué à l'œil mais pas au clavier ni aux lecteurs
   d'écran : c'est lui que lit `changeFondAlpha`. */
.turing-arc-fond__input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  opacity: 0;
}

/* ── F, k, l'échelle et l'agressivité (panneau de population) ──────────────
   REFONTE ERGONOMIQUE : ces quatre curseurs n'avaient jusqu'ici PAS de piste
   visible — l'<input type="range"> portait `hidden` dans le gabarit sans
   qu'aucune règle ne le lève ; seul le champ nombre (tapé) répondait. Piste et
   poignée natives sont de toute façon pensées pour une souris, trop fines
   pour un doigt — les deux sont donc explicitement redessinées ci-dessous.
   Empilés en PLEINE LARGEUR (une ligne par variable) plutôt qu'en colonnes
   côte à côte : une piste longue se vise mieux qu'une piste de 6em, et quatre
   colonnes côte à côte n'auraient de toute façon pas tenu sur un panneau
   étroit. */
.turing-champ--curseurs {
  flex-direction: column;
  align-items: stretch;
  gap: 0.55em;
}

.turing-curseur {
  display: flex;
  flex-direction: column;
  gap: 0.2em;
}

.turing-curseur__tete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5em;
}

.turing-curseur__nom {
  color: var(--ink-muted);
}

.turing-curseur__nombre {
  width: 4.5em;
  padding: 0 0.15em;
  border: none;
  border-bottom: 1px dashed color-mix(in lab, var(--ink) 35%, transparent);
  background: none;
  color: inherit;
  font: inherit;
  font-variant-numeric: tabular-nums;
  text-align: right;
  appearance: textfield;

  &::-webkit-outer-spin-button,
  &::-webkit-inner-spin-button {
    appearance: none;
    margin: 0;
  }

  &:focus-visible {
    outline: none;
    border-bottom-color: var(--ink);
  }
}

/* LA PISTE ET LA POIGNÉE, redessinées : `accent-color` seul ne contrôle pas
   leur TAILLE, or
   c'est elle qui manquait le plus à un doigt. La hauteur de l'élément
   (1.6em) sert toute entière de zone de frappe — bien plus que le seul trait
   visible de la piste (0.3em) — sans quoi viser resterait aussi étroit que
   la piste elle-même. */
.turing-curseur__glisse {
  appearance: none;
  width: 100%;
  height: 1.6em;
  margin: 0;
  background: none;
  accent-color: var(--ink);
  touch-action: pan-y;

  &::-webkit-slider-runnable-track {
    height: 0.3em;
    border-radius: 999px;
    background: color-mix(in lab, var(--ink) 20%, transparent);
  }

  &::-moz-range-track {
    height: 0.3em;
    border-radius: 999px;
    background: color-mix(in lab, var(--ink) 20%, transparent);
  }

  &::-webkit-slider-thumb {
    appearance: none;
    width: 1.3em;
    height: 1.3em;
    /* Centre une poignée de 1.3em sur une piste de 0.3em : (0.3 - 1.3) / 2. */
    margin-top: -0.5em;
    border-radius: 50%;
    background: var(--ink);
    box-shadow: 0 0 0 4px color-mix(in lab, var(--bg-card) 92%, transparent);
  }

  &::-moz-range-thumb {
    width: 1.3em;
    height: 1.3em;
    border: none;
    border-radius: 50%;
    background: var(--ink);
    box-shadow: 0 0 0 4px color-mix(in lab, var(--bg-card) 92%, transparent);
  }

  &:focus-visible {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
  }
}

/* ── Les trois tailles de pointe ────────────────────────────────────────────*/
.turing-champ--tailles {
  width: auto;
}

.turing-tailles {
  display: flex;
  gap: 0.25em;
}

.turing-taille {
  cursor: pointer;

  input {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
  }

  span {
    display: grid;
    place-items: center;
    width: 2.1em;
    height: 1.9em;
    border: 1px solid var(--input-border);
    border-radius: 0.35em;
    color: var(--ink-muted);
    transition: border-color 150ms, box-shadow 150ms, color 150ms;
  }

  &:hover span {
    border-color: color-mix(in lab, var(--ink) 55%, transparent);
  }

  input:checked~span {
    border-color: var(--ink);
    box-shadow: 0 0 0 1px var(--ink);
    color: var(--ink);
  }

  input:focus-visible~span {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
  }
}

/* ── Les deux réglages au cran ──────────────────────────────────────────────*/
.turing-champ {
  display: flex;
  align-items: center;
  gap: 0.45em;
}

/* Même piège que `.turing-population[hidden]` : sans cette ligne, « Mord » et
   « Fusionne » restent affichés, vides, quand il n'y a pas d'autre population. */
.turing-champ[hidden] {
  display: none;
}

.turing-champ__tete {
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-muted);
  white-space: nowrap;

  b {
    font-family: monospace;
    font-weight: normal;
    letter-spacing: 0;
    text-transform: none;
    opacity: 0.75;
  }
}

/* Cadrage et gomme ne règlent pas le motif : un filet les écarte des réglages. */
.turing-barre__fin {
  display: flex;
  align-items: center;
  gap: 0.4em;
  align-self: center;
  padding-left: 1em;
  border-left: 1px solid var(--input-border);
}

/* Un bouton d'icône qui tient un ÉTAT — le plateau entier — se montre enfoncé. */
.turing-icon-btn--actif {
  background: var(--ink);
  color: var(--bg-card);

  &:hover {
    background: var(--ink);
  }
}

/* Écran étroit : la barre se resserre, et les parts redescendent d'un cran —
   à cinq ou six pastilles, elles occuperaient sinon plusieurs lignes. */
@media (max-width: 48rem) {
  .turing-barre {
    gap: 0.5em 0.7em;
  }

  .turing-parts {
    font-size: x-small;
  }
}
/* LES CAHIERS DE RECHERCHES (notes/_cahier, notes/_note, cahier_controller,
   Admin::NotesController ; demande de l'auteur, 30 sept. 2026) : la suite des
   choix d'un dessin ou d'un projet, datés — une note : sa date, son texte OU son
   croquis (1er oct. 2026 : « pour les notes, je veux juste de quoi écrire du
   texte ; pas besoin d'avoir titre et descriptions »). Deux places :
     · LE MUR (`.art-cahier`, placé à gauche de l'oeuvre par art.scss.css) : un
       BOUTON « Cahier », et, cliqué, LA SCÈNE (`.cahier-scene`, posée sur le
       <body> par cahier_controller) — les croquis en FEUILLES éparpillées comme
       les autres dessins de l'accueil (`.feuille.papier` : les ombres, le bord du
       papier — accueil.css), les textes sur des PAPIERS TAPÉS À LA MACHINE
       (1er oct. 2026 : « des images un peu comme les autres ; pour les textes,
       des petits papiers avec des notes écrites à la machine à écrire ») ;
     · LA PAGE d'un projet (7 oct. 2026 : « que les notes et les croquis des diapos
       soient comme dans la galerie », puis « attachées aux projet-image__img plutôt
       qu'au projet global ») : LA MÊME SCÈNE, POUR CHAQUE IMAGE de la grille — l'oeuvre
       est l'image, qu'un clic ouvre, ou son onglet (projet.css) — ; sous chaque image,
       une BANDE pour l'admin (`.cahier--projet` : « + Note », « + Croquis »), cachée
       au visiteur.
   Pour l'admin, les champs ont l'allure du texte qu'ils remplacent (cf.
   `.art-figure__field`, art.scss.css) : le formulaire, directement, des deux côtés
   (2 oct. 2026 : « un formulaire beaucoup plus simple ; pas besoin d'avoir un bloc
   établi » — la lecture en double et les règles d'établi sont parties).
   PIÈGE : form.scss.css centre et borne tout <form>, habille tout <input> et donne
   48rem de haut à tout <textarea> — les formulaires d'ici reprennent leur place. */

:root {
  /* La machine à écrire : American Typewriter sur un Mac, sinon une Courier. */
  --police-machine: "American Typewriter", "Courier Prime", "Courier New", Courier, monospace;
}

.cahier form,
.cahier-scene form {
  max-width: none;
  margin: 0;
}

.cahier__tete {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.4em 0.8em;
}

/* (Sur le mur, rien à cliquer ici : C'EST LE CARTEL qui ouvre les papiers —
   art.scss.css, « Le cartel est un papier » ; un bouton « Cahier » puis
   « Papier » a vécu la journée du 1er oct. 2026.) */

.cahier__ajouts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3em;
}

.cahier__bouton,
.cahier__geste {
  display: inline-block;
  padding: 0.2em 0.6em;
  border: 1px solid var(--ink-10);
  border-radius: 999px;
  background: transparent;
  font: inherit;
  font-size: xx-small;
  color: var(--ink-muted);
  cursor: pointer;
  transition: border-color 150ms, color 150ms;
}

.cahier__bouton:hover,
.cahier__bouton:focus-visible,
.cahier__bouton:focus-within,
.cahier__geste:hover,
.cahier__geste:focus-visible,
.cahier__geste:focus-within {
  border-color: var(--input-border);
  color: var(--ink);
  outline: none;
}

.cahier__temoin,
.cahier__vide {
  margin: 0;
  font-size: xx-small;
  color: var(--ink-muted);
}

.cahier__temoin:empty {
  display: none;
}

/* ── Les notes ───────────────────────────────────────────────────────────── */
.cahier__notes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1em;
}

/* La liste n'est pas montrée dans son bloc : le cahier l'emporte sur sa scène. */
.art-cahier .cahier__notes,
.cahier--projet .cahier__notes,
.cahier--centre .cahier__notes {
  display: none;
}

.cahier__note {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.3em;
}

/* La lecture : une boîte qui n'en est pas une, ses lignes sont celles de la note. */
.cahier__lecture,
.cahier__form {
  display: contents;
}

.cahier__champ--date {
  font-size: xx-small;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.cahier__texte,
.cahier__champ--texte {
  margin: 0;
  font-size: x-small;
  line-height: 1.45;
  color: var(--ink);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.cahier__texte[hidden] {
  display: none;
}

/* Le croquis : l'image à nu, dans sa feuille (la scène lui donne sa hauteur). (Un
   tirage à marge blanche qu'un clic ouvrait de près — la page d'un projet, jusqu'au
   7 oct. 2026 — est parti avec la liste ; git le garde.) */
.cahier__tirage {
  display: block;
  margin: 0;
  padding: 0;
  background: transparent;
  border: 0;
}

.cahier__tirage img {
  display: block;
}

/* ── Admin : les champs ont l'allure du texte ────────────────────────────── */
.cahier__champ {
  width: 100%;
  height: auto;
  min-height: 0;
  padding: 0.15rem 0.3rem;
  font-family: inherit;
  font-weight: inherit;
  color: inherit;
  background: transparent;
  border: 0;
  border-bottom: 1px solid transparent;
  border-radius: 3px;
  resize: none;
  transition: background 0.2s, border-color 0.2s;
}

.cahier__champ--date {
  width: auto;
  font-family: inherit;
}

.cahier__champ::placeholder {
  color: var(--ink-10);
}

.cahier__champ:hover {
  border-bottom-color: var(--ink-10);
}

.cahier__champ:focus {
  outline: none;
  background: color-mix(in lab, var(--bg-card) 70%, transparent);
  border-bottom-color: var(--ink-muted);
}

.cahier__status {
  align-self: flex-end;
}

.cahier__gestes {
  display: flex;
  align-items: center;
  gap: 0.3em;
}

.cahier__croquis-form,
.cahier__retirer-form {
  display: inline;
}

.cahier__retirer:hover,
.cahier__retirer:focus-visible {
  color: var(--red);
}

/* ── La scène : le cahier étalé sur le mur ──────────────────────────────────
   Posée sur le <body> par cahier_controller, sur tout l'écran, SOUS la vue (35)
   et la loupe (40). Elle prend les clics : dans le vide, le cahier se range. Chaque feuille
   est posée par son centre (`transform`, écrit par le contrôleur : sa place, sa
   pente, sa hauteur en vol) et porte `--vol` pour ses ombres. Les feuilles
   arrivent du hors-champ (une version les faisait sortir de dessous l'image, la
   scène découpée sur l'oeuvre : retirée le jour même). */
.cahier-scene {
  position: fixed;
  inset: 0;
  z-index: 29;
  overflow: hidden;
  /* Elle ne prend que ses feuilles : dessous, le cartel se tire et s'écrit,
     « + Note » se clique (un clic dans le vide range quand même :
     cahier_controller, `_clicDehors`). */
  pointer-events: none;
}

/* L'OMBRE DE LA SOIE (1er oct. 2026 : « les ombres du papier ne collent pas avec
   l'ombre de l'image en grand » ; « si les papiers ont une ombre portée aussi
   loin, il faut qu'elle aille sur l'image de manière naturelle, et qu'elles
   arrivent sur le fond projetées plus loin ») : une feuille pend au même mur que
   l'image seule, juste devant elle (soie_gl.js : à `mur` du fond, l'ombre tombe
   dans l'AXE — la lumière vient d'en haut à gauche —, de FUITE px par px d'écart,
   sa pénombre s'ouvre avec l'écart, et elle est BLEUE, privée de la lumière chaude
   — jamais grise). D'où DEUX OMBRES par feuille, peintes À PART sous toutes les
   feuilles (cahier_controller, `_ombres`, `OMBRE_MUR` / `OMBRE_IMAGE`) :
     · SUR LE FOND, loin (~26 px à droite, ~33 px en bas, floue de ~18 px — la
       portée de l'image en grand), dans une couche PERCÉE de l'image, net
       (`--mur` ; un masque adouci sur l'ombre de l'image a été essayé : « un double
       dégradé », retiré) ;
     · SUR L'IMAGE, courte et dense (la feuille est posée dessus, ou presque),
       dans une couche RÉDUITE à l'image (`--image`).
   Soulevée (`--vol`), la feuille s'en éloigne : les deux filent, s'étalent et
   pâlissent. La forme de l'ombre a le bord du papier (`--bord`, le masque sur la
   forme, le flou sur la boîte — masquer la boîte floue couperait net la pénombre).
   Le cartel, lui, est à côté de l'image, sur le fond : une seule ombre, en
   `box-shadow`, aux mêmes chiffres (art.scss.css). */
.cahier-scene__ombres {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.cahier-ombre {
  position: absolute;
  left: 0;
  top: 0;
  will-change: transform, filter;
}

.cahier-ombre__forme {
  width: 100%;
  height: 100%;
  background: rgb(34 50 108);
  -webkit-mask: var(--bord, none) 0 0 / 100% 100% no-repeat;
  mask: var(--bord, none) 0 0 / 100% 100% no-repeat;
}

/* Le cartel a LES MÊMES DEUX OMBRES que les feuilles (cahier_controller,
   `_ombrerCartel` ; 1er oct. 2026, « l'ombre du cartel n'est pas bonne sur
   l'image ») : peintes dans sa figure, sous lui (`.cartel-ombres`, un bloc qui
   couvre la fenêtre en coordonnées de la figure) — plus de `box-shadow` à lui. */
.art-cartel,
.art-cartel.is-tenu,
.art-cartel[aria-expanded="true"] {
  box-shadow: none;
}

.cartel-ombres {
  position: absolute;
  pointer-events: none;
}

.cahier-scene .cahier__notes {
  display: contents;
}

.cahier-scene .cahier__note {
  position: absolute;
  /* Au coin de la scène : le contrôleur la pose par son centre, en px d'écran. */
  left: 0;
  top: 0;
  display: block;
  pointer-events: auto;
  touch-action: none;
  /* Pas d'ombre à elle (celle de `.feuille`, accueil.css) : ses deux ombres sont
     peintes à part, dessous (« L'ombre de la soie », plus bas). */
  box-shadow: none;
  margin: 0;
  will-change: transform;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
}

.cahier-scene .cahier__note.is-tenu {
  cursor: grabbing;
}

/* LE CROQUIS : une feuille comme les autres dessins — l'image à nu (pas de marge
   de tirage), de la hauteur que le contrôleur lui donne (`--h`), avec le bord du
   papier (`.papier` : `--bord`, `--tranche`, accueil.css). */
.cahier-scene .cahier__note--croquis {
  --vol: 0;
}

.cahier-scene .cahier__croquis {
  display: block;
}

.cahier-scene .cahier__tirage img {
  display: block;
  width: auto;
  height: var(--h, 32dvh);
  max-width: 80vw;
  object-fit: contain;
  -webkit-user-drag: none;
}

.cahier-scene .cahier__tirage:focus-visible img {
  outline: 2px solid var(--blue);
  outline-offset: 4px;
}

/* Sur une feuille, le crédit s'étale jusqu'au bord. */
.cahier-scene .cahier__croquis .credit {
  right: 0;
  bottom: 0;
  left: 0;
  padding: 1.4em 0.7em 0.5em;
}

/* LE PAPIER : UNE FEUILLE À PETITS CARREAUX (7 oct. 2026 : « que les notes
   ressemblent un peu plus à une feuille petit carreau ou à un post-it » — le petit
   papier crème a vécu du 1er au 7 oct., git le garde) : un papier blanc cassé
   quadrillé de 5 mm (`--carreau`, arrondi au pixel pour des traits nets — deux
   dégradés répétés, décalés d'un demi-carreau pour qu'aucun trait ne tombe sur le
   bord), des traits d'un bleu pâle (`--trait`), une pointe de lumière en haut ; et
   dessus la note TAPÉE À LA MACHINE (la police), UNE LIGNE PAR CARREAU — l'interligne
   est le carreau, la première ligne laisse un carreau vide au-dessus —, sans sa date
   (« je ne veux pas de date sur les notes dans art/show » ; l'admin l'a, sur la page
   d'un projet). Les retours à la ligne sont gardés. (Les lettres qui paraissaient une
   à une une fois le papier posé sont RETIRÉES le 1er oct. 2026.)
   UNE NOTE TROP GRANDE SE PAGINE (7 oct. 2026 : « si une note est trop grande, il
   faut la paginer ») : le texte vit dans un FEUILLET (`.cahier__feuillet`, qui
   enveloppe le texte du visiteur comme le champ de l'admin) de `--page-lignes`
   carreaux de haut au plus ; au-delà, des PAGES (cahier_controller, `_paginer` : un
   clic sur le papier, la molette ou les ‹ › du pied, `.cahier__pages`, tournent — le
   feuillet défile d'une page entière, ligne à ligne puisque l'interligne est le
   carreau, et un BLANC au bout, `--blanc`, fait de la dernière une page entière).
   Le feuillet de l'admin défile aussi tout seul, sans ascenseur, quand il tape.
   UN FORMAT, 82 × 128 mm (9 oct. 2026, #49 : « j'aimerais que les notes soient à un
   format 28 mm, 82 mm », puis « pardon, c'était 128 mm et 82 mm », puis « en format
   portrait », « et en taille réelle » — une carte debout, AU MM DE L'ÉCRAN : l'étalon
   de controllers/etalon, posé en `--mm` par table_controller et cahier_controller, et
   le carreau de 5 mm arrondi au pixel avec lui, `--carreau` ; sans eux, le mm du
   navigateur) : le papier a toujours cette taille, quoi qu'il porte — une ligne, ou vingt-et-une par page
   (`--page-lignes` : la hauteur moins les marges, moins la ligne de la date de l'admin) ;
   des marges d'un carreau et demi sur les côtés (une trentaine de caractères par
   ligne), d'un carreau en haut, du reste en bas (le pied) ; sur un écran plus étroit
   que lui, il se serre à la page (`max-width`). (Il faisait 30 caractères de large, ou
   ce que sa zone permettait, et la hauteur de son texte.) */
:is(.cahier-scene, .accueil-objet) .cahier__note--papier {
  --vol: 0;
  --mm: 1mm; /* un vrai mm sur cet écran (l'étalon, posé par le contrôleur) ; sinon celui du navigateur */
  --carreau: 19px; /* 5 mm, au pixel près (le contrôleur le recalcule avec l'étalon) */
  --trait: rgb(104 146 204 / 0.38); /* le bleu des carreaux */
  --page-lignes: 21; /* la hauteur d'une page, en carreaux : au-delà, on tourne */
  width: calc(82 * var(--mm));
  max-width: 100%;
  height: calc(128 * var(--mm));
  box-sizing: border-box;
  padding: var(--carreau) calc(var(--carreau) * 1.5) calc(var(--carreau) * 1.5);
  overflow: hidden;
  background:
    linear-gradient(180deg, rgb(255 255 255 / 0.5), rgb(255 255 255 / 0) 30%),
    repeating-linear-gradient(180deg, var(--trait) 0 1px, transparent 1px var(--carreau)) 0 calc(var(--carreau) / 2 - 0.5px),
    repeating-linear-gradient(90deg, var(--trait) 0 1px, transparent 1px var(--carreau)) calc(var(--carreau) / 2 - 0.5px) 0,
    #fcfbf6;
  color: #262a30;
  font-family: var(--police-machine);
  font-size: small;
  line-height: var(--carreau);
  letter-spacing: 0.02em;
  gap: 0;
}

:is(.cahier-scene, .accueil-objet) .cahier__note--papier .cahier__lecture {
  display: flex;
  flex-direction: column;
  gap: 0;
}

:is(.cahier-scene, .accueil-objet) .cahier__texte {
  font-size: inherit;
  line-height: inherit;
  color: inherit;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* LE FEUILLET : une page de haut, pas plus — le reste défile par pages (le
   contrôleur pose `scrollTop`), et le blanc de fin (`--blanc`, posé par lui) fait de
   la dernière une page entière. PIÈGE : un <textarea> ne défile pas au-delà de son
   texte, même avec un rembourrage de fin (Chrome) — d'où ce bloc autour, qui
   défile, le champ dedans prenant toute sa hauteur (`field-sizing`). Celui de
   l'admin défile librement (sans ascenseur) : le navigateur y suit le curseur. */
:is(.cahier-scene, .accueil-objet) .cahier__feuillet {
  max-height: calc(var(--page-lignes) * var(--carreau));
  overflow: hidden;
}

:is(.cahier-scene, .accueil-objet) .cahier__feuillet:has(textarea) {
  overflow: auto;
  scrollbar-width: none;
}

:is(.cahier-scene, .accueil-objet) .cahier__feuillet:has(textarea)::-webkit-scrollbar {
  display: none;
}

:is(.cahier-scene, .accueil-objet) .cahier__feuillet::after {
  content: "";
  display: block;
  height: var(--blanc, 0px);
}

/* Le pied de page : « ‹ 2 / 3 › », à la machine, au milieu de la marge du bas. */
.cahier__pages {
  position: absolute;
  right: 0;
  bottom: 0.3em;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.2em;
  font-size: xx-small;
  letter-spacing: 0.12em;
  color: #5f6b7a;
  pointer-events: none;
}

.cahier__pages button {
  padding: 0 0.4em;
  border: 0;
  background: transparent;
  font: inherit;
  line-height: 1;
  color: inherit;
  cursor: pointer;
  pointer-events: auto;
}

.cahier__pages button:hover,
.cahier__pages button:focus-visible {
  color: #262a30;
  outline: none;
}

/* Pour l'admin, le papier EST le formulaire : le texte en champ, à la machine
   aussi, sur le même papier. */
:is(.cahier-scene, .accueil-objet) .cahier__note--papier .cahier__form {
  display: flex;
  flex-direction: column;
  gap: 0;
}

:is(.cahier-scene, .accueil-objet) .cahier__champ {
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  letter-spacing: inherit;
  color: inherit;
  padding: 0;
  border-radius: 0;
}

.cahier-scene .cahier__champ--date {
  font-size: xx-small;
  letter-spacing: 0.12em;
  color: #5f6b7a;
}

:is(.cahier-scene, .accueil-objet) .cahier__champ--texte {
  field-sizing: content;
  min-height: 2.6em;
}

:is(.cahier-scene, .accueil-objet) .cahier__champ::placeholder {
  color: rgb(38 42 48 / 0.35);
}

:is(.cahier-scene, .accueil-objet) .cahier__champ:focus {
  background: rgb(255 255 255 / 0.3);
}

:is(.cahier-scene, .accueil-objet) .cahier__status {
  position: absolute;
  right: 0.5em;
  bottom: 0.3em;
  font-family: var(--font-sans, inherit);
}

/* Les gestes de l'admin : ✕ au coin d'un papier ; sous un croquis, son auteur,
   « croquis ↻ » et ✕ — ceux-là NE PARAISSENT QU'AU SURVOL de leur feuille (ou au
   clavier) : toujours là depuis que l'établi est parti (2 oct. 2026), ils
   couvraient les papiers voisins, et on les prenait en voulant tirer un papier.
   Collés au bas de la feuille (pas de marge, un rembourrage) : le survol ne se
   perd pas en descendant dessus. */
.cahier-scene .cahier__gestes--papier {
  position: absolute;
  top: 0.3em;
  right: 0.3em;
}

.cahier-scene .cahier__gestes--croquis {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  margin-top: 0;
  padding-top: 0.4em;
  flex-wrap: wrap;
  gap: 0.3em;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
}

.cahier-scene .cahier__note--croquis:hover .cahier__gestes--croquis,
.cahier-scene .cahier__note--croquis:focus-within .cahier__gestes--croquis {
  opacity: 1;
  pointer-events: auto;
}

.cahier-scene .cahier__gestes--croquis .cahier__form--credit {
  display: flex;
  flex: 1 1 8em;
  align-items: center;
  gap: 0.3em;
}

.cahier-scene .cahier__gestes--croquis .cahier__champ--credit {
  padding: 0.1rem 0.3rem;
  font-size: xx-small;
  background: color-mix(in lab, var(--bg-card) 80%, transparent);
  border-radius: 999px;
}

.cahier-scene .cahier__gestes .cahier__geste {
  background: color-mix(in lab, var(--bg-card) 80%, transparent);
}

/* (Un dépôt de fichiers à côté de l'image fait des croquis : la cible se dessine
   sur le mur, depot.css — art_depot_controller.) */

/* ── La page d'un projet : la bande de l'admin, sous chaque image ─────────────
   Le cahier s'étale sur la scène, comme sur le mur (7 oct. 2026 : « que les notes et
   les croquis des diapos soient comme dans la galerie », puis « attachées aux
   projet-image__img plutôt qu'au projet global ») : chaque image de la grille a le
   sien — elle est l'oeuvre, un clic dessus l'ouvre (le curseur le dit, projet.css),
   les feuilles suivent le défilement (cahier_controller). Ici, dans la figure de l'image, il ne reste pour l'admin que
   « + Note » et « + Croquis » (un bouton : pas de dépôt sur la page d'un projet) ;
   la liste est cachée, la scène l'emporte. Le visiteur n'a rien ici (le bloc est
   `hidden`). (La liste sous la grille — la date en colonne, le texte à côté, le
   croquis en tirage à marge —, LA VUE d'un croquis de près, `.art-vue`, puis un
   cahier du projet entier ont vécu du 30 sept. au 7 oct. 2026 ; git les garde.) */
.cahier--projet {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3em;
  padding: 0.3em 0 0;
}

/* ── LE CAHIER D'UNE FEUILLE AU CENTRE (lot 16, 14 oct. 2026, #63 à #66 : « que les
   notes et croquis se comportent comme des objets et que je puisse les placer autour
   de l'objet principal ») ── Les feuilles flottent AUTOUR de la feuille au centre,
   sur la scène du cahier (cahier_controller, mode centre) : ce bloc, dans la page
   dessous, n'est que la bande de l'admin (« + Note », « + Croquis ») — comme celle
   d'un projet — et sa liste, que la scène emporte ; les blocs de LECTURE d'un projet
   au centre (ids `show_…`) n'ont rien à montrer ici. (LA TABLE d'un dessin — #45,
   `.cahier--table`, table_controller — a vécu du 8 au 14 oct. 2026 ; git la garde.) */
.cahier--centre {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3em;
  padding: 0.3em 0 0;
}

.cahier--centre .cahier__vide {
  margin: 0;
  font-size: x-small;
  color: var(--ink-muted);
}
:root {
  /* === Base === */
  --white: #ffffff;
  --black: #000000;

  /* === Ink (texte) === */
  --ink: color-mix(in lab, var(--black) 75%, var(--blue));
  --ink-muted: color-mix(in lab, var(--ink) 65%, var(--bg));
  --ink-10: color-mix(in lab, var(--ink) 10%, transparent);
  --ink-faint: color-mix(in lab, var(--black) 10%, transparent);

  /* === Background === */
  --bg: #f6f6f6;
  --bg-card: var(--white);

  /* === Couleurs === */
  --blue: #1370ed;
  --red: #ec0018;
  --darkblue: #090058;
  --green: #00ee9a;
  --yellow: #ffb700;
  --purple: #530097;
  --orange: lab(73 32 71 / 100%);

  /* === Palette split-flap (inspirée du drapeau LGBT) === */
  --flag-0: #ffbbe5;
  --flag-1: #ffffff;
  --flag-2: #b0e5ff;
  --flag-3: #594138;
  --flag-4: #1b2733;
  --flag-5: #b639ff;
  --flag-6: #0dc2fd;
  --flag-7: #00ff97;
  --flag-8: #ff9200;
  --flag-9: #ff3e19;
  --flag-a: #fff000;

  /* === Typographie split-flap (couverture Unicode via fallback OS) ===
     Latin/symboles d'abord (Helvetica Bold), puis CJK et emoji du système :
     le navigateur substitue chaque glyphe manquant depuis ces polices. */
  --sfp-typeface:
    'Helvetica Neue', Helvetica, Arial, 'Noto Sans', 'Segoe UI', Roboto,
    'PingFang SC', 'Hiragino Sans', 'Hiragino Kaku Gothic ProN', 'Microsoft YaHei',
    'Noto Sans CJK SC', 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji',
    sans-serif;

  /* === Layout === */
  --radius: 1rem;
  --width: 48rem;
  --rail-width: 18rem;
  --timeline-width: 72rem;
  /* largeur de la colonne centrale = largeur du panneau split-flap */

  /* === Effets === */
  --shadow: 0.5px 0.5px 1px var(--ink-faint), 2px 2px 6px var(--ink-faint), 7px 7px 23px var(--ink-faint), 30px 30px 60px var(--ink-faint);
  --shadow--inset: inset 0.5px 0.5px 1px var(--ink-faint), inset 2px 2px 6px var(--ink-faint), inset 7px 7px 23px var(--ink-faint), inset 30px 30px 60px var(--ink-faint);

  /* === Composants === */
  --input-border: color-mix(in lab, var(--ink) 25%, transparent);
  --light-grey: color-mix(in lab, var(--ink) 12%, var(--bg));
  --calendar-border: color-mix(in lab, var(--black) 8%, transparent);
  --calendar-grid: color-mix(in lab, var(--blue) 25%, transparent);
  --calendar-highlight: color-mix(in lab, var(--blue) 8%, transparent);

  /* === Aliases === */
  --black--shadow: var(--ink-faint);
  --gray: var(--ink-muted);
  --grey: var(--ink-muted);
}
/* LA CORRESPONDANCE — la boîte flottante des pages du studio
   (pages/correspondance/_boite, correspondance_controller.js,
   CorrespondancesController) : une pastille en bas à droite, et la GRANDE boîte
   qu'elle ouvre (demande de l'auteur, 30 sept. 2026 : « que la correspondance
   prenne plus de place ») — presque tout l'écran, avec dedans un projet en deux
   colonnes : LE RAIL (qui y entre, puis les canaux — le général et un par image,
   chacun avec son résumé) et LE CANAL ouvert (son fil, son éditeur ; pour une
   image, LA PLANCHE : l'image, ses points, et les BULLES — le message d'un point,
   ou celle où l'on écrit sur un point). Même matière que la pastille du menu
   (menu.css) : une carte translucide, floutée, aux couleurs de la charte. Sur un
   téléphone, plein écran, et tout s'empile. Et le cadre « Les correspondances »
   de la page Contact (admin, pages/correspondance/_acces).
   PIÈGE : form.scss.css centre et borne tout <form> (48ch) et donne 48rem de
   haut à tout <textarea> — les formulaires d'ici reprennent leur place. */

.correspondance {
  /* Au-dessus de la loupe (40) et des pages, sous le menu (100) et le plan (200). */
  --correspondance-z: 90;
  --correspondance-bord: max(0.5rem, var(--page-gutter));
  --correspondance-rail: 19rem;
}

.correspondance form,
.correspondance-acces form {
  max-width: none;
  margin: 0;
}

/* ── La pastille ─────────────────────────────────────────────────────────── */
.correspondance__bouton {
  position: fixed;
  z-index: var(--correspondance-z);
  right: var(--correspondance-bord);
  bottom: var(--correspondance-bord);
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.45em 1em;
  border: 0;
  border-radius: 999px;
  background: color-mix(in lab, var(--bg-card) 86%, transparent);
  backdrop-filter: blur(1.5mm);
  box-shadow: 0 0.2em 1.2em rgba(18, 24, 44, 0.14);
  font: inherit;
  font-size: small;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  transition: background-color 150ms;
}

/* Cachée (l'accueil, sans projet au centre : `pastille: false`) — PIÈGE : le
   `display` ci-dessus l'emportait sur `hidden`, elle se voyait sur la home. */
.correspondance__bouton[hidden] {
  display: none;
}

.correspondance__bouton:hover,
.correspondance__bouton:focus-visible {
  background: var(--bg-card);
  outline: none;
}

.correspondance__bouton:focus-visible {
  box-shadow: 0 0 0 2px var(--blue), 0 0.2em 1.2em rgba(18, 24, 44, 0.14);
}

/* Boîte ouverte : la pastille s'efface derrière elle (le ✕ la referme). */
.correspondance__bouton[aria-expanded="true"] {
  visibility: hidden;
}

/* Admin : ce qui l'attend — les messages des clients pas encore validés. */
.correspondance__compte {
  min-width: 1.6em;
  padding: 0.1em 0.45em;
  border-radius: 999px;
  background: var(--blue);
  color: var(--white);
  font-size: x-small;
  text-align: center;
}

/* ── La boîte : presque tout l'écran ─────────────────────────────────────── */
.correspondance__boite {
  position: fixed;
  z-index: var(--correspondance-z);
  right: var(--correspondance-bord);
  bottom: var(--correspondance-bord);
  display: flex;
  flex-direction: column;
  width: min(84rem, calc(100vw - 2 * var(--correspondance-bord)));
  height: calc(100dvh - var(--menu-h) - 2 * var(--correspondance-bord));
  border-radius: var(--radius);
  background: color-mix(in lab, var(--bg-card) 94%, transparent);
  backdrop-filter: blur(3mm);
  box-shadow: var(--shadow);
  color: var(--ink);
  overflow: hidden;
}

.correspondance__boite[hidden] {
  display: none;
}

.correspondance__entete {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex: none;
  padding: 0.7em 0.8em 0.7em 1.2em;
  border-bottom: 1px solid var(--ink-10);
}

.correspondance__titre {
  font-size: small;
  font-weight: 600;
}

.correspondance__fermer {
  width: 2.2em;
  height: 2.2em;
  border: 0;
  border-radius: 50%;
  background: transparent;
  font: inherit;
  font-size: small;
  color: var(--ink-muted);
  cursor: pointer;
}

.correspondance__fermer:hover,
.correspondance__fermer:focus-visible {
  background: var(--light-grey);
  color: var(--ink);
  outline: none;
}

/* Le cadre : une colonne qui prend toute la boîte. */
.correspondance__cadre {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}

.correspondance__cadre[busy] {
  opacity: 0.6;
  transition: opacity 150ms 200ms;
}

/* Les écrans SANS projet (la porte, démarrer, les projets) : une colonne
   lisible au milieu de la grande boîte. */
.correspondance__attente,
.correspondance__porte,
.correspondance__liste {
  width: 100%;
  max-width: 40rem;
  margin: 0 auto;
  padding: 1.6em 1.4em;
  overflow-y: auto;
}

.correspondance__intro {
  margin: 0 0 1em;
  font-size: small;
  line-height: 1.45;
}

.correspondance__vide {
  margin: 0;
  color: var(--ink-muted);
  font-size: small;
}

.correspondance__erreur {
  margin: 0.6em 0 0;
  color: var(--red);
  font-size: x-small;
}

/* ── La porte : deux chemins — un nouveau projet, un projet en cours ─────── */
.correspondance__porte {
  display: flex;
  flex-direction: column;
  gap: 1.2em;
}

.correspondance__chemin + .correspondance__chemin {
  padding-top: 1.2em;
  border-top: 1px solid var(--ink-10);
}

.correspondance__chemin .correspondance__intro {
  margin-bottom: 0.8em;
}

.correspondance__chemin-titre {
  margin: 0 0 0.4em;
  font-size: small;
  font-weight: 600;
}

.correspondance__liste .correspondance__chemin-titre:not(:first-child) {
  margin-top: 1.2em;
}

/* Démarrer un projet : les champs l'un sous l'autre, puis l'éditeur. */
.correspondance__nouveau {
  display: flex;
  flex-direction: column;
  gap: 0.3em;
}

.correspondance__nouveau .correspondance__etiquette {
  margin: 0.5em 0 0;
}

.correspondance__nouveau .correspondance__barre {
  margin-top: 0.8em;
}

/* Le piège à robots : hors de l'écran, hors du clavier, hors des lecteurs. */
.correspondance__piege {
  position: absolute;
  left: -100vw;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.correspondance__retour-texte {
  align-self: flex-start;
  color: var(--ink-muted);
  font-size: x-small;
  text-decoration: none;
}

.correspondance__retour-texte:hover,
.correspondance__retour-texte:focus-visible {
  color: var(--blue);
  outline: none;
}

.correspondance__pied {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6em;
  margin-top: 1em;
  font-size: x-small;
}

.correspondance__pied form.correspondance__sortie {
  margin: 0;
}

.correspondance__etiquette {
  display: block;
  margin-bottom: 0.4em;
  color: var(--ink-muted);
  font-size: x-small;
}

.correspondance__ligne {
  display: flex;
  gap: 0.5em;
}

.correspondance__saisie,
.correspondance-acces__champ {
  flex: 1 1 auto;
  min-width: 0;
  padding: 0.55em 0.8em;
  border: 1px solid var(--input-border);
  border-radius: 999px;
  background: var(--bg-card);
  font: inherit;
  font-size: small;
  color: var(--ink);
}

.correspondance__saisie:focus,
.correspondance-acces__champ:focus {
  border-color: var(--blue);
  outline: none;
}

.correspondance__envoi {
  flex: none;
  display: inline-block;
  padding: 0.55em 1.1em;
  border: 0;
  border-radius: 999px;
  background: var(--blue);
  font: inherit;
  font-size: small;
  font-weight: 600;
  color: var(--white);
  text-decoration: none;
  cursor: pointer;
  transition: background-color 150ms;
}

.correspondance__envoi:hover,
.correspondance__envoi:focus-visible {
  background: color-mix(in lab, var(--blue) 70%, var(--black));
  outline: none;
}

/* L'entrée d'un client déjà en route : le chemin secondaire de la porte. */
.correspondance__envoi--discret {
  background: var(--light-grey);
  color: var(--ink);
}

.correspondance__envoi--discret:hover,
.correspondance__envoi--discret:focus-visible {
  background: color-mix(in lab, var(--ink) 18%, var(--bg));
}

/* ── Les projets ─────────────────────────────────────────────────────────── */
.correspondance__projets {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4em;
}

.correspondance__projet {
  display: flex;
  flex-direction: column;
  gap: 0.15em;
  padding: 0.7em 0.9em;
  border-radius: calc(var(--radius) / 1.5);
  background: var(--bg);
  color: var(--ink);
  text-decoration: none;
}

.correspondance__projet:hover,
.correspondance__projet:focus-visible {
  background: var(--light-grey);
  outline: none;
}

.correspondance__projet-nom {
  font-size: small;
  font-weight: 600;
}

.correspondance__projet-compte {
  color: var(--ink-muted);
  font-size: x-small;
}

.correspondance form.correspondance__sortie {
  margin-top: 1em;
}

/* ── Un projet : le rail et le canal ─────────────────────────────────────── */
.correspondance__conversation {
  display: grid;
  grid-template-columns: var(--correspondance-rail) minmax(0, 1fr);
  flex: 1 1 auto;
  min-height: 0;
}

/* Le rail : la tête du projet, puis ses canaux. Il défile s'il le faut. */
.correspondance__rail {
  display: flex;
  flex-direction: column;
  min-height: 0;
  border-right: 1px solid var(--ink-10);
  background: color-mix(in lab, var(--bg) 60%, transparent);
  overflow-y: auto;
}

.correspondance__tete {
  display: flex;
  align-items: flex-start;
  gap: 0.6em;
  padding: 0.9em 1em;
  border-bottom: 1px solid var(--ink-10);
}

.correspondance__retour {
  flex: none;
  padding: 0 0.3em;
  color: var(--ink-muted);
  font-size: medium;
  text-decoration: none;
}

.correspondance__retour:hover,
.correspondance__retour:focus-visible {
  color: var(--blue);
  outline: none;
}

.correspondance__tete-texte {
  min-width: 0;
}

.correspondance__projet-titre {
  margin: 0;
  font-size: small;
  font-weight: 600;
  line-height: 1.2;
}

.correspondance__qui {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3em;
  margin-top: 0.2em;
  color: var(--ink-muted);
  font-size: x-small;
}

.correspondance__qui a,
.correspondance__lien {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--blue);
  text-decoration: none;
  cursor: pointer;
}

.correspondance__qui form.correspondance__sortie {
  display: inline;
  margin: 0;
}

/* Les canaux : une ligne chacun, le courant marqué. */
.correspondance__canaux {
  list-style: none;
  margin: 0;
  padding: 0.5em;
  display: flex;
  flex-direction: column;
  gap: 0.15em;
}

.correspondance__canal {
  display: flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.45em 0.6em;
  border-radius: calc(var(--radius) / 2);
  color: var(--ink);
  text-decoration: none;
}

.correspondance__canal:hover,
.correspondance__canal:focus-visible {
  background: var(--light-grey);
  outline: none;
}

.correspondance__canal[aria-current="true"] {
  background: var(--bg-card);
  box-shadow: inset 0 0 0 1px var(--ink-10);
}

.correspondance__canal-diese {
  color: var(--ink-muted);
  font-weight: 600;
}

.correspondance__canal .correspondance__canal-diese {
  flex: none;
  width: 2.6rem;
  font-size: medium;
  text-align: center;
}

.correspondance__canal-vignette {
  flex: none;
  width: 2.6rem;
  height: 2.6rem;
  object-fit: cover;
  border-radius: calc(var(--radius) / 3);
  background: var(--light-grey);
}

.correspondance__canal-texte {
  display: flex;
  flex-direction: column;
  gap: 0.1em;
  min-width: 0;
}

.correspondance__canal-nom {
  overflow: hidden;
  font-size: small;
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.correspondance__canal-resume {
  color: var(--ink-muted);
  font-size: x-small;
}

.correspondance__rail-vide {
  padding: 0.4em 1.1em 1em;
  font-size: x-small;
}

/* Le canal ouvert : sa tête, son fil (qui défile), son éditeur. */
.correspondance__canal-corps {
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
}

.correspondance__canal-tete {
  flex: none;
  padding: 0.9em 1.4em 0.7em;
  border-bottom: 1px solid var(--ink-10);
}

.correspondance__canal-titre {
  margin: 0;
  font-size: medium;
  font-weight: 600;
  line-height: 1.2;
}

.correspondance__canal-sous {
  margin: 0.2em 0 0;
  color: var(--ink-muted);
  font-size: x-small;
}

/* ── Le fil : du plus ancien au plus récent, l'auteur à droite, le client à gauche ── */
.correspondance__fil {
  list-style: none;
  margin: 0;
  padding: 1em 1.4em;
  display: flex;
  flex-direction: column;
  gap: 0.8em;
  flex: 1 1 auto;
  min-height: 5rem;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.correspondance__message {
  align-self: flex-start;
  max-width: min(88%, 52rem);
  padding: 0.6em 0.8em;
  border-radius: calc(var(--radius) / 1.5);
  background: var(--bg);
}

.correspondance__message--auteur {
  align-self: flex-end;
  background: color-mix(in lab, var(--blue) 9%, var(--bg-card));
}

.correspondance__message.is-valide {
  box-shadow: inset 0 0 0 1px color-mix(in lab, var(--green) 70%, var(--ink));
}

.correspondance__signature {
  display: flex;
  align-items: center;
  gap: 0.6em;
  margin: 0 0 0.25em;
  font-size: x-small;
}

.correspondance__signature time {
  color: var(--ink-muted);
}

.correspondance__texte {
  font-size: small;
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.correspondance__texte > :first-child { margin-top: 0; }
.correspondance__texte > :last-child { margin-bottom: 0; }

.correspondance__texte p,
.correspondance__texte ul,
.correspondance__texte ol {
  margin: 0.4em 0;
}

.correspondance__texte ul,
.correspondance__texte ol {
  padding-left: 1.2em;
}

.correspondance__texte a {
  color: var(--blue);
}

.correspondance__gestes {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3em;
  margin-top: 0.4em;
}

.correspondance__geste-form {
  display: inline;
}

.correspondance__geste {
  padding: 0.2em 0.6em;
  border: 1px solid var(--ink-10);
  border-radius: 999px;
  background: transparent;
  font: inherit;
  font-size: x-small;
  color: var(--ink-muted);
  cursor: pointer;
}

.correspondance__geste:hover,
.correspondance__geste:focus-visible {
  border-color: var(--input-border);
  color: var(--ink);
  outline: none;
}

.correspondance__geste--valider[aria-pressed="true"] {
  border-color: transparent;
  background: color-mix(in lab, var(--green) 22%, var(--bg-card));
  color: color-mix(in lab, var(--green) 35%, var(--ink));
}

.correspondance__geste--effacer:hover,
.correspondance__geste--effacer:focus-visible {
  color: var(--red);
}

/* Un message sur un document, hors de son canal : le nom du document. */
.correspondance__sur {
  display: inline-block;
  margin-bottom: 0.25em;
  color: var(--blue);
  font-size: x-small;
  text-decoration: none;
}

/* Le numéro du point d'un message — le même que sur l'image ; cliqué, il ouvre
   la bulle du point. */
.correspondance__numero {
  min-width: 1.6em;
  padding: 0.05em 0.4em;
  border: 0;
  border-radius: 999px;
  background: var(--orange);
  font: inherit;
  font-size: x-small;
  font-weight: 600;
  color: var(--ink);
  text-align: center;
  cursor: pointer;
}

/* Un point cliqué : son message brille un instant. */
.correspondance__message.is-montre {
  animation: correspondance-montre 1.2s ease-out;
}

@keyframes correspondance-montre {
  from { box-shadow: 0 0 0 3px var(--orange); }
  to { box-shadow: 0 0 0 3px transparent; }
}

@media (prefers-reduced-motion: reduce) {
  .correspondance__message.is-montre { animation: none; box-shadow: 0 0 0 2px var(--orange); }
}

/* ── Le canal d'une image : la planche à côté du fil ─────────────────────── */
.correspondance__canal-corps--document {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 26rem;
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "tete    tete"
    "planche fil"
    "planche editeur";
}

.correspondance__canal-corps--document > .correspondance__canal-tete { grid-area: tete; }
.correspondance__canal-corps--document > .correspondance__fil { grid-area: fil; }
.correspondance__canal-corps--document > .correspondance__editeur { grid-area: editeur; }

.correspondance__planche-bloc {
  grid-area: planche;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  min-width: 0;
  padding: 1.2em;
  border-right: 1px solid var(--ink-10);
  background: var(--bg);
  overflow: hidden;
}

/* La planche épouse l'image : points et bulles se posent en fractions de sa taille. */
.correspondance__planche {
  position: relative;
  display: inline-block;
  max-width: 100%;
  line-height: 0;
  cursor: crosshair;
}

.correspondance__image {
  display: block;
  max-width: 100%;
  max-height: calc(100dvh - var(--menu-h) - 2 * var(--correspondance-bord) - 11rem);
  border-radius: 2px;
  box-shadow: var(--shadow);
  user-select: none;
}

.correspondance__epingle {
  position: absolute;
  z-index: 1;
  left: calc(var(--x) * 100%);
  top: calc(var(--y) * 100%);
  translate: -50% -50%;
  min-width: 2em;
  height: 2em;
  padding: 0 0.45em;
  border: 2px solid var(--white);
  border-radius: 999px;
  background: var(--orange);
  box-shadow: 0 0.1em 0.5em rgba(18, 24, 44, 0.35);
  font: inherit;
  font-size: x-small;
  font-weight: 600;
  line-height: 1;
  color: var(--ink);
  cursor: pointer;
}

.correspondance__epingle.is-valide {
  background: color-mix(in lab, var(--green) 60%, var(--white));
}

.correspondance__epingle:hover,
.correspondance__epingle:focus-visible,
.correspondance__epingle[aria-expanded="true"] {
  outline: 2px solid var(--blue);
  outline-offset: 1px;
}

/* Le point du prochain message, pas encore envoyé. */
.correspondance__epingle--nouvelle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--blue);
  color: var(--white);
  pointer-events: none;
}

.correspondance__epingle--nouvelle[hidden] {
  display: none;
}

/* LES BULLES, sur l'image : le message d'un point (ses gestes compris), ou le
   formulaire d'un nouveau point. Ancrées au point, ouvertes du côté où il y a
   de la place (data-cote : droite / gauche ; data-haut : bas / haut). */
.correspondance__bulle {
  position: absolute;
  z-index: 2;
  left: calc(var(--x) * 100%);
  top: calc(var(--y) * 100%);
  width: min(22rem, 80vw);
  translate: 1.4em 1.2em;
  border-radius: calc(var(--radius) / 1.5);
  background: var(--bg-card);
  box-shadow: var(--shadow), 0 0 0 1px var(--ink-10);
  line-height: normal;
  cursor: auto;
}

.correspondance__bulle[hidden] {
  display: none;
}

.correspondance__bulle[data-cote="gauche"] { translate: calc(-100% - 1.4em) 1.2em; }
.correspondance__bulle[data-haut="haut"] { translate: 1.4em calc(-100% - 1.2em); }
.correspondance__bulle[data-cote="gauche"][data-haut="haut"] { translate: calc(-100% - 1.4em) calc(-100% - 1.2em); }

.correspondance__fil--bulle {
  flex: none;
  min-height: 0;
  padding: 0.4em;
  overflow: visible;
}

.correspondance__fil--bulle .correspondance__message {
  align-self: stretch;
  max-width: none;
}

.correspondance__bulle-form {
  display: flex;
  flex-direction: column;
  gap: 0.5em;
  padding: 0.7em;
}

.correspondance__champ--bulle {
  max-height: 10rem;
}

/* ── L'éditeur : la barre, le texte, l'envoi ─────────────────────────────── */
.correspondance__editeur {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 0.4em;
  padding: 0.7em 1.4em 1em;
  border-top: 1px solid var(--ink-10);
}

.correspondance__barre {
  display: flex;
  gap: 0.2em;
}

.correspondance__outil {
  width: 2em;
  height: 2em;
  border: 0;
  border-radius: 0.4em;
  background: transparent;
  font: inherit;
  font-size: small;
  color: var(--ink-muted);
  cursor: pointer;
}

.correspondance__outil:hover,
.correspondance__outil:focus-visible {
  background: var(--light-grey);
  color: var(--ink);
  outline: none;
}

.correspondance__champ {
  width: 100%;
  min-height: 0;
  max-height: 14rem;
  padding: 0.6em 0.8em;
  border: 1px solid var(--input-border);
  border-radius: calc(var(--radius) / 1.5);
  background: var(--bg-card);
  font: inherit;
  font-size: small;
  line-height: 1.45;
  color: var(--ink);
  resize: none;
}

.correspondance__champ:focus {
  border-color: var(--blue);
  outline: none;
}

.correspondance__envoyer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.8em;
}

.correspondance__aide {
  color: var(--ink-muted);
  font-size: xx-small;
}

@media (hover: none) {
  .correspondance__aide { display: none; }
}

/* ── Écrans moyens : la planche au-dessus du fil ─────────────────────────── */
@media (max-width: 72rem) {
  .correspondance__canal-corps--document {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto minmax(0, 1fr) auto;
    grid-template-areas: "tete" "planche" "fil" "editeur";
  }

  .correspondance__planche-bloc {
    padding: 0.8em;
    border-right: 0;
    border-bottom: 1px solid var(--ink-10);
  }

  .correspondance__image {
    max-height: 42dvh;
  }
}

/* ── Sur un téléphone : plein écran, tout s'empile ───────────────────────── */
@media (max-width: 48rem) {
  .correspondance__boite {
    right: 0;
    bottom: 0;
    left: 0;
    width: auto;
    height: calc(100dvh - var(--menu-h) - 0.5rem);
    border-radius: var(--radius) var(--radius) 0 0;
  }

  .correspondance__conversation {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
  }

  /* Le rail devient une bande : la tête, puis les canaux côte à côte. */
  .correspondance__rail {
    border-right: 0;
    border-bottom: 1px solid var(--ink-10);
    overflow: visible;
  }

  .correspondance__tete {
    padding: 0.6em 1em;
  }

  .correspondance__canaux {
    flex-direction: row;
    gap: 0.3em;
    overflow-x: auto;
    overscroll-behavior-x: contain;
  }

  .correspondance__canal {
    flex: none;
    width: 11rem;
    padding: 0.35em 0.5em;
  }

  .correspondance__image {
    max-height: 36dvh;
  }

  .correspondance__bulle {
    width: min(20rem, calc(100vw - 2rem));
  }
}

/* ── La page Contact ─────────────────────────────────────────────────────── */
.correspondance-appel__boutons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5em;
  margin-top: 0.4em;
}

/* Admin : qui peut entrer. */
.correspondance-acces {
  gap: 0.6em;
}

.correspondance-acces form.correspondance-acces__ajout {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5em;
  margin-top: 0.4em;
}

.correspondance-acces__ajout select.correspondance-acces__champ {
  flex: 1 1 12rem;
}

.correspondance-acces__ajout input.correspondance-acces__champ {
  flex: 1 1 9rem;
}

.correspondance-acces__projets {
  list-style: none;
  margin: 0.6em 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.correspondance-acces__projet {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3em 0.8em;
  padding: 0.6em 0;
  border-top: 1px solid var(--ink-10);
}

.correspondance-acces__nom {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: small;
  font-weight: 600;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
}

.correspondance-acces__nom:hover,
.correspondance-acces__nom:focus-visible {
  color: var(--blue);
  outline: none;
}

.correspondance-acces__groupe {
  margin: 0.8em 0 0;
  font-size: small;
  font-weight: 600;
}

.correspondance-acces__documents {
  color: var(--ink-muted);
  font-size: x-small;
  text-decoration: none;
}

.correspondance-acces__documents:hover,
.correspondance-acces__documents:focus-visible {
  color: var(--blue);
  outline: none;
}

.correspondance-acces__contact {
  color: var(--ink-muted);
}

.correspondance-acces__contact a {
  color: inherit;
}

.correspondance-acces__compte {
  color: var(--ink-muted);
  font-size: x-small;
}

.correspondance-acces__prenoms {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.3em;
  flex-basis: 100%;
}

.correspondance-acces__prenom {
  display: inline-flex;
  align-items: center;
  gap: 0.2em;
  padding: 0.15em 0.2em 0.15em 0.7em;
  border-radius: 999px;
  background: var(--bg);
  font-size: x-small;
}

.correspondance-acces__retirer-form {
  display: inline;
}

.correspondance-acces__retirer {
  width: 1.7em;
  height: 1.7em;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  font: inherit;
  color: var(--ink-muted);
  cursor: pointer;
}

.correspondance-acces__retirer:hover,
.correspondance-acces__retirer:focus-visible {
  background: var(--light-grey);
  color: var(--red);
  outline: none;
}

.correspondance-acces__aucun {
  color: var(--ink-muted);
  font-size: x-small;
}
/* LE CRÉDIT d'une image (credits/_credit ; demande de l'auteur, 30 sept. 2026) :
   AU SURVOL, sa légende et son auteur — « © Andi Mustafaj » — sur un
   voile au bas de l'image : sur la grille d'un projet (`.projet-image__cadre`) et sur
   les croquis des cahiers (`.cahier__croquis`). Au doigt (pas de survol), sous
   l'image, toujours visible. Le champ de l'admin (credits/_champ) prend l'allure des
   champs de sa page (`classe`). */
.projet-image__cadre,
.cahier__croquis {
  position: relative;
}

.credit {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2em;
  padding: 1.6em 0.8em 0.6em;
  border-radius: 0 0 calc(var(--radius) / 2) calc(var(--radius) / 2);
  background: linear-gradient(to top, rgb(12 14 30 / 0.72), rgb(12 14 30 / 0));
  color: var(--white);
  font-size: x-small;
  line-height: 1.35;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
}

.projet-image__cadre:hover .credit,
.projet-image__cadre:focus-within .credit,
.cahier__croquis:hover .credit,
.cahier__croquis:focus-within .credit {
  opacity: 1;
  pointer-events: auto;
}

/* Sur le croquis d'un cahier, le voile s'arrête à la marge blanche du tirage. */
.cahier__croquis .credit {
  right: 0.3rem;
  bottom: 0.45rem;
  left: 0.3rem;
  padding: 1.2em 0.5em 0.4em;
  border-radius: 0;
  font-size: xx-small;
}

.credit__legende {
  font-weight: 600;
}

/* Au doigt : pas de survol — le crédit sous l'image, en clair. */
@media (hover: none) {
  .credit {
    position: static;
    padding: 0.4em 0 0;
    background: none;
    color: var(--ink-muted);
    opacity: 1;
    pointer-events: auto;
  }

  .cahier__croquis .credit {
    padding: 0.3em 0 0;
  }
}

/* ── Le champ auteur de l'admin : les auteurs qui existent déjà, PROPOSÉS ────
   (credits/_champ, auteur_controller) : une liste sous le champ, dès qu'on tape. */
.auteur-choix {
  position: relative;
  display: block;
}

.auteur-choix__liste {
  position: absolute;
  z-index: 50;
  top: 100%;
  left: 0;
  min-width: 14rem;
  max-width: 100%;
  margin: 0.2em 0 0;
  padding: 0.25em;
  list-style: none;
  border-radius: calc(var(--radius) / 2);
  background: var(--bg-card);
  box-shadow: var(--shadow), 0 0 0 1px var(--ink-10);
}

.auteur-choix__liste[hidden] {
  display: none;
}

.auteur-choix__option {
  padding: 0.35em 0.6em;
  border-radius: 0.35em;
  font-size: x-small;
  color: var(--ink);
  cursor: pointer;
}

.auteur-choix__option:hover,
.auteur-choix__option[aria-selected="true"] {
  background: var(--light-grey);
}

/* « + Créer l'auteur … » : en dernier, et d'une autre couleur — on crée, on ne choisit pas. */
.auteur-choix__option--creer {
  color: var(--blue);
}

/* Plusieurs auteurs : une pastille chacun (son nom, ✕), puis le champ pour en ajouter. */
.auteur-choix__puces {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25em;
}

.auteur-choix__puces:empty {
  display: none;
}

.auteur-puce {
  display: inline-flex;
  align-items: center;
  gap: 0.15em;
  margin: 0.2em 0 0.1em;
  padding: 0.1em 0.15em 0.1em 0.6em;
  border-radius: 999px;
  background: var(--light-grey);
  font-size: xx-small;
  color: var(--ink);
}

.auteur-puce__retirer {
  width: 1.5em;
  height: 1.5em;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  font: inherit;
  color: var(--ink-muted);
  cursor: pointer;
}

.auteur-puce__retirer:hover,
.auteur-puce__retirer:focus-visible {
  background: var(--bg-card);
  color: var(--red);
  outline: none;
}
/* ── Éditeur de deck ─────────────────────────────────────────────────────────
   Tokens locaux pour un rendu cohérent (filet, focus, rayon). */
.deck-editor {
  --edit-hair: color-mix(in lab, currentColor 14%, transparent);
  --edit-hair-strong: color-mix(in lab, currentColor 45%, transparent);
  --edit-focus: color-mix(in lab, currentColor 8%, transparent);
  --edit-measure: 46rem; /* largeur de lecture confortable pour la prose */

  max-width: 70rem;
  width: 100%;
  margin-inline: auto;
  padding: 2.5rem clamp(1rem, 4vw, 3rem) 6rem;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 2.5rem;
}
/* Le style de formulaire global (form.scss.css) centre les <form> (margin:auto),
   les limite à 48ch et impose un textarea géant : pensé pour les formulaires
   simples, pas pour cet éditeur. On reprend la main → pleine largeur, alignés à
   gauche ; la largeur de lecture est re-fixée par classe juste en dessous. */
.deck-editor form {
  margin: 0;
  max-width: none;
  width: 100%;
}
.deck-editor .deck-group__desc-form {
  max-width: var(--edit-measure);
}

/* ── Réglages du deck : panneau compact à largeur de lecture ─────────────── */
.deck-form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.deck-form__field {
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  max-width: var(--edit-measure);
}
.deck-form label {
  font-size: xx-small;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  opacity: 0.6;
}
.deck-form input[type="text"]:not(.deck-form__title),
.deck-form textarea {
  padding: 0.55rem 0.7rem;
  border: 1px solid color-mix(in lab, currentColor 22%, transparent);
  border-radius: 8px;
  font: inherit;
  width: 100%;
  box-sizing: border-box;
  background: var(--bg-card, transparent);
  transition: border-color 120ms, box-shadow 120ms;
}
.deck-form input[type="text"]:not(.deck-form__title):focus,
.deck-form textarea:focus {
  outline: none;
  border-color: var(--edit-hair-strong);
  box-shadow: 0 0 0 3px var(--edit-focus);
}

/* Titre du deck : le <h1> lui-même est éditable (input transparent à même le titre). */
.deck-form__title-line {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: x-large;
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.01em;
}
.deck-form__title {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;   /* hérite la taille/graisse du titre */
  color: inherit;
  margin-left: -0.45rem;
  padding: 0.1rem 0.45rem;
  border: 1px solid transparent;
  border-radius: 9px;
  background: transparent;
  transition: background 120ms, box-shadow 120ms;
}
.deck-form__title::placeholder {
  font-weight: 600;
  opacity: 0.35;
}
.deck-form__title:hover {
  background: color-mix(in lab, currentColor 5%, transparent);
}
.deck-form__title:focus {
  outline: none;
  background: var(--bg-card, transparent);
  box-shadow: 0 0 0 2px var(--edit-hair-strong);
}
.deck-form__title-line .deck-form__status {
  flex: 0 0 auto;
  font-size: xx-small;
}
.deck-form textarea {
  min-height: 4.5rem;
  line-height: 1.5;
  resize: none;    /* hauteur gérée par le contrôleur autogrow */
  overflow: hidden;
}
.deck-form__actions {
  display: flex;
  gap: 1rem;
  align-items: center;
  font-size: x-small;
}

/* Liste des groupes : rythme régulier via gap (pas de marges sur les cartes). */
#deck-groups {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

/* ── Carte de groupe ─────────────────────────────────────────────────────── */
.deck-group {
  border: 1px solid var(--edit-hair);
  border-radius: 14px;
  padding: 1.25rem 1.4rem;
  background: var(--bg-card, transparent);
  box-shadow: 0 1px 3px color-mix(in lab, currentColor 6%, transparent);
  transition: opacity 150ms, box-shadow 150ms, border-color 150ms;
}
.deck-group:hover {
  border-color: color-mix(in lab, currentColor 22%, transparent);
}
.deck-group.is-dragging {
  opacity: 0.4;
}
.deck-group__header {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin-bottom: 0.85rem;
}
.deck-group__grip {
  cursor: grab;
  user-select: none;
  opacity: 0.35;
  font-size: small;
  padding: 0.1rem 0.15rem;
  transition: opacity 120ms;
}
.deck-group:hover .deck-group__grip {
  opacity: 0.7;
}
.deck-group__grip:active {
  cursor: grabbing;
}

/* Nom du groupe : titre éditable en ligne (auto-enregistré). */
.deck-group__name-form {
  flex: 1 1 12rem;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}
.deck-group__name-input {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;
  font-size: small;
  font-weight: 600;
  padding: 0.25rem 0.45rem;
  border: 1px solid transparent;
  border-radius: 7px;
  background: transparent;
  transition: background 120ms, box-shadow 120ms;
}
.deck-group__name-input::placeholder {
  font-weight: 500;
  opacity: 0.45;
}
.deck-group__name-input:hover {
  background: color-mix(in lab, currentColor 5%, transparent);
}
.deck-group__name-input:focus {
  outline: none;
  background: var(--bg-card, transparent);
  box-shadow: 0 0 0 2px var(--edit-hair-strong);
}
.deck-group__count {
  flex: 0 0 auto;
  padding: 0.15rem 0.6rem;
  border: 1px solid var(--edit-hair);
  border-radius: 999px;
  font-size: xx-small;
  opacity: 0.7;
  white-space: nowrap;
}
.deck-group__remove {
  flex: 0 0 auto;
  margin-left: 0.25rem;
}
.deck-group__remove button,
.deck-images__delete button {
  background: none;
  border: none;
  cursor: pointer;
  opacity: 0.55;
  font: inherit;
  font-size: xx-small;
  transition: opacity 120ms, color 120ms;
}
.deck-group__remove button:hover,
.deck-images__delete button:hover {
  opacity: 1;
  color: #c0392b;
}

/* Description du groupe : largeur de lecture, hauteur auto (autogrow). */
.deck-group__desc-form {
  margin: 0 0 1rem;
  max-width: var(--edit-measure);
}
.deck-group__desc {
  width: 100%;
  box-sizing: border-box;
  font: inherit;
  font-size: x-small;
  line-height: 1.5;
  min-height: 2.75rem;
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--edit-hair);
  border-radius: 8px;
  background: transparent;
  resize: none;
  overflow: hidden;
  transition: border-color 120ms, box-shadow 120ms;
}
.deck-group__desc::placeholder {
  opacity: 0.5;
}
.deck-group__desc:hover {
  border-color: color-mix(in lab, currentColor 26%, transparent);
}
.deck-group__desc:focus {
  outline: none;
  border-color: var(--edit-hair-strong);
  background: var(--bg-card, transparent);
  box-shadow: 0 0 0 3px var(--edit-focus);
}

/* ── Grille d'images ─────────────────────────────────────────────────────── */
.deck-images__grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: flex-start;
}
.deck-images__item {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  width: 8.5rem;
  position: relative;
}
.deck-images__item img {
  width: 100%;
  height: 6.5rem;
  object-fit: cover;
  border-radius: 8px;
  box-shadow: 0 1px 3px color-mix(in lab, currentColor 14%, transparent);
}
/* Vignette « poignée » : glisser pour réordonner / changer de groupe (pointer events).
   touch-action:none empêche le scroll tactile de voler le geste de glissé. */
.deck-images__drag {
  cursor: grab;
  touch-action: none;
  -webkit-user-drag: none;
  user-select: none;
  transition: transform 120ms, box-shadow 120ms;
}
.deck-images__drag:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 10px color-mix(in lab, currentColor 20%, transparent);
}
.deck-images__drag:active {
  cursor: grabbing;
}
/* Image en cours de déplacement (réordonnancement / changement de groupe). */
.deck-images__item.is-dragging {
  opacity: 0.4;
}
/* Pendant qu'on déplace une image, chaque grille signale qu'elle accepte le dépôt. */
.deck-editor.is-moving-image .deck-images__grid {
  outline: 2px dashed color-mix(in lab, currentColor 20%, transparent);
  outline-offset: 8px;
  border-radius: 8px;
}
/* Grille survolée pendant un déplacement : cible active du dépôt. */
.deck-editor.is-moving-image .deck-images__grid.is-drop-target {
  outline-style: solid;
  outline-color: var(--edit-hair-strong);
  background: color-mix(in lab, currentColor 5%, transparent);
}
.deck-images__caption {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}
.deck-images__caption input {
  width: 100%;
  box-sizing: border-box;
  font-size: xx-small;
  padding: 0.3rem 0.4rem;
  border: 1px solid color-mix(in lab, currentColor 16%, transparent);
  border-radius: 6px;
  background: transparent;
  transition: border-color 120ms, box-shadow 120ms;
}
.deck-images__caption input:focus {
  outline: none;
  border-color: var(--edit-hair-strong);
  box-shadow: 0 0 0 2px var(--edit-focus);
}
.deck-images__status {
  font-size: xx-small;
  min-width: 1em;
  opacity: 0.7;
}
.deck-images__delete {
  position: absolute;
  top: 0.3rem;
  right: 0.3rem;
  opacity: 0;
  transition: opacity 120ms;
}
.deck-images__item:hover .deck-images__delete,
.deck-images__delete:focus-within {
  opacity: 1;
}
.deck-images__delete button {
  background: color-mix(in lab, var(--bg-card, white) 82%, transparent);
  border-radius: 50%;
  width: 1.5rem;
  height: 1.5rem;
  line-height: 1;
  backdrop-filter: blur(2px);
}

/* ── Les couches (images posées sur une autre, cf. Image#base) ───────────────
   La vignette montre la PILE : chaque couche est posée sur l'image de base, au
   même cadrage (`cover`, même boîte), et s'y MULTIPLIE — le blanc d'un calque
   disparaît, son trait reste, la couleur du dessous se voit au travers. Elles ne
   prennent aucun geste : c'est toujours la base qu'on glisse. */
.deck-images__item .deck-images__overlay {
  position: absolute;
  top: 0;
  left: 0;
  mix-blend-mode: multiply;
  box-shadow: none;
  pointer-events: none;
}
/* La liste des couches, du bas vers le haut, sous la légende. */
.deck-images__layers {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.deck-images__layer {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: xx-small;
}
.deck-images__item .deck-images__layer img {
  flex: 0 0 auto;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 4px;
}
.deck-images__layer-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  opacity: 0.75;
}
.deck-images__detach {
  flex: 0 0 auto;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  font: inherit;
  font-size: xx-small;
  text-decoration: underline;
  opacity: 0.55;
  transition: opacity 120ms;
}
.deck-images__detach:hover {
  opacity: 1;
}
/* « Poser sur… » : fait de cette image une couche d'une autre image du groupe. */
.deck-images__stack select {
  width: 100%;
  box-sizing: border-box;
  font: inherit;
  font-size: xx-small;
  padding: 0.25rem 0.3rem;
  border: 1px solid color-mix(in lab, currentColor 16%, transparent);
  border-radius: 6px;
  background: transparent;
  color: inherit;
  opacity: 0.7;
  cursor: pointer;
  transition: opacity 120ms, border-color 120ms;
}
.deck-images__stack select:hover,
.deck-images__stack select:focus {
  opacity: 1;
  outline: none;
  border-color: var(--edit-hair-strong);
}

/* Zone d'ajout d'images dans un groupe */
.deck-images__dropzone {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  min-height: 6.5rem;
  width: 8.5rem;
  border: 2px dashed color-mix(in lab, currentColor 22%, transparent);
  border-radius: 8px;
  cursor: pointer;
  opacity: 0.7;
  font-size: xx-small;
  padding: 0.5rem;
  box-sizing: border-box;
  transition: opacity 150ms, border-color 150ms, background 150ms;
}
.deck-images__dropzone small {
  opacity: 0.7;
}
.deck-images__dropzone:hover,
.deck-images__dropzone.is-drag-over {
  opacity: 1;
  border-color: currentColor;
  background: color-mix(in lab, currentColor 6%, transparent);
}
.deck-images__dropzone input[type="file"] {
  display: none;
}

/* ── Ajouter un groupe : bloc séparé, à largeur de lecture ───────────────── */
.deck-groups__new {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  margin-top: 1.75rem;
  padding-top: 1.5rem;
  border-top: 1px dashed color-mix(in lab, currentColor 16%, transparent);
  max-width: var(--edit-measure);
}
.deck-groups__new-title {
  margin: 0;
  font-size: x-small;
  font-weight: 600;
}
/* Créer un groupe vide : titre + description, sans images. */
.deck-groups__blank {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.85rem;
  border: 1px solid var(--edit-hair);
  border-radius: 12px;
  background: color-mix(in lab, currentColor 2.5%, transparent);
}
.deck-groups__blank-name,
.deck-groups__blank-desc {
  font: inherit;
  width: 100%;
  box-sizing: border-box;
  padding: 0.5rem 0.6rem;
  border: 1px solid color-mix(in lab, currentColor 18%, transparent);
  border-radius: 8px;
  background: var(--bg-card, transparent);
  transition: border-color 120ms, box-shadow 120ms;
}
.deck-groups__blank-name:focus,
.deck-groups__blank-desc:focus {
  outline: none;
  border-color: var(--edit-hair-strong);
  box-shadow: 0 0 0 3px var(--edit-focus);
}
.deck-groups__blank-name {
  font-weight: 600;
}
.deck-groups__blank-desc {
  font-size: x-small;
  line-height: 1.5;
  min-height: 2.75rem;
  resize: none;
  overflow: hidden;
}
.deck-groups__blank-submit {
  align-self: flex-start;
  font: inherit;
  font-size: x-small;
  padding: 0.45rem 1rem;
  border: 1px solid color-mix(in lab, currentColor 35%, transparent);
  border-radius: 999px;
  background: transparent;
  cursor: pointer;
  opacity: 0.85;
  transition: opacity 120ms, background 120ms;
}
.deck-groups__blank-submit:hover {
  opacity: 1;
  background: color-mix(in lab, currentColor 7%, transparent);
}

@media (max-width: 48rem) {
  .deck-editor {
    padding: 1.5rem 1rem 4rem;
    gap: 2rem;
  }
  .deck-group {
    padding: 1rem 1.1rem;
  }
}

/* ── La fiche d'un projet du portfolio, et la largeur de ses images ───────────
   (deck « PORTFOLIO » seulement, cf. admin/decks/_group et _image_card). Même
   matière que la description du groupe. */
.deck-group__fiche {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 1rem;
  max-width: var(--edit-measure);
}
.deck-group__fiche-champ {
  flex: 1 1 10rem;
  min-width: 0;
  font: inherit;
  font-size: x-small;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--edit-hair);
  border-radius: 8px;
  background: transparent;
  transition: border-color 120ms, box-shadow 120ms;
}
.deck-group__fiche-champ--court {
  flex: 0 1 6rem;
}
.deck-group__fiche-champ:hover {
  border-color: color-mix(in lab, currentColor 26%, transparent);
}
.deck-group__fiche-champ:focus {
  outline: none;
  border-color: var(--edit-hair-strong);
  background: var(--bg-card, transparent);
  box-shadow: 0 0 0 3px var(--edit-focus);
}
.deck-images__largeur {
  margin-top: 0.35rem;
}
.deck-images__largeur select {
  width: 100%;
  font: inherit;
  font-size: xx-small;
  padding: 0.3rem 0.4rem;
  border: 1px solid var(--edit-hair);
  border-radius: 6px;
  background: transparent;
}
/* LE DÉPÔT DE FICHIERS sur le mur (art_depot_controller, admin seul) : pendant le
   glisser (`is-depot` sur `.art-featured`), la cible se dessine — « où tu lâches
   décide de ce que ça devient » (`data-depot`) : le MUR (de nouveaux dessins), ou,
   en image seule, L'IMAGE (un calque) et le reste de l'écran (un croquis au
   cahier). Ce qui reste de l'établi, retiré le 2 oct. 2026 (« pas besoin d'avoir
   un bloc établi ») : le tableau de bord, le cadre et leurs styles sont partis
   avec atelier.css (git les garde). `require_tree` compile tout : rien à déclarer. */

/* Le cadre du mur : de nouveaux dessins (hors image seule), ou des croquis (en
   image seule, à côté de l'image). */
.art-featured.is-depot .art-mur::after {
  content: "Déposer : de nouveaux dessins sur ce mur";
  position: absolute;
  inset: 0.4rem;
  z-index: 5;
  display: grid;
  place-content: start center;
  padding-top: 0.7rem;
  border: 1.5px dashed color-mix(in lab, var(--ink) 30%, transparent);
  border-radius: 10px;
  font-size: x-small;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: color-mix(in lab, var(--ink) 55%, transparent);
  pointer-events: none;
  transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
}

.art-featured.is-depot[data-depot="dessin"] .art-mur::after {
  border-color: var(--ink);
  color: var(--ink);
  background: color-mix(in lab, var(--bg-card) 22%, transparent);
}

.art-featured.is-depot[data-depot="croquis"] .art-mur::after,
.art-featured.is-depot[data-depot="calque"] .art-mur::after {
  content: "Déposer à côté de l'image : des croquis au cahier";
  place-content: end center;
  padding-bottom: 0.8rem;
}

.art-featured.is-depot[data-depot="croquis"] .art-mur::after {
  border-color: var(--ink);
  color: var(--ink);
}

/* L'image seule : un calque. Le cadre a la place exacte de l'image (`--img-*`,
   le rectangle d'arrivée écrit par le carrousel sur la figure). */
.art-featured.is-depot .art-featured__figure.is-focus::after {
  content: "Déposer sur l'image : un calque";
  position: absolute;
  top: var(--img-y, 0px);
  left: var(--img-x, 0px);
  width: var(--img-w, 0px);
  height: var(--img-h, 0px);
  box-sizing: border-box;
  z-index: 6;
  display: grid;
  place-content: center;
  border: 1.5px dashed color-mix(in lab, var(--ink) 30%, transparent);
  border-radius: 6px;
  font-size: x-small;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-align: center;
  color: color-mix(in lab, var(--ink) 55%, transparent);
  pointer-events: none;
  transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
}

.art-featured.is-depot[data-depot="calque"] .art-featured__figure.is-focus::after {
  border-color: var(--ink);
  color: var(--ink);
  background: color-mix(in lab, var(--bg-card) 55%, transparent);
}

/* Des fichiers partent : le temps qu'ils arrivent. */
.art-featured.is-envoi {
  cursor: progress;
}
/* L'ÉTALON D'UN ÉCRAN (controllers/etalon ; 8 oct. 2026 : « j'ai différents écrans et
   la taille n'est pas la bonne », puis « par rapport à une pièce de 1 € ») : un panneau
   par-dessus tout, sur un voile ; la pièce à poser contre l'écran, un cercle de 23,25 mm
   — sa couronne dorée, son cœur argenté, comme la pièce, et un filet net à son bord :
   c'est sur lui qu'on règle — que le curseur agrandit ou rétrécit, posé sur un fond uni.
   (Une carte bancaire a précédé, une heure.) */
.etalon {
  position: fixed;
  inset: 0;
  z-index: 100000;
  display: grid;
  place-items: center;
  padding: 1rem;
  background: rgb(20 24 34 / 0.45);
  backdrop-filter: blur(2px);
}

.etalon__panneau {
  display: grid;
  gap: 0.9rem;
  justify-items: center;
  max-width: min(36rem, 100%);
  padding: 1.4rem 1.6rem;
  border-radius: 0.8rem;
  background: var(--bg-card);
  box-shadow: 0 0.6rem 2.4rem rgba(18, 24, 44, 0.3);
  color: var(--ink);
  text-align: center;
}

.etalon__titre {
  margin: 0;
  font-size: large;
  font-weight: 700;
}

.etalon__texte,
.etalon__ecran {
  max-width: 34em;
  margin: 0;
  font-size: small;
  line-height: 1.45;
}

.etalon__ecran {
  font-size: x-small;
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
}

/* La table : un fond uni, assez grand pour la carte à toutes les densités. */
.etalon__table {
  display: grid;
  place-items: center;
  width: 100%;
  min-height: 12rem;
  padding: 0.8rem;
  gap: 0.5rem;
  border-radius: 0.5rem;
  background: color-mix(in lab, var(--ink) 6%, var(--bg-card));
  overflow: hidden;
}

.etalon__piece {
  position: relative;
  flex: none;
  box-sizing: border-box;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #f3dc8e, #c9a24a 70%, #b08a36);
  box-shadow: 0 0 0 1px var(--ink);
}

/* Le cœur argenté : 16,25 mm sur 23,25 (la pièce bimétallique — le doré dehors). */
.etalon__coeur {
  width: 69.9%;
  height: 69.9%;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #eceef0, #aeb2b8 70%, #92969c);
}

.etalon__mesure {
  font-size: x-small;
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
}

/* LA RÈGLE DE 5 CM (« ajoute une règle qui devrait faire 5 cm aussi ») : une bande
   claire, un trait par mm depuis son bord haut — plus long tous les 5 mm et tous les
   cm, les cm chiffrés —, sa longueur posée par le réglage (comme la pièce). */
.etalon__regle {
  position: relative;
  flex: none;
  height: 1.6rem;
  margin-top: 0.6rem;
  background: var(--bg-card);
  box-shadow: 0 0 0 1px color-mix(in lab, var(--ink) 25%, transparent);
}

.etalon__trait {
  position: absolute;
  top: 0;
  width: 1px;
  height: 0.35rem;
  translate: -50% 0;
  background: var(--ink);
}

.etalon__trait--demi {
  height: 0.55rem;
}

.etalon__trait--cm {
  height: 0.8rem;
}

.etalon__chiffre {
  position: absolute;
  bottom: 0.1rem;
  translate: -50% 0;
  font-size: xx-small;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.etalon__reglage {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
}

.etalon__curseur {
  flex: 1;
  accent-color: var(--ink);
}

.etalon__pas,
.etalon__bouton {
  padding: 0.4em 0.9em;
  border: 0;
  border-radius: 999px;
  background: color-mix(in lab, var(--ink) 8%, var(--bg-card));
  font: inherit;
  font-size: small;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}

.etalon__pas {
  width: 2.2rem;
  padding: 0.3em 0;
  font-size: medium;
}

.etalon__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
}

.etalon__enregistrer {
  background: var(--ink);
  color: var(--bg-card);
}

.etalon__pas:focus-visible,
.etalon__bouton:focus-visible,
.etalon__curseur:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}
form {
  max-width: 48ch;
  margin: 0 auto;

  .field:has(input[type="email"]:placeholder-shown) label,
  .field:has(input[type="password"]:placeholder-shown) label,
  .field:has(input[type="text"]:placeholder-shown) label,
  .field:has(textarea:placeholder-shown) label {
    opacity: 0; top: 1em;
    transition: opacity 150ms, top 150ms;
  }
  .field input::placeholder {
    font-size: xx-small;
  }
  .field:has(textarea) {
    height: 100%;
  }

  .field:has(input[type="email"]) label,
  .field:has(input[type="password"]) label,
  .field:has(input[type="text"]) label,
  .field:has(textarea) label
  {
    background: var(--bg-card);
    padding: .25em 0.5em 0em 0.5em;
    border-radius: 4px 4px 0px 0px;

    font-size: x-small;

    border: 1px solid var(--input-border);
    border-bottom: 0px;
    position: relative;
    z-index: 0;
    left: calc(10px - 0.5em);
    opacity: 1; top: 0em;
    transition: opacity 250ms, top 250ms, font-size 250ms;

  }

  input {
    border-radius: 5px;
    border: 1px solid var(--input-border);
    padding: 10px;
    width: 100%;
    position: relative;
    z-index: 1;
    box-sizing: border-box;
    transition: border-color 0.3s ease;

    &:focus {
      border-color: var(--blue);
      outline: none;
    }
  }

  input[type="submit"] {
    background-color: var(--blue);
    border: none;
    padding: 10px 20px;
    color: var(--white);
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s ease;
    &:hover {
      background-color: color-mix(in lab, var(--blue) 65%, var(--black));
    }
  }
  textarea {
    border-radius: 5px;
    border: 1px solid var(--input-border);
    padding: 10px;
    width: 100%;
    height: 100%;
    min-height: 48rem;
    box-sizing: border-box;
    transition: border-color 0.3s ease;
    font-family: inherit;
    &:focus {
      border-color: var(--blue);
      outline: none;
    }
  }
}
/* La loupe — pour tout le site, plus seulement la zone Art. Le verre et sa
   tache sont montés sur le <body> par `loupe_controller`, qui peut les poser
   sur n'importe quelle image, ou sur la page elle-même ; la touche L l'appelle
   partout. Ces règles ont
   donc quitté `bento/art.scss.css` en même temps que le contrôleur.
   (`require_tree` compile tout dans une seule feuille : rien à déclarer.) */

/* L'image qu'une vue a confiée à la loupe (le mode « image seule » de la
   zone Art) : à la taille d'un curseur, c'est le verre qu'on suit des yeux —
   et on voit le dessin au travers. Une flèche posée dessus le couvrirait
   presque entier.
   La GRANDE goutte, elle, garde le pointeur du système (demande de l'auteur :
   « voir le curseur à l'intérieur de la bulle ») : il se dessine par-dessus
   le verre, sa pointe au centre — le point regardé —, avec la forme que lui
   donne ce qu'il survole (main sur un lien, barre sur un texte, croix sur
   Turing). Une première version l'effaçait partout. */
img.is-loupe:not(.is-loupe-full) {
  cursor: none;
}

/* La monture, ajoutée au <body> par le contrôleur : elle suit le pointeur en
   `fixed`, donc elle peut déborder du carrousel sans être rognée par son
   overflow. Sa taille est posée EN LIGNE par le contrôleur (constante LENS) :
   en WebGL, le carré laisse autour du disque la place de la goutte étirée
   (cf. `loupe_drop`) ; le disque plat, lui, garde le diamètre du verre. Le
   verre est le canvas posé dedans (cf. `loupe_gl`) ; le fond CSS n'est que le
   repli plat, servi aux machines qui ne savent pas le rendre. */
.art-loupe {
  position: fixed;
  z-index: 40;
  margin: 0;
  /* `--loupe-scale` : la loupe vit à deux tailles, celle d'un curseur et la
     sienne, et passe de l'une à l'autre au clic. La course est menée en JS
     (loupe_controller#_tick) et non par une transition CSS : l'échelle doit
     être repeinte à chaque image, parce que le shader la reçoit lui aussi —
     sans quoi le dessin enflerait avec le verre au lieu de garder son
     grossissement. */
  transform: translate(-50%, -50%) scale(var(--loupe-scale, 1));
  /* Pas de fond, pas de découpe ronde : le verre est une goutte qui déborde du
     disque quand elle s'étire, et son bord est déjà adouci par le shader — un
     fond se verrait au travers et cernerait la loupe. */
  pointer-events: none;
}

.art-loupe__glass {
  display: block;
  width: 100%;
  height: 100%;
  /* L'ombre portée décolle la loupe de l'oeuvre, comme un verre tenu
     au-dessus. Portée par le canvas, et non par le rond : elle épouse la forme
     de la goutte au lieu de rester un cercle. */
  filter: drop-shadow(0 6px 14px color-mix(in lab, var(--ink) 5%, transparent));
}

/* Le repli plat : un disque, l'image en fond. Le contrôleur pose en ligne le
   fond et la couleur du support mesurée sous l'oeuvre. */
.art-loupe[data-backend="css"] {
  border-radius: 50%;
  overflow: hidden;
  background-repeat: no-repeat;
  box-shadow: 0 6px 28px color-mix(in lab, var(--ink) 5%, transparent);
}

.art-loupe[hidden] {
  display: none;
}

/* La lumière projetée sur la feuille : l'ombre du verre, et le foyer clair
   qu'il concentre en son milieu. Posée sur l'oeuvre, sous la loupe, et décalée
   dans l'axe de la lumière — le reflet du verre venant d'en haut à gauche, la
   tache tombe en bas à droite et déborde du disque, sans quoi la loupe la
   couvrirait entièrement.

   `hard-light` fait le reste, et c'est le seul qui le fasse : sous 50 % il
   multiplie (la couronne assombrit le papier), au-dessus il écrante (le foyer
   lave les traits sombres du dessin). `soft-light` et `overlay`, eux, sont
   neutres sur le blanc pur — sur une feuille blanche ils ne peignent rien. */
.art-loupe-cast {
  position: fixed;
  z-index: 39;
  margin: 0;
  display: block;
  pointer-events: none;
  mix-blend-mode: hard-light;
  /* Le contrôleur pose sa transform en entier, échelle comprise, parce qu'elle
     porte aussi le décalage de la tache. */
  /* C'est un canvas, peint par `loupe_gl` (paintCast) avec la fonction même que
     le shader applique dans le verre — d'où l'absence de forme ici : ni rayon,
     ni dégradé. Un dégradé CSS n'aurait su faire qu'un rond ou une ellipse
     droite, jamais la goutte d'une caustique. Rien à régler dans ce fichier. */
}

.art-loupe-cast[hidden] {
  display: none;
}

/* L'indicateur du réglage (Ctrl + Option + glisser, cf. loupe_controller) :
   taille, épaisseur et grossissement qui en découle, posés sous la goutte le
   temps du geste — comme le HUD du pinceau de Photoshop. Ajouté au <body> par
   le contrôleur, qui le place (left/top : le bas de la goutte). */
.art-loupe-hud {
  position: fixed;
  z-index: 41;
  margin: 0.8em 0 0;
  padding: 0.3em 0.8em;
  transform: translateX(-50%);
  border-radius: 999px;
  background: color-mix(in lab, var(--bg-card) 88%, transparent);
  box-shadow: 0 2px 10px var(--ink-faint);
  color: var(--ink);
  font-size: x-small;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  pointer-events: none;
}

.art-loupe-hud[hidden] {
  display: none;
}
/* LA BARRE — la pastille « Menu » en haut à droite de toutes les pages, et les
   PORTES qu'elle ouvre (cf. layouts/_menu.html.erb, menu_controller.js). C'est la
   navigation visible du site, par public ; le plan du clic droit (site_menu.css)
   est l'autre. Même matière que lui et que le tableau de bord des pierres : une
   carte translucide, floutée, aux couleurs de la charte. */

:root {
  /* La hauteur que la pastille prend en haut de l'écran. Les pages qui DÉFILENT
     (Profil, CV, les pages simples, les galeries) commencent dessous ; les zones
     plein écran (les dessins, Turing, les pierres) restent entières et la
     pastille flotte dessus — seuls les volets en carte de l'atelier et ce
     que Turing pose en haut à droite se décalent d'autant
     (voir le bas de ce fichier et bento/turing.scss.css). */
  --menu-h: 3rem;
}

.menu {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  /* Au-dessus de la loupe (40) et des pièces, sous le plan du clic droit (200). */
  z-index: 100;
  /* La barre ne prend rien : seuls la pastille, le voile et les portes reçoivent
     le pointeur (même remède que .nav, application.css). */
  pointer-events: none;
}

/* ── La pastille ─────────────────────────────────────────────────────────── */
.menu__bouton {
  pointer-events: auto;
  position: absolute;
  z-index: 2;
  top: 0.5rem;
  right: max(0.5rem, var(--page-gutter));
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  padding: 0.45em 0.9em 0.45em 1em;
  border: 0;
  border-radius: 999px;
  background: color-mix(in lab, var(--bg-card) 86%, transparent);
  backdrop-filter: blur(1.5mm);
  box-shadow: 0 0.2em 1.2em rgba(18, 24, 44, 0.14);
  font: inherit;
  font-size: small;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
  transition: background-color 150ms;
}

.menu__bouton:hover,
.menu__bouton:focus-visible {
  background: var(--bg-card);
  outline: none;
}

.menu__bouton:focus-visible {
  box-shadow: 0 0 0 2px var(--blue), 0 0.2em 1.2em rgba(18, 24, 44, 0.14);
}

/* Où l'on est : la porte courante, en retrait avant le mot. */
.menu__ici {
  font-weight: 400;
  color: var(--ink-muted);
}

.menu__ici::after {
  content: "·";
  margin-left: 0.6em;
}

.menu__fermer,
.menu.is-ouvert .menu__ouvrir {
  display: none;
}

.menu.is-ouvert .menu__fermer {
  display: inline;
}

.menu__icone {
  width: 1em;
  height: 1em;
  overflow: visible;
}

.menu__trait {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  stroke-linecap: round;
  transform-box: view-box;
  transform-origin: center;
  transition: transform 180ms ease, opacity 180ms ease;
}

.menu.is-ouvert .menu__trait--haut {
  transform: translateY(2.75px) rotate(45deg);
}

.menu.is-ouvert .menu__trait--milieu {
  opacity: 0;
}

.menu.is-ouvert .menu__trait--bas {
  transform: translateY(-2.75px) rotate(-45deg);
}

/* ── Le voile ────────────────────────────────────────────────────────────── */
.menu__voile {
  pointer-events: auto;
  position: fixed;
  inset: 0;
  z-index: 0;
  background: color-mix(in lab, var(--bg) 35%, transparent);
}

.menu__voile[hidden] {
  display: none;
}

/* ── Les portes ──────────────────────────────────────────────────────────── */
.menu__portes {
  pointer-events: auto;
  position: absolute;
  z-index: 1;
  top: calc(var(--menu-h) + 0.25rem);
  right: max(0.5rem, var(--page-gutter));
  left: max(0.5rem, var(--page-gutter));
  max-height: calc(100dvh - var(--menu-h) - 1rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1rem 1.25rem 0.9rem;
  border-radius: var(--radius);
  background: color-mix(in lab, var(--bg-card) 92%, transparent);
  backdrop-filter: blur(1.5mm);
  box-shadow: var(--shadow);
  color: var(--ink);
  opacity: 1;
  transform: none;
  transition: opacity 180ms ease, transform 180ms ease;
}

/* Même fondu que le contenu de zone (application.css) : repasser de `hidden` à
   visible remet les portes au rang des fraîchement rendues. */
@starting-style {
  .menu__portes {
    opacity: 0;
    transform: translateY(-6px);
  }
}

.menu__portes[hidden] {
  display: none;
}

.menu__portes:focus {
  outline: none;
}

/* Sur grand écran, les portes n'ont pas besoin de toute la largeur : la planche
   se range sous la pastille, contre le bord droit. */
@media (min-width: 64rem) {
  .menu__portes {
    left: auto;
    width: min(64rem, calc(100vw - 2 * max(0.5rem, var(--page-gutter))));
  }
}

.menu__nom {
  margin: 0;
  font-size: x-small;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.menu__question {
  margin: 0.15rem 0 0.9rem;
  font-size: large;
  font-weight: 600;
  line-height: 1.1;
}

.menu__liste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 0.75rem 1rem;
}

/* Une porte : qui elle accueille, son nom, ses pages. Le liseré du haut est
   celui du tableau de bord des pierres ; il prend le bleu là où l'on est. */
.menu__porte {
  min-width: 0;
  padding: 0.65rem 0.85rem 0.75rem;
  border-top: 2px solid var(--ink-10);
  border-radius: 0 0 calc(var(--radius) / 2) calc(var(--radius) / 2);
}

.menu__porte.is-ici {
  border-top-color: var(--blue);
  background: color-mix(in lab, var(--blue) 5%, transparent);
}

.menu__public {
  margin: 0 0 0.2rem;
  font-size: x-small;
  color: var(--ink-muted);
}

.menu__secteur {
  display: inline-block;
  margin-bottom: 0.45rem;
  font-size: large;
  font-weight: 700;
  color: inherit;
  text-decoration: none;
}

.menu__secteur:hover,
.menu__secteur:focus-visible {
  color: var(--blue);
  outline: none;
}

.menu__pages {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.1rem 0.9rem;
}

.menu__page {
  display: inline-block;
  padding: 0.15em 0;
  border-bottom: 1px solid transparent;
  font-size: small;
  color: var(--ink);
  text-decoration: none;
}

.menu__page:hover,
.menu__page:focus-visible {
  border-bottom-color: currentColor;
  outline: none;
}

/* Le bleu ne dit qu'une chose, comme dans le plan : c'est ICI que l'on est. */
.menu__page[aria-current] {
  color: var(--blue);
  font-weight: 600;
}

.menu__pied {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 1rem 0 0;
  font-size: x-small;
  color: var(--ink-muted);
}

.menu__pied a {
  color: inherit;
  text-decoration: none;
}

.menu__pied a:hover,
.menu__pied a:focus-visible {
  color: var(--ink);
  text-decoration: underline;
  outline: none;
}

@media (prefers-reduced-motion: reduce) {
  .menu__portes,
  .menu__trait {
    transition: none;
  }
}

@media (max-width: 40rem) {
  /* Sur un téléphone la pastille reste courte : le mot seul. */
  .menu__ici {
    display: none;
  }
}

/* ── Ce que la pastille demande aux pages ────────────────────────────────────
   Les pages qui défilent commencent sous elle ; dans l'atelier, les
   volets en carte (Chladni, les astres, le split-flap) aussi — Turing et les
   pierres, plein écran, gardent tout et la pastille flotte dessus. La galerie des
   dessins n'y touche pas : son mur va jusqu'au bord de l'écran, et rien n'y
   vit en haut à droite. */
.moi-layout,
.cv-layout,
.lab-layout__section:not(.lab-layout__section--full) {
  padding-top: var(--menu-h);
}
/* LES PAGES SIMPLES — Portfolio, Contact, Boutique, mentions légales,
   confidentialité (cf. docs/ARBORESCENCE.md) : une colonne de bentos, de la
   largeur d'un article (--width, charte.css), qui défile. Comme les écrans à
   colonnes (Profil, CV), elle commence sous la pastille du menu (--menu-h,
   menu.css). Le conteneur est un <main>, pas un <div> : `div:has(.bento)`
   (application.css) le mettrait en `flex-wrap: wrap`. */
.page-layout {
  display: flex;
  flex-direction: column;
  gap: 1ex;
  max-width: var(--width);
  margin: 0 auto;
  padding-top: var(--menu-h);
  padding-bottom: var(--bottom-clearance);
}

.page-bento {
  width: 100%;
  gap: 0.6em;
  padding: 1.5em;
}

.page-bento__titre {
  margin: 0;
  font-size: x-large;
  font-weight: bold;
  line-height: 1.1;
  color: var(--ink);
}

.page-bento__soustitre {
  margin: 0.6em 0 0;
  font-size: medium;
  font-weight: bold;
  color: var(--ink);
}

.page-bento .bento-copy {
  margin: 0;
  max-width: 60ch;
}

/* Les pages LARGES (le portfolio, un projet) : la largeur des écrans à colonnes
   (Profil, CV), pour que les images aient de la place. */
.page-layout--large {
  max-width: calc(var(--timeline-width) + var(--rail-width) + 1ex);
}
.header {
  display: flex;
  align-items: center;
  gap: 1ex;
  padding-top: 0.25lh;
  padding-bottom: 0.5lh;
}

.header .infos {
  max-width: 18rem;
}

.title {
  align-self: center;
  flex-grow: 1;
  font-size: large;
  font-weight: bold;
  color: var(--ink);
}

.title i {
  margin-right: 1.25ch;
  margin-left: 0.75ch;
}

.job {
  position: relative;
  transition: opacity 0.2s, filter 0.2s;
}

/* Curseur de la timeline hors de la période de cette carte : on la grise. */
.job.is-out-of-period {
  opacity: 0.35;
  filter: grayscale(1);
}

.edit-inline {
  position: absolute;
  right: 1em;
}


form.job--edit {
  max-width: unset;
  margin: 0;
}

.job--edit input,
.job--edit textarea,
.job--edit select {
  background: transparent;
  border: none;
  border-bottom: 1px solid var(--gray);
  border-radius: 0;
  padding: 0.1em 0.25em;
  width: 100%;
  box-sizing: border-box;
  font-family: inherit;
  font-size: inherit;
  color: inherit;
  outline: none;
}

.job--edit input:focus,
.job--edit textarea:focus,
.job--edit select:focus {
  border-bottom-color: var(--ink);
}

.job--edit .title {
  display: flex;
  flex-direction: column;
  gap: 0.25em;
}

.job--edit .title input.society {
  font-weight: bold;
  font-size: large;
}

.job--edit .title input.role {
  font-weight: bold;
  font-size: medium;
}

.job--edit .infos {
  flex-direction: column;
  align-items: stretch;
  gap: 0.25em;
}

.job--edit .infos input,
.job--edit .infos select {
  font-size: xx-small;
  font-weight: bold;
  text-align: right;
}

.job--edit .description {
  margin-left: 0;
}

.job--edit .description textarea {
  resize: vertical;
  font-size: small;
  color: var(--gray);
  min-height: unset;
  height: auto;
}

.job__image-field {
  align-self: center;
}

.job__image-field input {
  font-size: xx-small;
  text-align: center;
}

.job__controls {
  grid-column: span 3;
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.job__controls input[type="submit"] {
  background: var(--black);
  color: var(--white);
  border: none;
  padding: 0.25em 1em;
  border-radius: 3px;
  cursor: pointer;
  font-size: small;
  width: auto;
}

.job__cancel {
  font-size: small;
  opacity: 0.5;
  text-decoration: none;
  cursor: pointer;
}

.job__errors {
  grid-column: span 3;
  color: red;
  font-size: small;
}

.job {
  display: grid;
  grid-template: auto auto / 3rem auto auto;
  gap: 0.5lh;
  padding-bottom: 0.75lh;
  margin-top: 0.25lh;
}

.job .infos {
  flex-direction: column;
  align-items: flex-end;
}

.job .society,
.job .role {
  font-weight: bold;
  font-size: medium;
}

.job .society {
  font-size: large;
}

.job img {
  height: 3em;
  aspect-ratio: 1;
  object-fit: contain;
  margin-right: 1ch;
  justify-self: center;
  align-self: center;
}

.job .description {
  color: var(--gray);
  padding-top: 0.25lh;
  grid-column: span 3;
  margin-left: 3.5rem;
}

.infos {
  display: flex;
  flex-wrap: wrap;
  justify-content: end;
}

.infos:has(.info--text) {
  margin-top: 0.25lh;
}

.info--label,
.info--text {
  font-weight: bold;
  font-size: xx-small;
  padding: 0.125lh 0.5lh;
  margin: 0.25px;
}

.info--label {
  border-radius: 2px;
}

.info--text.blue {
  color: var(--blue);
}

.info--text.orange {
  color: var(--purple);
}

.info--text.black {
  color: var(--ink);
}

.info--text.red {
  color: var(--red);
}

.info--label.blue {
  background: var(--green);
  color: var(--blue);
}

.info--label.orange {
  background: var(--yellow);
  color: var(--purple);
}

.info--label.black {
  background: var(--black);
  color: var(--white);
}

.info--label.red {
  background: var(--red);
  color: var(--white);
}
/* LE PASSAGE (controllers/passage.js) : d'une page à l'autre, un dessin — de
   l'accueil à son show sur le mur, et retour. Un voile de la couleur du fond sur
   tout l'écran, et la copie du dessin par-dessus, à sa place exacte. Accrochés à
   <html>, hors du <body> : ils survivent au changement de page. Au-dessus de
   tout (le menu est à 100, le plan du site à 200). */
.passage-voile {
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: var(--bg);
  pointer-events: none;
}

.passage-copie {
  position: fixed;
  z-index: 1001;
  isolation: isolate; /* ses calques ne se multiplient que sur lui */
  pointer-events: none;
}

.passage-copie img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: fill;
  display: block;
}

/* Ses calques : comme ceux des dessins de l'accueil (accueil.css, « Les calques »). */
/* LA PIERRE QUI ROULE — la pièce du volet « pierres » de l'atelier
   (cf. `pages/bento/_pierres`, `pierre_controller`).

   Elle a été, un temps, un CURSEUR pour tout le site : un canevas `fixed` ajouté
   au <body>, ouvert et refermé par la touche R n'importe où. Elle a maintenant
   SA PLANCHE, et n'existe plus ailleurs — d'où ce qui a disparu d'ici : le
   `fixed`, le fondu de sortie (`.is-leaving`) et les classes posées sur <html>.
   Tout est désormais local à la planche.

   Formes, tons et lumière sont dans le contrôleur, la marche dans `pierre_roche`.
   (`require_tree` compile tout dans une seule feuille : rien à déclarer.) */

/* LA PLANCHE : le terrain de jeu. Même dessin que les autres pièces génératives
   (cf. `.turing-bento`, `.chladni-bento`) — c'est elle qui porte le fond de carte
   et qui reçoit les événements, le canevas n'en prenant aucun.
   Le volet la met en plein écran (`.lab-layout__section--full>.bento` dans
   profile.scss.css : 100 % de large et de haut, `aspect-ratio: auto`, pas
   d'arrondi) ; ce carré-ci n'est donc qu'un repli si on la sortait un jour de son
   volet plein écran. */
.pierre-planche {
  position: relative;
  aspect-ratio: 1 / 1;
  padding: 0;
  overflow: hidden;
  /* Au doigt, promener la troupe ne doit pas faire défiler la page : la planche
     prend le geste. (Le panneau des réglages le rend, plus bas : un curseur de
     taille a besoin du sien.) */
  touch-action: none;
  /* La planche est sa propre PILE : dedans, le panneau passe au-dessus du
     canevas, et c'est tout ce qu'il y a à ordonner. Dehors, elle reste un bloc
     sans rang (`z-index: auto`), donc sous la goutte de la loupe (40) et sa
     tache (39), qui sont posées sur le <body> — l'ordre voulu, et sans que les
     deux pièces aient à s'accorder sur des chiffres. */
  isolation: isolate;
}

/* LE CANEVAS : les pierres, leurs ombres et leur poussière y sont peintes. Tendu
   sur la planche, et non plus sur la fenêtre. */
.pierre {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  /* Sous la goutte (40) et sa tache (39) : le verre passe au-dessus des pierres
     — la loupe, elle, est restée un curseur de tout le site. Rien entre la
     planche et le <body> ne fait de pile à part, les deux ordres se comparent
     donc bien. (`loupe_page.js` écarte `.pierre` de son instantané : pris dans
     l'image, les pierres y resteraient figées sous le verre.) */
  z-index: 38;
  /* Il couvre la planche : il ne doit prendre aucun clic, aucun survol, ni
     compter pour le plan du site (`elementsFromPoint`). C'est la PLANCHE qui
     écoute (cf. `_onPress` dans pierre_controller). */
  pointer-events: none;
}

/* (Il y avait ici `.is-appui`, posée le temps qu'un clic enfoncé PROMÈNE la
   troupe : le clic normal ne mène plus rien — seul le clic DROIT pose un objectif
   — et la classe n'a plus d'objet.) */

/* Le glisser-déposer de la meneuse (cf. `_onPress` / `_onRelease`). Le canevas
   ne prend aucun événement, il ne peut donc pas porter de curseur : ce sont ces
   classes, posées sur la planche par le contrôleur, qui ouvrent la main au-dessus
   de la meneuse et la referment quand on la porte. */
.pierre-planche.is-survol {
  cursor: grab;
}

.pierre-planche.is-portee {
  cursor: grabbing;
  user-select: none;
  -webkit-user-select: none;
}

/* ── LE TABLEAU DE BORD ──────────────────────────────────────────────────────
   L'interface d'un JEU (l'auteur : « une UX/UI digne d'un jeu vidéo ») — la
   barre de commandement d'un jeu de stratégie, bâtie par `_batirPanneau` :
   en bas, LA TROUPE en PORTRAITS et LA FICHE de la pierre choisie ; sur le
   flanc droit, L'ÉPURE ; en haut, LES COMMANDES. Tout ce qui se règle se
   voit : la fiche et l'épure prennent la TEINTE de la pierre choisie
   (`--ton` / `--ton-sombre`, posées par `_rafraichirPanneau`) — le liseré,
   les puces prises, les curseurs remplis —, chaque portrait dit sa roche, sa
   démarche (le GLYPHE : l'empreinte de ses pieds) et son état.
   Sobre, comme le reste du site : la matière des autres pièces (la carte, un
   peu transparente, ce qui passe dessous flouté), la charte pour les
   couleurs, aucun néon. Les mouvements sont courts et s'effacent en
   `prefers-reduced-motion`.

   Le tableau porte `data-loupe-barriere` : c'est un MUR pour la troupe comme
   pour la goutte (cf. `_murs` dans pierre_controller). */
.pierre-hud {
  /* Ce que la pierre choisie donne au tableau, et deux tons de la charte. */
  --ton: var(--light-grey);
  --ton-sombre: var(--ink);
  --hud-bord: color-mix(in lab, var(--ink) 14%, transparent);
  --hud-muet: color-mix(in lab, var(--ink) 62%, transparent);
  position: absolute;
  z-index: 39; /* au-dessus du canevas (38), dans la pile de la planche */
  bottom: 1em;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  gap: 0.6em;
  width: max-content;
  max-width: calc(100% - 2em);
  max-height: calc(100% - 4.5em);
  overflow: auto;
  padding: 0.7em 0.9em 0.8em;
  border-radius: var(--radius);
  background: color-mix(in lab, var(--bg-card) 88%, transparent);
  backdrop-filter: blur(6px);
  box-shadow: 0 0.2em 1.2em rgba(18, 24, 44, 0.14);
  /* Le LISERÉ : une ligne de la teinte de la pierre choisie, en haut du tableau
     — c'est le bandeau de couleur d'une faction. Il change avec la pierre. */
  border-top: 3px solid var(--ton-sombre);
  transition: border-color 0.2s ease;
  /* La planche prend tous les gestes du doigt (`touch-action: none`) pour
     promener la troupe : le tableau les REND, sans quoi un curseur ne
     glisserait pas. */
  touch-action: auto;
  color: var(--ink);
}

/* CACHÉ tant que la troupe n'existe pas (volet pas encore à l'écran, cf.
   `_rafraichirPanneau`). Le `display: flex` ci-dessus est une règle d'AUTEUR :
   il gagne sur le `display: none` que la feuille du navigateur donne à
   `[hidden]`, et le tableau resterait là, vide. Même piège que
   `.lab-layout__section[hidden]` (profile.scss.css). */
.pierre-hud[hidden],
.pierre-epure[hidden],
.pierre-aide[hidden] {
  display: none;
}

/* ── La troupe : les portraits ──────────────────────────────────────────── */
.pierre-hud__rang {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5em 1.2em;
}

.pierre-hud__troupe {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55em;
  padding: 0.25em 0.1em;
}

/* UN PORTRAIT : le JETON (la teinte de la pierre, le glyphe de sa démarche),
   son RANG en écusson (M, 1, 2… — la touche d'une unité), et son ÉTAT en
   anneau autour (`data-etat`, posé par `_rafraichirEtat`). Un bouton nu : tout
   le dessin est dans ses deux enfants. */
.pierre-portrait {
  position: relative;
  flex: none;
  width: 2.5em;
  height: 2.5em;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ton-sombre, var(--ink));
  font-size: small;
  cursor: pointer;
}

/* La MENEUSE est plus grosse sur la planche : son portrait aussi. */
.pierre-portrait--meneuse {
  width: 3.1em;
  height: 3.1em;
}

.pierre-portrait__jeton {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid var(--ton-sombre, var(--ink));
  /* La roche, éclairée d'en haut à gauche comme sur la planche. */
  background: radial-gradient(circle at 35% 30%, color-mix(in lab, var(--ton, var(--light-grey)) 80%, white), var(--ton, var(--light-grey)) 75%);
  box-shadow: 0 1px 2px rgba(18, 24, 44, 0.18);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.pierre-portrait__jeton svg {
  width: 64%;
  height: 64%;
}

.pierre-portrait__rang {
  position: absolute;
  right: -0.3em;
  bottom: -0.3em;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 1.35em;
  height: 1.35em;
  padding: 0 0.3em;
  border-radius: 999px;
  background: var(--bg-card);
  box-shadow: 0 0 0 1px var(--hud-bord);
  color: var(--ink);
  font-size: xx-small;
  font-weight: 600;
  line-height: 1;
}

/* L'ANNEAU D'ÉTAT : rien de posé ; en marche, un pointillé qui TOURNE (le
   trait d'une unité en mouvement) ; en main, le jeton se soulève. */
.pierre-portrait::before {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  border: 1.5px dashed transparent;
  pointer-events: none;
}

.pierre-portrait[data-etat="marche"]::before,
.pierre-portrait[data-etat="route"]::before {
  border-color: var(--ton-sombre, var(--ink));
  animation: pierre-tourne 7s linear infinite;
}

.pierre-portrait[data-etat="route"]::before {
  animation-duration: 14s;
  opacity: 0.5;
}

.pierre-portrait[data-etat="portee"] .pierre-portrait__jeton {
  transform: translateY(-3px) scale(1.06);
  box-shadow: 0 5px 9px rgba(18, 24, 44, 0.28);
}

.pierre-portrait[data-etat="bloquee"]::before {
  border-style: solid;
  border-color: var(--red);
  opacity: 0.6;
}

.pierre-portrait:hover .pierre-portrait__jeton,
.pierre-portrait:focus-visible .pierre-portrait__jeton {
  transform: translateY(-2px);
  box-shadow: 0 3px 6px rgba(18, 24, 44, 0.22);
}

.pierre-portrait:focus-visible {
  outline: none;
}

/* CHOISI : cerné de sa propre teinte, un peu levé. */
.pierre-portrait.is-choisie .pierre-portrait__jeton {
  transform: translateY(-2px);
  box-shadow: 0 0 0 2px var(--bg-card), 0 0 0 3.5px var(--ton-sombre, var(--ink)), 0 3px 6px rgba(18, 24, 44, 0.22);
}

/* Une pierre qui vient d'être ajoutée SURGIT. */
.pierre-portrait.is-neuve .pierre-portrait__jeton {
  animation: pierre-surgit 0.3s cubic-bezier(0.2, 0.9, 0.3, 1.25);
}

/* Le « + » : pas une pierre, donc pas de teinte — juste un contour. */
.pierre-portrait--ajout {
  color: var(--hud-muet);
  font-size: medium;
}

.pierre-portrait--ajout .pierre-portrait__jeton {
  border: 1px dashed color-mix(in lab, var(--ink) 40%, transparent);
  background: transparent;
  box-shadow: none;
  line-height: 1;
}

.pierre-portrait--ajout:hover .pierre-portrait__jeton {
  border-style: solid;
  color: var(--ink);
}

@keyframes pierre-tourne {
  to {
    transform: rotate(360deg);
  }
}

@keyframes pierre-surgit {
  from {
    transform: scale(0.4);
    opacity: 0;
  }
}

/* ── La fiche de la pierre choisie ──────────────────────────────────────── */
.pierre-fiche {
  display: flex;
  flex-direction: column;
  gap: 0.6em;
  padding-top: 0.55em;
  border-top: 1px solid var(--hud-bord);
}

/* LA TÊTE : le grand jeton, le nom et ce qu'elle est, l'état à droite. */
.pierre-fiche__tete {
  display: flex;
  align-items: center;
  gap: 0.7em;
}

.pierre-fiche__jeton {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.8em;
  height: 2.8em;
  border-radius: 50%;
  border: 1px solid var(--ton-sombre);
  background: radial-gradient(circle at 35% 30%, color-mix(in lab, var(--ton) 80%, white), var(--ton) 75%);
  box-shadow: 0 1px 2px rgba(18, 24, 44, 0.18);
  color: var(--ton-sombre);
  font-size: small;
}

.pierre-fiche__jeton svg {
  width: 64%;
  height: 64%;
}

.pierre-fiche__noms {
  min-width: 0;
}

.pierre-fiche__nom {
  margin: 0;
  font-size: medium;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: normal;
}

.pierre-fiche__sous {
  margin: 0.1em 0 0;
  font-size: x-small;
  color: var(--hud-muet);
}

/* L'ÉTAT : une pastille, un point qui dit l'état d'un coup d'oeil — posée
   (gris), en route (sa teinte), en marche (vert, qui bat), rendue (sa teinte,
   plein), bloquée (rouge), en main (bleu). */
.pierre-etat {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  padding: 0.3em 0.7em;
  border-radius: 999px;
  border: 1px solid var(--hud-bord);
  font-size: xx-small;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  white-space: nowrap;
  color: var(--hud-muet);
}

.pierre-etat i {
  width: 0.6em;
  height: 0.6em;
  border-radius: 50%;
  background: var(--hud-muet);
}

.pierre-etat[data-etat="route"] i {
  background: var(--ton-sombre);
  opacity: 0.6;
}

.pierre-etat[data-etat="marche"] {
  color: var(--ink);
  border-color: color-mix(in lab, var(--green) 45%, var(--hud-bord));
}

.pierre-etat[data-etat="marche"] i {
  background: var(--green);
  animation: pierre-bat 1.2s ease-in-out infinite;
}

.pierre-etat[data-etat="rendue"] {
  color: var(--ink);
}

.pierre-etat[data-etat="rendue"] i {
  background: var(--ton-sombre);
}

.pierre-etat[data-etat="bloquee"] i {
  background: var(--red);
}

.pierre-etat[data-etat="portee"] i {
  background: var(--blue);
}

@keyframes pierre-bat {
  50% {
    transform: scale(0.6);
    opacity: 0.5;
  }
}

/* LE CORPS de la fiche : des BLOCS (forme, teinte, mesures, démarche), puis
   « Affiner » et « Retirer ». */
.pierre-fiche__corps {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.6em 1.4em;
}

.pierre-bloc {
  display: flex;
  flex-direction: column;
  gap: 0.35em;
  min-width: 0;
}

.pierre-bloc__titre {
  font-size: x-small;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--hud-muet);
}

.pierre-bloc--formes,
.pierre-bloc--demarche {
  flex-basis: 100%;
}

/* Ce que la démarche choisie FAIT, en une phrase, sous ses puces. */
.pierre-bloc__dit {
  margin: 0;
  font-size: x-small;
  line-height: 1.35;
  color: var(--hud-muet);
  max-width: 46em;
}

/* LES MESURES : la taille, les pieds, la vitesse, sur une ligne. */
.pierre-bloc--mesures {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5em 1.2em;
}

/* ── Les puces ──────────────────────────────────────────────────────────── */
.pierre-puces {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3em;
}

/* Un trait entre les pierres et les dés. */
.pierre-puces__sep {
  width: 1px;
  height: 1.4em;
  margin: 0 0.3em;
  background: var(--hud-bord);
}

/* UNE PUCE : un bouton à choix unique. Prise (`aria-pressed`), elle se remplit
   de la teinte de la pierre. Pressée, elle s'enfonce. */
.pierre-puce {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  padding: 0.3em 0.65em;
  border: 1px solid var(--hud-bord);
  border-radius: 999px;
  background: transparent;
  color: var(--ink);
  font-size: x-small;
  line-height: 1.2;
  cursor: pointer;
  transition: border-color 0.12s ease, background-color 0.12s ease, transform 0.08s ease;
}

.pierre-puce:hover,
.pierre-puce:focus-visible {
  border-color: var(--ton-sombre);
  outline: none;
}

.pierre-puce:active {
  transform: scale(0.96);
}

.pierre-puce[aria-pressed="true"] {
  background: var(--ton);
  border-color: var(--ton-sombre);
  color: var(--ton-sombre);
  font-weight: 600;
}

.pierre-puce svg {
  width: 1.5em;
  height: 1.5em;
  flex: none;
}

/* Les puces de DÉMARCHE : le glyphe devant le nom. */
.pierre-puces--demarches .pierre-puce {
  padding-left: 0.4em;
}

/* Les puces de TEINTE : des pastilles de roche, clair et sombre. */
.pierre-puces--teintes {
  gap: 0.4em;
}

.pierre-puce--teinte {
  width: 1.55em;
  height: 1.55em;
  padding: 0;
  border-color: var(--puce-sombre);
  background: linear-gradient(135deg, var(--puce-clair) 45%, var(--puce-sombre) 120%);
  font-size: small;
}

.pierre-puce--teinte:hover,
.pierre-puce--teinte:focus-visible {
  transform: translateY(-1px);
}

.pierre-puce--teinte[aria-pressed="true"] {
  background: linear-gradient(135deg, var(--puce-clair) 45%, var(--puce-sombre) 120%);
  box-shadow: 0 0 0 2px var(--bg-card), 0 0 0 3.5px var(--puce-sombre);
}

/* ── Les champs : curseurs, compteur, interrupteurs ─────────────────────── */
.pierre-champ {
  display: flex;
  flex-direction: column;
  gap: 0.3em;
  min-width: 0;
  font-size: x-small;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--hud-muet);
}

/* Le nom à gauche, la valeur à droite, sur la même ligne. */
.pierre-champ__nom {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.8em;
}

.pierre-champ output {
  font-size: x-small;
  text-transform: none;
  letter-spacing: normal;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

/* Un champ ÉTEINT reste en place (les curseurs de silhouette d'un dé ou d'une
   sphère, la foulée d'une reptation) : le tableau ne doit pas changer de taille
   en passant d'une pierre à l'autre. */
.pierre-champ.is-muet {
  opacity: 0.4;
}

/* LES CURSEURS : une piste fine, REMPLIE de la teinte jusqu'au pouce (`--pct`,
   posée par `_afficher`), un pouce rond — la jauge d'un jeu. */
.pierre-champ--curseur input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  width: 7.5em;
  height: 4px;
  margin: 0.35em 0;
  border-radius: 2px;
  background: linear-gradient(to right, var(--ton-sombre) var(--pct, 0%), var(--hud-bord) var(--pct, 0%));
  outline: none;
  cursor: pointer;
}

.pierre-champ--curseur input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  border: 1.5px solid var(--ton-sombre);
  background: var(--bg-card);
  box-shadow: 0 1px 2px rgba(18, 24, 44, 0.25);
  transition: transform 0.1s ease;
}

.pierre-champ--curseur input[type="range"]::-moz-range-thumb {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 1.5px solid var(--ton-sombre);
  background: var(--bg-card);
  box-shadow: 0 1px 2px rgba(18, 24, 44, 0.25);
}

.pierre-champ--curseur input[type="range"]:hover::-webkit-slider-thumb,
.pierre-champ--curseur input[type="range"]:focus-visible::-webkit-slider-thumb {
  transform: scale(1.15);
}

.pierre-champ--curseur input[type="range"]:disabled {
  cursor: default;
}

/* LE COMPTEUR des pieds : − , le nombre, + , dans une pilule. */
.pierre-pas {
  display: inline-flex;
  align-items: center;
  gap: 0.1em;
  padding: 0.1em;
  border: 1px solid var(--hud-bord);
  border-radius: 999px;
}

.pierre-pas__bouton {
  width: 1.7em;
  height: 1.7em;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
  font-size: small;
  line-height: 1;
  cursor: pointer;
  transition: background-color 0.12s ease, transform 0.08s ease;
}

.pierre-pas__bouton:hover:not(:disabled) {
  background: var(--ton);
  color: var(--ton-sombre);
}

.pierre-pas__bouton:active:not(:disabled) {
  transform: scale(0.9);
}

.pierre-pas__bouton:disabled {
  opacity: 0.3;
  cursor: default;
}

.pierre-pas output {
  min-width: 1.6em;
  text-align: center;
  font-size: small;
  font-weight: 600;
  text-transform: none;
  letter-spacing: normal;
  color: var(--ink);
}

/* LES INTERRUPTEURS (le rassemblement, le droit de sauter) : une case devenue
   un vrai interrupteur, qui glisse. */
.pierre-bascule {
  display: flex;
  align-items: center;
  gap: 0.45em;
  font-size: x-small;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--hud-muet);
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
}

.pierre-bascule input {
  -webkit-appearance: none;
  appearance: none;
  position: relative;
  flex: none;
  width: 2.1em;
  height: 1.2em;
  margin: 0;
  border-radius: 999px;
  background: color-mix(in lab, var(--ink) 22%, transparent);
  cursor: pointer;
  transition: background-color 0.15s ease;
  font-size: small;
}

.pierre-bascule input::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: calc(1.2em - 4px);
  height: calc(1.2em - 4px);
  border-radius: 50%;
  background: var(--bg-card);
  box-shadow: 0 1px 2px rgba(18, 24, 44, 0.3);
  transition: transform 0.15s ease;
}

.pierre-bascule input:checked {
  background: var(--ton-sombre);
}

.pierre-bascule input:checked::after {
  transform: translateX(0.9em);
}

.pierre-bascule input:focus-visible {
  outline: 2px solid var(--ton-sombre);
  outline-offset: 2px;
}

.pierre-bascule:hover {
  color: var(--ink);
}

/* Le rassemblement, dans la rangée de la troupe : il reste sur sa ligne. */
.pierre-bascule--troupe {
  flex: none;
}

/* ── Affiner, retirer ───────────────────────────────────────────────────── */
/* LES RÉGLAGES FINS, repliés d'origine (l'auteur : « des paramètres plus
   simples ») : le corps, la foulée, le temps au sol, la hauteur du pas, le
   saut. Sur leur propre ligne. */
.pierre-fin {
  flex: 1 1 auto;
  margin: 0;
}

.pierre-fin__titre {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  cursor: pointer;
  font-size: x-small;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--hud-muet);
  list-style: none;
}

.pierre-fin__titre::-webkit-details-marker {
  display: none;
}

.pierre-fin__titre::before {
  content: "";
  width: 0.45em;
  height: 0.45em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 0.15s ease;
}

.pierre-fin[open] .pierre-fin__titre::before {
  transform: rotate(45deg);
}

.pierre-fin__titre:hover {
  color: var(--ink);
}

.pierre-fin__champs {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.5em 1.2em;
  padding-top: 0.6em;
}

/* Un BOUTON d'action : « Retirer », « Retailler ». */
.pierre-action {
  align-self: flex-end;
  padding: 0.45em 0.8em;
  border: 1px solid var(--hud-bord);
  border-radius: 999px;
  background: transparent;
  color: var(--ink);
  font-size: x-small;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  cursor: pointer;
  transition: border-color 0.12s ease, background-color 0.12s ease, transform 0.08s ease;
}

.pierre-action:hover:not(:disabled) {
  border-color: var(--ton-sombre);
  background: var(--ton);
  color: var(--ton-sombre);
}

.pierre-action:active:not(:disabled) {
  transform: scale(0.96);
}

.pierre-action:disabled {
  cursor: default;
  opacity: 0.4;
}

.pierre-action--retirer {
  margin-left: auto;
}

.pierre-action--retirer:hover:not(:disabled) {
  border-color: var(--red);
  background: color-mix(in lab, var(--red) 10%, transparent);
  color: var(--red);
}

/* ── LES COMMANDES ───────────────────────────────────────────────────────────
   L'aide d'un jeu (`_batirAide`) : trois gestes en TOUCHES, en haut de la
   planche. Ouverte à la première visite, elle se replie en un « ? » quand le
   premier objectif est posé, ou d'un clic. Ce n'est pas un mur : la troupe
   passe dessous. Elle laisse le coin du plan du site (72 px en haut à gauche)
   tranquille : elle est au centre. */
.pierre-aide {
  position: absolute;
  z-index: 39;
  top: 1em;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  max-width: calc(100% - 2em);
  font-size: x-small;
  color: var(--hud-muet);
}

.pierre-aide__liste {
  display: none;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.4em 1.1em;
  padding: 0.45em 0.5em 0.45em 0.9em;
  border-radius: 999px;
  background: color-mix(in lab, var(--bg-card) 84%, transparent);
  backdrop-filter: blur(4px);
  box-shadow: 0 0.2em 1.2em rgba(18, 24, 44, 0.1);
  animation: pierre-descend 0.25s ease-out;
}

.pierre-aide__liste > span {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  white-space: nowrap;
}

.pierre-aide.is-ouverte .pierre-aide__liste {
  display: flex;
}

.pierre-aide.is-ouverte .pierre-aide__bouton {
  display: none;
}

/* Une TOUCHE : un cabochon, comme sur un clavier. */
.pierre-aide kbd {
  font-family: inherit;
  font-size: xx-small;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.15em 0.5em;
  border: 1px solid var(--hud-bord);
  border-bottom-width: 2px;
  border-radius: 0.4em;
  background: var(--bg-card);
  color: var(--ink);
}

.pierre-aide__bouton,
.pierre-aide__fermer {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.8em;
  height: 1.8em;
  padding: 0;
  border: 1px solid var(--hud-bord);
  border-radius: 50%;
  background: color-mix(in lab, var(--bg-card) 84%, transparent);
  backdrop-filter: blur(4px);
  color: var(--ink);
  font-size: small;
  line-height: 1;
  cursor: pointer;
}

.pierre-aide__fermer {
  border-color: transparent;
  background: transparent;
  color: var(--hud-muet);
}

.pierre-aide__bouton:hover,
.pierre-aide__fermer:hover {
  border-color: var(--ink);
  color: var(--ink);
}

@keyframes pierre-descend {
  from {
    opacity: 0;
    transform: translateY(-0.4em);
  }
}

/* ── L'ÉPURE ─────────────────────────────────────────────────────────────────
   Le dessin technique de la pierre qu'on regarde (cf. `_batirEpure` dans
   pierre_controller, et `pierre_epure.js` pour le trait) : une carte sur le
   flanc DROIT de la planche — le dessin, qu'on tourne au doigt, les cinq
   curseurs de silhouette, et « Retailler ». Même matière que le tableau, le
   même liseré de la teinte choisie, et un mur comme lui (`data-loupe-barriere`). */
.pierre-epure {
  --ton: var(--light-grey);
  --ton-sombre: var(--ink);
  --hud-bord: color-mix(in lab, var(--ink) 14%, transparent);
  --hud-muet: color-mix(in lab, var(--ink) 62%, transparent);
  position: absolute;
  z-index: 39;
  right: 1em;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.6em;
  width: 14em;
  padding: 0.7em 0.8em 0.8em;
  border-radius: var(--radius);
  border-top: 3px solid var(--ton-sombre);
  background: color-mix(in lab, var(--bg-card) 88%, transparent);
  backdrop-filter: blur(6px);
  box-shadow: 0 0.2em 1.2em rgba(18, 24, 44, 0.14);
  transition: border-color 0.2s ease;
  touch-action: auto;
  max-height: calc(100% - 2em);
  overflow: auto;
  color: var(--ink);
}

.pierre-epure__tete {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.6em;
}

.pierre-epure__astuce {
  font-size: xx-small;
  color: var(--hud-muet);
}

/* LE DESSIN : un canevas carré. Sa couleur de TEXTE est l'encre du trait — c'est
   là que `_dessinerEpure` va la lire, résolue par le navigateur (un `var(--ink)`
   lu tel quel serait un `color-mix()` que le contexte 2D ne comprendrait pas). */
.pierre-epure__toile {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  color: var(--ink);
  border: 1px solid var(--hud-bord);
  border-radius: calc(var(--radius) / 2);
  /* Un papier quadrillé très pâle, comme une feuille de dessin technique. */
  background:
    linear-gradient(var(--hud-bord) 1px, transparent 1px) 0 0 / 1.2em 1.2em,
    linear-gradient(90deg, var(--hud-bord) 1px, transparent 1px) 0 0 / 1.2em 1.2em,
    var(--bg-card);
  cursor: grab;
  /* On la tourne au doigt : la carte a rendu les gestes à la page
     (`touch-action: auto`), le canevas les reprend pour lui. */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}

.pierre-epure__toile.is-tournee {
  cursor: grabbing;
}

/* Les cinq curseurs, en colonne, sur toute la largeur de la carte. */
.pierre-epure__reglages {
  display: flex;
  flex-direction: column;
  gap: 0.4em;
}

.pierre-epure .pierre-champ--curseur input[type="range"] {
  width: 100%;
}

.pierre-epure .pierre-action {
  align-self: stretch;
}

/* ── Le mouvement réduit ────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .pierre-portrait::before,
  .pierre-portrait.is-neuve .pierre-portrait__jeton,
  .pierre-etat i,
  .pierre-aide__liste {
    animation: none;
  }

  .pierre-hud,
  .pierre-epure,
  .pierre-puce,
  .pierre-portrait__jeton,
  .pierre-bascule input,
  .pierre-bascule input::after,
  .pierre-action,
  .pierre-pas__bouton {
    transition: none;
  }
}

/* ── Sur un écran moyen ─────────────────────────────────────────────────── */
/* L'épure est sur le flanc droit, à mi-hauteur : le tableau lui laisse sa place
   (ses puces passent à la ligne) plutôt que de finir dessous. */
@media (min-width: 40rem) and (max-width: 100rem) {
  .pierre-hud {
    max-width: calc(100% - 32em);
  }
}

/* ── Sur un écran étroit ────────────────────────────────────────────────── */
/* La carte de l'épure ne peut pas tenir sur le flanc : elle passe en haut, sur
   toute la largeur, sous les commandes, et son dessin se fait plus petit. Le
   tableau garde le bas, et défile s'il le faut. */
@media (max-width: 40rem) {
  .pierre-epure {
    right: 1em;
    left: 1em;
    top: 3.4em;
    transform: none;
    width: auto;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-start;
    max-height: 40%;
  }

  .pierre-epure__tete {
    flex-basis: 100%;
  }

  .pierre-epure__toile {
    width: 6.5em;
    flex: 0 0 auto;
  }

  .pierre-epure__reglages {
    flex: 1 1 8em;
  }

  .pierre-hud {
    max-height: 52%;
  }

  .pierre-bloc__dit {
    display: none;
  }
}
/* Les écrans à colonnes (Profil, CV) et l'atelier (ex-zone Recherches).

   Profil et CV ont pour conteneur un <div> qui contient des bentos :
   `div:has(.bento)` (application.css, chargé en dernier par require_self) le
   met en `flex-wrap: wrap` et gagne en spécificité sur une classe seule —
   inutile d'essayer d'en faire une grille. Leur mise en page vient donc, comme
   partout ailleurs dans le projet, de la largeur explicite de chaque colonne ;
   le navigateur replie les colonnes tout seul quand la fenêtre rétrécit.
   L'atelier, lui, n'a plus de colonnes depuis qu'elle est découpée en
   volets : elle est décrite plus bas, à part.

   Tous partagent la même largeur totale pour qu'on ne sente pas la page
   « respirer » en passant de l'un à l'autre.
   --rail-width et --timeline-width sont définis dans la charte (:root). */

.cv-layout,
.lab-layout,
.moi-layout {
  --zone-width: calc(var(--timeline-width) + var(--rail-width) + 1ex);

  margin: 0 auto;
  max-width: var(--zone-width);
  justify-content: center;
  align-items: start;
  /* Seuls écrans du site qui défilent (Art et Design tiennent dans la fenêtre).
     La platine de navigation est fixée au bord bas : sans cette réserve, le bas
     du contenu passe dessous et n'en ressort jamais, si loin qu'on défile. */
  padding-bottom: var(--bottom-clearance);
}

/* Colonne principale (CV) et rails. */
.cv-layout__main {
  width: var(--timeline-width);
}

.cv-layout__rail,
.moi-layout__rail {
  width: var(--rail-width);
}

.cv-layout__main,
.cv-layout__rail,
.moi-layout__rail {
  display: flex;
  flex-direction: column;
  gap: 1ex;
  min-width: 0;
}

/* ── L'atelier : cinq volets, un seul à l'écran ──────────────────────────────
   Un volet par pièce (cf. atelier.html.erb, zone_sections_controller) : la
   colonne et le rail d'avant n'existent plus, chaque pièce a la zone entière
   pour elle. Son conteneur est un <section> et non un <div>, sans quoi
   `div:has(.bento)` (application.css) le mettrait en `flex-wrap: wrap` et
   poserait les volets côte à côte. */
.lab-layout {
  /* Ce qu'il faut retirer de la fenêtre pour que la zone y tienne : la
     gouttière du <body> (en haut ET en bas) plus l'air laissé sous elle. */
  --lab-chrome: calc(2 * var(--page-gutter) + var(--bottom-clearance));

  display: flex;
  flex-direction: column;
  gap: 1ex;
  /* La zone remplit la fenêtre : un seul volet à l'écran, elle y tient comme
     Art et Offres. Une hauteur FERME et non un plancher — c'est elle qui donne
     au volet la hauteur définie dont son carré se mesure (voir plus bas). Un
     volet trop grand pour elle (les deux instruments empilés sur un téléphone)
     la déborde alors sans être rogné, et la page rend le défilement. */
  height: calc(100dvh - var(--lab-chrome));
  /* Le conteneur est vertical : ce que la règle partagée centre à l'horizontale
     centrerait ici à la verticale, et son `align-items: start` rognerait les
     volets à la largeur de leur contenu. Sa réserve basse est déjà comptée dans
     --lab-chrome. */
  justify-content: flex-start;
  align-items: stretch;
  padding-bottom: 0;
}

/* Le volet à l'écran prend toute la hauteur restante et y centre sa pièce.
   Même fondu que le contenu de zone à chaque changement de volet (cf.
   application.css) : repasser de `display: none` à visible remet
   l'élément au rang des fraîchement rendus, et @starting-style rejoue. */
.lab-layout__section {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 1ex;
  align-items: center;
  justify-content: center;
  opacity: 1;
  transition: opacity 0.28s ease;
}

@starting-style {
  .lab-layout__section {
    opacity: 0;
  }
}

/* `div:has(.bento)` pose un `display: flex` d'AUTEUR sur ces volets : il gagne
   sur le `display: none` que la feuille du navigateur donne à `[hidden]`, et le
   volet caché resterait à l'écran. D'où ce rappel. */
.lab-layout__section[hidden] {
  display: none;
}

/* Une pièce générative seule dans son volet (Turing, Chladni) : carrée
   (`aspect-ratio` sur le bento), aussi grande que le volet le permet — la zone
   étant plus large que haute, c'est en général sa HAUTEUR qui la borne. Son
   contenu est entièrement en position absolue : elle ne peut pas se
   dimensionner seule, d'où la largeur explicite.
   Le côté se mesure sur LE VOLET (100cq*) et non sur la fenêtre : c'est le
   volet qui borne vraiment le carré, et tout ce que la zone lui prendrait un
   jour en hauteur, il le reprendrait au carré plutôt que de faire déborder la
   page. `container-type: size` demande au volet une hauteur définie, et son
   `flex: 1` la lui donne. */
.lab-layout__section--piece {
  container-type: size;
}

.lab-layout__section--piece>.bento {
  width: min(100cqw, 100cqh);
}

/* ── Un volet plein écran (le motif de Turing) ───────────────────────────────
   Certaines pièces ne se regardent pas dans une carte : elles prennent l'écran
   entier. Le volet garde sa place dans le flux ; c'est la ZONE qui, quand un
   tel volet est à l'écran, annule la gouttière du <body> (haut, bas et côtés —
   sur petit écran elle vaut zéro, et ces marges aussi), oublie sa largeur
   maximale et prend exactement 100dvh. Rien ne dépasse donc, et la page ne
   défile pas. Le plan du site reste au-dessus (z-index 200, cf. site_menu.css).
   `:has()` plutôt que `[data-current-section="turing"]` : la règle décrit le
   volet, pas son nom, et vaudra pour la prochaine pièce qui en voudra autant. */
.lab-layout:has(> .lab-layout__section--full:not([hidden])) {
  max-width: none;
  height: 100dvh;
  margin: calc(-1 * var(--page-gutter));
  padding: 0;
}

.lab-layout__section--full {
  padding: 0;
  /* Une seule pièce, qui doit prendre tout : pas de centrage à sa taille. */
  align-items: stretch;
}

.lab-layout__section--full>.bento {
  width: 100%;
  height: 100%;
  /* Le carré du bento (aspect-ratio) et l'arrondi des cartes n'ont plus cours :
     la pièce est le fond de l'écran. */
  aspect-ratio: auto;
  border-radius: 0;
}

/* Un format figé (Turing, cf. FORMATS/`_updateView` dans turing_controller.js)
   ne touche plus à la BOÎTE affichée : il calibre l'échelle de ce qu'elle
   montre (un cadre au ratio choisi, répété par le tore pour couvrir tout
   l'écran — jamais letterboxé, jamais étiré), donc rien à ajouter ici. Le
   bento reste 100 % × 100 % dans les deux cas ; `data-turing-format` n'est
   plus qu'un repère sur l'élément, sans effet CSS. */

.content-grid {
  display: grid;
  gap: 1ex;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
}

.cv-layout a.bento,
.lab-layout a.bento,
.moi-layout a.bento {
  text-decoration: none;
}

.identity-bento,
.timeline-bento,
.globe-bento,
.contact-bento {
  width: 100%;
}

.cv-layout__main>.bento {
  width: 100%;
}

.bento-headline {
  color: var(--ink);
  font-size: medium;
  font-weight: bold;
  line-height: 1.05;
}

.bento-copy {
  color: var(--grey);
  line-height: 1.35;
}

.bento-kicker {
  color: var(--gray);
  font-size: x-small;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.timeline-bento,
.globe-bento,
.content-grid .formations,
.content-grid .experiences {
  .header {
    margin-bottom: 0.75rem;
  }
}

@media (max-width: 64rem) {
  .cv-layout,
  .lab-layout,
  .moi-layout {
    max-width: 48rem;
  }

  .cv-layout,
  .moi-layout {
    /* Le bas reste le dégagement de la platine : ce raccourci écrasait sinon le
       `padding-bottom` posé plus haut, et le contenu repassait sous elle. */
    padding: 0 1rem var(--bottom-clearance);
  }

  /* L'atelier compte déjà ce dégagement dans --lab-chrome : le lui
     ajouter en padding le retirerait une seconde fois du volet à l'écran. */
  .lab-layout {
    padding: 0 1rem;
  }

  /* Une seule colonne : tout s'empile dans l'ordre du DOM. */
  .cv-layout__main,
  .cv-layout__rail,
  .moi-layout__rail {
    width: 100%;
  }

  .content-grid {
    grid-template-columns: 1fr;
  }

  .identity-bento {
    min-height: 12rem;
  }

}
/* LE PORTFOLIO (le studio, cf. docs/ARBORESCENCE.md) : la page d'un projet
   (pages/projet, pages/projet/_grille) — leur index est une figure de l'accueil
   (`/design`, accueil.css ; la page `/studio` n'existe plus).
   La mise en page d'un projet tient dans UNE grammaire : six colonnes, et chaque
   image y prend sa largeur — pleine (6), demi (3), tiers (2) — dans l'ordre du
   groupe. Le rythme est à l'auteur ; typographie, marges et alignements restent
   au site. */

/* ── La page d'un projet ─────────────────────────────────────────────────── */
/* LES DEUX PORTES, EN HAUT ET EN BAS DE L'ÉCRAN (7 oct. 2026 : « je souhaite garder
   le titre 'studio' en bas et le titre 'galerie' en haut » — « au niveau des shows
   des diapos » ; pages/projet/_portes) : les titres en lettres de l'accueil
   (`.accueil-art__galerie`, `.accueil-art__porte`, `.accueil-art__design`,
   accueil.css : corps, espacement, flèches qui se retournent sur la porte
   courante, ornements qui tombent sur un écran étroit), FIXÉS au milieu du haut
   et du bas, à `28px` du bord — la hauteur de « La galerie » envolée sur /art —,
   au-dessus de la page, sous le menu (100) et la correspondance. « La galerie » est
   la porte d'à côté : discrète, comme sur la planche. La page commence dessous et
   finit au-dessus. */
.portes .portes__galerie,
.portes .portes__studio {
  position: fixed;
  left: 50%;
  z-index: 20;
  margin: 0;
  transform: translateX(-50%);
  white-space: nowrap;
}

.portes .portes__galerie {
  top: 28px;
  opacity: 0.55;
}

.portes .portes__studio {
  bottom: 28px;
}

.projet {
  padding-top: calc(var(--menu-h) + 2.5rem);
  padding-bottom: 5.5rem;
}

.projet__retour {
  align-self: flex-start;
  color: var(--ink-muted);
  font-size: x-small;
  text-decoration: none;
}

.projet__retour:hover,
.projet__retour:focus-visible {
  color: var(--blue);
  outline: none;
}

.projet__cartouche {
  margin: 0;
  color: var(--ink-muted);
  font-size: x-small;
}

/* Le logo du client, celui du CV (`Product#client_logo`), devant le cartouche :
   à la hauteur d'une ligne et demie, dans la ligne. */
.projet__logo {
  display: inline-block;
  height: 1.6em;
  width: auto;
  max-width: 8em;
  margin-right: 0.5em;
  vertical-align: middle;
  object-fit: contain;
}

.projet__intro {
  max-width: 60ch;
}

.projet__intro > :first-child {
  margin-top: 0;
}

.projet__intro > :last-child {
  margin-bottom: 0;
}

/* ── La grille ───────────────────────────────────────────────────────────── */
.projet-grille {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 1ex;
}

.projet-image {
  position: relative;
  grid-column: span 6;
  margin: 0;
  min-width: 0;
}

.projet-image--demi {
  grid-column: span 3;
}

.projet-image--tiers {
  grid-column: span 2;
}

.projet-image__img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: calc(var(--radius) / 2);
  background: var(--bg-card);
}

.projet-image__legende {
  margin-top: 0.4em;
  color: var(--ink-muted);
  font-size: x-small;
}

/* Sur un téléphone, une colonne : tout en pleine largeur. */
@media (max-width: 40rem) {
  .projet-image--demi,
  .projet-image--tiers {
    grid-column: span 6;
  }
}

/* ── Les outils de l'admin, sur la grille ────────────────────────────────────
   Une pastille par image, en haut à droite : la poignée pour réordonner et les
   trois largeurs en puces (aria-pressed sur la courante). Discrète tant qu'on ne
   la survole pas, comme le ✎ des bentos (.bento__edit). Le formulaire de chaque
   puce n'a pas de boîte (display: contents) : ses champs cachés ne prennent pas
   de place, son bouton se range dans la file. */
.projet-image__outils {
  position: absolute;
  top: 0.5em;
  right: 0.5em;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 0.2em;
  padding: 0.25em 0.4em;
  border-radius: 999px;
  background: color-mix(in lab, var(--bg-card) 86%, transparent);
  backdrop-filter: blur(1.5mm);
  box-shadow: 0 0.2em 1.2em rgba(18, 24, 44, 0.14);
  opacity: 0.45;
  transition: opacity 150ms;
}

.projet-image:hover .projet-image__outils,
.projet-image__outils:focus-within {
  opacity: 1;
}

.projet-image__poignee {
  padding: 0 0.3em;
  color: var(--ink-muted);
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
}

.projet-image.is-dragging {
  opacity: 0.5;
}

.projet-grille.is-sorting {
  cursor: grabbing;
}

.projet-largeur__form {
  display: contents;
}

.projet-largeur {
  padding: 0.2em 0.55em;
  border: 0;
  border-radius: 999px;
  background: none;
  font: inherit;
  font-size: xx-small;
  color: var(--ink);
  cursor: pointer;
}

.projet-largeur:hover,
.projet-largeur:focus-visible {
  background: var(--ink-10);
  outline: none;
}

.projet-largeur[aria-pressed="true"] {
  background: var(--ink);
  color: var(--white);
}

/* ── L'édition SUR PLACE (admin) : pas de page d'édition ─────────────────────
   Demande de l'auteur (30 sept. 2026) : « les inputs directement dans le show ».
   La fiche (pages/projet/_fiche) et les légendes de la grille sont des champs qui
   ont l'allure du texte qu'ils remplacent — même corps, même couleur — et ne se
   révèlent qu'au survol ou à la saisie, par un filet (comme le cartel de la
   galerie, `.art-figure__field`). Tout s'enregistre seul (autosave).
   PIÈGE : form.scss.css centre et borne tout <form> (48ch), habille tout <input>
   (bordure, 10px de marge) et donne 48rem de haut à tout <textarea>. */
.projet__form,
.projet-image__legende-form,
.projet-ajout,
.projet__supprimer-form {
  max-width: none;
  margin: 0;
}

.projet__form {
  display: flex;
  flex-direction: column;
  gap: 0.6em;
}

.projet__champ {
  width: 100%;
  height: auto;
  min-height: 0;
  padding: 0.1em 0.25em;
  margin-left: -0.25em;
  border: 0;
  border-bottom: 1px solid transparent;
  border-radius: 3px;
  background: transparent;
  font-family: inherit;
  font-weight: inherit;
  line-height: inherit;
  color: inherit;
  resize: none;
  transition: background 0.2s, border-color 0.2s;
}

.projet__champ::placeholder {
  color: var(--ink-10);
}

.projet__champ:hover {
  border-bottom-color: var(--ink-10);
}

.projet__champ:focus {
  outline: none;
  background: color-mix(in lab, var(--bg-card) 70%, var(--bg));
  border-bottom-color: var(--ink-muted);
}

.projet__champ--titre {
  font-size: x-large;
  font-weight: bold;
}

.projet__champ--intro {
  font-size: small;
}

/* Le cartouche en champs : client · année · prestation, sur une ligne. */
.projet__cartouche--champs {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.2em 0.4em;
}

.projet__cartouche--champs .projet__champ {
  width: auto;
  min-width: 6ch;
  field-sizing: content;
  font-size: x-small;
}

.projet__cartouche--champs select.projet__champ {
  appearance: none;
  cursor: pointer;
}

.projet__statut {
  height: 0;
  align-self: flex-end;
  font-size: x-small;
  color: var(--ink-muted);
}

.projet__fil {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4em 1em;
}

/* LE CAHIER DE RECHERCHES DE L'IMAGE (7 oct. 2026 : « que les notes et croquis
   soient attachées aux projet-image__img plutôt qu'au projet global ») : quand
   l'image a des notes (`data-papiers`, posé par cahier_controller sur sa figure),
   un clic dessus étale ses feuilles autour d'elle (la scène, cahier.css) — le
   curseur le dit, rien d'autre (un onglet de papier quadrillé qui comptait les notes
   au coin de l'image a vécu une heure : « retire-les »). */
.projet-image:not([data-papiers="0"])[data-papiers] .projet-image__img {
  cursor: pointer;
}

.projet__prive {
  padding: 0.1em 0.6em;
  border-radius: 999px;
  background: color-mix(in lab, var(--yellow) 25%, var(--bg-card));
  font-size: x-small;
  color: var(--ink);
}

.projet__supprimer {
  padding: 0.3em 0.9em;
  border: 1px solid var(--ink-10);
  border-radius: 999px;
  background: transparent;
  font: inherit;
  font-size: x-small;
  color: var(--ink-muted);
  cursor: pointer;
}

.projet__supprimer {
  align-self: flex-start;
}

.projet__supprimer:hover,
.projet__supprimer:focus-visible {
  border-color: var(--red);
  color: var(--red);
  outline: none;
}

/* La légende d'une image, en champ, à la place de la légende lue. */
input.projet-image__legende {
  margin-top: 0.3em;
  font-size: x-small;
  color: var(--ink-muted);
}

.projet-image__retirer:hover,
.projet-image__retirer:focus-visible {
  background: color-mix(in lab, var(--red) 15%, transparent);
  color: var(--red);
}

/* La case d'AJOUT, en queue de grille : cliquer, ou y déposer des fichiers — le
   champ couvre la case, transparent, et prend le dépôt lui-même. */
.projet-ajout {
  grid-column: span 2;
}

.projet-ajout__case {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 9rem;
  height: 100%;
  border: 1.5px dashed var(--input-border);
  border-radius: calc(var(--radius) / 2);
  color: var(--ink-muted);
  text-align: center;
  cursor: pointer;
  transition: border-color 150ms, color 150ms, background-color 150ms;
}

.projet-ajout__case:hover,
.projet-ajout__case:focus-within {
  border-color: var(--blue);
  color: var(--blue);
  background: color-mix(in lab, var(--blue) 5%, transparent);
}

.projet-ajout__texte {
  display: flex;
  flex-direction: column;
  gap: 0.3em;
  font-size: small;
  font-weight: 600;
}

.projet-ajout__texte small {
  font-size: x-small;
  font-weight: normal;
}

.projet-ajout__champ {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}

@media (max-width: 40rem) {
  .projet-ajout {
    grid-column: span 6;
  }
}
/* Le plan du site, ouvert au clic droit (appui long au doigt) — cf.
   posts/bento/_site_menu.html.erb et site_menu_controller.js. Il a pris la
   place des platines d'astrolabe : la navigation ne s'affiche plus en
   permanence, elle vient sous le pointeur quand on la demande.

   Position et point de croissance viennent du contrôleur (`left`/`top`,
   `--from-x`/`--from-y`) : il n'y a ici que l'habillage. */

.site-menu {
  position: fixed;
  top: 0;
  left: 0;
  /* Au-dessus de tout, loupe comprise (z-index 40, cf. loupe.css). */
  z-index: 200;
  min-width: 11rem;
  max-width: min(18rem, calc(100vw - 2 * 0.5rem));
  /* Surtout PAS de rognage : les tiroirs des zones sont posés hors de cette
     boîte, à côté d'elle (cf. .site-menu__sub). Le menu, lui, ne fait jamais que
     quelques lignes — le sujet et les trois zones — et tient toujours. */
  overflow: visible;
  padding: 0.35rem;
  border-radius: var(--radius);
  background: color-mix(in lab, var(--bg-card) 86%, transparent);
  backdrop-filter: blur(1.5mm);
  box-shadow: var(--shadow);
  color: var(--ink);
  /* Un menu ne se surligne pas : le glisser qui l'a ouvert ne doit pas y
     laisser une sélection de texte derrière lui. */
  user-select: none;
  -webkit-user-select: none;
  /* Il grandit depuis le pointeur, pas depuis son coin. */
  transform-origin: var(--from-x, 0) var(--from-y, 0);
  /* Une ANIMATION, pas une transition, et c'est délibéré : au repos le menu
     n'est donc pas transformé, seulement transparent. Le contrôleur peut ainsi
     le placer ET ranger le tiroir d'une zone en mesurant l'état FINAL — une
     transition partant d'un `scale` fausserait toutes ces boîtes de 6 %
     (cf. site_menu_controller#open et #_reveal). */
  opacity: 0;
}

.site-menu[hidden] {
  display: none;
}

.site-menu:focus {
  outline: none;
}

.site-menu.is-open {
  opacity: 1;
  animation: site-menu-in 130ms ease-out;
}

@keyframes site-menu-in {
  from {
    opacity: 0;
    transform: scale(0.94);
  }
}

@media (prefers-reduced-motion: reduce) {
  .site-menu.is-open {
    animation: none;
  }
}

/* ── Les entrées ─────────────────────────────────────────────────────────── */
/* Lien ou bouton selon qu'il y a une page à atteindre ou seulement un état de
   page à demander : les deux doivent se ressembler en tout point. */
.site-menu__entry {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 0.35em 0.7em;
  border: 0;
  border-radius: calc(var(--radius) / 2);
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.site-menu__entry:hover,
.site-menu__entry:focus-visible {
  background: var(--ink-10);
  outline: none;
}

.site-menu__entry--zone {
  font-weight: 600;
}

/* ── Les zones : un nom, un chevron ──────────────────────────────────────── */
.site-menu__zone {
  /* Le repère du tiroir, qui se pose par rapport à ce rang. */
  position: relative;
}

.site-menu__row {
  display: flex;
  align-items: stretch;
  gap: 0.1rem;
}

.site-menu__row .site-menu__entry {
  flex: 1;
  min-width: 0;
}

/* Le chevron est un bouton à part : au doigt, c'est lui qui ouvre le tiroir,
   pendant que le nom de la zone reste une destination. */
.site-menu__chevron {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  padding: 0;
  border: 0;
  border-radius: calc(var(--radius) / 2);
  background: none;
  color: var(--ink-muted);
  cursor: pointer;
}

.site-menu__chevron svg {
  width: 0.5rem;
  height: 0.75rem;
}

.site-menu__chevron:hover,
.site-menu__chevron:focus-visible {
  background: var(--ink-10);
  color: inherit;
  outline: none;
}

.site-menu__chevron[aria-expanded="true"] {
  color: var(--blue);
}

/* Le bleu ne dit qu'une chose : c'est ICI que l'on se trouve. Il tombe donc sur
   le nom de la zone courante ET sur l'entrée exacte de son tiroir — jamais sur
   tout le tiroir, qui n'aurait alors plus rien à distinguer. */
.site-menu__entry[aria-current] {
  color: var(--blue);
  font-weight: 600;
}

/* ── Le sujet : ce qu'il y a sous le pointeur ────────────────────────────── */
.site-menu__subject {
  padding-bottom: 0.35rem;
  margin-bottom: 0.35rem;
  border-bottom: 1px solid var(--ink-10);
}

.site-menu__subject[hidden] {
  display: none;
}

/* Le nom de l'objet visé : un titre, pas une commande — il ne se clique pas. */
.site-menu__label {
  margin: 0 0 0.15rem;
  padding: 0.15em 0.7em;
  font-size: x-small;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Le plan ─────────────────────────────────────────────────────────────── */
.site-menu__map,
.site-menu__sub {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* LE TIROIR d'une zone : une planche à part, posée contre le flanc du menu —
   le sous-menu d'un logiciel. Hors du flux, il ne change donc rien à la taille
   du menu ; c'est site_menu_controller#_reveal qui décide du flanc (`is-flipped`)
   puis du recentrage (`--sub-x`, `--sub-y`) d'après la place restante à l'écran. */
.site-menu__sub {
  position: absolute;
  top: 0;
  left: 100%;
  z-index: 1;
  min-width: 9rem;
  max-width: 14rem;
  /* Un tiroir peut être long (les groupes ART) : lui, il défile. */
  max-height: calc(100dvh - 1rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* L'écart au menu compte DEPUIS SON BORD, pas depuis le rang : `left: 100%`
     tombe au ras de la liste, donc encore à l'intérieur du rembourrage du menu
     (0.35rem). Sans quoi le tiroir viendrait mordre dessus. */
  margin-left: calc(0.35rem + 0.25rem);
  padding: 0.35rem;
  border-radius: var(--radius);
  background: color-mix(in lab, var(--bg-card) 92%, transparent);
  backdrop-filter: blur(1.5mm);
  box-shadow: var(--shadow);
  transform: translate(var(--sub-x, 0px), var(--sub-y, 0px));
}

/* Pas la place à droite : le tiroir passe de l'autre côté. */
.site-menu__zone.is-flipped > .site-menu__sub {
  left: auto;
  right: 100%;
  margin-left: 0;
  margin-right: calc(0.35rem + 0.25rem);
}

.site-menu__sub[hidden] {
  display: none;
}

/* Les états D'UNE page du tiroir (les groupes des dessins) : en retrait sous elle, comme les feuilles sous une branche — et en
   sourdine, sauf celui où l'on est (le bleu, ci-dessus, gagne). */
.site-menu__entry--sous {
  padding-left: 1.6em;
  color: var(--ink-muted);
}
/* La soie — zone Art. Les dessins du carrousel sont repeints sur leur support
   (du papier aquarelle, et du calque pour les couches — cf. soie_supports.js) sur UN canevas WebGL
   (`soie_controller`, `soie_gl`), posé DERRIÈRE le carrousel : tout ce qui est écrit par-dessus l'oeuvre (le bandeau du mode
   « image seule », sur petit écran) reste donc au-dessus du tissu.
   (`require_tree` compile tout dans une seule feuille : rien à déclarer.) */

/* Le canevas passe sous le contenu de la zone (`z-index: -1`) ; `isolation`
   garde ce « dessous » à l'intérieur de `.art-featured` — sans elle il filerait
   sous le fond de la page. */
.art-featured.a-soie {
  isolation: isolate;
  /* Ce que le canevas déborde vers le HAUT, jusqu'au bord de l'écran (la marge
     intérieure haute de `.art-zone`, cf. art.scss.css) : le mur et les ombres des
     feuilles vont jusque-là. */
  --soie-haut: calc(0.75rem + var(--page-gutter));
  /* … et ce que le canevas déborde vers le BAS, jusqu'au bord de l'écran (la marge
     intérieure basse de `.art-zone`, cf. art.scss.css) : l'ombre des feuilles tombe
     par là, elle y était coupée net. */
  --soie-bas: calc(0.75rem + var(--art-bas, 0px));
}

/* Il déborde de `.art-featured` en haut et en bas, jusqu'aux bords de l'écran (les
   marges intérieures de `.art-zone`, cf. art.scss.css) : le mur couvre tout l'écran
   et l'ombre d'une feuille n'est coupée par rien. */
.soie {
  position: absolute;
  inset: calc(-1 * var(--soie-haut)) 0 calc(-1 * var(--soie-bas));
  width: 100%;
  height: calc(100% + var(--soie-haut) + var(--soie-bas));
  z-index: -1;
  pointer-events: none;
}

/* ── Avant que la pièce ait tranché ─────────────────────────────────────────
   `avant-soie` est posée par le GABARIT (pages/art/_featured) et retirée par
   `soie_controller#connect` — qu'il allume la pièce ou non. Sans elle, le
   navigateur peint les dessins à plat (avec leur ombre portée, sur la page nue)
   pendant que le JS démarre, puis tout bascule en tissu quand la pièce s'allume :
   c'était le FLASH au chargement (l'auteur, 2026-09-22).
   Le FILET : si le contrôleur ne connecte JAMAIS (JavaScript coupé ou en panne),
   l'animation rend les dessins au bout de `--soie-secours` — mieux vaut une
   attente qu'une zone vide. Elle ne peut pas contrarier la pièce : `connect`
   retire la classe, et l'animation avec. Long exprès : si elle se déclenchait
   avant un démarrage lent, on reverrait le flash qu'on corrige ici. */
.art-featured.avant-soie {
  --soie-secours: 2s;
}

.art-featured.avant-soie .art-featured__img,
.art-featured.avant-soie .art-featured__couche {
  opacity: 0;
  animation: soie-secours 1ms linear var(--soie-secours) forwards;
}

@keyframes soie-secours {
  to {
    opacity: 1;
  }
}

/* Les images dont le tissu est peint : toujours là (mise en page, clics, loupe,
   lecteurs d'écran), mais on ne les voit plus — leur ombre non plus, c'est le
   tissu qui porte la sienne. Transparentes DÈS QUE LA PIÈCE EST ALLUMÉE (`a-soie`,
   posée dans `connect`), et non une fois chaque dessin sur la carte : une image
   arrive quand elle veut (`loading="lazy"`), et si elle finit de charger APRÈS le
   `requestAnimationFrame` de la pièce, le navigateur la peint à plat — avec son
   ombre portée — pendant une image, avant que la soie ne la reprenne. C'était le
   FLASH au chargement (l'auteur, 2026-09-22). Sans WebGL, contexte perdu ou
   mouvement réduit, `a-soie` n'est pas posée (ou est retirée) : les images restent
   des images. */
.a-soie .art-featured__img,
.a-soie .art-featured__couche {
  opacity: 0;
}

/* Une couche transparente n'a plus rien à MÉLANGER : son `mix-blend-mode: multiply`
   (le repli sans soie, art.scss.css) est retiré tant que la pièce est allumée — une
   précaution posée sur une fausse piste (le « carré noir » du zoom, 25 sept. 2026, venait
   du pinceau : le calque d'une voisine qui s'efface multipliait encore, cf. soie_gl.js,
   « Une COUCHE », et docs/claude/soie.md). Sans effet visible ; gardé, il ne coûte rien. */
.a-soie .art-featured__couche {
  mix-blend-mode: normal;
}

/* … sauf celle que la carte REFUSE (une autre origine : elle souillerait le
   canevas). Elle ne sera jamais peinte en tissu — elle reste une image. C'est
   aussi ce que `loupe_page` pose sur la COPIE d'une image, pour que l'instantané
   de page montre le dessin à plat sous le verre. Sous `.a-soie` : trois classes
   contre deux, la règle ci-dessus ne dépend pas de l'ordre des fichiers. */
.a-soie .art-featured__img.sans-soie,
.a-soie .art-featured__couche.sans-soie {
  opacity: 1;
}

/* Le témoin : le nom du support qu'on vient de choisir (touche S, ou plan du
   site), en bas de la zone, le temps de le lire. Même pastille que le témoin
   de réglage de la loupe (`.art-loupe-hud`). */
.soie-temoin {
  position: absolute;
  left: 50%;
  bottom: 2.4rem;
  z-index: 2;
  margin: 0;
  padding: 0.3em 0.8em;
  transform: translateX(-50%);
  border-radius: 999px;
  background: color-mix(in lab, var(--bg-card) 88%, transparent);
  box-shadow: 0 2px 10px var(--ink-faint);
  color: var(--ink);
  font-size: x-small;
  white-space: nowrap;
  pointer-events: none;
}

.soie-temoin[hidden] {
  display: none;
}
.sfp.bento {
  /* --sfp-typeface (pile Unicode) est défini dans la charte (:root). */
  --sfp-housing: var(--bg-card);
  --sfp-tile: color-mix(in lab, var(--ink) 6%, var(--bg-card));

  /* Volets sombres à glyphe blanc (design flip-clock). Un volet PORTANT un
     caractère est sombre ; un volet VIDE est clair et se fond dans le panneau. */
  --flap-hi: #2a2a2e;
  --flap: #181818;
  --flap-lo: #0c0c0d;
  --glyph: #ffffff;
  --flap-empty-hi: #ffffff;
  --flap-empty: #f4f5f7;
  --flap-empty-lo: #e2e5ea;

  --sfp-cols: 25;
  --sfp-font: 1rem;

  background: var(--sfp-housing);
  display: grid;
  grid-template-columns: repeat(var(--sfp-cols), 1fr);
  gap: 2px;
  padding: 0.6rem 0.8rem;
  font-family: var(--sfp-typeface);
  font-size: var(--sfp-font);
  font-weight: 700;
  line-height: 1;
  user-select: none;
  width: 100%;
}

/* ── Tuile « volet unique » (flip-clock) ────────────────────────────────────
   Une tuile est coupée par un axe horizontal en son centre. Elle superpose :
   - .sfp-top / .sfp-bottom : les deux moitiés statiques
   - .sfp-flap : le volet articulé sur l'axe central, posé sur la moitié haute,
     qui pivote de 0° à -180° (chute vers l'avant : recto = haut de l'actuel,
     verso = bas du prochain).
   Chaque face contient un .sfp-glyph (glyphe pleine hauteur) clippé à sa moitié. */
.sfp-tile {
  --sfp-tile-radius: 4px;
  position: relative;
  width: 100%;
  aspect-ratio: 3 / 4;
  border-radius: var(--sfp-tile-radius);
  /* Les faces (moitiés) remplissent la tuile et portent les coins arrondis ;
     inutile de clipper la tuile — le volet peut « sortir » en 3D pendant le flip. */
  perspective: 6em;
  box-shadow: 0 3px 8px -5px rgba(10, 12, 16, 0.55);
}

/* Moitiés statiques : chacune = 50 % de la tuile. */
.sfp-top,
.sfp-bottom {
  position: absolute;
  left: 0;
  right: 0;
  height: 50%;
  overflow: hidden;
  color: var(--glyph);
}

.sfp-top {
  top: 0;
  border-radius: var(--sfp-tile-radius) var(--sfp-tile-radius) 0 0;
  background: linear-gradient(180deg, var(--flap-hi), var(--flap));
}

.sfp-bottom {
  top: 50%;
  border-radius: 0 0 var(--sfp-tile-radius) var(--sfp-tile-radius);
  background: linear-gradient(180deg, var(--flap), var(--flap-lo));
}

/* Faces du volet : elles remplissent le volet (= 50 % de la tuile). */
.sfp-flap-front,
.sfp-flap-back {
  position: absolute;
  inset: 0;
  overflow: hidden;
  color: var(--glyph);
  backface-visibility: hidden;
}

.sfp-flap-front {
  border-radius: var(--sfp-tile-radius) var(--sfp-tile-radius) 0 0;
  background: linear-gradient(180deg, var(--flap-hi), var(--flap));
}

.sfp-flap-back {
  border-radius: var(--sfp-tile-radius) var(--sfp-tile-radius) 0 0;
  background: linear-gradient(180deg, var(--flap), var(--flap-lo));
}

/* Volet VIDE (aucun caractère) : faces claires, se fondent dans le panneau. */
.sfp-top.is-empty,
.sfp-flap-front.is-empty {
  background: linear-gradient(180deg, var(--flap-empty-hi), var(--flap-empty));
}

.sfp-bottom.is-empty,
.sfp-flap-back.is-empty {
  background: linear-gradient(180deg, var(--flap-empty), var(--flap-empty-lo));
}

/* Glyphe pleine hauteur, centré ; chaque face n'en montre que sa moitié. */
.sfp-glyph {
  position: absolute;
  left: 0;
  right: 0;
  height: 200%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.sfp-top .sfp-glyph,
.sfp-flap-front .sfp-glyph {
  top: 0;
}

.sfp-bottom .sfp-glyph,
.sfp-flap-back .sfp-glyph {
  top: -100%;
}

/* Axe central : liseré sombre en travers de la tuile, posé AU-DESSUS du volet
   (le volet pivote derrière). Masqué sur un volet vide, qui reste clair et lisse. */
.sfp-tile::after {
  content: '';
  position: absolute;
  left: 0;
  top: calc(50% - 1px);
  width: 100%;
  height: 2px;
  z-index: 5;
  background: linear-gradient(90deg,
      rgba(0, 0, 0, 0.55),
      rgba(0, 0, 0, 0.22) 20%,
      rgba(0, 0, 0, 0.22) 80%,
      rgba(0, 0, 0, 0.55));
}

.sfp-tile--empty::after {
  opacity: 0;
}

/* Le volet : moitié haute, pivote sur l'axe central (arête basse). */
.sfp-flap {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 50%;
  transform-origin: center bottom;
  transform-style: preserve-3d;
  transform: rotateX(0deg);
  z-index: 2;
}

.sfp-flap-front,
.sfp-flap-back {
  backface-visibility: hidden;
}

.sfp-flap-back {
  transform: rotateX(180deg);
}

.sfp-flap.sfp-flip {
  animation: sfp-flip var(--sfp-flip-dur, 100ms) ease-in forwards;
}

/* Le volet tombe vers l'avant (arête haute qui pique vers le spectateur). */
@keyframes sfp-flip {
  from {
    transform: rotateX(0deg);
  }

  to {
    transform: rotateX(-180deg);
  }
}

.sfp-admin__section form {
  max-width: unset;
}

/* ── Interface d'administration des phrases ─────────────────────────────── */
.sfp-admin {
  max-width: 72ch;
  margin: 0 auto;
  padding: 2rem 1rem 4rem;
  display: flex;
  flex-direction: column;
  gap: 2.5rem;

  h1 {
    margin: 0;
  }

  h2 {
    margin: 0 0 1rem;
    font-size: x-small;
    color: var(--ink-muted);
  }

  .sfp-admin__hint {
    margin: 0.5rem 0 0;
    color: var(--ink-muted);
    font-size: xx-small;
  }

  .sfp-admin__flash {
    background: color-mix(in lab, var(--blue) 12%, var(--bg-card));
    color: var(--blue);
    padding: 0.6rem 0.9rem;
    border-radius: 8px;
    margin: 0;
  }

  .sfp-admin__errors {
    color: #c0392b;
    background: color-mix(in lab, #c0392b 8%, var(--bg-card));
    border-radius: 8px;
    padding: 0.6rem 0.9rem 0.6rem 1.6rem;
    margin: 0 0 0.75rem;
  }

  .sfp-admin__empty {
    color: var(--ink-muted);
    font-style: italic;
  }

  /* Ligne de la liste : aperçu + actions */
  .sfp-admin__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.9rem;
    border: 1px solid var(--input-border);
    border-radius: 12px;
    background: var(--bg-card);
    margin-bottom: 1rem;
  }

  /* Réordonnancement par glisser-déposer (poignée + état pendant le glissé). */
  .sfp-admin__row.is-dragging {
    opacity: 0.4;
  }

  .sfp-admin__row-main {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-width: 0;
  }

  .sfp-admin__grip {
    flex-shrink: 0;
    cursor: grab;
    touch-action: none;
    user-select: none;
    opacity: 0.4;
    font-size: small;
    line-height: 1;
    transition: opacity 120ms;
  }

  .sfp-admin__row:hover .sfp-admin__grip {
    opacity: 0.75;
  }

  .sfp-admin__grip:active {
    cursor: grabbing;
  }

  .sfp-admin__row-actions {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    flex-shrink: 0;
  }

  .sfp-admin__delete {
    margin: 0;
  }

  /* Boutons non-<a> (button_to, liens d'action) */
  .sfp-admin__btn {
    --color: var(--blue);
    cursor: pointer;
    text-decoration: none;
    color: var(--color);
    background-color: color-mix(in srgb, var(--color) 15%, transparent);
    font: inherit;
    padding: 0.4em 0.8em;
    border: none;
    border-radius: 6px;
    transition: background-color 150ms;

    &:hover {
      background-color: color-mix(in srgb, var(--color) 25%, transparent);
    }
  }

  .sfp-admin__btn--danger {
    --color: #c0392b;
  }
}

/* ── Éditeur de disposition (grille de saisie 25×6) ─────────────────────── */
.sfp-editor {
  --sfp-cols: 25;
  margin-bottom: 1rem;

  /* Même largeur que le panneau final (colonne centrale) : on déborde du
     conteneur admin étroit en se recentrant sur la page → aperçu 1:1. */
  width: min(var(--timeline-width), 100vw - 2rem);
  position: relative;
  left: 50%;
  transform: translateX(-50%);

  /* Barre d'outils : pinceau texte + palette + gomme */
  .sfp-editor__palette {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin-bottom: 0.6rem;
  }

  .sfp-editor__swatch {
    width: 1.9rem;
    height: 1.9rem;
    padding: 0;
    border-radius: 6px;
    border: 2px solid var(--input-border);
    background: var(--swatch, var(--bg-card));
    color: var(--ink);
    cursor: pointer;
    font: inherit;
    font-weight: bold;
    line-height: 1;
    transition: transform 100ms, border-color 100ms, box-shadow 100ms;

    &:hover {
      transform: translateY(-1px);
    }

    &.is-active {
      border-color: var(--ink);
      box-shadow: 0 0 0 2px var(--bg-card), 0 0 0 4px var(--ink);
    }
  }

  .sfp-editor__swatch--text,
  .sfp-editor__swatch--erase {
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-card);
    color: var(--ink-muted);
    font-size: x-small;
  }

  .sfp-editor__grid {
    display: grid;
    grid-template-columns: repeat(var(--sfp-cols), 1fr);
    gap: 2px;
    padding: 0.6rem 0.8rem;
    /* identique au panneau (.sfp) pour des cases de même largeur */
    border-radius: var(--radius);
    background: color-mix(in lab, var(--ink) 4%, var(--bg-card));
    touch-action: none;
    /* évite le scroll pendant la peinture au doigt */
  }

  .sfp-editor__cell {
    width: 100%;
    aspect-ratio: 3 / 4;
    min-width: 0;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 2px;
    background: var(--cell-bg, color-mix(in lab, var(--ink) 6%, var(--bg-card)));
    color: var(--ink);
    font-family: var(--sfp-typeface);
    font-weight: 700;
    /* Même taille que le panneau final (posée par split_flap_editor_controller). */
    font-size: var(--sfp-font, 1rem);
    text-align: center;
    line-height: 1;
    box-sizing: border-box;
    transition: border-color 120ms;

    &:focus {
      outline: none;
      border-color: var(--blue);
      box-shadow: inset 0 0 0 1px var(--blue);
    }
  }

  .sfp-editor__toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin: 0.5rem 0 0.25rem;
  }

  .sfp-editor__tools {
    display: flex;
    gap: 1rem;
  }

  .sfp-editor__counter {
    font-size: xx-small;
    color: var(--ink-muted);
    font-variant-numeric: tabular-nums;
  }

  .sfp-editor__clear {
    cursor: pointer;
    font: inherit;
    font-size: xx-small;
    color: var(--ink-muted);
    background: none;
    border: none;
    text-decoration: underline;

    &:hover {
      color: var(--ink);
    }
  }

  .field--position {
    margin-top: 1rem;
    max-width: 12rem;
  }
}

/* ── Aperçu statique d'une disposition ──────────────────────────────────── */
.sfp-preview {
  flex: 1;
  min-width: 0;
  display: grid;
  grid-template-columns: repeat(var(--sfp-cols), 1fr);
  gap: 1px;
  padding: 0.4rem;
  border-radius: 8px;
  background: color-mix(in lab, var(--ink) 4%, var(--bg-card));
  font-family: var(--sfp-typeface);
  font-weight: 700;
  font-size: xx-small;
  line-height: 1;

  .sfp-preview__cell {
    aspect-ratio: 3 / 4;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 1px;
    background: var(--cell-bg, color-mix(in lab, var(--ink) 7%, var(--bg-card)));
    color: var(--ink);
    overflow: hidden;
  }
}
.timeline-section {
  position: relative;
  width: 100%;
  padding: 0.35rem 0 0.4rem;
  box-sizing: border-box;
}

/* ── Scroll horizontal + contenu à largeur pilotée par le zoom ─────────── */
/* Pas de scrollbar : la navigation passe par la minimap et la molette. */
.timeline__scroll {
  position: relative;
  width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
}

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

.timeline__content {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 100%;
  cursor: grab;
  touch-action: none;
  user-select: none;
}

.timeline__content:active {
  cursor: grabbing;
}

.timeline__tracker {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--black);
  pointer-events: none;
  opacity: 0.5;
  z-index: 3;
}

.timeline__tracker.is-locked {
  opacity: 1;
}

/* ── Minimap : fenêtre = navigation, poignées = zoom ──────────────────── */
.timeline__map {
  position: relative;
  height: 12px;
  margin-top: 0.4rem;
  touch-action: none;
  user-select: none;
  cursor: pointer;
}

.timeline__map-strip {
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 4px;
  transform: translateY(-50%);
  border-radius: 2px;
  background: var(--calendar-border);
}

.timeline__map-seg {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: 2px;
  opacity: 0.55;
}

.timeline__map-seg.cat--life {
  background: var(--green);
}

.timeline__map-seg.cat--black {
  background: var(--black);
}

.timeline__map-seg.cat--blue {
  background: var(--blue);
}

.timeline__map-seg.cat--red {
  background: var(--red);
}

.timeline__map-seg.cat--orange {
  background: var(--orange);
}

.timeline__map-window {
  position: absolute;
  top: 0;
  bottom: 0;
  box-sizing: border-box;
  min-width: 12px;
  border: 1px solid var(--white);
  border-radius: 5px;
  background: color-mix(in srgb, var(--white) 10%, transparent);
  cursor: grab;
  transition: background 0.15s;
  box-shadow: 0 0 2px 0px color-mix(in srgb, var(--ink) 50%, transparent);
}

.timeline__map-window:hover {
  background: color-mix(in srgb, var(--gray) 18%, transparent);
}

.timeline__map-window:active {
  cursor: grabbing;
}

.timeline__map-handle {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 12px;
  cursor: ew-resize;
}

.timeline__map-handle--left {
  left: -6px;
}

.timeline__map-handle--right {
  right: -6px;
}

.timeline__map-handle::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 3px;
  height: 8px;
  border-radius: 2px;
  background: var(--gray);
  transform: translate(-50%, -50%);
  opacity: 0;
  transition: opacity 0.15s;
}

.timeline__map:hover .timeline__map-handle::after {
  opacity: 1;
}

.timeline__axis {
  position: relative;
  height: 1em;
  margin-bottom: 0.1rem;
  z-index: 2;
}

.timeline__year {
  position: absolute;
  transform: translateX(-50%);
  font-size: x-small;
  color: var(--gray);
  opacity: 0.6;
  pointer-events: none;
  user-select: none;
  white-space: nowrap;
}

/* ── Grille : trait vertical au début de chaque année ─────────────────── */
.timeline__grid {
  position: absolute;
  top: 1.1em;
  /* sous les labels d'année */
  bottom: 0;
  left: 0;
  right: 0;
  pointer-events: none;
  z-index: 0;
}

.timeline__gridline {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--calendar-border);
  opacity: 0.45;
}

.timeline__line {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin-bottom: 0.2rem;
  position: relative;
  z-index: 1;
}


.timeline__track {
  flex: 1;
  position: relative;
  background: transparent;
  border-radius: 3px;
}

/* ── Segments ─────────────────────────────────────────────────────────── */

.timeline__segment {
  position: absolute;
  border-radius: 2px;
  opacity: 0.3;
  cursor: default;
  transition: opacity 0.15s;
}

.timeline__segment.is-current {
  opacity: 1;
}

.timeline-section.is-show-all .timeline__segment {
  opacity: 1;
}

/* Hover sur un segment de la timeline */
.timeline-section:has(.timeline__segment:hover) .timeline__segment {
  opacity: 0.3;
}

.timeline-section:has(.timeline__segment:hover) .timeline__segment:hover {
  opacity: 1;
}

/* Hover sur une carte d'expérience */
.timeline-section.has-focus .timeline__segment {
  opacity: 0.3;
}

.timeline-section.has-focus .timeline__segment.is-active {
  opacity: 1;
}

/* Couleurs par couleur de l'expérience */
.timeline__segment.cat--life {
  background: var(--green);
}

.timeline__segment.cat--black {
  background: var(--black);
}

.timeline__segment.cat--blue {
  background: var(--blue);
}

.timeline__segment.cat--red {
  background: var(--red);
}

.timeline__segment.cat--orange {
  background: var(--orange);
}

/* ── Événements personnels ────────────────────────────────────────────── */

.timeline__track--events {
  background: transparent;
  height: 0.9rem;
}

.timeline__event-dot {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--gray);
  opacity: 0.4;
  cursor: default;
  transition: opacity 0.15s;
}

.timeline__event-dot:hover {
  opacity: 1;
}

.timeline__event-label {
  position: absolute;
  bottom: calc(100% + 4px);
  left: 50%;
  transform: translateX(-50%);
  font-size: x-small;
  white-space: nowrap;
  color: var(--gray);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s;
}

.timeline__event-dot:hover .timeline__event-label {
  opacity: 1;
}
/**
 * Layout unifié pour la section Astres : soleil | globe | lune en rangée
 * (`.astres-orbit-row`), contrôles (juste le bouton « ici et maintenant » —
 * lieu, date, signes et heure sont sur `.globe-orbit-ring`, pas ici) en
 * dessous. Ni horloge analogique ni compteur du prochain équinoxe/solstice :
 * retirés explicitement (cf. docs/claude/astres.md) — plus de
 * `.astres-clock-container`/`pages/bento/_datetime.html.erb`, supprimé.
 * Chaque pièce restante a une taille PLAFONNÉE (soleil/lune : cf.
 * `.astres-sun-icon` ; globe : cf. `.globe-canvas-wrapper`) — aucune ne
 * grandit plus pour absorber l'espace en trop (flex-grow: 0 partout), pour
 * ne pas reproduire le bug qui laissait le globe (ou sa rangée) gonfler
 * jusqu'à toute la hauteur disponible sur un écran haut, ouvrant un vide
 * entre lui et la lune. Seule `.astres-orbit-row` garde le droit de
 * RÉTRÉCIR (flex-shrink) en dernier recours, sur un écran vraiment trop
 * court — jamais les contrôles (cf. docs/claude/astres.md, « signes astro
 * poussés hors de l'écran ») : `justify-content: center` sur `.astres-screen`
 * centre alors le tout, espace en trop réparti au-dessus/en dessous du
 * groupe entier plutôt qu'à l'intérieur de la rangée.
 *
 * Fusionné avec l'ancien `globe.scss.css` : ce fichier (base du bento globe)
 * n'existe plus séparément — ses règles (préfixe `.globe-*` sans
 * `.astres-…`) ne s'appliquaient de toute façon plus qu'ICI. `pages/bento/
 * _globe.html.erb` (qui pose ces classes) n'est rendu que depuis l'écran
 * astres ; les cartes CV montent le contrôleur globe sans host, donc sans
 * jamais fabriquer ce balisage (cf. docs/claude/astres.md). Les déclarations
 * reprises ci-dessous sont FUSIONNÉES dans les règles `.astres-…` déjà
 * existantes (pas simplement recopiées à côté) : une propriété que l'ancien
 * fichier posait et que ces règles ne recouvraient pas (ex. `flex-shrink` du
 * globe, la couleur de `.globe-date-input`) est intégrée à la règle
 * `.astres-…` correspondante ; une propriété entièrement redéclarée à
 * l'identique ou remplacée y est simplement absente désormais.
 */

:root {
  --globe-ocean: transparent;
  --globe-land: var(--black);
  --globe-land-stroke: var(--black);
  --globe-marker: var(--black);
  --globe-border: var(--black);
}

/* Plus d'horloge ni de compteur d'évènement (retirés explicitement, cf.
   docs/claude/astres.md) : `.astres-screen` n'a plus que la rangée
   soleil | globe | lune et les contrôles (le bouton « ici et maintenant »)
   à empiler — `justify-content: center` centre ce bloc de deux comme un
   tout, la rangée (donc le globe) restant proche du centre de l'écran sans
   qu'un troisième élément (l'ex-horloge) ne soit plus là pour la border en
   haut. */
.astres-screen {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  height: 100%;
  width: 100%;
  position: relative;
  padding: 1rem;
  box-sizing: border-box;
}

.astres-orbit-row {
  flex: 0 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(1rem, 4vw, 3rem);
  width: 100%;

}

/* Sur un téléphone, soleil | globe | lune sur une seule ligne serait trop
   à l'étroit : on repasse en colonne, comme avant l'écran en rangée — trois
   blocs de plus à empiler avec les contrôles, donc un écart resserré et un
   globe encore un peu plus petit qu'en rangée pour que le tout tienne sans
   défiler sur les téléphones les plus compacts (vérifié sur un gabarit
   iPhone SE, 375×667). */
@media (max-width: 30rem) {
  .astres-orbit-row {
    flex-direction: column;
    gap: 0.75rem;
  }

  .astres-globe-container .globe-canvas-wrapper {
    width: 8rem;
    height: 8rem;
  }
}

.astres-sun-container,
.astres-moon-container {
  position: relative;
}

.astres-sun-icon,
.astres-moon-icon {
  display: block;
  width: 8rem;
  height: 8rem;
  mix-blend-mode: multiply;
  /* Le triangle de décan (DECAN_POINT_RADIUS, globe_controller.js) dépasse
     volontairement le `viewBox` (-50..50) pour un écart net avec l'anneau du
     disque — sans ça, l'`overflow: hidden` implicite du <svg> racine le
     rognerait. */
  overflow: visible;
}

/* Triangle du décan (cf. setDecanTriangle, globe_controller.js) : estompé
   par défaut, encre pleine sur `.is-decan-active` — LEQUEL des 3 points
   s'allume dit le décan (1er → la pointe seule, 2e → la base seule, 3e →
   tout, cf. commentaire du <g> dans atelier.html.erb), la rotation posée
   en JS sur le <g> (pas ici) dit si ça pointe vers le haut ou le bas.
   Transitions douces : le flip de pointe et le changement de décan restent
   visibles comme un mouvement plutôt qu'un saut. */
.astres-decan-points {
  transition: transform 0.4s ease;
}

.astres-decan-points circle {
  fill: transparent;
  stroke: var(--ink);
  stroke-width: 1;
  transition: fill 0.3s ease;
}

.astres-decan-points circle.is-decan-active {
  fill: var(--ink);
}

/* Globe : taille ferme posée par .globe-canvas-wrapper plus bas, donc plus
   besoin de grandir pour « remplir » — `flex: 0 1 auto` ne fait que lui
   laisser le droit de rétrécir si la rangée elle-même doit céder de la
   place (cf. commentaire en tête de fichier). */
.astres-globe-container {
  flex: 0 1 auto;
  align-self: stretch;
  display: flex;
  justify-content: center;
}

.astres-globe-container .globe-bento {
  width: 100%;
  display: flex;
  justify-content: center;
}

.astres-globe-container .globe-host,
.astres-globe-container .globe-panel {
  display: flex;
  justify-content: center;
}

/* Ancre pour l'anneau lieu/date (`.globe-orbit-ring`) ET pour sa saisie
   (`.globe-location-wrapper`/`.globe-date-wrapper` plus bas), affichés ICI
   plutôt que dans `.globe-canvas-wrapper` (qui, lui, est `overflow: hidden`
   — rognerait l'anneau, DÉCALÉ au-delà du bord du globe, et l'input dès
   qu'il dépasse le cercle, cf. mountCanvas()). Même boîte que
   `.globe-canvas-wrapper` en pratique : `.globe-panel` ne contient rien
   d'autre que lui. */
.astres-globe-container .globe-panel {
  position: relative;
}

.astres-globe-container .globe-canvas-wrapper {
  /* Taille FERME (pas `100%` d'un ancêtre) : depuis que plus rien ici ne
     force la colonne à une hauteur précise (`.astres-globe-container` est
     `flex: 0 1 auto`, cf. plus haut — il ne grandit plus pour remplir), un
     `height: 100%` en cascade sur `.globe-bento`/`.globe-host`/`.globe-panel`
     se serait résolu à `auto` (pourcentage contre un ancêtre lui-même en
     hauteur `auto`) et aurait fait s'effondrer le globe à une taille
     quasi nulle — `resizeGlobeCanvas()` lit `min(rect.width, rect.height)`
     de CE wrapper, il lui faut donc une taille propre, pas héritée. */
  width: 50rem;
  height: 50rem;
  overflow: hidden;
  /* Empêche le globe d'être compressé par le flex du panneau si jamais
     l'espace vient à manquer — il garde sa taille ferme ci-dessus, quitte à
     déborder plutôt qu'à rétrécir en silence. */
  flex-shrink: 0;
}

.astres-globe-container .globe-canvas-wrapper canvas {
  margin: 0 auto;
}

/* Lieu, date, ascendant, signe solaire : affichés EN COURBE autour du globe
   plutôt que dans les contrôles du bas — groupés par paire, date+lieu au
   NORD (haut), signe solaire+ascendant au SUD (bas), chacun décalé de part
   et d'autre de son pôle (cf. mountCanvas(), globe_controller.js) — ligne de
   base = la circonférence du disque DÉCALÉE vers l'extérieur (ORBIT_RADIUS =
   GLOBE_EDGE_RADIUS + ORBIT_GAP — ORBIT_GAP est LA variable à changer pour
   resserrer/écarter les 4 étiquettes à la fois). L'anneau épouse
   `.globe-panel` (PAS `.globe-canvas-wrapper`, `overflow: hidden` —
   rognerait le décalage) : son cercle grandit/rétrécit avec le globe sans
   synchronisation JS, `viewBox="0 0 100 100"` oblige. */
.globe-orbit-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.globe-orbit-ring .globe-location,
.globe-orbit-ring .globe-date {
  fill: var(--ink);
  font-family: monospace;
  font-weight: bold;
  cursor: pointer;
  pointer-events: auto;
}

/* Signe solaire + ascendant (deux <textPath> qui partagent un point pour
   garder leur flèche fixe, cf. mountCanvas()) et heure, au SUD de l'anneau :
   en toutes lettres/chiffres, même style que lieu/date mais PAS cliquables —
   ce sont des valeurs DÉRIVÉES (de la date/du lieu), rien à éditer dessus
   (`cursor`/`pointer-events` par défaut, hérités de `.globe-orbit-ring`
   ci-dessus, donc pas répétés ici). */
.globe-orbit-ring .globe-solar-sign,
.globe-orbit-ring .globe-ascendant-sign,
.globe-orbit-ring .globe-orbit-time {
  fill: var(--ink);
  font-family: monospace;
  font-weight: bold;
}

/* Contrôles : en bas, centrés. Toujours à leur taille naturelle — c'est le
   globe (flex: 1 ci-dessus) qui cède la place, jamais eux. */
.astres-controls {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

/* Infos du globe — plus qu'un bouton (« ici et maintenant ») depuis que
   lieu/date/signes/heure ont rejoint l'anneau et que l'horloge/le compteur
   d'évènement ont été retirés (cf. docs/claude/astres.md). Le filet du haut
   (border-top/margin-top) sépare visuellement ce bouton de la rangée
   soleil | globe | lune au-dessus. */
.astres-controls .globe-info {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  width: 100%;
  height: 0lh;
}

/* Signe solaire (colonne soleil) et ascendant (colonne lune) : chacun sous
   son astre plutôt qu'ensemble sous le globe (cf. z_astres.scss.css avant
   la rangée soleil/globe/lune). Taille réduite par rapport à l'ancien bloc
   du bas : l'espace disponible à côté du globe est plus étroit. */
.astres-sun-info .globe-detail,
.astres-moon-info .globe-detail {
  color: color-mix(in srgb, var(--ink) 100%, transparent);
  font-size: xxx-large;
  font-family: monospace;
  position: absolute;
  top: calc(50% - 2px);
  left: 50%;
  transform: translate(-50%, -50%);
  mix-blend-mode: multiply;
}

.astres-controls .globe-reset {
  font-size: x-small;
  color: var(--grey);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  font-family: monospace;
  opacity: 0.5;
  margin-top: 0.2rem;

  &:hover {
    opacity: 1;
  }
}

/* Input de lieu ET de date : édités DIRECTEMENT SUR LE GLOBE désormais (cf.
   .globe-orbit-ring plus haut), donc plus scopés à .astres-controls —
   affichés dans `.globe-panel` (cf. mountCanvas()), superposés au centre,
   pile à l'emplacement de l'anneau qu'ils remplacent le temps de la saisie
   (le texte concerné se met en pause, cf. mountCanvas()). */
.globe-location-wrapper,
.globe-date-wrapper {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.globe-location-input,
.globe-date-input {
  font-size: small;
  font-family: monospace;
  background: var(--white--true);
  border: 1px solid var(--calendar-border);
  border-radius: 6px;
  padding: 0.6rem 0.9rem;
  outline: none;
  width: auto;
  min-width: 16rem;
  text-align: center;
  transition: border-color 0.15s ease;
}

/* Le lieu reste en gras/encre pleine, la date en gris — même divergence
   qu'avant leur déplacement sur le globe. */
.globe-location-input {
  font-weight: bold;
  color: var(--ink);
}

.globe-date-input {
  font-weight: 700;
  color: var(--grey);
}

.globe-location-input:focus,
.globe-date-input:focus {
  border-color: var(--ink);
}

.globe-location-suggestions {
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  background: var(--bg-card);
  border: 1px solid var(--grey);
  list-style: none;
  padding: 0;
  margin: 0.25rem 0 0;
  z-index: 100;
  min-width: 16rem;

  li {
    padding: 0.5rem 0.75rem;
    cursor: pointer;
    font-size: small;
    font-family: monospace;
    white-space: nowrap;

    &:hover {
      background: var(--light-grey);
    }
  }
}
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS (and SCSS, if configured) file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *


 */

:root {
  font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  font-size: x-small;
  /* Gouttière de la page : le retrait du contenu par rapport au bord de l'écran.
     Les zones qui se veulent pleine largeur l'annulent par une marge négative
     (cf. .art-zone) — d'où la variable plutôt qu'un 1em recopié de part et
     d'autre : elle tombe à zéro sur petit écran, et la marge négative avec. */
  --page-gutter: 1em;
  /* Gouttière basse : l'air laissé sous le contenu d'une zone, qu'elle borne sa
     hauteur (Art, Design) ou qu'elle défile (les écrans de À Propos). C'était
     autrefois le dégagement des platines de navigation, fixées au bord bas
     (--wheel-clearance, 7rem) ; le plan du site ayant pris leur place, elles ne
     mangent plus l'écran et il ne reste ici qu'un peu d'air. */
  --bottom-clearance: 2rem;
}

* {
  box-sizing: border-box;
}

img {
  -webkit-user-drag: none;
  user-drag: none;
  -moz-user-drag: none;
  user-select: none;
  /* iOS ouvre son propre panneau (« Enregistrer l'image ») au bout d'un appui
     long : c'est exactement le geste par lequel on demande le plan du site
     (site_menu_controller). On lui laisse la main. */
  -webkit-touch-callout: none;
}

body {
  background: var(--bg);
  margin: 0;
  padding: var(--page-gutter);
}

/* Transition douce du contenu de zone (art/design/moi/cv/labo) à chaque
   navigation Turbo : sans elle, le contenu apparaît d'un coup (« refresh »
   brut) alors que le header, lui, reste en place (`data-turbo-permanent`).
   `@starting-style` fait fondre en fondu l'élément fraîchement inséré, sans
   JS — dégradation silencieuse sur les navigateurs qui ne le supportent pas
   encore (le contenu apparaît alors directement, comme avant). */
[data-current-zone] {
  opacity: 1;
  transition: opacity 0.28s ease, transform 0.28s ease;
}

@starting-style {
  [data-current-zone] {
    opacity: 0;
    transform: translateY(6px);
  }
}

/* SANS ENTRÉE (1er oct. 2026) : d'un dessin de l'accueil rangé à son show, et
   retour, le fond est le même (les papiers japonais) et le dessin est tenu par sa
   copie (controllers/passage) — la zone qui arrive n'a rien à faire paraître :
   elle est là d'un coup. Posée par art_carousel_controller (`sans-vol`) et
   envol_controller (`_regagner`) à la connexion, avant la première image. */
[data-current-zone].sans-entree {
  transition: none;
}

a.link {
  text-decoration: none;
  color: var(--blue);
  font-weight: bold;
}

a.btn {
  --color: var(--blue);
  position: relative;
  text-decoration: none;
  color: var(--color);
  z-index: 1;
  background-color: color(from var(--color) srgb r g b / 0.15);
  font-size: large;
  padding: 0.25em 0.5em;
  border-radius: 4px;
  transition: background-color 150ms;

  &:hover {
    background-color: color(from var(--color) srgb r g b / 0.25);
  }
}

div:has(.bento) {
  display: flex;
  gap: 1ex;
  flex-wrap: wrap;
}

.bento {
  display: flex;
  flex-direction: column;
  background: var(--bg-card);
  border-radius: var(--radius);
  position: relative;
  padding: 1em;
}

/* Bouton d'édition admin, en surimpression d'un bento */
.bento__edit {
  position: absolute;
  top: 0.6em;
  right: 0.6em;
  z-index: 40;
  width: 1.8em;
  height: 1.8em;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: color-mix(in lab, var(--bg-card) 75%, transparent);
  font-size: xx-small;
  text-decoration: none;
  color: inherit;
  opacity: 0.35;
  transition: opacity 150ms;
}
.bento:hover .bento__edit {
  opacity: 0.7;
}
.bento__edit:hover {
  opacity: 1 !important;
}

@media (max-width: 48rem) {
  main {
    box-shadow: none;
    border-radius: 0rem;
  }

  /* Pleine largeur : plus de gouttière — et donc plus rien à annuler chez les
     zones qui débordaient volontairement dessus. */
  :root {
    --page-gutter: 0px;
  }
}

