/* ECRANS HORS JEU, dans l'ordre ou le joueur les traverse : splash,
   avertissement, autorisations, accueil. L'inscription, elle, vit dans
   aventure.css. Charge apres base.css (cf. son en-tete). */

/* ============================ SPLASH ============================ */

.splash-inner {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center;
  /* Le splash garde son retrait genereux : c'est le seul ecran qui respire, et
     il a ete cale a l'oeil sur l'appareil. Le +14px reprend le plancher retire
     de --safe-top, pour ne rien bouger ici en le supprimant ailleurs. */
  padding: calc(var(--safe-top) + 14px + 4vh) 20px calc(var(--safe-bot) + 16px);
  text-align: center;
}
/* Le logo est seul au milieu : deux marges automatiques, l'une au-dessus de
   lui, l'autre au-dessus du pied de chargement. Le flex partage l'espace libre
   a parts egales entre les deux, ce qui centre le bloc du titre dans tout ce
   qui reste au-dessus de la barre — sans hauteur ecrite nulle part, donc sans
   rien a recaler quand la dalle change. `.brand-slot` etant en
   `display: contents`, c'est bien l'image qui porte la marge, pas son
   conteneur. */
.splash-logo {
  margin-top: auto;
  width: min(66%, 262px); filter: drop-shadow(0 10px 26px rgba(0,0,0,0.75));
}
#screen-splash .wordmark-sub { font-size: 1.2rem; }
.splash-foot { margin-top: auto; width: 100%; max-width: 380px; }
.splash-label { font-size: 0.94rem; color: #e6efdd; text-shadow: 0 2px 6px rgba(0,0,0,0.8); margin-bottom: 10px; }
.load-track {
  height: 18px; border-radius: 999px;
  background: rgba(4, 14, 9, 0.72);
  border: 1px solid rgba(150, 220, 150, 0.45);
  box-shadow: inset 0 2px 6px rgba(0,0,0,0.6), 0 0 20px rgba(110, 200, 120, 0.25);
  padding: 3px; overflow: hidden;
}
.load-fill {
  height: 100%; width: 4%;
  border-radius: 999px;
  background: linear-gradient(90deg, #4d9a52, #8fd97f 70%, #b6ec9d);
  box-shadow: 0 0 14px rgba(140, 230, 140, 0.7);
  transition: width 0.35s linear;
}
.splash-tags {
  margin-top: 12px; font-size: 0.68rem; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: #cfe0c4;
  text-shadow: 0 2px 6px rgba(0,0,0,0.8);
}
.splash-hint {
  margin-top: 22px; font-family: var(--display); font-style: italic;
  font-size: 0.86rem; color: #d8e4cd; text-shadow: 0 2px 6px rgba(0,0,0,0.8);
}
.splash-version {
  margin-top: 14px; font-size: 0.62rem; font-weight: 700;
  letter-spacing: 0.08em; color: rgba(216, 228, 205, 0.55);
  text-shadow: 0 2px 6px rgba(0,0,0,0.8);
}

/* Le splash sur une dalle courte — un petit telephone, un clavier ouvert, le
   paysage. Rien n'y defile : ce qui deborde est simplement perdu, et c'est la
   barre de chargement qu'on perd en premier, celle qui dit que l'application
   demarre. On rend donc la hauteur dans l'ordre inverse de ce qu'elle vaut :
   d'abord les ornements, puis le titre, qui se reduit avant de disparaitre —
   la barre et son intitule restent toujours.

   Des paliers de hauteur, et non un calcul : le logo est une image dessinee,
   sa lisibilite ne suit pas une formule. */
.splash-inner { overflow: hidden; }

@media (max-height: 720px) {
  .splash-inner { padding-top: calc(var(--safe-top) + 10px); }
  .splash-logo { width: min(54%, 210px); }
  .splash-hint { margin-top: 14px; font-size: 0.78rem; }
  .splash-version { margin-top: 10px; }
}

@media (max-height: 620px) {
  /* La feuille et sa promesse sont un ornement : elles partent avant le nom. */
  .splash-hint { display: none; }
  .splash-logo { width: min(44%, 168px); }
  #screen-splash .baseline { font-size: 0.82rem; }
  #screen-splash .wordmark-sub { font-size: 0.98rem; }
}

@media (max-height: 520px) {
  /* Plus de place pour le titre : il s'efface. On sait ou l'on est — c'est le
     premier ecran, il dure trois secondes — et la barre de chargement, elle,
     ne se devine pas. */
  .splash-logo, #screen-splash .baseline { display: none; }
  .splash-tags { margin-top: 8px; }
  .splash-inner { padding-top: calc(var(--safe-top) + 6px); }
}

/* ============================ AVERTISSEMENT ============================ */

.brand-head { text-align: center; margin-bottom: 16px; }
/* Le titre est pose par Assets.brand() dans une balise vide. La ou l'ecran
   arrange deja ses enfants (splash, accueil, barre du jeu), la balise
   disparait de la mise en page : sans display:contents, elle formerait une
   boite de plus au milieu d'un flex et casserait l'alignement. */
.brand-slot { display: contents; }
.brand-title { width: min(64%, 236px); filter: drop-shadow(0 6px 16px rgba(0,0,0,0.7)); display: block; margin: 0 auto; }
.consent-panel { padding: 18px 14px 16px; }

.rule {
  display: flex; gap: 13px; align-items: flex-start;
  padding: 13px 14px;
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.045);
  border: var(--line-soft);
  box-shadow: var(--bevel);
  margin-bottom: 10px;
}
.rule.flat { background: rgba(0, 0, 0, 0.20); }
/* Medaillon peint : l'anneau et le halo sont dans l'image, pas en CSS. */
.rule-ic {
  width: var(--rule-ic); height: var(--rule-ic); flex: none;
  object-fit: contain;
  filter: drop-shadow(0 3px 8px rgba(0, 0, 0, 0.5));
}
.rule-txt h3 { color: var(--moss); font-size: 0.94rem; letter-spacing: 0.04em; margin-bottom: 4px; }
.rule-txt h3.warn { color: var(--ember); }
.rule-txt h3.plain { color: var(--parchment); }
.rule-txt p { margin: 0; font-size: 0.79rem; color: var(--parch-dim); line-height: 1.6; }

/* ---- consignes : un seul ecran, jamais de defilement ----------------------
   Le joueur doit voir les quatre regles ET les deux boutons d'un coup, sur un
   petit iPhone comme sur un grand. Tout ce qui occupe de la hauteur est donc
   exprime en vh, borne par clamp() pour rester lisible en haut et tenable en
   bas ; le panneau, lui, ne defile pas (overflow: hidden), il se resserre. */
/* Sans cette variable, .rule-ic tombe sur une largeur invalide et l'image
   s'affiche a sa taille native (~380 px) : tout ecran qui reutilise .rule doit
   figurer ici. */
#screen-consent, #screen-perms { --rule-ic: clamp(34px, 5.6vh, 52px); }

.consent-fit {
  display: flex; flex-direction: column;
  /* Le cadre prend la hauteur de son texte, pas toute la place : l'ensemble se
     centre alors dans ce qui reste, plutot que d'etirer le panneau et de
     laisser un vide entre la derniere regle et les boutons.

     Le centrage se fait par MARGES AUTOMATIQUES et non par
     `justify-content: center`, et c'est ce qui permet de le laisser defiler.
     Un contenu plus haut que la boite centre par `justify-content` deborde
     des DEUX cotes : le haut passe au-dessus de l'origine du defilement et
     devient inatteignable. Le cas n'etait pas theorique — la piece « Donnees
     hors ligne » grandit pendant le telechargement, et l'ecran d'installation
     porte un mode d'emploi entier. Avec des marges auto, l'ensemble se centre
     tant qu'il y a la place et se contente de defiler ensuite. */
  justify-content: flex-start;
  overflow-y: auto; overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  padding: calc(var(--safe-top) + clamp(6px, 1.6vh, 18px)) 14px
           calc(var(--safe-bot) + clamp(6px, 1.4vh, 16px));
}
.consent-fit > :first-child { margin-top: auto; }
.consent-fit > :last-child { margin-bottom: auto; }
/* Le panneau ne se COMPRIME pas. Un enfant de flex a pour taille minimale
   automatique celle de son contenu — sauf s'il porte `overflow: hidden`, ce
   que `.panel` fait pour ses angles arrondis : sa minimale retombe alors a
   zero, il se laisse ecraser, et son contenu est simplement coupe au lieu de
   faire defiler la colonne. C'est ainsi que le mode d'emploi d'installation
   disparaissait sous le pli sans qu'aucun defilement ne le rattrape. */
.consent-fit > .panel { flex: none; }
#screen-consent .brand-head, #screen-perms .brand-head,
#screen-install .brand-head { flex: none; margin-bottom: clamp(4px, 1.2vh, 12px); }
/* Meme entete pour les consignes et les autorisations : le titre seul, sans
   tete de troll, et le nom du terrain centre et colle sous les lettres. */
#screen-consent .brand-title, #screen-perms .brand-title { width: min(58%, 210px); }
#screen-consent .wordmark-sub, #screen-perms .wordmark-sub {
  margin-top: clamp(-8px, calc(-1vh + 2px), -2px);
  font-size: clamp(0.8rem, 1.6vh, 1.05rem);
}

