/* ==========================================================================
   KokoroWorks — Acte III · Le Livre
   Un grimoire ancien dans la pénombre d'un atelier. Par défaut (noscript,
   reduced-motion, mobile), ses pages sont posées à plat : un manuscrit
   complet, lisible, accompli. Sous html.cinema, le livre se referme en 3D
   et le scroll devient la main du lecteur.
   ========================================================================== */

:root {
  --atelier: #241B26;
  --bois: #2E2118;
  --cuir: #4E2230;
  --cuir-sombre: #341721;
  --or: #E2BE7F;
  --or-clair: #F6E27A;
  --or-sombre: #9C7328;
  --papier-livre: #F7EBD7;
  --papier-ombre: #E4D2B4;
  --brunissure: #7A5428;
  --rousseur: #A9713D;
  --encre-livre: #4A3527;
  --encre-livre-douce: #79604B;
  --page-h: min(78svh, 730px);
  --page-w: min(37vw, calc(var(--page-h) * .74));
}

body {
  background: var(--atelier);
  color: var(--encre-livre);
}
.grain { opacity: .22; }

/* ==========================================================================
   Le seuil — la nuit entière, devenue portail.
   Pendant la charge et l'attente : noir profond, une seule faible lueur DOM
   (.seuil-lueur) qui s'éveille quand le monde est prêt. L'entrée, la levée
   du voile et la marche sont pilotées par livre.js.
   ========================================================================== */
.seuil { display: none; }
html.js .seuil {
  display: block;
  position: fixed;
  inset: 0;
  z-index: 200;
  overflow: hidden;
}
/* le voile de nuit, séparé du seuil : la nuit reste entière pendant toute
   l'attente — rien du monde ne se montre, seule la petite lueur DOM
   respire. C'est le geste d'entrée qui pose est-entrouvert : le voile se
   fond alors en 3 s et la grotte émerge lentement sous la floraison */