#screen-consent .consent-panel, #screen-perms .consent-panel {
  flex: 0 1 auto; min-height: 0;
  display: flex; flex-direction: column;
  padding: clamp(8px, 1.6vh, 18px) clamp(10px, 2.6vw, 14px) clamp(8px, 1.4vh, 16px);
}
#screen-consent .wood-sign, #screen-perms .wood-sign {
  flex: none;
  margin-top: -10px;
  margin-bottom: clamp(3px, 0.9vh, 12px);
  font-size: clamp(0.98rem, 2.2vh, 1.36rem);
}
#screen-consent .consent-h2, #screen-perms .consent-h2 {
  flex: none;
  margin-bottom: clamp(2px, 0.5vh, 6px);
  font-size: clamp(0.9rem, 1.9vh, 1.16rem);
}
#screen-consent .consent-lead, #screen-perms .consent-lead {
  flex: none;
  margin: 0 0 clamp(6px, 1.4vh, 14px);
  font-size: clamp(0.7rem, 1.5vh, 0.86rem);
  line-height: 1.45;
}
#screen-consent .rule {
  align-items: center;
  gap: clamp(8px, 2.6vw, 13px);
  padding: clamp(4px, 1.1vh, 13px) clamp(9px, 2.6vw, 14px);
  margin-bottom: clamp(3px, 0.8vh, 16px);
}
#screen-consent .rule-txt h3, #screen-perms .rule-txt h3 { font-size: clamp(0.74rem, 1.6vh, 0.94rem); margin-bottom: 2px; }
#screen-consent .rule-txt p, #screen-perms .rule-txt p { font-size: clamp(0.62rem, 1.35vh, 0.79rem); line-height: 1.34; }
#screen-consent .consent-rules { display: grid; gap: 0; }
#screen-perms .perm {
  gap: clamp(8px, 2.6vw, 13px);
  padding: clamp(7px, 1.3vh, 12px) clamp(9px, 2.6vw, 14px);
  margin-bottom: clamp(4px, 1vh, 10px);
}
#screen-perms .perm-note { margin: clamp(2px, 0.6vh, 6px) 0 clamp(4px, 1vh, 12px); }
#screen-consent .consent-ack, #screen-perms .consent-ack {
  flex: none;
  margin: clamp(4px, 1vh, 10px) 0 clamp(4px, 1vh, 12px);
  font-size: clamp(0.58rem, 1.15vh, 0.72rem);
}
#screen-consent .consent-acts, #screen-perms .consent-acts { flex: none; display: grid; gap: clamp(6px, 1vh, 10px); }
#screen-consent .consent-acts .btn, #screen-perms .consent-acts .btn { min-height: clamp(36px, 5vh, 52px); }

/* Sous 660 px de haut le sous-titre saute : la pancarte dit deja de quoi il
   s'agit, et ce sont les quatre regles qui doivent tenir. */
@media (max-height: 660px) {
  #screen-consent .consent-h2, #screen-perms .consent-h2 { display: none; }
}

/* Paysage court : deux colonnes de regles et deux boutons cote a cote, sinon
   rien ne rentre. Le logo saute — la pancarte suffit a nommer l'ecran. */
@media (orientation: landscape) and (max-height: 560px) {
  #screen-consent .brand-head, #screen-perms .brand-head { display: none; }
  #screen-consent .consent-h2, #screen-perms .consent-h2 { display: none; }
  #screen-consent .wood-sign, #screen-perms .wood-sign { max-width: 380px; }
  #screen-consent .consent-rules { grid-template-columns: 1fr 1fr; column-gap: 10px; }
  #screen-consent .consent-acts, #screen-perms .consent-acts { grid-template-columns: 1fr 1fr; }
  .consent-fit { max-width: 760px; }
}

/* ==================== AUTORISATIONS DU TELEPHONE ==================== */

/* Les trois acces portent desormais les medaillons peints de assets/badges/,
   comme les consignes : l'anneau et le halo sont dans l'image. La pastille
   cerclee en CSS (.perm-ic) qui encadrait un SVG a disparu avec eux. */
.perm {
  display: flex; gap: 13px; align-items: center;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  background: rgba(255, 255, 255, 0.045);
  border: var(--line-soft);
  box-shadow: var(--bevel);
  margin-bottom: 10px;
  transition: border-color 0.25s var(--ease), background 0.25s var(--ease);
}
.perm .rule-txt { flex: 1; min-width: 0; }
.perm-state {
  width: 30px; height: 30px; flex: none;
  display: grid; place-items: center;
  color: var(--parch-dim);
}
.perm-state svg { width: 20px; height: 20px; }
.perm.pending .perm-state { animation: pulse 1.2s ease-in-out infinite; }
.perm.ok { border-color: rgba(127, 208, 127, 0.55); background: rgba(74, 150, 90, 0.14); }
.perm.ok .perm-state { color: var(--moss); }
.perm.ko { border-color: rgba(217, 105, 92, 0.55); background: rgba(150, 70, 60, 0.14); }
.perm.ko .perm-state { color: var(--ember); }
.perm-note { margin: 4px 0 12px; }

/* ============================ ACCUEIL ============================ */

/* `--ground-h` : la hauteur du sol de foret, aussi utilisee comme reserve en
   bas du scroller — le contenu ne doit jamais finir cache derriere le decor.

   `overflow: hidden` n'est pas decoratif : le fond et le sol debordent
   volontairement de l'ecran pour pouvoir deriver sans decouvrir de bande vide,
   et sans cette coupe leur depassement se verrait le long du bord.

   **Un fond sombre PLEIN sous tout le reste.** Les deux calques du decor
   derivent, et un calque anime est une couche a part que le compositeur
   redessine a des decalages fractionnaires : son bord y est interpole, et sur
   un ou deux pixels il devient a demi transparent. On voyait alors au travers
   la photo de foret du fond general (`#bg-photo`), bien plus claire — le trait
   clair le long du bord gauche. Avec cette couleur dessous, ce qui filtre
   n'est plus qu'un vert presque noir, c'est-a-dire rien.

   **Deux ecrans portent `.home-bg`** — l'accueil et « En savoir plus ». Le fond
   de secours et le voile ci-dessous valent donc pour les deux, et ces listes
   sont a tenir alignees avec le HTML : un troisieme ecran qui reprendrait ce
   decor sans se nommer ici perdrait son assombrissement. */
#screen-home,
#screen-more {
  overflow: hidden;
  background: #08150f;
}
#screen-home { --ground-h: min(54vw, 24vh); }

/* L'ASSOMBRISSEMENT NE DERIVE PAS. Il vivait sur le calque du fond
   (`.home-bg::after`) et voyageait donc avec lui : partout ou ce calque anime
   etait rogne par le bord de l'ecran, il manquait aussi le voile, et il ne
   restait qu'un trait clair le long du bord gauche. Pose sur l'ecran, qui ne
   bouge pas, il couvre la dalle entiere une fois pour toutes.

   Il se glisse entre le decor (z-index 0) et le contenu (z-index 1) sans
   z-index a lui : un pseudo-element ::after est le dernier enfant, il passe
   donc devant ses freres de meme plan et derriere ceux qui montent. */
#screen-home::after,
#screen-more::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(120% 70% at 50% -8%, rgba(8, 26, 18, 0.30), transparent 58%),
    linear-gradient(180deg, rgba(6, 20, 14, 0.52), rgba(5, 16, 11, 0.30) 55%, rgba(4, 12, 8, 0.10));
}

/* L'accueil a son propre fond, plus lumineux que #bg-photo.

   Il derive lentement de 11 px, et le sol devant lui derive de 5 px dans
   l'autre sens : c'est l'ecart entre les deux qui donne la profondeur, pas le
   deplacement lui-meme. Le fond deborde donc de 16 px de chaque cote, le sol de
   11 px, sinon la derive decouvrirait une bande vide au bord.

   Deux periodes premieres entre elles (13 s et 9 s) : avec la meme, les deux
   calques repasseraient ensemble par leur point de depart et le mouvement se
   lirait comme un balancier. Et seulement `transform`, que le compositeur
   traite sans repeindre — sur un ecran qu'on laisse ouvert au parking, une
   animation qui repeint coute une batterie.

   Ce calque ne porte plus que la photo : l'assombrissement est monte sur
   `#screen-home::after` (voir plus haut), parce qu'un voile qui derive avec ce
   qu'il assombrit n'assombrit plus rien la ou il est rogne. */
.home-bg {
  position: absolute; inset: 0 -16px; z-index: 0;
  background: url("../assets/bg/accueil.jpg") center/cover no-repeat;
  animation: home-drift 13s ease-in-out infinite alternate;
  will-change: transform;
}
@keyframes home-drift {
  from { transform: translate3d(-11px, 0, 0); }
  to   { transform: translate3d(11px, 0, 0); }
}
@keyframes home-drift-front {
  from { transform: translate3d(5px, 0, 0); }
  to   { transform: translate3d(-5px, 0, 0); }
}
/* Certains ne supportent pas le mouvement de fond, et le systeme le dit. */
@media (prefers-reduced-motion: reduce) {
  .home-bg, .home-ground::before { animation: none; }
}
/* Sol detoure colle au bas de l'ecran, bord a bord (le scroller, lui, est
   borne a 560 px).

   **Bord a bord, sans borne de largeur.** Une borne a 780 px paraissait sage
   tant qu'on regardait un telephone ; des 800 px de large — une tablette en
   portrait, un telephone couche, une fenetre de bureau — elle laissait un
   lisere clair de quelques pixels le long de chaque bord, la ou le sol
   s'arretait et ou le fond, plus lumineux, reparaissait. Le sol s'etire donc
   sur toute la largeur : une souche allongee ne se remarque pas, un trait clair
   au bord de l'ecran, si.

   L'image et la note manuscrite se calent toutes deux en pourcentage de CETTE
   boite : elles s'etirent ensemble, et la note reste sur le rondin quelle que
   soit la largeur. */
.home-ground {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  height: var(--ground-h);
  pointer-events: none;
}
/* L'image du sol vit dans un calque a part, et non sur `.home-ground` :
   celui-ci garde sa boite intacte parce que la note manuscrite s'y positionne
   en pourcentage. Le calque, lui, deborde de 9 px de chaque cote pour pouvoir
   deriver sans decouvrir le fond au bord de l'ecran. */
.home-ground::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: -11px; right: -11px;
  background: url("../assets/bg/accueil-sol.webp") bottom center/100% 100% no-repeat;
  animation: home-drift-front 9s ease-in-out infinite alternate;
  will-change: transform;
}
/* La note suit la pente du rondin, cinq degres anti-horaire. */
.ground-note {
  position: absolute; left: 26%; right: 13%; top: calc(47% + 1.04em - 8px);
  text-align: center;
  font-family: var(--hand); font-weight: 700;
  font-size: min(4.8vw, 22px); line-height: 1.04;
  color: #201304;
  text-shadow: 0 1px 1px rgba(255, 238, 205, 0.50);
  transform: rotate(-5deg);
}

.home-scroll { z-index: 1; padding-bottom: calc(var(--ground-h) + 16px + var(--safe-bot)); }
.home-scroll .btn.xl { margin-top: 30px; }
/* Fonder et rejoindre sont les deux moities du meme choix : elles se lisent
   d'un coup d'oeil, collees, et non comme deux propositions separees. */
#home-join { margin-top: 10px; }

.home-top { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.home-hero { text-align: center; margin: 2px 0 14px; }
/* Planche "large" (le mot coiffe de la tete). Elle a deja son modele de
   placement, celui de la barre du jeu (#topbar-main .tb-brand) : la tete
   occupe le premier tiers de l'image, donc le nom du terrain se centre sur les
   65 % de droite — sous le MOT, pas sous la planche entiere — et remonte de
   27 % de la hauteur du logo pour combler le vide que la tete laisse sous le
   mot. Le calage se fait donc sur une HAUTEUR nommee, comme --title-h la-bas :
   la marge negative ne peut pas se deduire d'une largeur. */
#screen-home .home-hero { --home-title-h: min(24vw, 96px); }
.home-logo {
  height: var(--home-title-h); width: auto;
  filter: drop-shadow(0 10px 24px rgba(0,0,0,0.7));
}
#screen-home .wordmark-sub {
  width: 100%; padding-left: 35%;
  /* Une demi-hauteur de texte en plus que le modele de la barre du jeu : sur
     l'accueil le logo est bien plus grand, et le vide sous le mot avec lui. */
  margin-top: calc(-0.27 * var(--home-title-h) - 0.5em);
  text-align: center; text-indent: 0.34em;
}

/* Le cadre du recit passe DERRIERE la pierre et s'arrete a son milieu ; il est
   plus court de 5 % en haut et en bas, si bien que la pierre a l'air d'y
   reposer. C'est la pierre qui fixe la mesure et le cadre qui s'y cale : lier
   l'inverse (pierre calee sur la hauteur du cadre) boucle sans converger, le
   texte se resserrant a chaque fois que la pierre grandit. */
/* C'est la PIERRE qui fixe la mesure et le cadre qui s'y cale. Le lien inverse
   (pierre calee sur la hauteur du cadre, via top/bottom en pourcentage) parait
   plus juste mais boucle sans converger : chaque agrandissement de la pierre
   resserre le texte, qui rallonge le cadre, qui regrandit la pierre. */
.story-row {
  position: relative;
  --stone-w: min(38vw, 158px);
  --stone-h: calc(var(--stone-w) * 640 / 508);
  padding-right: calc(var(--stone-w) / 2);
}
.story-panel {
  padding: 13px 14px;
  /* Le cadre s'arrete au milieu de la pierre, le TEXTE avant son bord gauche :
     d'ou une demi-pierre de plus en retrait interieur. */
  padding-right: calc(var(--stone-w) / 2 + 10px);
  /* 90 % : la pierre depasse de 5 % en haut et en bas, et parait poser
     dessus. Un texte plus long repousse le cadre et mange ce debord. */
  min-height: calc(var(--stone-h) * 0.9);
}
.stone-sign {
  position: absolute; right: 0; top: 50%;
  transform: translateY(-50%);
  width: var(--stone-w); height: var(--stone-h);
  background: url("../assets/ui/pierre-pancarte.webp") center/contain no-repeat;
  filter: drop-shadow(0 10px 20px rgba(0,0,0,0.6));
}

/* Sapin en lettrine : le texte s'ecoule autour, d'ou le float. En colonne a
   part il etranglerait le texte, deja pris entre le sapin et la pierre. */
.story-fir {
  float: left;
  margin: 0 10px 2px 0;
  filter: drop-shadow(0 2px 4px rgba(0,0,0,0.45));
}
/* Pastille dessinee et non emoji : le sapin systeme changeait de dessin d'un
   telephone a l'autre, et jurait avec les briques juste dessous. */
.story-fir img { width: 42px; height: 42px; display: block; }
.story-head { font-weight: 750; font-size: 0.8rem; margin-bottom: 6px; line-height: 1.34; }
.story-panel p { margin: 0; font-size: 0.72rem; line-height: 1.5; }