.seuil-voile {
  position: absolute;
  inset: 0;
  /* un noir de nuit profond, à peine violacé au centre */
  background: radial-gradient(120vw 110svh at 50% 46%, #0B0810 30%, #020103 78%);
  transition: opacity 3s ease;
}
.seuil.est-entrouvert .seuil-voile { opacity: 0; }
/* le statut du chargement : pour les lecteurs d'écran seulement */
.seuil-statut {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.seuil-passer {
  position: absolute;
  /* à gauche : le bas droite est réservé à la pastille son qui suivra */
  left: clamp(16px, 3vw, 40px);
  bottom: 6svh;
  padding: .55em 1.1em;
  border: 1px solid rgba(246, 239, 231, .4);
  border-radius: 999px;
  background: rgba(15, 10, 18, .55);
  color: #F6EFE7;
  font: inherit;
  font-size: .92rem;
  cursor: pointer;
}
.seuil-passer:hover, .seuil-passer:focus-visible { border-color: #F6EFE7; }
/* pendant la marche : le bouton a quitté le seuil (détruit après l'entrée)
   et vit sur le body, posé au-dessus de la scène comme la pastille son —
   il naît ici (invisible avant la marche), d'où le fondu d'arrivée */
.seuil-passer.est-hors-seuil {
  position: fixed;
  z-index: 110;
  animation: seuil-passer-entre .9s ease-out both;
}
@keyframes seuil-passer-entre { from { opacity: 0; } }

/* ---- La lueur qui attend : le seuil devient portail ----
   Chargé, le monde ne se donne plus tout seul : la lueur respire, une
   invitation murmure, et c'est le geste du visiteur qui lève la nuit —
   le même geste débloque la musique (musique.js). */
.seuil-lueur {
  position: absolute;
  left: 50%; top: 46%;
  width: min(34vmin, 260px);
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  /* couleurs en dur : sur le seuil, --lueur fut jadis un nombre de
     progression — pas question qu'un réglage JS invalide ce dégradé */
  background: radial-gradient(circle,
    #FFFEF8 0%,
    #FFE9C0 22%,
    rgba(255, 211, 168, .55) 48%,
    transparent 72%);
  filter: blur(10px);
  mix-blend-mode: screen;
  /* pendant le chargement : une présence à peine — la nuit domine */
  opacity: .3;
  scale: .45;
  pointer-events: none;
  transition: opacity 1.2s var(--allume), scale 1.6s var(--allume);
}
/* le monde est prêt : la lueur s'éveille — faible toujours — et respire */
.seuil.est-en-attente .seuil-lueur {
  opacity: .55;
  scale: 1;
  animation: seuil-respire 4s ease-in-out 1.6s infinite;
}
@keyframes seuil-respire {
  0%, 100% { scale: 1; opacity: .55; }
  50%      { scale: 1.12; opacity: .75; }
}
/* la floraison : au geste d'entrée, la lumière s'ouvre lentement pendant
   que le voile se fond — la grotte émerge dans son halo */
.seuil.est-fleuri .seuil-lueur { animation: seuil-fleurit 3s var(--allume) forwards; }
@keyframes seuil-fleurit {
  to { scale: 5; opacity: .95; filter: blur(30px); }
}

/* ---- La vie de la lueur : l'appel, puis la volée ----
   Les conteneurs sont dans le markup (index.html) ; livre.js sème leurs
   enfants <i> et leurs variables aléatoires (semerVieDuSeuil) — ici le CSS
   fait tout le mouvement. Rien ne s'anime avant est-en-attente : la fenêtre
   de préchargement garde un budget d'effets zéro. Couleurs en dur, comme la
   lueur (voir plus haut : --lueur a une autre vie JS sur cet écran). */

/* le voile irisé : une seconde couche de halo, plus large et plus faible,
   qui dérive lentement — le bord de la lueur devient organique. Cinéma
   seulement : le halo mobile reste le dégradé simple. */
.seuil-voile-irise {
  display: none;
  position: absolute;
  left: 50%; top: 46%;
  width: min(54vmin, 420px);
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(255, 211, 168, .28) 0%,
    rgba(255, 190, 180, .14) 45%,
    transparent 70%);
  filter: blur(18px);
  mix-blend-mode: screen;
  opacity: 0;
  pointer-events: none;
  transition: opacity 2s var(--allume);
}
html.cinema .seuil-voile-irise { display: block; }
.seuil.est-en-attente .seuil-voile-irise {
  opacity: 1;
  animation: seuil-irise 9s ease-in-out infinite alternate;
}
@keyframes seuil-irise {
  from { translate: calc(-50% - 1.5vmin) calc(-50% + 1vmin); scale: .96; }
  to   { translate: calc(-50% + 1.5vmin) calc(-50% - 1vmin); scale: 1.05; }
}

/* l'appel : des poussières d'or naissent aux confins de la nuit et dérivent
   vers la lueur, comme aspirées — elles s'éteignent juste avant de toucher
   le cœur. Les conteneurs sont des points ancrés sur le centre-lueur ;
   chaque enfant se place par rotation + distance. */
.seuil-appel, .seuil-volee {
  position: absolute;
  left: 50%; top: 46%;
  mix-blend-mode: screen;
  pointer-events: none;
}
.seuil-appel i {
  position: absolute;
  left: 0; top: 0;
  width: var(--taille, 4px);
  aspect-ratio: 1;
  margin: calc(var(--taille, 4px) / -2);
  border-radius: 50%;
  background: #FFE2B0;
  box-shadow: 0 0 8px 2px rgba(255, 224, 160, .35);
  opacity: 0;
  transform: rotate(var(--angle, 0deg)) translateY(calc(-1 * var(--d0, 38vmin)));
}
.seuil.est-en-attente .seuil-appel i {
  animation: seuil-appel var(--duree, 10s) ease-in var(--retard, 0s) infinite;
}
@keyframes seuil-appel {
  0%   { opacity: 0; transform: rotate(var(--angle, 0deg)) translateY(calc(-1 * var(--d0, 38vmin))); }
  18%  { opacity: var(--op, .6); }
  86%  { opacity: calc(var(--op, .6) * .7); }
  100% { opacity: 0; transform: rotate(var(--angle, 0deg)) translateY(-3vmin); }
}

/* la volée : au geste d'entrée, la lueur expulse ses graines de lumière —
   le miroir des .graines du grimoire (ici la lumière donne, là-bas elle
   rassemble). Départ vif, longue décélération : un souffle, pas une
   explosion. Tout est retombé à ~1,6 s, bien avant la destruction du seuil. */
.seuil-volee i {
  position: absolute;
  left: 0; top: 0;
  width: var(--taille, 9px);
  aspect-ratio: 1;
  margin: calc(var(--taille, 9px) / -2);
  border-radius: 50%;
  background: radial-gradient(circle at 42% 38%, #FFFEF6, #FFE9B0 55%, rgba(244, 190, 120, 0) 78%);
  box-shadow: 0 0 12px 3px rgba(255, 224, 160, .55);
  opacity: 0;
}
.seuil.est-fleuri .seuil-volee i {
  animation: seuil-volee 1.4s cubic-bezier(.15, .75, .3, 1) forwards;
}
@keyframes seuil-volee {
  0%   { opacity: 1; transform: rotate(var(--angle, 0deg)) translateY(0); }
  66%  { opacity: .9; }
  100% { opacity: 0; transform: rotate(var(--angle, 0deg)) translateY(calc(-1 * var(--dist, 26vmin))); }
}

/* l'onde : un seul anneau fin qui s'étend et s'éteint — la deuxième serait
   du spectacle de trop */
.seuil-onde {
  position: absolute;
  left: 50%; top: 46%;
  width: min(34vmin, 260px);
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  border: 2px solid rgba(255, 211, 168, .6);
  filter: blur(4px);
  mix-blend-mode: screen;
  opacity: 0;
  pointer-events: none;
}
.seuil.est-fleuri .seuil-onde { animation: seuil-onde 1.2s ease-out forwards; }
@keyframes seuil-onde {
  from { opacity: .5; scale: 1; }
  to   { opacity: 0; scale: 5; }
}

/* au toucher, la floraison avale le reste : les poussières d'appel
   s'effacent en plein vol (leurs boucles continuent, invisibles, jusqu'à la
   destruction du seuil — aucun saut à couvrir), le voile irisé se fond */
.seuil.est-fleuri .seuil-appel { opacity: 0; transition: opacity .4s ease; }
.seuil.est-fleuri .seuil-voile-irise { opacity: 0; transition: opacity 1s ease; }

/* l'invitation : un bouton plein écran invisible — toute la nuit est la
   cible, la lueur n'est que le point focal */
.seuil-entrer {
  position: absolute;
  inset: 0;
  background: none;
  border: 0;
  cursor: pointer;
  font: italic 400 clamp(1rem, 2.2vw, 1.25rem) var(--famille-plume);
  letter-spacing: .14em;
  color: #F6EFE7;
  display: grid;
  place-items: end center;
  padding-bottom: 32svh;
}
.seuil-entrer:focus-visible { outline-offset: -6px; }
.seuil-entrer span {
  opacity: 0;
  translate: 0 8px;
  transition: opacity 1.4s var(--allume) .8s, translate 1.4s var(--allume) .8s;
}
.seuil.est-en-attente .seuil-entrer span { opacity: .92; translate: 0 0; }
.seuil.est-fleuri .seuil-entrer span { opacity: 0; transition: opacity .3s ease; }

@media (prefers-reduced-motion: reduce) {
  html.js .seuil { display: none; } /* le manuscrit à plat est leur état final : rien à masquer */
}
body.seuil-actif { overflow: hidden; }
/* la nuit qui se dissout ne doit plus rien intercepter : sans ça, un clic
   sur la pastille son pendant le fondu atterrit sur le seuil (z-index 200)
   et passerLaMarche écourte la marche au lieu de basculer la musique */
.seuil.est-leve { opacity: 0; transition: opacity 2.6s ease; pointer-events: none; }

/* le monde d'abord : la nav n'apparaît qu'une fois arrivé au grimoire.
   body > header : le sélecteur nu `header` attrapait aussi les .page-entete
   du livre — et sa transition d'opacité luttait contre leurs révélations. */
body.intro-en-cours > header {
  opacity: 0;
  pointer-events: none;
}
/* la feuille de la nav attend un souffle plus haut : au retrait de la
   classe, elle est DÉPOSÉE — elle descend (translate, 1.2s --pose,
   kokoro.css) pendant que l'opacité monte. */
body.intro-en-cours .nav { translate: 0 -14px; }
/* et la luciole du curseur attend elle aussi la sortie de la grotte */
body.intro-en-cours .luciole-curseur { visibility: hidden; }
html.cinema body > header { transition: opacity .9s ease; }

/* le jaillissement : la lumière qui sourd du grimoire quand le regard se
   pose sur lui — un cœur radiant qui pulse, des rais divins en rotation
   lente, un anneau rose mystique. Le conteneur est gonflé par GSAP ;
   mix-blend-mode screen : la lumière n'assombrit jamais la scène. */
.jaillissement {
  position: absolute;
  left: 50%; top: 50%;
  width: min(64vw, 980px);
  aspect-ratio: 1;
  translate: -50% -50%;
  opacity: 0;
  pointer-events: none;
  mix-blend-mode: screen;
}
.jaillissement::before {
  /* le cœur : blanc chaud, respiration courte */
  content: '';
  position: absolute;
  inset: 18%;
  border-radius: 50%;
  background: radial-gradient(circle,
    #FFFEF8 12%,
    #FFE9C0 38%,
    rgba(255, 196, 150, .6) 60%,
    transparent 76%);
  filter: blur(6px);
}
.jaillissement-rais {
  /* les rais : un soleil d'aquarelle qui tourne à peine */
  position: absolute;
  inset: -4%;
  border-radius: 50%;
  background: repeating-conic-gradient(from 0deg,
    rgba(255, 240, 210, 0) 0deg 9deg,
    rgba(255, 236, 200, .5) 12deg 15deg,
    rgba(255, 240, 210, 0) 18deg 24deg);
  -webkit-mask-image: radial-gradient(circle, #000 16%, rgba(0, 0, 0, .45) 46%, transparent 72%);
          mask-image: radial-gradient(circle, #000 16%, rgba(0, 0, 0, .45) 46%, transparent 72%);
}
.jaillissement::after {
  /* l'anneau mystique, rosé comme les sakuras */
  content: '';
  position: absolute;
  inset: 5%;
  border-radius: 50%;
  background: radial-gradient(circle,
    transparent 52%,
    rgba(255, 214, 235, .5) 60%,
    rgba(244, 169, 184, .26) 67%,
    transparent 75%);
  filter: blur(4px);
}
@media (prefers-reduced-motion: no-preference) {
  /* limitées à l'intro : infinies, elles continuaient d'animer un halo
     invisible après la coupe et retenaient sa couche au compositeur */
  body.intro-en-cours .jaillissement::before { animation: jaillissement-pouls 1.1s ease-in-out infinite alternate; }
  body.intro-en-cours .jaillissement-rais { animation: jaillissement-tourne 8s linear infinite; }
  @keyframes jaillissement-pouls {
    from { transform: scale(.94); }
    to   { transform: scale(1.06); }
  }
  @keyframes jaillissement-tourne {
    to { rotate: 1turn; }
  }
}

/* le recueillement : l'inspiration avant l'éclat. La clairière s'assombrit
   et seul le grimoire reste dans la lumière — le trou du dégradé est centré
   sur le livre peint (ancrage x/y posé par livre.js à chaque frame).
   Dimensionné au plus juste (150vmax : demi-diagonale du viewport + marge
   de décentrage) — plus grand, sa texture composite pèse sur le budget
   GPU et fait scintiller les autres couches. */
.recueillement {
  position: absolute;
  left: 50%; top: 50%;
  width: 150vmax;
  aspect-ratio: 1;
  translate: -50% -50%;
  opacity: 0;
  pointer-events: none;
  background: radial-gradient(circle,
    transparent 7%,
    rgba(30, 16, 28, .38) 17.5%,
    rgba(24, 12, 22, .52) 35%,
    rgba(20, 10, 20, .58) 100%);
}

/* les graines de lumière : la poussière d'or du grimoire. Le conteneur est
   ancré et dimensionné sur le livre peint (livre.js) ; chaque graine est
   positionnée en % du conteneur et animée par la marche. */
.graines {
  position: absolute;
  left: 50%; top: 50%;
  width: min(64vw, 980px);
  aspect-ratio: 1;
  translate: -50% -50%;
  pointer-events: none;
  mix-blend-mode: screen;
}
.graines i {
  position: absolute;
  left: 50%; top: 50%;
  width: 9px;
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  opacity: 0;
  background: radial-gradient(circle at 42% 38%, #FFFEF6, #FFE9B0 55%, rgba(244, 190, 120, 0) 78%);
  box-shadow: 0 0 12px 3px rgba(255, 224, 160, .55);
}
.graines i:nth-child(3n) { width: 6px; }
.graines i:nth-child(4n) { width: 12px; box-shadow: 0 0 16px 5px rgba(255, 224, 160, .5); }

/* l'éblouissement : le voile de lumière chaude qui couvre le passage du
   seuil de la grotte (la bascule de tableau se fait sous lui) */
.eblouissement {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
  background: radial-gradient(90vw 80svh at 50% 44%, #FFF9EC 38%, #FFE9C4 62%, rgba(255, 214, 170, .9) 100%);
}

/* ==========================================================================
   Le monde de Kokomi — la clairière aux cerisiers, et ses habitants
   ========================================================================== */
.atelier { position: fixed; inset: 0; z-index: 0; pointer-events: none; }

/* La pile multiplane : chaque calque est un div à fond WebP, injecté par
   livre.js (cinéma seulement). Tous partagent le même cadrage cover centré :
   la composition peinte reste enregistrée entre calques, quel que soit le
   viewport. Animés en transform/opacity uniquement (compositor). */
.calques { position: absolute; inset: 0; }
/* le canvas du monde WebGL (monde.js) remplit son conteneur */
.calques canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}
/* .calque : chemin de secours DOM statique, sans WebGL */
.calque {
  position: absolute;
  inset: -3%;
  background: center / cover no-repeat;
}
/* la promotion GPU ne vaut que pendant la marche : promue en permanence,
   la pile (16 calques plein écran) déborde le budget de textures et Chrome
   évince/re-rasterise en boucle — c'est le clignotement de la V1 */
body.intro-en-cours .theatre { will-change: transform, opacity; }
/* tant que le livre est clos, il est rendu À PLAT : la 3D (perspective +
   preserve-3d) ne sert qu'à l'ouverture des pages. Fermé, ses feuilles
   coplanaires se disputent le test de profondeur au moindre mouvement
   (le « livre qui clignote » pendant la lutte) — et pendant la marche,
   l'aplatissement évite la re-rasterisation du sous-arbre à chaque frame.
   La classe tombe sous le blanc de l'éclat, juste avant la révélation du
   théâtre (livre.js) : la 3D doit être en place AVANT que le grimoire se
   montre — une perspective qui s'allume plus tard se voit (c'est un coup).
   Le grimoire arrive DROIT (rotationX 0, livre.js) et ne prend ses 7° que
   pendant la descente de la feuille, en douceur. L'état clos reste sûr :
   est-clos garde feuilles et page finale hors rendu, et la lutte borne
   déjà son élastique pour la 3D. */
body.livre-plat .scene-livre { perspective: none; }
body.livre-plat .theatre,
body.livre-plat .livre { transform-style: flat; }
/* livre (quasi) clos : les feuilles ET la page finale statique sortent de
   l'arbre de rendu — la couverture les cache de toute façon, et ce qui
   n'est pas rendu ne peut pas clignoter. La page finale surtout : statique
   à z≈0, elle est coplanaire avec la couverture qui se referme, et c'est
   elle qui flashait à travers (z-fighting en preserve-3d). */
html.cinema .livre.est-clos .feuille,
html.cinema .livre.est-clos .page-finale { visibility: hidden; }
/* fond de secours si les calques manquent (échec réseau) : un lavis chaud */
html.cinema .calques {
  background: linear-gradient(#F7E9DC 20%, #EFD9C4 60%, #DCC5A8 100%);
}
.monde-vignette {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse at 50% 50%, transparent 60%, rgba(0, 0, 0, .28) 100%);
}

/* le bestiaire d'ambiance (papillons, fée, pétales, lucioles, rais…) vit
   dans ambiances.css, semé scène par scène par ambiances.js */

/* ==========================================================================
   Le papier — la page de manuscrit (commune aux deux mondes)
   ========================================================================== */
.page {
  position: relative;
  /* le parchemin vécu : lumière du haut, taches d'humidité, double passe de
     grain (480px + 280px en multiply — la répétition de tuile se casse),
     posé sur une base réchauffée. La couleur vient en dernier : même avant
     les images, jamais de blanc neuf */
  background:
    radial-gradient(120% 100% at 50% 0%, rgba(255, 252, 244, .5), transparent 60%),
    url('../assets/textures/taches.webp'),
    url('../assets/textures/parchemin.webp'),
    url('../assets/textures/parchemin.webp')
    color-mix(in srgb, var(--papier-livre) 84%, var(--papier-ombre));
  background-size: auto, 720px, 280px, 480px;
  background-position: 0 0, var(--decal-taches, 0 0), 0 0, 0 0;
  background-blend-mode: normal, multiply, multiply, normal;
  color: var(--encre-livre);
  padding: clamp(26px, 4vw, 52px) clamp(22px, 3.6vw, 48px) clamp(40px, 5vw, 60px);
  box-shadow: 0 18px 50px rgba(8, 5, 10, .5);
  overflow: hidden;
}
/* le vieillissement : bords brûlés, auréoles, rousseurs. Rangé dans une
   variable : sous cinéma, l'ombre du pli s'empile dessus dans le même
   ::after au lieu de l'écraser (voir les règles --pli plus bas) */
.page {
  --vieillissement:
    radial-gradient(46% 34% at 96% 4%, color-mix(in srgb, var(--brunissure) 30%, transparent), transparent 70%),
    radial-gradient(40% 30% at 2% 88%, color-mix(in srgb, var(--brunissure) 26%, transparent), transparent 70%),
    radial-gradient(26% 18% at 78% 96%, rgba(138, 100, 50, .2), transparent 70%),
    radial-gradient(14% 10% at 22% 12%, rgba(138, 100, 50, .18), transparent 70%),
    /* les rousseurs : l'âge pique les marges, jamais la zone de lecture */
    radial-gradient(2.6% 2% at calc(5% + var(--saut-rousseurs, 0%)) 22%, color-mix(in srgb, var(--rousseur) 55%, transparent), transparent 72%),
    radial-gradient(1.7% 1.3% at 7% calc(64% - var(--saut-rousseurs, 0%)), color-mix(in srgb, var(--rousseur) 45%, transparent), transparent 72%),
    radial-gradient(2.2% 1.7% at 94% calc(18% + var(--saut-rousseurs, 0%)), color-mix(in srgb, var(--rousseur) 50%, transparent), transparent 72%),
    radial-gradient(1.4% 1.1% at calc(92% - var(--saut-rousseurs, 0%)) 55%, color-mix(in srgb, var(--rousseur) 42%, transparent), transparent 72%),
    radial-gradient(2% 1.5% at 95% 83%, color-mix(in srgb, var(--rousseur) 48%, transparent), transparent 72%),
    radial-gradient(1.6% 1.2% at 38% 4.5%, color-mix(in srgb, var(--rousseur) 40%, transparent), transparent 72%),
    radial-gradient(2.1% 1.6% at calc(30% + var(--saut-rousseurs, 0%)) 95%, color-mix(in srgb, var(--rousseur) 45%, transparent), transparent 72%);
}
.page::after {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  background: var(--vieillissement);
  box-shadow: inset 0 0 96px color-mix(in srgb, #926C3A 40%, transparent),
              inset 0 0 32px color-mix(in srgb, var(--brunissure) 32%, transparent),
              inset 0 0 6px rgba(94, 62, 28, .38);
}
/* deux pages voisines ne partagent jamais leur usure : chaque feuille
   décale ses taches et ses rousseurs (les variables héritent aux .page) */
.feuille[data-feuille="2"] { --decal-taches: 42% 26%; --saut-rousseurs: 2.2%; }
.feuille[data-feuille="3"] { --decal-taches: 18% 64%; --saut-rousseurs: -1.6%; }
.feuille[data-feuille="4"] { --decal-taches: 66% 12%; --saut-rousseurs: 1.1%; }
.page-finale { --decal-taches: 30% 80%; --saut-rousseurs: -2.4%; }
/* la garde est un ex-libris, pas une page de lecture : l'âge s'y fait discret */
.couverture-garde::after { opacity: .55; }
.page-droite { border-radius: 3px 12px 12px 3px; }
.page-gauche { border-radius: 12px 3px 3px 12px; }
.page-droite::before { /* l'ombre de la reliure */
  content: '';
  position: absolute; top: 0; bottom: 0; left: 0; width: 9%;
  background: linear-gradient(90deg, color-mix(in srgb, #8A6B45 30%, transparent), transparent);
  pointer-events: none;
}
.page-gauche::before {
  content: '';
  position: absolute; top: 0; bottom: 0; right: 0; width: 9%;
  background: linear-gradient(-90deg, color-mix(in srgb, #8A6B45 30%, transparent), transparent);
  pointer-events: none;
}

/* le fleuron d'angle des pages de droite — discret, comme poinçonné */
.page-droite .page-entete::before {
  content: '';
  position: absolute;
  top: clamp(10px, 1.6svh, 18px);
  right: clamp(10px, 1.6svh, 18px);
  width: 40px; height: 40px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40'%3E%3Cpath d='M38 2 C30 4 26 4 22 8 M38 2 C36 10 36 14 32 18' fill='none' stroke='%239C7328' stroke-width='1.4' stroke-linecap='round'/%3E%3Cpath d='M28 7 C31 4 35 6 34 10 C33 13 29 13 28 10' fill='none' stroke='%239C7328' stroke-width='1.2'/%3E%3Ccircle cx='23' cy='15' r='1.3' fill='%239C7328'/%3E%3C/svg%3E") no-repeat center / contain;
  opacity: .5;
  pointer-events: none;
}

.page-entete { text-align: center; margin-bottom: clamp(14px, 2.4svh, 26px); }
.page-entete .fleuron {
  display: block;
  font-size: 1.3rem;
  color: var(--or-sombre);
  margin-bottom: var(--s2);
}
.page-entete h2 {
  font-size: clamp(1.5rem, 2.2vw, 2.1rem);
  letter-spacing: .02em;
  color: var(--encre-livre);
}
.page-entete::after {
  content: '';
  display: block;
  width: 120px; height: 3px;
  margin: var(--s3) auto 0;
  background: linear-gradient(90deg, transparent, var(--or-sombre) 20%, var(--or) 50%, var(--or-sombre) 80%, transparent);
  border-radius: 2px;
}

.page-texte {
  font-size: calc(clamp(.94rem, .55vw + .72rem, 1.08rem) * var(--echelle-manuscrit, 1));
  line-height: 1.62;
  font-weight: 600;
}
.page-texte p + p { margin-top: var(--s4); }
.page-texte em { font-family: var(--famille-plume); font-style: italic; color: var(--framboise-encre); }
.page-studio { color: var(--encre-livre-douce); font-size: .92em; }

/* les versions courtes : le petit paysage remplace certains textes longs
   par une variante resserrée — même histoire, moins d'encre (la bascule
   vit dans le bloc petit paysage, en fin de fichier) */
.texte-court { display: none; }
/* les mots semés par le fil d'écriture (livre.js) : inline-block pour
   porter transform et filter, les blancs entre eux font la césure */
.mot { display: inline-block; }
/* la migration de mise en page : ce que le petit paysage cache (paysage-cache)
   ou révèle (paysage-seul) — l'équipe se répartit sur les deux pages.
   Classe doublée : le masquage doit gagner sur les display posés ailleurs
   (.roles { display: grid } arrive plus bas), quel que soit l'ordre. */
.paysage-seul.paysage-seul { display: none; }

/* la lettrine — la première lettre enluminée */
.lettrine > p:first-child::first-letter,
.lettrine-seule::first-letter {
  font-family: var(--famille-plume);
  font-weight: 620;
  font-size: 3.1em;
  line-height: .82;
  float: inline-start;
  padding-block: .04em 0;
  padding-inline: 0 .12em;
  color: var(--framboise-encre);
  text-shadow: 1px 1px 0 color-mix(in srgb, var(--or) 55%, transparent);
}

.page-essence {
  text-align: center;
  font-size: calc(clamp(1.05rem, 1.4vw, 1.3rem) * var(--echelle-manuscrit, 1));
  margin-bottom: var(--s4);
}

.valeurs {
  margin: clamp(14px, 2.4svh, 24px) 0 0;
  padding: 0;
  list-style: none;
  font-size: .92em;
  display: grid;
  gap: var(--s2);
}
.valeurs li::before { content: '❧ '; color: var(--or-sombre); }
.valeurs strong { font-family: var(--famille-plume); font-weight: 620; }

.roles { margin: var(--s4) 0 0; display: grid; gap: var(--s3); }
.roles dt {
  font-family: var(--famille-plume);
  font-weight: 620;
  font-size: calc(1.02rem * var(--echelle-manuscrit, 1));
}
.roles dd {
  margin: 0;
  color: var(--encre-livre-douce);
  font-size: calc(.9rem * var(--echelle-manuscrit, 1));
  padding-bottom: var(--s2);
  border-bottom: 1px dotted color-mix(in srgb, var(--encre-livre-douce) 40%, transparent);
}
.page-note {
  margin-top: var(--s4);
  font-size: .78rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--encre-livre-douce);
}

/* le sceau se pose au centre, à sa taille de cire — jamais étiré sur toute
   la largeur par la colonne flex des pages cinéma */
.cta-page { margin-top: clamp(14px, 2.6svh, 26px); align-self: center; }
html:not(.cinema) .cta-page { display: flex; width: fit-content; margin-inline: auto; }
.page-adresse {
  display: block;
  margin-top: var(--s2);
  text-align: center;
  font-size: .9rem;
  color: var(--encre-livre-douce);
}

.folio {
  position: absolute;
  bottom: clamp(12px, 2svh, 20px);
  left: 50%;
  translate: -50% 0;
  font-family: var(--famille-plume);
  font-style: italic;
  font-size: .85rem;
  color: var(--encre-livre-douce);
}

/* les planches (pages de gauche) */
.planche { margin: 0; text-align: center; width: 100%; }
.gravure {
  position: relative;
  margin: 0 auto;
  width: min(88%, 440px);
  padding: 10px;
  background: color-mix(in srgb, var(--papier-ombre) 55%, var(--papier-livre));
  border: 1px solid color-mix(in srgb, var(--encre-livre-douce) 45%, transparent);
  box-shadow: inset 0 0 0 3px var(--papier-livre),
              inset 0 0 0 4px color-mix(in srgb, var(--or-sombre) 60%, transparent);
}
.gravure svg { display: block; width: 100%; height: auto; }
/* les planches photographiques (captures des apps) : même geste que les
   gravures dessinées — l'image emplit le cadre, la marie-louise fait le reste */
.gravure img { display: block; width: 100%; height: auto; }
.gravure-nuit { background: #241B26; }
.gravure-nuit svg { padding: 8%; }
.planche figcaption {
  margin-top: var(--s4);
  font-family: var(--famille-plume);
  font-style: italic;
  font-size: .95rem;
  color: var(--encre-livre-douce);
}
.planche-kokomi {
  position: absolute;
  right: 4%;
  bottom: 12%;
  width: clamp(70px, 7vw, 110px) !important;
  height: auto !important;
  rotate: 4deg;
  filter: drop-shadow(0 6px 14px rgba(40, 20, 10, .4));
}
.planche { position: relative; }

.portraits {
  position: relative; /* le plan des étincelles du survol (livre.js) */
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(10px, 1.6vw, 20px);
  max-width: 82%;
  margin: 0 auto;
}
.portraits img {
  width: 100%;
  border-radius: 50%;
  border: 3px double color-mix(in srgb, var(--or-sombre) 75%, transparent);
  filter: sepia(.16) saturate(.92);
  box-shadow: 0 10px 26px rgba(30, 15, 8, .35);
}
/* l'éveil d'un portrait : le sépia se lève, le visage retrouve ses couleurs
   pleines — la classe est posée par livre.js (survol, focus ou tap), qui
   fait aussi parler Kokomi (bulle + voix du prénom) */
.portraits img[data-prenom] {
  /* l'éveil se pose en douceur — la courbe de ce qui se pose, pas de ce
     qui s'éclaire */
  transition: filter .6s var(--pose), scale .6s var(--pose),
              box-shadow .6s var(--pose), border-color .6s var(--pose);
}
/* le curseur ne peut pas venir d'un :hover (les faces tournées échappent au
   hit-testing, voir livre.js) : c'est le visage manuel qui pose la classe */
html.vise-portrait .scene-livre { cursor: pointer; }
.portraits img.est-eveille {
  filter: none;
  scale: 1.04;
  border-color: var(--or);
  box-shadow: 0 12px 32px rgba(30, 15, 8, .45);
}
.portraits img:focus-visible {
  outline: 3px solid var(--or);
  outline-offset: 4px;
}
/* les étincelles du survol : des grains de lumière qui s'échappent du
   médaillon éveillé (semés par livre.js, jamais dans le HTML source) */
.etincelle-portrait {
  position: absolute;
  top: 0; left: 0;
  width: 7px; height: 7px;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle, rgba(255, 238, 202, .95), rgba(217, 179, 106, 0) 70%);
}
.etincelle-portrait.est-rose {
  background: radial-gradient(circle, rgba(250, 214, 210, .95), rgba(232, 122, 120, 0) 70%);
}
@media (prefers-reduced-motion: reduce) {
  /* sans mouvement : l'éveil vit dans le seul lever du sépia */
  .portraits img[data-prenom] { transition: filter .6s var(--pose); }
  .portraits img.est-eveille { scale: none; }
}

.colophon {
  margin-top: clamp(18px, 3svh, 32px);
  padding-top: var(--s4);
  border-top: 3px double color-mix(in srgb, var(--or-sombre) 55%, transparent);
  text-align: center;
  font-size: .82rem;
  color: var(--encre-livre-douce);
}
.colophon a { color: var(--framboise-encre); font-weight: 700; }
.colophon p + p { margin-top: var(--s2); }
/* le sceau japonais ne se coupe jamais en fin de ligne */
.colophon .jp { white-space: nowrap; }
/* la page finale respire : le message tient le centre de la page, le
   colophon descend en pied de page, juste au-dessus du folio (les marges
   auto n'agissent que dans la colonne flex du cinéma) */
html.cinema .page-finale .page-entete { margin-top: auto; }
html.cinema .page-finale .colophon { margin-top: auto; }
/* même écrasée (petites hauteurs), la page garde un souffle avant le colophon */
html.cinema .page-finale .page-adresse { margin-bottom: clamp(18px, 3svh, 32px); }

/* ==========================================================================
   La couverture — cuir profond, gaufrage d'or
   ========================================================================== */
.couverture-cuir {
  position: relative;
  background:
    /* le lavis : un voile d'aquarelle chaude qui adoucit le cuir (V2) */
    radial-gradient(95% 75% at 46% 26%, rgba(255, 226, 214, .34), rgba(238, 196, 188, .12) 55%, transparent 78%),
    /* l'usure : coins et bords râpés, plus clairs */
    radial-gradient(26% 20% at 2% 2%, rgba(216, 178, 148, .16), transparent 70%),
    radial-gradient(24% 18% at 98% 3%, rgba(216, 178, 148, .13), transparent 70%),
    radial-gradient(26% 20% at 97% 97%, rgba(216, 178, 148, .15), transparent 70%),
    radial-gradient(20% 16% at 3% 96%, rgba(216, 178, 148, .12), transparent 70%),
    /* les taches d'humidité, sombres */
    radial-gradient(30% 22% at 70% 84%, rgba(12, 4, 8, .35), transparent 72%),
    radial-gradient(22% 16% at 18% 30%, rgba(12, 4, 8, .28), transparent 70%),
    /* le semis d'or, à peine visible */
    radial-gradient(circle 1.1px at 31px 37px, rgba(226, 190, 127, .3), transparent 2px),
    radial-gradient(circle 1.1px at 73px 89px, rgba(226, 190, 127, .22), transparent 2px),
    linear-gradient(160deg, rgba(52, 16, 30, .28), rgba(28, 8, 16, .55)),
    url('../assets/textures/cuir-grain.webp'),
    radial-gradient(120% 90% at 30% 20%, color-mix(in srgb, var(--cuir) 88%, #7A4050), var(--cuir) 45%, var(--cuir-sombre));
  background-size: auto, auto, auto, auto, auto, auto, auto, 104px 118px, 104px 118px, auto, 300px, auto;
  background-blend-mode: soft-light, normal, normal, normal, normal, multiply, multiply, normal, normal, multiply, soft-light, normal;
  border-radius: 6px 14px 14px 6px;
  box-shadow:
    inset 0 0 46px rgba(0, 0, 0, .5),
    inset 0 0 5px rgba(255, 220, 170, .12),
    2px 2px 0 #E6D3A4, 3px 3px 0 #C9A44E, /* le filet doré de la tranche */
    5px 5px 0 #D3BF98, 7px 7px 0 #C8B48B, 9px 9px 0 #BCA87E,
    16px 18px 50px rgba(5, 3, 8, .65);
  display: grid;
  place-items: center;
  align-content: center;
  gap: var(--s3);
  text-align: center;
  padding: 12%;
  overflow: hidden;
}
/* le cuir a vécu : craquelure multipliée, et deux fines éraflures */
.couverture-cuir::before {
  content: '';
  position: absolute; inset: 0;
  background: url('../assets/textures/craquelure.webp');
  background-size: 560px;
  mix-blend-mode: multiply;
  opacity: .5;
  pointer-events: none;
}

/* l'auréole gravée, les écoinçons — l'or à froid */
.medaillon .aureole-or {
  position: absolute;
  left: -52%; top: -52%;
  width: 204%; height: 204%;
  color: color-mix(in srgb, var(--or) 72%, transparent);
  filter: drop-shadow(0 1px 0 rgba(0, 0, 0, .45)) drop-shadow(0 -1px 0 rgba(255, 236, 180, .14));
  pointer-events: none;
}
.ecoincon {
  position: absolute;
  width: clamp(22px, 8%, 34px);
  height: auto;
  color: color-mix(in srgb, var(--or) 78%, transparent);
  filter: drop-shadow(0 1px 0 rgba(0, 0, 0, .5));
  pointer-events: none;
}
.ecoincon-hg { top: 7.5%; left: 7.5%; }
.ecoincon-hd { top: 7.5%; right: 7.5%; transform: scaleX(-1); }
.ecoincon-bg { bottom: 7.5%; left: 7.5%; transform: scaleY(-1); }
.ecoincon-bd { bottom: 7.5%; right: 7.5%; transform: scale(-1); }

/* le cœur irradie — l'artefact est vivant */
.medaillon::after {
  content: '';
  position: absolute;
  inset: 12%;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--lueur) 40%, transparent), transparent 66%);
  opacity: .5;
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .medaillon::after { animation: coeur-irradie 4.6s ease-in-out infinite alternate; }
  @keyframes coeur-irradie {
    from { opacity: .3; scale: .92; }
    to   { opacity: .75; scale: 1.06; }
  }
}

/* les éclats : quatre branches, l'or accroche la lumière de la lampe */
.eclat {
  position: absolute;
  width: 14px; height: 14px;
  background: radial-gradient(circle, #FFF4D8 18%, rgba(255, 236, 180, .7) 34%, transparent 60%);
  clip-path: polygon(50% 0, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0 50%, 40% 40%);
  opacity: 0;
  pointer-events: none;
}
.eclat-1 { top: 6%; left: 8%; }
.eclat-2 { top: 39%; left: 63%; }
.eclat-3 { bottom: 8%; right: 10%; }
@media (prefers-reduced-motion: no-preference) {
  .eclat { animation: eclat-brille 7.5s ease-in-out infinite; }
  .eclat-2 { animation-delay: 2.6s; animation-duration: 8.5s; }
  .eclat-3 { animation-delay: 5.1s; animation-duration: 9.5s; }
  @keyframes eclat-brille {
    0%, 88%, 100% { opacity: 0; scale: .4; rotate: 0deg; }
    92% { opacity: .95; scale: 1; rotate: 24deg; }
    96% { opacity: 0; scale: .5; rotate: 40deg; }
  }
}

/* le reflet : une lumière lente balaie le cuir */
.reflet {
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 42%, rgba(255, 238, 198, .085) 50%, transparent 58%);
  transform: translateX(-130%);
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .reflet { animation: reflet-passe 9s ease-in-out infinite; }
  @keyframes reflet-passe {
    0%, 55% { transform: translateX(-130%); }
    85%, 100% { transform: translateX(130%); }
  }
}

/* les ferrures d'angle */
.ferrure {
  position: absolute;
  width: clamp(42px, 14%, 62px);
  height: auto;
  filter: drop-shadow(1px 2px 2px rgba(0, 0, 0, .55)) saturate(.82) brightness(.9);
}
.ferrure-hg { top: -2px; left: -2px; }
.ferrure-hd { top: -2px; right: -2px; transform: scaleX(-1); }
.ferrure-bg { bottom: -2px; left: -2px; transform: scaleY(-1); }
.ferrure-bd { bottom: -2px; right: -2px; transform: scale(-1); }
.cadre-or {
  position: absolute;
  inset: 5.5%;
  border: 2px solid transparent;
  border-image: linear-gradient(135deg, var(--or-clair), var(--or-sombre) 34%, var(--or) 52%, var(--or-sombre) 78%, var(--or-clair)) 1;
  pointer-events: none;
}
.cadre-or::before {
  content: '';
  position: absolute;
  inset: 8px;
  border: 1px solid color-mix(in srgb, var(--or) 55%, transparent);
}
.medaillon {
  position: relative;
  --medaillon-w: clamp(84px, 34%, 150px);
  width: var(--medaillon-w);
  /* l'auréole déborde du médaillon en absolu, la grille ne la voit pas :
     on réserve son empreinte basse pour qu'elle ne touche jamais le titre */
  margin-bottom: calc(var(--medaillon-w) * .35);
  aspect-ratio: 1;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: var(--or);
  background:
    radial-gradient(circle at 34% 28%, color-mix(in srgb, var(--cuir) 70%, #8A4A5C), var(--cuir-sombre) 74%);
  box-shadow:
    inset 0 2px 6px rgba(0, 0, 0, .6),
    inset 0 -1px 2px color-mix(in srgb, var(--or) 30%, transparent),
    0 0 0 2px color-mix(in srgb, var(--or-sombre) 80%, transparent),
    0 0 0 4px color-mix(in srgb, var(--or) 45%, transparent),
    0 1px 3px rgba(0, 0, 0, .5);
}
.medaillon svg {
  width: 56%;
  filter: drop-shadow(0 1px 0 rgba(0, 0, 0, .6)) drop-shadow(0 -1px 0 rgba(255, 236, 180, .25));
}
/* la couronne festonnée du médaillon */
.medaillon::before {
  content: '';
  position: absolute;
  inset: -6%;
  border-radius: 50%;
  background: repeating-conic-gradient(from 3deg,
    color-mix(in srgb, var(--or) 70%, transparent) 0deg 5deg,
    transparent 5deg 15deg);
  -webkit-mask: radial-gradient(circle, transparent 74%, black 76% 90%, transparent 92%);
  mask: radial-gradient(circle, transparent 74%, black 76% 90%, transparent 92%);
  opacity: .55;
}

.couverture-titre {
  font-family: var(--famille-plume);
  font-weight: 620;
  font-size: clamp(1.5rem, calc(var(--page-w) * .1), 2.4rem);
  letter-spacing: .04em;
  background: linear-gradient(168deg, var(--or-clair) 12%, var(--or) 38%, var(--or-sombre) 62%, var(--or-clair) 88%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 1px 0 rgba(0, 0, 0, .65)) drop-shadow(0 -1px 0 rgba(255, 240, 200, .18));
}
.couverture-titre span { font-style: italic; }
.couverture-sous {
  font-size: clamp(.72rem, .9vw, .86rem);
  font-weight: 700;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--or) 80%, transparent);
}
.couverture-jp {
  font-size: .78rem;
  color: color-mix(in srgb, var(--or) 55%, transparent);
}

/* le papier de garde — l'intérieur de la couverture */
.couverture-garde { display: grid; place-items: center; }
.exlibris {
  text-align: center;
  display: grid;
  justify-items: center;
  gap: var(--s3);
  max-width: 32ch;
}
.exlibris-coeur { width: 74px; color: var(--framboise-encre); opacity: .9; }
.exlibris-mantra { font-size: clamp(1.1rem, 1.5vw, 1.35rem); }
.exlibris-jp { font-size: .8rem; color: var(--encre-livre-douce); }
.exlibris-note {
  font-family: var(--famille-plume);
  font-style: italic;
  font-size: .95rem;
  color: var(--encre-livre-douce);
}
.exlibris-kokomi { width: clamp(110px, 10vw, 150px); height: auto; margin-top: var(--s2); }

/* ==========================================================================
   Kokomi, gardienne du livre
   ========================================================================== */
.kokomi-livre { position: relative; }
/* la feuille-tapis : son point de chute, posé au sol avant elle.
   Sous les poses par ordre DOM ; le squash s'écrase depuis le sol. */
.feuille-tapis {
  position: absolute;
  /* descendre la feuille sous les pattes de Kokomi : le conteneur n'a
     pas de hauteur (enfants absolus), un bottom en % est donc inerte —
     la marge en %, elle, se résout sur la LARGEUR du conteneur */
  bottom: 0;
  margin-bottom: -12%;
  /* nettement plus large que Kokomi : elle se tient DESSUS, la feuille
     déborde des deux côtés de ses pattes. Le max-width global de
     kokoro.css plafonnerait à 100% : on le lève ici. */
  width: 200%; max-width: none; height: auto;
  /* on centre le LIMBE (mesuré à 56.7% de l'image — le pétiole part en
     bas à gauche) sur le centre de Kokomi, via left seul (% du conteneur,
     sans l'ambiguïté du translate en %) :
     left = 50% − 200% × 56.7% ≈ −63.4% */
  left: -63.4%;
  transform-origin: 50% 100%;
  pointer-events: none;
}
/* pendant la descente de la feuille, le conteneur est visible (elle vole)
   mais Kokomi n'existe pas encore : son corps attend derrière le rideau */
html.cinema .kokomi-livre.corps-cache .pose,
html.cinema .kokomi-livre.corps-cache .puff,
html.cinema .kokomi-livre.corps-cache .bulle,
html.cinema .kokomi-livre.corps-cache .traits-vitesse,
html.cinema .kokomi-livre.corps-cache .impact-fx,
html.cinema .kokomi-livre.corps-cache .tourbillon { visibility: hidden; }
/* le corps de Kokomi : tout ce qui tombe et gesticule — jamais la feuille.
   (nommé corps-kokomi : .corps est déjà le bloc de feuillets du livre) */
.kokomi-livre .corps-kokomi { position: absolute; inset: 0; }
.kokomi-livre .pose {
  position: absolute;
  bottom: 0; left: 50%;
  /* max-width : le plafond global de kokoro.css (img { max-width: 100% })
     écraserait toutes les largeurs par pose > 100 % ci-dessous — les poses
     rendraient TOUTES à 100 %, tailles fausses. Levé ici comme pour la
     feuille-tapis. */
  width: 100%; max-width: none; height: auto;
  translate: -50% 0;
  opacity: 0;
  transition: opacity .35s var(--allume);
}
.kokomi-livre .pose.est-active { opacity: 1; }
/* elle respire, toujours */
@media (prefers-reduced-motion: no-preference) {
  .kokomi-livre .pose.est-active {
    transform-origin: 50% 100%;
    animation: kokomi-souffle 4.2s ease-in-out infinite alternate;
  }
  @keyframes kokomi-souffle {
    from { scale: 1 1; }
    to   { scale: 1.015 1.035; }
  }
}
/* la séquence chute/relevé : des cuts secs, façon animé — le fondu des
   poses est suspendu le temps de la séquence (posé/retiré par l'accueil) */
.kokomi-livre.en-sequence .pose { transition: none; }
/* les poses de la séquence débordent du canvas de référence (588 = 100 %) :
   la masse du personnage reste constante, c'est le cadrage qui s'élargit */
.kokomi-livre .pose-chute { width: 110%; }
.kokomi-livre .pose-chute-2 { width: 108%; }
.kokomi-livre .pose-chute-3 { width: 112%; }
.kokomi-livre .pose-ecrasee { width: 129%; }
.kokomi-livre .pose-etourdie { width: 151%; }
.kokomi-livre .pose-frotte-la-tete { width: 113%; }
.kokomi-livre .pose-quatre-pattes { width: 126%; }
.kokomi-livre .pose-pousse-1 { width: 120%; }
.kokomi-livre .pose-pousse-2 { width: 126%; }
.kokomi-livre .pose-pousse-3 { width: 135%; }
.kokomi-livre .pose-pousse-max-1 { width: 152%; }
.kokomi-livre .pose-pousse-max-2 { width: 134%; }
.kokomi-livre .pose-pousse-fatigue-1 { width: 123%; }
.kokomi-livre .pose-pousse-fatigue-2 { width: 126%; }
.kokomi-livre .pose-pousse-genoux { width: 118%; }
.kokomi-livre .pose-epuisee-1 { width: 126%; }
.kokomi-livre .pose-epuisee-2 { width: 129%; }
/* le coucou : frames debout, même posture que salut — ici c'est la HAUTEUR
   du corps qui est alignée (pas la masse : une frame au bras tendu a plus
   d'aire, la masse constante rapetisserait le corps et l'animation
   tremblerait d'une frame à l'autre).
   Le translate par frame corrige la POSITION : l'ancrage standard centre le
   canvas (la bbox), or le bras tendu élargit la bbox d'un seul côté — le
   corps de salut vit à −68 px du centre de son canvas, ceux des frames à
   +16…+48 px. Décalages trouvés par corrélation des silhouettes avec salut
   (en % de la largeur de la frame : ils suivent l'échelle de la scène). */
.kokomi-livre .pose-bonjour-1 { width: 105%; translate: -60% 0; }
.kokomi-livre .pose-bonjour-2 { width: 111%; translate: -62.3% 0; }
.kokomi-livre .pose-bonjour-3 { width: 115%; translate: -63.5% 0; }
.kokomi-livre .pose-bonjour-4 { width: 103%; translate: -60.4% 0; }
.kokomi-livre .pose-bonjour-5 { width: 107%; translate: -62.6% 0; }
.kokomi-livre .pose-bonjour-6 { width: 101%; translate: -63% 0; }
.kokomi-livre .pose-bonjour-7 { width: 107%; translate: -61.6% 0; }
.kokomi-livre .pose-bonjour-8 { width: 102%; translate: -61% 0; }
.kokomi-livre .pose-bonjour-9 { width: 104%; translate: -60.3% 0; }
.kokomi-livre .pose-bonjour-10 { width: 104%; translate: -60.3% 0; }
/* les anciens assets (fournée d'origine, jamais normalisés) rejoignent la
   masse de salut — mesurés au canal alpha : esprit-aventure et dodo
   pesaient 60 % de la référence, curieux 118 %. curieux, debout comme
   salut, est aligné en hauteur ; warmth et gratitude sont déjà justes. */
.kokomi-livre .pose-curieux { width: 91%; }
.kokomi-livre .pose-motive { width: 118%; }
.kokomi-livre .pose-courage { width: 107%; }
.kokomi-livre .pose-celebration { width: 111%; }
.kokomi-livre .pose-avec-amour { width: 105%; }
.kokomi-livre .pose-esprit-aventure { width: 129%; }
.kokomi-livre .pose-dodo { width: 129%; }
/* surpris est un ancien asset (173×264) cadré plus serré en hauteur que le
   canvas de référence : à 100 % il rend Kokomi ~20 % trop grande. On aligne
   sa hauteur debout sur salut : (748/588) ÷ (264/173) ≈ 83 % */
.kokomi-livre .pose-surpris { width: 83%; }

/* ---- les effets de la séquence : dessinés ici, allumés par GSAP ---- */
.traits-vitesse, .impact-fx, .tourbillon {
  position: absolute; inset: 0;
  opacity: 0;
  pointer-events: none;
}
/* les traits de vitesse : au-dessus du corps, ils s'étirent pendant la chute */
.traits-vitesse i {
  position: absolute;
  width: 2px;
  background: linear-gradient(to bottom,
    transparent,
    color-mix(in srgb, var(--encre-douce) 34%, transparent) 35%,
    transparent);
  transform-origin: 50% 0;
}
.traits-vitesse i:nth-child(1) { left: 14%; top: -8%;  height: 22%; }
.traits-vitesse i:nth-child(2) { left: 37%; top: -18%; height: 32%; }
.traits-vitesse i:nth-child(3) { left: 63%; top: -12%; height: 26%; }
.traits-vitesse i:nth-child(4) { left: 86%; top: -5%;  height: 18%; }
/* l'éclat de l'impact : deux étoiles d'or et un peu de poussière au ras du sol */
.impact-fx i { position: absolute; }
.impact-fx .etoile {
  width: 26px; height: 26px;
  background: var(--or);
  clip-path: polygon(50% 0, 61% 39%, 100% 50%, 61% 61%, 50% 100%, 39% 61%, 0 50%, 39% 39%);
}
.impact-fx .etoile:nth-child(1) { left: -7%; bottom: 18%; }
.impact-fx .etoile:nth-child(2) { right: -9%; bottom: 26%; width: 19px; height: 19px; }
.impact-fx .poussiere {
  width: 22px; height: 13px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--creme) 88%, transparent);
  filter: blur(2px);
  bottom: 3%;
}
.impact-fx .poussiere:nth-child(3) { left: 2%; }
.impact-fx .poussiere:nth-child(4) { left: 44%; width: 27px; }
.impact-fx .poussiere:nth-child(5) { right: 0; }
/* le tourbillon d'étourdissement : au-dessus de sa tête (couchée, tête à gauche) */
.tourbillon {
  inset: auto;
  left: 8%; bottom: 86%;
  width: 38%;
  color: var(--or);
}

.kokomi-livre .bulle { opacity: 0; }
.kokomi-livre .bulle.est-dite { opacity: 1; }

.bulle {
  position: absolute;
  left: 50%;
  bottom: calc(100% + var(--s4));
  /* la bulle s'étend vers la droite, du côté libre : jamais derrière le livre */
  translate: -20% 0;
  width: max-content;
  max-width: 30ch;
  margin: 0;
  padding: var(--s3) var(--s6);
  background: var(--papier-livre);
  color: var(--encre-livre);
  border-radius: var(--rayon-doux);
  box-shadow: 0 10px 34px rgba(8, 5, 10, .55);
  font-size: 1.02rem;
  transition: opacity .4s var(--allume);
}
.bulle::after {
  content: '';
  position: absolute;
  left: 24%;
  bottom: -7px;
  width: 14px; height: 14px;
  background: inherit;
  rotate: 45deg;
}

.puff { position: absolute; left: 50%; bottom: 10%; pointer-events: none; }
.puff i {
  position: absolute;
  width: 12px; height: 12px;
  opacity: 0;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(240, 222, 190, .95), rgba(240, 222, 190, 0) 70%);
}

.aide-indice {
  position: fixed;
  left: 50%;
  bottom: 4svh;
  translate: -50% 0;
  z-index: 20;
  margin: 0;
  padding: var(--s2) var(--s6);
  background: color-mix(in srgb, var(--papier-livre) 88%, transparent);
  border-radius: var(--rayon-pilule);
  box-shadow: 0 6px 24px rgba(60, 30, 20, .35);
  color: var(--encre-livre);
  font-size: .95rem;
  text-align: center;
}
.aide-indice strong { color: var(--framboise-encre); }
@media (prefers-reduced-motion: no-preference) {
  .aide-indice:not([hidden]) { animation: indice-pulse 2.2s ease-in-out infinite; }
  @keyframes indice-pulse { 50% { opacity: .55; } }
}

/* ==========================================================================
   LE MANUSCRIT À PLAT — le monde par défaut
   (noscript, reduced-motion, mobile : tout est là, posé avec soin)
   ========================================================================== */
.scene-livre { position: relative; z-index: 2; }
html:not(.cinema) .scene-livre {
  padding: calc(var(--s24) + var(--s12)) clamp(var(--s4), 4vw, var(--s12)) var(--s16);
}
html:not(.cinema) .livre {
  max-width: 700px;
  margin: 0 auto;
  display: grid;
  gap: clamp(var(--s8), 5svh, var(--s16));
}
html:not(.cinema) .couverture,
html:not(.cinema) .corps,
html:not(.cinema) .feuille { display: contents; }
html:not(.cinema) .couverture-cuir {
  min-height: min(88svh, 640px);
  border-radius: 10px 16px 16px 10px;
}
html:not(.cinema) .couverture-cuir { rotate: -.4deg; }
html:not(.cinema) .page:nth-of-type(odd) { rotate: .35deg; }
html:not(.cinema) .page { min-height: min(80svh, 600px); }
html:not(.cinema) .dos,
html:not(.cinema) .ruban { display: none; }
html:not(.cinema) .kokomi-livre {
  width: clamp(140px, 30vw, 190px);
  aspect-ratio: 1 / 1.15;
  margin: 0 auto var(--s8);
}
html:not(.cinema) .kokomi-livre .bulle { opacity: 1; }
html:not(.cinema) .aide-indice { display: none; }
/* la feuille et les effets de séquence appartiennent à la mise en scène
   cinématique uniquement */
html:not(.cinema) .feuille-tapis,
html:not(.cinema) .traits-vitesse,
html:not(.cinema) .impact-fx,
html:not(.cinema) .tourbillon { display: none; }

/* ==========================================================================
   LE LIVRE EN 3D — sous html.cinema uniquement
   État par défaut : le livre est OUVERT sur son premier spread (le cinéma
   part de la couverture fermée et anime vers cet état).
   ========================================================================== */
html.cinema .scene-livre {
  height: 100svh;
  perspective: 1900px;
  perspective-origin: 50% 42%;
}
/* le théâtre : tout ce que la caméra embrasse (pupitre, livre, Kokomi) */
html.cinema .theatre {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  transform-style: preserve-3d;
  transform-origin: 50% 66%;
}
html:not(.cinema) .theatre { display: contents; }

/* la rémanence : la lumière de l'éclat qui s'attarde autour du grimoire
   à son arrivée, puis se dissout (fondu piloté par la marche, livre.js).
   Centrée sur la couverture close (moitié droite du livre), posée derrière
   lui dans la profondeur — sous l'ombre portée (-40px). */
.remanence { display: none; }
html.cinema .remanence {
  display: block;
  position: absolute;
  left: calc(50% + var(--page-w) / 2);
  top: 50%;
  width: calc(var(--page-h) * 1.35);
  aspect-ratio: 1;
  translate: -50% -50%;
  transform: translateZ(-60px);
  opacity: 0;
  pointer-events: none;
  /* pas de mix-blend-mode ici : un blend dans un contexte preserve-3d
     au-dessus du canvas WebGL provoque des glitches de compositing —
     un dégradé alpha suffit sur la forêt claire */
  background: radial-gradient(circle,
    rgba(255, 249, 232, .95) 0%,
    rgba(255, 231, 186, .55) 32%,
    rgba(255, 214, 235, .22) 55%,
    transparent 72%);
}

/* la vignette : pénombre chaude (cuir sombre, jamais du noir) qui resserre
   la lumière sur le livre à l'arrivée. Un objectif de caméra : hors du
   théâtre, insensible au travelling, transparente là où vivent les pages.
   Le fondu d'apparition appartient à la timeline de la marche (livre.js). */
.vignette { display: none; }
html.cinema .vignette {
  display: block;
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse at 50% 55%, transparent 55%, rgba(52, 23, 33, .32) 100%);
  opacity: 0;
}

/* le pupitre est peint dans le tableau de la clairière : aucun meuble DOM —
   le livre vient se poser sur la peinture à la fin du plan-séquence */
html.cinema .livre {
  position: relative;
  width: calc(var(--page-w) * 2);
  height: var(--page-h);
  transform-style: preserve-3d;
  transform: rotateX(7deg);
}
html.cinema .livre::after { /* l'ombre portée sur la table */
  content: '';
  position: absolute;
  left: 4%; right: 4%; bottom: -7%;
  height: 12%;
  background: radial-gradient(50% 100% at 50% 50%, rgba(5, 3, 8, .6), transparent 70%);
  filter: blur(10px);
  transform: translateZ(-40px);
}
/* Le hit-testing se fait sur la géométrie, pas sur les pixels : .livre,
   transparent mais étendu sur tout le plan z=0, gobe le pointeur avant
   qu'il n'atteigne le corps, qui vit à -2px derrière lui — :hover et
   clics n'arrivaient jamais aux pages (lucioles des CTA muettes, liens
   morts). On rend le livre traversant, et seules les faces des pages
   redeviennent tangibles. */
html.cinema .livre { pointer-events: none; }
html.cinema .livre .face,
html.cinema .livre .page-finale { pointer-events: auto; }

html.cinema .couverture,
html.cinema .feuille {
  position: absolute;
  top: 0; left: 50%;
  width: var(--page-w);
  height: 100%;
  transform-style: preserve-3d;
  transform-origin: left center;
}
/* Sous cinéma la couverture part fermée : c'est la seule entorse au
   principe « CSS accompli », car html.cinema n'existe que si ce script vit. */
html.cinema .couverture { transform: rotateY(0deg); z-index: 60; }

html.cinema .face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

/* ---- le fermoir ----------------------------------------------------------
   Charnière au bord droit : GSAP le fait cliqueter pendant la lutte,
   puis basculer quand l'aide arrive. Sans cinéma, le livre est ouvert :
   pas de fermoir. */
.fermoir { display: none; }
html.cinema .fermoir {
  display: block;
  position: absolute;
  right: -10px;
  width: clamp(40px, 12%, 56px);
  height: auto;
  translate: 0 -50%;
  transform-origin: 88% 50%;
  filter: drop-shadow(1px 2px 3px rgba(0, 0, 0, .6)) saturate(.85) brightness(.92);
  z-index: 3;
}
html.cinema .fermoir-haut { top: 30%; }
html.cinema .fermoir-bas { top: 70%; }

/* ---- le pompon de soie ---------------------------------------------------
   Pendu sous le fermoir bas, comme sur les grimoires peints : cordon d'or,
   perle, gland de soie rose qui se balance à peine. */
.pompon { display: none; }
html.cinema .pompon {
  display: block;
  position: absolute;
  right: 2px;
  top: calc(70% + 16px);
  width: 16px;
  height: 48px;
  z-index: 3;
  pointer-events: none;
  transform-origin: 50% 0;
}
html.cinema .pompon::before {
  /* le cordon, et sa perle d'or à la naissance du gland */
  content: '';
  position: absolute;
  left: calc(50% - 1px);
  top: 0;
  width: 2px;
  height: 18px;
  background: linear-gradient(#C9A44E, #8A651F);
  box-shadow: 0 17px 0 2px #C9A44E;
  border-radius: 1px;
}
html.cinema .pompon::after {
  /* le gland : soie rose, mèches plus sombres, lumière en tête */
  content: '';
  position: absolute;
  left: 0;
  top: 21px;
  width: 16px;
  height: 26px;
  border-radius: 50% 50% 44% 44% / 32% 32% 68% 68%;
  background:
    repeating-linear-gradient(90deg, rgba(178, 58, 72, .22) 0 2px, transparent 2px 4px),
    linear-gradient(#F7C9D4 8%, #F0A8BC 45%, #DE7690);
  box-shadow:
    inset 0 2px 2px rgba(255, 240, 244, .75),
    inset 0 -3px 4px rgba(140, 40, 60, .35),
    0 2px 3px rgba(40, 10, 20, .35);
}
@media (prefers-reduced-motion: no-preference) {
  html.cinema .pompon { animation: pompon-balance 3.6s ease-in-out infinite alternate; }
  @keyframes pompon-balance {
    from { transform: rotate(-4deg); }
    to   { transform: rotate(5deg); }
  }
}

/* ---- l'épaisseur du plat : les chants de cuir ---------------------------- */
.chant { display: none; }
html.cinema .chant {
  display: block;
  position: absolute;
  background: linear-gradient(#4A1F30, #241016);
}
html.cinema .chant-droit {
  top: 1px; bottom: 1px; right: 0;
  width: 13px;
  transform-origin: right center;
  transform: rotateY(90deg);
  border-radius: 3px;
  background: linear-gradient(180deg, #452031, #2B1119 60%, #1C0A10);
}
html.cinema .chant-haut {
  left: 2px; right: 2px; top: 0;
  height: 13px;
  transform-origin: center top;
  transform: rotateX(-90deg);
}
html.cinema .chant-bas {
  left: 2px; right: 2px; bottom: 0;
  height: 13px;
  transform-origin: center bottom;
  transform: rotateX(90deg);
}

/* ---- l'épaisseur du corps : les piles de feuillets -----------------------
   Le corps entier vit un cheveu derrière le plan de la couverture : sans ce
   retrait, son bloc de feuillets (::after) est strictement coplanaire avec
   le plat fermé et se dispute chaque pixel avec lui — la « page vide » qui
   clignotait à la refermeture. preserve-3d obligatoire : un transform sans
   lui aplatirait les tournes de pages. */
html.cinema .corps {
  /* le transform fait de .corps le containing block de ses feuilles
     absolues : il doit épouser exactement la boîte du livre */
  position: absolute;
  inset: 0;
  transform: translateZ(-2px);
  transform-style: preserve-3d;
}
html.cinema .corps::after {
  content: '';
  position: absolute;
  top: .8%; bottom: -.4%;
  left: 50%;
  width: var(--page-w);
  border-radius: 3px 12px 12px 3px;
  background: var(--papier-ombre);
  box-shadow: 2px 2px 0 #D8C6A2, 4px 4px 0 #CDBB97, 6px 7px 0 #C2B08C, 8px 10px 0 #B4A27E,
              12px 16px 26px rgba(5, 3, 8, .55);
  z-index: 0;
}
html.cinema .corps::before {
  content: '';
  position: absolute;
  top: .8%; bottom: -.4%;
  left: 50%;
  margin-left: calc(-1 * var(--page-w));
  width: var(--page-w);
  border-radius: 12px 3px 3px 12px;
  background: var(--papier-ombre);
  box-shadow: -2px 2px 0 #D8C6A2, -4px 4px 0 #CDBB97, -6px 7px 0 #C2B08C, -8px 10px 0 #B4A27E,
              -12px 16px 26px rgba(5, 3, 8, .55);
  opacity: 0;
  transition: opacity .7s var(--allume);
  z-index: 0;
  /* sous la garde : la couverture ouverte vit à -3px (livre.js), la pile
     gauche doit rester derrière elle — -2px relatifs, -4px absolus */
  transform: translateZ(-2px);
}
html.cinema .livre.est-ouvert .corps::before { opacity: 1; }
html.cinema .verso,
html.cinema .couverture-garde { transform: rotateY(180deg); }

html.cinema .page {
  position: absolute;
  inset: 0;
  box-shadow: none;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* les deux faces du plat ne partagent pas exactement le même plan :
   dos à dos et coplanaires, cuir et garde peuvent scintiller l'un à
   travers l'autre aux angles rasants */
html.cinema .couverture-cuir { position: absolute; inset: 0; transform: translateZ(.3px); }

/* l'ombrage du pli : piloté par --pli (0 = à plat, 1 = dressée).
   Sur les pages, le pli s'empile sur le vieillissement — même ::after. */
html.cinema .feuille .recto::after,
html.cinema .couverture-cuir::after {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  background: linear-gradient(to left, rgba(30, 14, 8, calc(var(--pli, 0) * .34)), transparent 52%);
}
html.cinema .feuille .recto::after {
  background:
    linear-gradient(to left, rgba(30, 14, 8, calc(var(--pli, 0) * .34)), transparent 52%),
    var(--vieillissement);
}
html.cinema .feuille .verso .page::after { box-shadow: none; }
html.cinema .feuille .verso::after {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  background:
    linear-gradient(to right, rgba(30, 14, 8, calc(var(--pli, 0) * .3)), transparent 52%),
    var(--vieillissement);
}

/* ---- la courbure : les facettes ------------------------------------------
   Générées par livre.js dans chaque feuille (jamais dans le HTML source).
   Trois tranches pleine page découpées au clip (coupes à 38 % / 72 %, un
   soupçon de recouvrement contre le jour des jointures) ; deux charnières
   qu'une seule variable --courbure cintre : 0 = plane, 1 = retard max du
   bord libre (2 × 7°), négatif = dépassement. Le clip vit sur chaque clone
   (pas sur la facette : il aplatirait le contexte 3D), et comme chaque
   clone est la page entière, pli et vieillissement restent continus d'une
   facette à l'autre. Hors tourne, le jeu n'est pas rendu (livre.js). */
html.cinema .feuille-facettes {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  pointer-events: none;
}
/* la bascule originaux/facettes, pilotée par --tourne (livre.js) : 0 hors
   tourne, 1 pendant. L'opacité vit sur les faces PLATES — jamais sur le
   conteneur 3D, une opacité < 1 y aplatirait les charnières.
   Rampes décalées, pas de fondu croisé : deux calques à 50 % ne font pas
   un opaque (la dernière page transparaissait au travers) — ici, à tout
   instant, au moins un des deux est pleinement opaque. */
html.cinema .facette > .face { opacity: clamp(0, calc(var(--tourne, 0) * 4 - 1), 1); }
html.cinema .feuille > .face { opacity: clamp(0, calc(3 - var(--tourne, 0) * 4), 1); }
html.cinema .charniere {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transform: rotateY(calc(var(--courbure, 0) * 7deg));
}
html.cinema .charniere-1 { transform-origin: 38% 50%; }
html.cinema .charniere-2 { transform-origin: 72% 50%; }
html.cinema .facette {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}
/* les fenêtres du verso sont en miroir : il est retourné (rotateY 180) */
html.cinema .facette-1 > .recto { clip-path: inset(0 61.9% 0 0); }
html.cinema .facette-1 > .verso { clip-path: inset(0 0 0 61.9%); }
html.cinema .facette-2 > .recto { clip-path: inset(0 27.9% 0 37.9%); }
html.cinema .facette-2 > .verso { clip-path: inset(0 37.9% 0 27.9%); }
html.cinema .facette-3 > .recto { clip-path: inset(0 0 0 71.9%); }
html.cinema .facette-3 > .verso { clip-path: inset(0 71.9% 0 0); }
/* hors cinéma elles ne sont pas construites — ceinture et bretelles */
html:not(.cinema) .feuille-facettes { display: none; }

html.cinema .page-finale { left: 50%; width: var(--page-w); z-index: 1; }

/* le dos et le ruban n'apparaissent qu'une fois le livre ouvert */
html.cinema .dos {
  position: absolute;
  top: -1%;
  left: 50%;
  margin-left: calc(-1 * var(--page-w) - 16px);
  width: 16px;
  height: 102%;
  background: linear-gradient(90deg, var(--cuir-sombre), var(--cuir));
  border-radius: 8px 0 0 8px;
  opacity: 0;
  transform: translateZ(-6px);
}
html.cinema .dos {
  background:
    url('../assets/textures/craquelure.webp'),
    linear-gradient(90deg, var(--cuir-sombre), var(--cuir));
  background-size: 280px, auto;
  background-blend-mode: multiply, normal;
}
html.cinema .dos i {
  position: absolute;
  left: 1px; right: 1px;
  height: 6px;
  border-radius: 3px;
  background: linear-gradient(color-mix(in srgb, var(--or-sombre) 45%, var(--cuir)), var(--cuir-sombre));
  box-shadow: 0 -3px 0 -1px color-mix(in srgb, var(--or) 35%, transparent),
              0 3px 0 -1px color-mix(in srgb, var(--or) 25%, transparent);
}
html.cinema .dos i:nth-child(1) { top: 12%; }
html.cinema .dos i:nth-child(2) { top: 36%; }
html.cinema .dos i:nth-child(3) { top: 60%; }
html.cinema .dos i:nth-child(4) { top: 84%; }
html.cinema .livre.est-ouvert .dos { opacity: 1; transition: opacity .8s var(--allume); }

html.cinema .ruban {
  position: absolute;
  top: -6px;
  left: calc(50% - var(--page-w) * .9);
  width: 20px;
  height: 24%;
  opacity: 0;
  transform: translateZ(2px);
}
html.cinema .livre.est-ouvert .ruban { opacity: 1; transition: opacity .8s var(--allume) .3s; }

/* le geste du marque-page (docs/features/ruban-vivant) : UNE grandeur,
   --repli — la part du tissu déjà avalée par le rouleau (0% posé, 65% levé),
   animée par livre.js seul. Tissu et rouleau en dérivent par calc() : rivés
   à la même valeur, ils ne peuvent pas se désynchroniser. Le corps porte la
   suspension (transform) et l'ombre : le filter vit ici et jamais sur .ruban,
   qui perdrait son plan translateZ dans le théâtre preserve-3d. */
html.cinema .ruban-corps {
  position: absolute;
  inset: 0;
  --repli: 0%;
  filter: drop-shadow(0 6px 8px rgba(8, 5, 10, .4));
  transition: filter .55s var(--pose); /* l'ombre se resserre avec la pose */
}
html.cinema .ruban-corps.est-leve {
  filter: drop-shadow(0 20px 14px rgba(8, 5, 10, .22)); /* détachée, adoucie */
  transition: filter .45s var(--allume);
}
/* le tissu, peint une fois pour toutes — jamais comprimé ni recoloré, la
   variable le rogne. Son V vit dans ses derniers 12% : le max() l'avale en
   premier à la levée et ne le rend qu'en toute fin de pose — la physique
   par construction, sans chorégraphie séparée. */
html.cinema .ruban-tissu {
  position: absolute;
  inset: 0;
  background: linear-gradient(var(--framboise-encre), #8C2B38);
  clip-path: polygon(0 0, 100% 0,
    100% calc(100% - var(--repli)),
    50% calc(100% - var(--repli) - max(0%, 12% - var(--repli))),
    0 calc(100% - var(--repli)));
}
/* le rouleau : le tissu enroulé sur lui-même, centré sur la ligne
   d'enroulement — il naît fin (la pointe qui amorce sa boucle) et grossit
   à mesure qu'il avale. Invisible posé ; livre.js anime son opacité. */
html.cinema .ruban-rouleau {
  position: absolute;
  left: -10%;
  right: -10%;
  top: calc(100% - var(--repli));
  height: calc(1.5% + var(--repli) * .11);
  border-radius: 10px;
  background: linear-gradient(#c2495a, #8C2B38 55%, #5e1c26);
  box-shadow: inset 0 3px 3px rgba(255, 235, 235, .35), inset 0 -4px 5px rgba(20, 5, 8, .45);
  transform: translateY(-50%);
  opacity: 0;
}
/* la lisière du tissu enroulé : une fine couture sur le dessus */
html.cinema .ruban-rouleau::after {
  content: '';
  position: absolute;
  left: 8%;
  right: 8%;
  top: 22%;
  height: 1.5px;
  border-radius: 1px;
  background: rgba(20, 5, 8, .35);
}

/* Kokomi au chevet du livre */
html.cinema .kokomi-livre {
  position: absolute;
  left: calc(50% + var(--page-w) * 1.08);
  bottom: calc(50% - var(--page-h) / 2 - 12px);
  width: clamp(150px, 12.5vw, 205px);
  aspect-ratio: 1 / 1.12;
  z-index: 70;
  /* le théâtre est en preserve-3d et le livre est incliné (rotateX 7°,
     ~9° pendant la lutte, soit ±57px de profondeur à ses bords) : sans
     profondeur propre, le plan de Kokomi (z=0) croisait celui du livre
     et la feuille se faisait trancher net à la ligne d'intersection.
     On la place franchement DERRIÈRE (−70px, au-delà du bord le plus
     reculé) : en vol elle disparaît derrière le livre (occlusion
     naturelle), ouverte ou fermée elle ne flotte jamais devant les
     pages. scale(1.037) annule le rétrécissement de projection
     (1900 / (1900 + 70)). Pendant l'intro à plat (body.livre-plat,
     aucune 3D), c'est le z-index ci-dessus qui la garde devant. */
  transform: translateZ(-70px) scale(1.037);
}

/* En cinéma, les folios impairs suggèrent les pages tournées */
html.cinema .scene-livre { isolation: isolate; }

/* ==========================================================================
   Petit paysage — le téléphone tourné, la hauteur est la ressource rare.
   Le voile (voile.css) garde le portrait ; ici on recalibre le cinéma pour
   ~320–430 px de haut : des pages un peu plus larges (le ratio livre .74
   laisserait trop peu de largeur de lecture), des encres réduites mais
   jamais illisibles, Kokomi ramenée à l'échelle du grimoire (le rapport
   du desktop : un grimoire ~3,5 fois plus haut qu'elle). Premier réglage —
   la recette sur appareil réel affine (docs/features/paysage-obligatoire-mobile).
   ========================================================================== */
@media (pointer: coarse) and (max-height: 520px) {
  :root {
    --page-h: 76svh; /* toujours < 730px ici : le min() d'origine est inutile */
    --page-w: min(41vw, calc(var(--page-h) * .82));
  }
  html.cinema .kokomi-livre {
    /* 1.10 (> desktop 1.08) : à 1.02 la feuille collait au grimoire et
       laissait le bord droit vide — on la recale dans cet espace */
    left: calc(50% + var(--page-w) * 1.10);
    width: clamp(80px, 22svh, 130px);
  }
  /* Kokomi touche le bord droit : la bulle s'étend vers la gauche ici
     (le côté libre du desktop n'existe plus), la flèche la suit */
  .bulle { max-width: 22ch; translate: -55% 0; }
  .bulle::after { left: calc(55% - 7px); }
  /* les encres du manuscrit : resserrées, lisibles */
  html.cinema .page { padding: 14px 16px 16px; }
  .page-entete { margin-bottom: 8px; }
  .page-entete h2 { font-size: 1.12rem; }
  .page-entete .fleuron { font-size: .95rem; margin-bottom: 2px; }
  .page-entete::after { width: 80px; height: 2px; margin-top: 6px; }
  .page-texte { font-size: .84rem; line-height: 1.45; }
  .page-texte p + p { margin-top: var(--s2); }
  .page-essence { font-size: .92rem; margin-bottom: var(--s2); }
  .lettrine > p:first-child::first-letter,
  .lettrine-seule::first-letter { font-size: 2.3em; }
  .valeurs { margin-top: 8px; gap: 4px; }
  .roles { margin-top: var(--s2); gap: var(--s2); }
  .roles dd { padding-bottom: 4px; }
  .page-droite .page-entete::before { width: 26px; height: 26px; }
  /* le bouton « Passer l'intro » reste une vraie cible tactile */
  .seuil-passer { min-height: 44px; }

  /* ---- les textes lisent leur version courte ---- */
  .texte-long { display: none; }
  .texte-court { display: revert; } /* p redevient bloc, span redevient inline */
  .valeurs-courtes {
    margin: var(--s2) 0 0;
    font-size: .84rem;
    color: var(--encre-livre);
  }
  .valeurs-courtes strong { font-family: var(--famille-plume); font-weight: 620; }

  /* ---- l'équipe se répartit sur les deux pages ----
     Les portraits se serrent en rangée et accueillent Adrien et Mickaël ;
     la page de droite garde Léna et Miguel — les quatre textes entiers. */
  .paysage-cache { display: none; }
  .paysage-seul.paysage-seul { display: revert; }
  .portraits { grid-template-columns: repeat(4, 1fr); max-width: 100%; gap: 8px; }
  .portraits + figcaption { display: none; } /* la place est aux artisans */
  /* les rôles, à l'encre continue : le nom ouvre la phrase */
  .roles { display: block; margin-top: var(--s2); }
  .roles div + div { margin-top: var(--s2); }
  .roles dt { display: inline; font-size: .84rem; }
  .roles dt::after { content: ' — '; color: var(--encre-livre-douce); font-weight: 400; }
  .roles dd {
    display: inline;
    margin: 0;
    padding-bottom: 0;
    border-bottom: 0;
    font-size: .8rem;
    line-height: 1.4;
  }
  .roles-planche { text-align: left; margin-top: var(--s3); }
  /* le marque-page : discret — la rangée des portraits vit juste dessous */
  html.cinema .ruban { width: 14px; height: 11%; }

  /* ---- les planches : le cadre suit l'image, bornée par la hauteur ----
     (la planche IV est carrée : sans plafond en svh, elle déborde) */
  .gravure { width: fit-content; max-width: 88%; margin-inline: auto; }
  .gravure img { max-height: 46svh; width: auto; max-width: 100%; }
  .planche figcaption { margin-top: var(--s2); font-size: .8rem; }
  /* les vignettes de Kokomi : réduites, posées sur le coin du cadre —
     jamais sur la légende */
  .planche-kokomi {
    width: clamp(40px, 9svh, 64px) !important;
    right: 1%;
    bottom: calc(2.6em + var(--s2)); /* au-dessus des deux lignes de légende */
  }
}