/* La pancarte occupe le bas de l'image : ces bornes suivent le parchemin. */
.stone-sign > span {
  position: absolute; left: 12%; right: 8%; top: calc(65% + 6px);
  text-align: center;
  font-family: var(--hand); font-weight: 700;
  font-size: min(3.9vw, 16.5px); line-height: 1.04;
  color: #2a1a06;
  text-shadow: 0 1px 0 rgba(255, 255, 255, 0.32);
  transform: rotate(-1deg);
}

/* "Comment ca marche" a quitte le bas de page pour la pilule d'entete : c'est
   la premiere question qu'on se pose, elle ne se lit pas apres tout le reste.
   Sa pastille dessinee remplace le pictogramme plat, comme partout ailleurs. */
.home-top .pill-btn { font-size: 0.78rem; padding: 6px 12px 6px 8px; }
.home-top .pill-ic img { width: 30px; height: 30px; display: block; }

/* ---------------------------- LES BRIQUES ----------------------------
   Trois chiffres et deux portes, en verre sombre sur la photo. Le chiffre
   passe AVANT son libelle en corps, jamais en ordre : on lit "Joueurs 128",
   pas un nombre orphelin. */
.brick-row {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
  margin-top: 14px;
}
.brick-row.two { grid-template-columns: repeat(2, 1fr); margin-top: 12px; }

.brick {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 10px; text-align: left;
  border-radius: var(--radius-sm);
  border: var(--line);
  background: linear-gradient(165deg, rgba(30, 66, 48, 0.62), rgba(9, 24, 18, 0.72));
  box-shadow: var(--shadow-1), var(--bevel);
  color: var(--parchment);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.brick-ic { flex: none; }
.brick-ic img { width: 26px; height: 26px; display: block; }
.brick-ic.big img { width: 34px; height: 34px; }
.brick-txt { min-width: 0; }
.brick-txt b { display: block; font-size: 0.7rem; font-weight: 750; line-height: 1.2; }
.brick-txt i {
  display: block; font-style: normal;
  font-size: 0.56rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--parch-faint); line-height: 1.2;
}
/* Un compteur se lit d'un coup d'oeil : chiffre grave, libelle au-dessus. */
.brick-txt i + b { font-size: 0.98rem; font-weight: 800; color: var(--gold); margin-top: 1px; }

.brick.door {
  font: inherit; cursor: pointer;
  padding: 11px 11px;
  transition: transform 0.12s var(--ease), border-color 0.2s;
}
.brick.door:active { transform: scale(0.97); }
.brick.door .brick-txt i { text-transform: none; letter-spacing: 0; margin-top: 2px; }

/* ==================== EN SAVOIR PLUS, ZONE DE JEU ====================
   Ces ecrans ne defilent pas : entete, onglets, pile, jauge, du haut au bas de
   la dalle. Une page qui glisse sous le doigt ne cohabite pas avec un
   scroller — les deux se disputeraient le meme geste. */
#screen-more.active, #screen-zone.active {
  display: flex; flex-direction: column;
  padding: calc(var(--safe-top) + 10px) 12px calc(var(--safe-bot) + 10px);
}

.deck-head {
  position: relative; z-index: 1; flex: none;
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 8px;
}
.deck-title { flex: 1; min-width: 0; }
.deck-title b {
  display: block; font-family: var(--display); font-weight: 800;
  font-size: 0.98rem; color: var(--parchment);
}
.deck-title i {
  display: block; font-style: normal; font-size: 0.62rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--parch-faint);
}
.deck-badge img { width: 34px; height: 34px; display: block; opacity: 0.9; }

/* La pile : une fenetre qui coupe, un rail qui glisse. touch-action: pan-y
   laisse le systeme garder le geste vertical (fermeture, rafraichissement)
   et nous confie l'horizontal. */
.deck {
  position: relative; z-index: 1; flex: 1; min-height: 0;
  overflow: hidden;
  touch-action: pan-y;
  -webkit-tap-highlight-color: transparent;
  /* Sans cela, glisser sur une image lance le glisser-deposer natif du
     navigateur : le pointeur est capture par lui, la pile recoit un
     pointercancel au troisieme pixel et ne tourne jamais. */
  user-select: none; -webkit-user-select: none;
}
.deck img { -webkit-user-drag: none; user-drag: none; }
/* Pas de `will-change: transform` ici, et c'est deliberé : le rail fait
   SOIXANTE-QUATRE ecrans de large a l'onglet des personnages. Promu en couche,
   il demande au compositeur un tampon de la taille du rail entier — quelque
   sept cents megaoctets sur une dalle a densite 3 — et le telephone tuait
   l'onglet en pleine lecture. La transition suffit : elle promeut la couche le
   temps du glissement, et la rend ensuite. */
.deck-rail {
  display: flex; height: 100%;
  transition: transform 0.36s var(--ease);
}
/* Une page hors du champ n'est pas PEINTE : `visibility` la retire du rendu
   sans toucher a la mise en page — chaque page garde sa largeur, donc le
   decalage du rail reste juste. Sans cela, soixante-quatre ombres portees
   (`drop-shadow`, un filtre, donc une couche) etaient rasterisees d'un coup. */
.deck-slide[data-far] { visibility: hidden; }
.deck-slide {
  flex: 0 0 100%; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; padding: 4px 6px;
}
/* La carte porte deja son cadre, peint dans l'image : aucun panneau autour,
   seulement l'ombre qui la decolle du sous-bois. */
.deck-card {
  max-width: 100%; min-height: 0;
  flex: 1 1 auto; object-fit: contain;
  aspect-ratio: 950 / 1393;
  filter: drop-shadow(0 18px 38px rgba(0, 0, 0, 0.7));
  /* Les voisines sont chargees d'avance : elles s'effacent tant qu'on ne les
     a pas amenees au centre, sinon on verrait la suivante depasser. */
  opacity: 0.35; transition: opacity 0.3s var(--ease), transform 0.36s var(--ease);
  transform: scale(0.94);
}
.deck-slide.on .deck-card { opacity: 1; transform: none; }
/* Le portrait detoure sous sa carte : c'est cette tete-la qu'on choisit a
   l'inscription. Pierre a lichen dessous, comme le choix d'avatar — aucune
   troupe n'est encore connue. */
.deck-av {
  --av-bg: #6d7a63;
  flex: none; width: 62px; height: 62px; border-radius: 20px;
}

.deck-bar {
  flex: none; height: 3px; margin-top: 10px;
  border-radius: 999px; background: rgba(238, 241, 230, 0.12);
  overflow: hidden;
}
.deck-bar span {
  display: block; height: 100%; width: 2%;
  border-radius: 999px; background: linear-gradient(90deg, var(--gold-deep), var(--gold));
  transition: width 0.3s var(--ease);
}

/* --------------------- les onglets d'En savoir plus ---------------------
   Trois onglets en pastille : on doit pouvoir passer de l'histoire aux
   personnages d'un pouce, sans revenir en arriere. Ils se serrent a trois sur
   la largeur d'un telephone, d'ou l'ellipse plutot qu'un retour a la ligne. */
.more-tabs {
  position: relative; z-index: 1; flex: none;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px;
  margin-bottom: 8px;
}
.more-tab {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 6px 8px; min-width: 0;
  font: inherit; font-size: 0.66rem; font-weight: 700; cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--parch-dim);
  border-radius: 999px;
  border: 1px solid rgba(238, 241, 230, 0.10);
  background: rgba(9, 26, 19, 0.62);
  transition: color 0.2s, border-color 0.2s, background 0.2s;
}
.more-tab img { width: 22px; height: 22px; display: block; flex: none; }
.more-tab.on {
  color: var(--parchment);
  border-color: rgba(127, 208, 127, 0.55);
  background: rgba(74, 150, 90, 0.18);
}

/* Une page de texte : elle occupe la pile comme une carte, mais se lit — d'ou
   un panneau plein plutot qu'une image posee sur le sous-bois. */
.more-slide { padding: 4px 2px; }
.more-page {
  width: 100%; max-width: 460px; margin: auto;
  padding: 20px 20px 22px;
  display: flex; flex-direction: column; align-items: center; text-align: center;
}
.more-ic { width: clamp(64px, 22vw, 104px); height: auto; margin-bottom: 12px; }
.more-page h3 {
  margin: 0 0 10px; font-size: 0.94rem; font-weight: 800;
  letter-spacing: 0.06em; color: var(--gold);
}
.more-page p { margin: 0; font-size: 0.78rem; line-height: 1.62; color: var(--parch-dim); }

/* ==================== INSTALLER L'APPLICATION ====================

   Un mode d'emploi, et c'est tout ce qu'il doit etre : trois pas numerotes,
   un dessin par pas. Il emprunte `.perm` a l'ecran de la besace — meme forme,
   meme rythme, parce que ce sont les deux ecrans de preparation et qu'on les
   enchaine. Sa variante `.plain` retire seulement la colonne d'etat : ici
   rien n'est accorde ni refuse, on explique. */

/* `.perm` est un flex, pas une grille : la variante n'a donc rien a retirer,
   c'est l'absence de `.perm-state` dans le HTML qui suffit. Elle ne sert plus
   qu'a dire que cette ligne n'attend aucun verdict — d'ou le cadre neutre,
   qui ne virera jamais au vert ni au rouge. */
.perm.plain { transition: none; }

/* Les deux systemes : deux onglets et non deux ecrans. On ne sait pas
   toujours ce qu'on tient en main, et personne ne veut revenir en arriere
   pour changer de mode d'emploi. */
.ins-tabs {
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px;
  margin: 16px 0 10px;
}
.ins-tab {
  padding: 9px 8px; font: inherit; font-size: 0.78rem; font-weight: 700;
  cursor: pointer; color: var(--parch-dim);
  border-radius: 999px;
  border: 1px solid rgba(238, 241, 230, 0.10);
  background: rgba(9, 26, 19, 0.62);
  transition: color 0.2s, border-color 0.2s, background 0.2s;
}
.ins-tab.on {
  color: var(--parchment);
  border-color: rgba(127, 208, 127, 0.55);
  background: rgba(74, 150, 90, 0.18);
}

.ins-how { margin-bottom: 4px; }

.ins-steps { list-style: none; margin: 0; padding: 0; }
.ins-steps li {
  display: grid; grid-template-columns: auto 1fr auto;
  align-items: center; gap: 12px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: var(--line-soft);
  background: rgba(9, 26, 19, 0.45);
  font-size: 0.82rem; color: var(--parch-dim);
  /* Un enfant de grille vaut `min-width: auto` : sans cela, une ligne un peu
     longue pousse le dessin hors de l'ecran au lieu de passer a la ligne. */
  min-width: 0;
}
.ins-steps li + li { margin-top: 6px; }
.ins-steps li > span:nth-child(2) { min-width: 0; }
.ins-steps b { color: var(--parchment); }

.ins-num {
  width: 24px; height: 24px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%;
  font-size: 0.72rem; font-weight: 900; color: var(--ink-900);
  background: var(--gold);
}

/* Le dessin du geste : il imite un bouton d'un AUTRE logiciel, il porte donc
   le gris du systeme et non l'or du jeu — sinon on le chercherait dans notre
   propre interface. */
.ins-fig {
  width: 34px; height: 34px; flex: none;
  display: grid; place-items: center;
  border-radius: 10px;
  color: var(--parchment);
  border: 1px solid rgba(238, 241, 230, 0.16);
  background: rgba(238, 241, 230, 0.06);
}
.ins-fig svg { width: 20px; height: 20px; display: block; }

#ins-go { margin-top: 10px; }

/* La porte du cartographe n'est pas celle des joueurs, et rien ne le disait
   avant cinq essais rates. */
.note-reserve {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 0 0 16px; padding: 10px 12px;
  border-radius: var(--radius-sm);
  border: 1px solid rgba(226, 201, 141, 0.24);
  background: rgba(179, 147, 79, 0.10);
  font-size: 0.74rem; line-height: 1.5; color: var(--parch-dim);
  text-align: left;
}
.note-reserve b { color: var(--gold); }
.note-reserve .brick-ic { flex: none; }

/* ==================== REGLAGES DE L'APPAREIL ====================
   Trois ecrans de bureau sur un telephone : ils defilent, contrairement au jeu
   de cartes, parce qu'on y lit plus qu'on n'y touche. */

/* Meme entete pour les reglages de l'appareil et pour les portes des outils
   de l'organisateur : retour, titre, pastille. */
.opt-head, .tool-head {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 12px;
}
.opt-panel { margin-bottom: 10px; }
.opt-lab { display: flex; align-items: flex-start; gap: 9px; margin-bottom: 10px; }
.opt-lab .brick-ic img { width: 28px; height: 28px; display: block; }
.opt-lab .brick-txt i { text-transform: none; letter-spacing: 0; font-size: 0.62rem; margin-top: 3px; }
.opt-danger { border-color: rgba(217, 105, 92, 0.32); }

/* Une porte pleine largeur : meme brique que l'accueil, la fleche en plus. */
.brick.wide-door { width: 100%; margin-bottom: 10px; gap: 10px; }
.brick.wide-door .brick-txt { flex: 1; }
.brick.wide-door .pill-arrow svg { width: 14px; height: 14px; opacity: 0.5; }

/* Les quatre calages tiennent dans une liste deroulante : le reglage se touche
   une fois dans la vie de l'appareil, quatre paves deplies lui donnaient le
   tiers de l'ecran. La note dit ce que repare le calage choisi — sans elle on
   choisirait au hasard. */
#fit-select { padding: 11px 13px; font-size: 0.78rem; font-weight: 700; }
.fit-note {
  margin: 7px 2px 0; font-size: 0.6rem; line-height: 1.34;
  color: var(--parch-faint);
}

/* Le rattrapage en pixels, sur une ligne : deux boutons et le chiffre entre
   eux. C'est le seul reglage de hauteur qui se voit sur une app installee,
   ou les unites du navigateur renvoient toutes la meme chose. */
.fit-adj {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin-top: 9px;
}
.fit-adj b {
  min-width: 62px; text-align: center;
  font-size: 0.78rem; font-weight: 800; color: var(--parchment);
}
.fit-adj .btn { flex: none; padding: 8px 12px; }

/* Un cran de GPS : le nom, ce qu'il donne, ce qu'il coute. Les trois lignes
   ensemble — un intitule seul ne permet pas d'arbitrer entre precision et
   batterie, et c'est le seul arbitrage que ce reglage demande. */
.gps-choice {
  display: block; width: 100%; text-align: left;
  padding: 12px 14px; margin-bottom: 8px;
  border-radius: var(--radius-sm); border: var(--line);
  background: var(--glass-2); color: var(--parchment);
  font-family: inherit; cursor: pointer;
}
.gps-choice.on { border-color: var(--gold); background: var(--glass-1); }
.gps-choice b { display: block; font-size: 0.86rem; font-weight: 800; }
.gps-choice.on b::after { content: ' ✓'; color: var(--gold); }
.gps-choice i {
  display: block; margin-top: 3px; font-style: normal;
  font-size: 0.66rem; line-height: 1.34; color: var(--parch-dim);
}
.gps-choice u {
  display: block; margin-top: 4px; text-decoration: none;
  font-size: 0.6rem; line-height: 1.32; color: var(--parch-faint);
}

/* Etat d'un capteur : la pastille de couleur porte l'information, le texte la
   detaille. Memes trois etats que l'ecran des autorisations. */
.sensor-row {
  display: flex; align-items: baseline; gap: 10px;
  padding: 9px 12px; margin-bottom: 6px;
  border-radius: var(--radius-sm); border: var(--line);
  background: rgba(9, 26, 19, 0.62);
}
.sensor-row::before {
  content: ""; flex: none; align-self: center;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--parch-faint);
}
.sensor-row.ok::before { background: var(--moss); box-shadow: 0 0 8px rgba(127, 208, 127, 0.6); }
.sensor-row.ko::before { background: var(--rot); }
.sensor-row.wait::before { background: var(--gold); animation: pulse 1.2s ease-in-out infinite; }
.sensor-row b { font-size: 0.7rem; font-weight: 750; width: 78px; flex: none; }
.sensor-row i { font-style: normal; font-size: 0.64rem; color: var(--parch-dim); }

/* Journal des versions : la premiere est celle qui tourne, marquee comme telle
   — sans cela on ne sait pas si la mise a jour est deja prise. */
.upd .upd-top { display: flex; align-items: baseline; gap: 8px; margin-bottom: 5px; }
.upd .upd-top b { font-size: 0.86rem; color: var(--gold); font-weight: 800; }
.upd .upd-top i { font-style: normal; font-size: 0.58rem; color: var(--parch-faint); margin-left: auto; }
.upd-tag {
  font-size: 0.52rem; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 999px;
  color: var(--moss); border: 1px solid rgba(127, 208, 127, 0.45);
}
.upd ul { margin: 0; padding-left: 16px; }
.upd li { font-size: 0.66rem; line-height: 1.45; color: var(--parch-dim); }
.upd.now { border-color: rgba(127, 208, 127, 0.35); }

/* =========================== LA ZONE DE JEU =========================== */

.zone-canvas {
  flex: 1; min-height: 0; width: 100%;
  border-radius: var(--radius); border: var(--line);
  box-shadow: var(--shadow-2);
  background: var(--ink-900);
  touch-action: none;
}
.zone-note {
  flex: none; display: flex; align-items: center; gap: 10px;
  margin-top: 10px; padding: 9px 12px;
  border-radius: var(--radius-sm); border: var(--line);
  background: linear-gradient(165deg, rgba(30, 66, 48, 0.72), rgba(9, 24, 18, 0.78));
  color: var(--parchment);
}
.zone-note .brick-txt i { text-transform: none; letter-spacing: 0; font-size: 0.6rem; margin-top: 2px; }


/* ------------------- les personnages : la carte et la main -------------------

   La carte en grand occupe tout le cadre, et le rang de portraits se
   chevauche dessous, comme un jeu qu'on tient en main. Le portrait du
   personnage, lui, est POSE SUR sa carte en bas a droite : sous elle, il
   volait la hauteur de ce qu'on est venu regarder. */
.card-slide { padding: 2px 6px; }
/* LE CADRE A LA FORME DE LA CARTE, et c'est ce qui repare deux choses d'un
   coup. Il occupait toute la fenetre : `object-fit: contain` centrait bien le
   dessin, mais l'element, lui, debordait de cinquante pixels en haut et en
   bas — si bien que le portrait, pose « en bas a droite du cadre », tombait
   SOUS la carte, a moitie dans le vide. Et la page paraissait mal centree
   parce que la carte flottait dans une boite plus grande qu'elle.
   L'`aspect-ratio` sur le cadre lui donne exactement la forme du dessin : le
   portrait se pose alors sur la carte, et le centrage devient celui du
   contenu, pas celui d'une boite. */
/* Le cadre epouse la carte : `fit-content` dans les deux sens, et c'est
   l'image qui donne la mesure. L'element occupait toute la fenetre, avec le
   dessin centre dedans par `object-fit` — cinquante pixels de vide en haut et
   en bas que rien ne signalait, sinon le portrait « pose en bas a droite du
   cadre » qui tombait SOUS la carte, a moitie dans le vide. La page paraissait
   mal centree pour la meme raison : la carte flottait dans une boite plus
   grande qu'elle.
   L'image se dimensionne donc d'elle-meme (`width`/`height` en auto) et les
   deux maxima la bornent en gardant ses proportions, comme toute image
   remplacee. Une `aspect-ratio` sur le cadre ne suffisait pas : avec une
   hauteur definie, elle deborde la largeur au lieu de s'y plier. */
.card-wrap {
  position: relative;
  flex: 0 1 auto; min-height: 0;
  width: fit-content; height: fit-content;
  max-width: 100%; max-height: 100%;
  margin: auto;
}
.card-slide .deck-card {
  display: block; flex: none;
  width: auto; height: auto;
  max-width: 100%; max-height: 100%;
}
/* Assez gros pour se reconnaitre d'un coup d'oeil : c'est cette tete-la qu'on
   choisit a l'inscription, pas la carte peinte. */
.card-slide .deck-av {
  position: absolute; right: 4%; bottom: 3%;
  width: 86px; height: 86px; border-radius: 24px;
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.65);
  opacity: 0; transition: opacity 0.3s var(--ease);
}
.deck-slide.on .card-slide .deck-av,
.card-slide.on .deck-av { opacity: 1; }
@media (max-height: 700px) {
  .card-slide .deck-av { width: 64px; height: 64px; border-radius: 18px; }
}

/* Le rang de portraits qui se chevauchent : chacun mord sur le precedent,
   comme un jeu de cartes etale. Le courant se detache et remonte. */
/* `position: relative; z-index: 1` n'est pas decoratif : `.home-bg` est un
   calque positionne en z-index 0, et un element en flux normal passe DESSOUS.
   La bande etait bien la, aux bonnes coordonnees, mais cachee par le fond —
   seul le portrait actif s'en sortait, parce qu'il porte un z-index a lui.
   `.deck` porte deja la meme paire, pour la meme raison. */
.deck-strip {
  position: relative; z-index: 1;
  flex: none; display: flex; align-items: center;
  padding: 8px 12px 2px;
  overflow-x: auto; scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.deck-strip::-webkit-scrollbar { display: none; }
.strip-av {
  flex: none; width: 46px; height: 46px; padding: 0;
  margin-left: -14px;          /* le chevauchement */
  border-radius: 14px; cursor: pointer;
  background: #6d7a63;
  border: 2px solid rgba(12, 24, 18, 0.85);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.5);
  overflow: hidden;
  transition: transform 0.16s var(--ease), border-color 0.16s;
}
.strip-av:first-child { margin-left: 0; }
.strip-av img { width: 100%; height: 100%; display: block; object-fit: cover; }
.strip-av.on {
  transform: translateY(-7px) scale(1.1);
  border-color: var(--moss);
  z-index: 2;
}

/* Les points de pagination. Au-dela de douze pages ils laissent la place a
   « 7 / 64 … » : soixante-quatre points ne se comptent pas du regard, et une
   barre qui se remplit n'annonce jamais combien il en reste. */
.deck-dots {
  position: relative; z-index: 1;
  flex: none; display: flex; justify-content: center; align-items: center;
  gap: 6px; min-height: 18px; margin-top: 8px;
}
.deck-dot {
  width: 18px; height: 18px; padding: 0; border: 0; background: none;
  cursor: pointer; position: relative;
}
.deck-dot::after {
  content: ""; position: absolute; inset: 6px;
  border-radius: 50%; background: rgba(238, 241, 230, 0.28);
  transition: background 0.2s, transform 0.2s var(--ease);
}
.deck-dot.on::after { background: var(--gold); transform: scale(1.4); }
.deck-more {
  font-size: 0.62rem; font-weight: 700; letter-spacing: 0.06em;
  color: var(--parch-faint);
}
.deck-more b { color: var(--gold); }

/* ==================== LE LIVRE : les contes de Vouillant ====================

   Le recit vient de `story/`, converti par `prepare_story.py`, et il se lit
   ICI COMME LA-BAS : une page d'illustration, une page de PAPIER. C'est la
   seule chose de l'application qui ne soit pas du verre vert, et c'est
   volontaire — un conte se lit sur du papier, et ce changement de matiere
   dit qu'on a quitte le jeu pour le livre.

   Trois regles portent la lisibilite, et chacune repare un defaut precis :

   1. LE TEXTE COULE, il n'est pas centre. Chaque phrase du livre reste un
      `.story-line`, mais elles se suivent dans un seul bloc aligne a gauche.
      Une phrase par paragraphe centre donnait quinze lignes en drapeau : on
      les dechiffrait au lieu de les lire.
   2. RIEN N'EST COUPE. Le recit defile a l'interieur du papier, titre et pied
      restant en place. Avant, ce qui depassait de la page n'existait plus, et
      les dernieres phrases n'ont jamais ete lues.
   3. LES DEUX ORIENTATIONS PARTAGENT LE MEME HTML. En portrait l'illustration
      surmonte le papier ; en paysage elles forment la double page, reliure au
      milieu. Deux rendus auraient fini par diverger, et c'est le meme conte. */

.book-slide { padding: 0; }

.book-spread {
  display: flex; flex-direction: column;
  width: 100%; height: 100%; min-height: 0;
  border-radius: 10px; overflow: hidden;
  /* La tranche de bois du livre : le papier ne flotte pas sur la foret. */
  background: #5a4528;
  box-shadow: 0 26px 50px rgba(0, 0, 0, 0.62), 0 2px 4px rgba(0, 0, 0, 0.5);
}

.book-page { min-height: 0; display: flex; flex-direction: column; position: relative; }
.book-page.left { flex: 0 0 34%; }
.book-page.right { flex: 1 1 auto; min-height: 0; }

/* ---- la page d'illustration ----
   Elle occupe SA page en entier (`cover`), comme dans le livre : une image
   posee au milieu d'une marge ressemble a une vignette, pas a une planche. */
.book-art {
  position: relative; margin: 0; height: 100%; min-height: 0;
  overflow: hidden; background: #253329;
}
.book-img {
  width: 100%; height: 100%; object-fit: cover; object-position: center 45%;
  display: block;
  cursor: zoom-in; -webkit-tap-highlight-color: transparent;
}
/* Le voile du bas : la legende manuscrite se pose dessus, et sans lui elle
   tombe une fois sur deux sur une zone claire du dessin. */
.book-art::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(0deg, rgba(8, 29, 23, 0.88), transparent 34%);
}
.art-caption {
  position: absolute; left: 18px; right: 18px; bottom: 14px; z-index: 2;
  text-align: center; font-family: var(--hand); font-size: 1.16rem;
  line-height: 1.15; color: #f6e9c5; text-shadow: 0 2px 10px rgba(0, 0, 0, 0.9);
}
.art-number {
  position: absolute; top: 12px; left: 12px; z-index: 2;
  padding: 5px 9px; font-size: 0.56rem; letter-spacing: 0.18em;
  color: #f7ebce; border: 1px solid rgba(255, 255, 255, 0.28);
  background: rgba(23, 40, 32, 0.45); backdrop-filter: blur(4px);
}

/* ---- la page de papier ---- */
.book-paper {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column;
  padding: 18px 20px 12px;
  color: #30392b;
  /* Le grain du papier : un bord plus sombre du cote de la reliure, un
     eclaircissement en haut a droite. Deux degrades, aucun bitmap. */
  background:
    radial-gradient(ellipse at 100% 0%, rgba(255, 250, 240, 0.66), transparent 65%),
    linear-gradient(180deg, #c9bea2 0, #e9e1cb 1.2%, #f4efdf 6%, #f4efdf 100%);
}
/* Le filet imprime a l'interieur de la marge. */
.book-paper::before {
  content: ''; position: absolute; inset: 12px 13px; pointer-events: none;
  border: 1px solid rgba(136, 119, 70, 0.14);
}

.chapter-label {
  display: flex; align-items: center; gap: 10px; flex: none;
  margin: 0 0 8px; font-size: 0.56rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: #827551;
}
.chapter-label::after {
  content: ''; height: 1px; flex: 1; background: rgba(174, 156, 105, 0.32);
}
.book-paper h3 {
  flex: none; margin: 0 0 4px;
  font-family: Georgia, "Times New Roman", serif; font-weight: 400;
  font-size: clamp(1.24rem, 5.4vw, 1.62rem); line-height: 1.08;
  letter-spacing: -0.01em; color: #35432d; text-wrap: balance;
}
.book-time {
  flex: none; margin: 0 0 12px;
  font: italic 0.76rem/1.3 Georgia, "Times New Roman", serif; color: #908263;
}

/* Le recit lui-meme : c'est LUI qui defile, pas la page. Le titre et le pied
   restent donc sous les yeux pendant qu'on lit la fin. */
.prose {
  flex: 1 1 auto; min-width: 0; min-height: 0; overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin; scrollbar-color: #a79a73 transparent;
  padding-right: 6px;
}
.prose::-webkit-scrollbar { width: 3px; }
.prose::-webkit-scrollbar-thumb { background: #bcae86; border-radius: 3px; }
.prose p {
  margin: 0;
  font-family: Georgia, "Times New Roman", serif;
  font-size: clamp(0.95rem, 4.1vw, 1.05rem); line-height: 1.78;
  color: #30392b; text-align: left; text-wrap: pretty;
}
/* Les phrases gardent leur identite (le livre imprime les met a la ligne)
   mais coulent ici les unes derriere les autres : sur une page de telephone,
   une phrase par ligne fait une colonne de moignons. */
.story-line { display: inline; }
/* La lettrine : le signe qui dit « ceci est un conte », et le seul ornement
   que la page s'autorise. */
.prose p::first-letter {
  float: left; font: 2.9rem/0.82 Georgia, serif; color: #6b7846;
  padding: 6px 6px 0 0;
}

/* « La suite en dessous ». Une page de conte ne tient pas sur un telephone :
   elle defile, et sans repere on croit avoir lu la fin alors qu'il reste
   quatre phrases — c'est exactement ce qui rendait le recit incomprehensible.
   Le degrade dit que le papier continue, la fleche ou l'on va. Les deux
   s'effacent des qu'on touche le bas (`data-end`, pose par app.js) : un
   indicateur qui ment une fois ne se lit plus jamais. */
.prose-wrap { position: relative; flex: 1 1 auto; min-height: 0; display: flex; }
.prose-wrap::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 34px;
  pointer-events: none;
  background: linear-gradient(0deg, #f4efdf, rgba(244, 239, 223, 0));
  opacity: 1; transition: opacity 0.25s ease;
}
.prose-more {
  position: absolute; right: 4px; bottom: 2px; z-index: 2;
  pointer-events: none;
  font: 700 0.5rem/1 var(--sans, inherit); letter-spacing: 0.14em;
  text-transform: uppercase; color: #8a7c56;
  opacity: 1; transition: opacity 0.25s ease;
}
.prose-wrap[data-end]::after,
.prose-wrap[data-end] .prose-more { opacity: 0; }

.page-footer {
  flex: none; display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-top: 10px; padding-top: 9px;
  border-top: 1px solid rgba(176, 162, 123, 0.4);
}
/* Le souvenir de la page : l'objet que l'on rapporte de ce chapitre. Il fait
   le lien entre le conte et la besace du jeu — c'est le meme dessin. */
.keepsake {
  display: flex; align-items: center; gap: 9px; min-width: 0; color: #807456;
}
.keepsake img { width: 34px; height: 34px; object-fit: contain; flex: none; }
.keepsake small {
  display: block; font-size: 0.46rem; letter-spacing: 0.16em;
  text-transform: uppercase; margin-bottom: 2px;
}
.keepsake > span:last-child {
  font: italic 0.74rem/1.25 Georgia, serif; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; display: block;
}
.folio { flex: none; font: 1rem Georgia, serif; color: #887b58; }

/* ---- paysage : le livre ouvert ----
   La reliure au centre, l'illustration a gauche, le recit a droite. C'est la
   seule chose que l'ecran fait en paysage : le jeu, lui, s'y refuse (voir
   `landscapeGuard` dans app.js). */
@media (orientation: landscape) {
  .book-spread { flex-direction: row; }
  .book-page.left { flex: 1 1 50%; }
  .book-page.right { flex: 1 1 50%; }
  /* Un livre ouvert se CREUSE au milieu, il ne se coupe pas : deux ombres
     portees vers l'interieur, une de chaque cote de la reliure. */
  .book-page.left .book-art { box-shadow: inset -22px 0 30px -20px rgba(0, 0, 0, 0.85); }
  .book-paper {
    padding: 14px 18px 10px;
    box-shadow: inset 22px 0 30px -22px rgba(90, 69, 40, 0.75);
  }
  .book-paper h3 { font-size: clamp(1.05rem, 2.6vw, 1.4rem); }
  .book-time { margin-bottom: 8px; font-size: 0.7rem; }
  .prose p { font-size: clamp(0.82rem, 1.9vw, 0.95rem); line-height: 1.62; }
  .prose p::first-letter { font-size: 2.3rem; padding: 4px 5px 0 0; }
  .art-caption { font-size: 1rem; bottom: 11px; }
  .keepsake img { width: 26px; height: 26px; }
  .keepsake > span:last-child { font-size: 0.66rem; }
  .folio { font-size: 0.82rem; }

  /* EN PAYSAGE, LE LIVRE PREND TOUT. Un telephone tourne a l'horizontale, ce
     n'est plus un ecran d'application : c'est un livre ouvert, et tout ce qui
     l'entoure lui vole de la hauteur. L'entete, les onglets, les points et la
     barre disparaissent — ils appartiennent au portrait, ou l'on navigue.
     Ici on lit, et l'on tourne les pages du doigt.

     Il reste donc DEUX choses a l'ecran, et elles sont sur l'image : le
     numero de page, et le retour juste dessous. Un livre qu'on ne peut pas
     refermer serait un piege ; un bandeau entier pour un seul bouton serait
     du gachis. */
  #screen-more.active { padding: 0; }
  #screen-more .deck-head,
  #screen-more .more-tabs,
  #screen-more .deck-dots,
  #screen-more .deck-bar { display: none; }
  #screen-more .deck { border-radius: 0; }
  #screen-more .book-spread { border-radius: 0; box-shadow: none; }
  /* Le numero descend sous l'encoche : en paysage elle passe sur le cote,
     mais la barre d'etat, elle, occupe toujours le haut. */
  .art-number {
    top: calc(var(--safe-top) + 10px);
    left: calc(env(safe-area-inset-left, 0px) + 12px);
  }
  /* Selecteur porte par l'ecran : la regle de base qui le cache est declaree
     APRES ce bloc, et a specificite egale c'est la derniere qui gagne. */
  #screen-more .more-back {
    display: flex;
    top: calc(var(--safe-top) + 46px);
    left: calc(env(safe-area-inset-left, 0px) + 12px);
  }
  /* Le pied de page du papier vient buter sur la barre de geste. */
  .book-paper { padding-bottom: calc(var(--safe-bot) + 8px); }
}

/* Le retour du paysage : pose sur l'illustration, sous le numero de page, et
   nulle part ailleurs. En portrait c'est celui de l'entete qui sert — deux
   boutons visibles en meme temps pour le meme geste feraient douter du
   second. */
.more-back {
  position: absolute; z-index: 4; display: none;
  align-items: center; justify-content: center;
  width: 38px; height: 38px; padding: 0;
  border-radius: 50%; cursor: pointer;
  color: #f7ebce;
  border: 1px solid rgba(255, 255, 255, 0.28);
  background: rgba(23, 40, 32, 0.55);
  backdrop-filter: blur(4px);
}
.more-back svg { width: 20px; height: 20px; }

/* Les dalles vraiment basses : la lettrine et le souvenir mangent une place
   qu'il n'y a plus. On garde le texte, on lache l'ornement. */
@media (orientation: landscape) and (max-height: 400px) {
  .prose p::first-letter { float: none; font-size: inherit; padding: 0; color: inherit; }
  .keepsake small { display: none; }
  .chapter-label { margin-bottom: 4px; }
}

/* ---- le feuilletage ----
   La page qui arrive pivote sur sa reliure. `perspective` vit sur le cadre,
   pas sur la page : sans elle, une rotation en Y est une simple compression
   horizontale, et cela ne ressemble a rien.
   La perspective ne vaut QUE pendant le feuilletage. Posee en permanence,
   elle ouvre un contexte 3D sur tout le rail : le navigateur cesse alors de
   decouper le rendu en tuiles et garde le rail entier en memoire. Elle arrive
   avec la classe `turning`, qui ne vit que six cents millisecondes. */
#more-deck.turning { perspective: 1400px; }
#more-deck.turning .deck-slide.on .book-page.right {
  animation: page-turn 0.6s var(--ease) both;
  transform-origin: left center;
}
#more-deck.turning .deck-slide.on .book-page.left {
  animation: page-fade 0.6s var(--ease) both;
}
@keyframes page-turn {
  from { transform: rotateY(-58deg); opacity: 0.25; }
  to   { transform: none; opacity: 1; }
}
@keyframes page-fade {
  from { opacity: 0.35; }
  to   { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  #more-deck.turning .deck-slide.on .book-page.right,
  #more-deck.turning .deck-slide.on .book-page.left { animation: none; }
}

/* ------------------------------------------------------ stockage

   Un remplissage de mille cinq cents fichiers se regarde : sans chiffre, une
   barre qui avance lentement ressemble a une barre bloquee, et le joueur ferme
   l application au milieu. La barre porte donc SON POURCENTAGE, ecrit dedans
   plutot qu a cote — c est la seule place ou l oeil le cherche. */
.off-step { font-size: 0.82rem; color: var(--parch-dim); margin-bottom: 8px; }
/* Le detail du travail EN COURS, famille par famille. Classes a part : `.off-fam`
   dit deja ce qui EST garde sur l'appareil, avec son pictogramme et son aide —
   c'est une autre question que « ou en est le telechargement ».
   Deux colonnes plutot qu'une liste : quatre lignes de plus dans une piece
   d'equipement pousseraient le bouton « TOUT AUTORISER » sous le pli, au
   moment precis ou l'on veut voir les deux ensemble. */
.pack-fams {
  display: grid; grid-template-columns: 1fr 1fr; gap: 2px 14px;
  margin: 0 0 8px;
}
.pack-fam {
  display: flex; align-items: baseline; gap: 6px; min-width: 0;
  font-size: 0.68rem; color: var(--parch-faint);
}
.pack-fam i { font-style: normal; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pack-fam b { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--parch-dim); }
.pack-fam.done b { color: var(--moss); }

/* Dans la piece d'equipement, la barre se serre : le cadre porte deja un
   pictogramme, un titre et quatre lignes de detail. */
.perm-live .st-bar.big { height: 18px; }
.perm-live .off-step { font-size: 0.74rem; margin-bottom: 6px; }
.perm-live .off-count { font-size: 0.66rem; }
.perm-stop { margin-top: 8px; }
.off-count { font-size: 0.72rem; color: var(--parch-faint); margin-top: 6px; text-align: right; }

/* La grande barre : assez haute pour qu un chiffre y tienne. Le texte est pose
   PAR-DESSUS le remplissage et non dedans, sinon il serait coupe en deux au
   passage du trait — et il porte une ombre, parce qu il passe successivement
   sur le fond sombre et sur le vert clair. */
.st-bar.big { height: 22px; border-radius: 999px; position: relative; }
.st-bar.big > i { position: absolute; inset: 0 auto 0 0; }
.st-bar.big > b {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.72rem; font-weight: 800; letter-spacing: 0.02em;
  color: var(--parchment);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
}

/* Les familles : « 61 Mo utilises » ne repond pas a « la carte est-elle
   complete ? ». Une ligne par famille, avec son compte a droite. */
/* `grid-template-columns: 1fr` et `min-width: 0` ensemble : un enfant de
   grille vaut `min-width: auto` par defaut, donc il REFUSE de retrecir sous son
   contenu — la description en une ligne poussait le compte hors de l ecran. */
.off-fams { margin-top: 12px; display: grid; grid-template-columns: 1fr; gap: 6px; }
.off-fam {
  display: flex; align-items: center; gap: 10px;
  min-width: 0; overflow: hidden;
  padding: 8px 10px;
  border: var(--line); border-radius: var(--radius-sm);
  background: var(--glass-3);
}
.off-fam .brick-ic { flex: none; width: 26px; height: 26px; }
.off-fam .brick-ic img { width: 100%; height: 100%; object-fit: contain; }
.off-fam .brick-txt { flex: 1; min-width: 0; display: block; }
.off-fam .brick-txt b { display: block; font-size: 0.8rem; color: var(--parchment); }
.off-fam .brick-txt i {
  display: block; font-style: normal; font-size: 0.66rem; color: var(--parch-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.off-fam em {
  flex: none; font-style: normal; font-size: 0.92rem; font-weight: 900;
  color: var(--gold); font-variant-numeric: tabular-nums;
}
/* Famille vide : elle reste visible — savoir que la carte manque fait partie
   de ce qu on vient verifier — mais elle ne reclame plus l oeil. */
.off-fam.vide { opacity: 0.5; }
.off-fam.vide em { color: var(--parch-faint); }
