/* RunRunFar — le jeu dans le navigateur (jeu.html).
 *
 * Ce fichier habille /jeu comme l'APPLICATION, pas comme le site. Les deux
 * n'ont pas le meme role : index.html est une vitrine qui doit se lire sur un
 * grand ecran, /jeu est le jeu, et le jeu est un telephone. Sur un ordinateur
 * il s'affiche donc dans une fenetre etroite posee sur un fond sombre, plutot
 * que de s'etaler — un plateau de jeu de 1 400 px de large ne ressemblerait
 * plus a rien.
 *
 * Tous les dessins viennent de `apps/ios/RunRunFar/Assets.xcassets`, convertis en WebP
 * par `tools/export-habillage.py` dans `/assets/img/jeu/`. On ne redessine
 * rien pour le web : si l'app change d'enseigne, on relance l'export.
 *
 * Portage Android : ce fichier part tel quel dans la coque Capacitor. C'est
 * meme lui qui fait que l'application Android ressemblera a l'iPhone.
 */

/* ---------------------------------------------------------------------------
   1. Le plateau : un telephone, meme sur un ordinateur
   --------------------------------------------------------------------------- */

.jeu-body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  overflow: hidden;
  background: #0A1118;
}
/* Derriere la fenetre du telephone, le meme decor, flou et assombri : on reste
   dans le jeu sans que l'oeil aille y chercher quelque chose. Le flou passe par
   une couche a part — on ne peut pas flouter un fond sans flouter le contenu. */
.jeu-body::before {
  content: "";
  position: fixed; inset: -30px; z-index: 0;
  background: url("/assets/img/jeu/fond.webp") center / cover no-repeat;
  filter: blur(16px) saturate(.6) brightness(.38);
}
.jeu-app { z-index: 1; }

.jeu-app {
  position: relative;
  width: 100%;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  isolation: isolate;
  container-type: inline-size;
  color: var(--cream);
  /* Le fond illustre, assombri comme dans l'app (RRFBackground, darkening .35). */
  background:
    linear-gradient(180deg, rgba(0,0,0,.21), rgba(0,0,0,.49)),
    url("/assets/img/jeu/fond.webp") center / cover no-repeat,
    var(--night);
}
/* L'ecran Courir a son propre decor dans l'app ; Ma ville garde le fond
   general, puisque la ville elle-meme est dessinee au milieu. */
.jeu-app[data-fond="ville"] {
  background-image: none;
  background-color: #0E1720;
}
/* Le dessin de Courir n'est pas un fond CSS : c'est `#courir-fond`, un calque
   pose par jeu-courir.js (voir le commentaire la-bas). Ici, seule la couleur
   qui prend le relais quand le dessin est passe — celle de son bas, assombrie
   comme lui. */
.jeu-app[data-fond="courir"] {
  background-image: none;
  background-color: #4F3A22;
}
.courir-fond {
  position: absolute; z-index: 0; top: 0; left: 0; right: 0;
  aspect-ratio: 758 / 2073;          /* la taille vraie de l'illustration */
  background:
    linear-gradient(180deg, rgba(0,0,0,.18), rgba(0,0,0,.46)),
    url("/assets/img/jeu/fond-courir.webp") top center / 100% auto no-repeat;
  pointer-events: none;
  will-change: transform;
}
.jeu-app[data-fond="courir"] .jeu-ecran,
.jeu-app[data-fond="courir"] .jeu-tabs { position: relative; z-index: 1; }
/* Sur Courir — et la seulement — la barre du haut FLOTTE au-dessus de
   l'ecran. C'est le seul onglet ou le decor defile : une barre en flux y
   occupait une bande a elle, qui montrait un morceau de dessin detache de
   ce qu'il y avait dessous. Ailleurs on la laisse en flux, sinon les listes
   du Classement et des Messages passeraient en toutes lettres sous le logo.
   La colonne se reserve la hauteur de la barre en marge haute. */
.jeu-app[data-fond="courir"] .jeu-top {
  position: absolute; top: 0; left: 0; right: 0;
  height: var(--barre-haut); box-sizing: border-box;
}
.jeu-app[data-fond="courir"] .jeu-ecran { padding-top: var(--barre-haut); }

/* Sur un telephone, le jeu EST l'ecran : on n'en sort pas par une croix.
   Deux classes : `.bouton-rond`, declare plus bas, gagnerait a egalite. */
.bouton-rond.jeu-quitter,
.bouton-rond.jeu-admin { display: none; }

/* Dans la coque, la croix n'a nulle part ou ramener : trois selecteurs, elle
   gagne donc aussi contre la regle d'ecran large plus bas. */
html[data-coque] .bouton-rond.jeu-quitter,
html[data-coque] .bouton-rond.jeu-admin { display: none; }

/* Sur un ecran assez grand, la fenetre du telephone. En dessous, plein cadre. */
@media (min-width: 520px) and (min-height: 680px) {
  .jeu-app {
    width: 430px;
    height: min(94dvh, 932px);
    border-radius: 30px;
    border: 3px solid #05090D;
    box-shadow:
      0 0 0 10px #141C24,
      0 0 0 12px #2A343E,
      0 30px 70px rgba(0,0,0,.65);
  }
  /* La croix est posee a cote du coin haut droit. Elle ne peut pas etre dans
     `.jeu-app`, qui est en `overflow: hidden` : elle est fixe, et calquee sur
     les memes mesures que le cadre (430 px de large, centre, cercle de 12 px
     d'encadrement). */
  .bouton-rond.jeu-quitter {
    display: grid;
    position: fixed; z-index: 5;
    top: calc(50% - min(94dvh, 932px) / 2);
    left: calc(50% + 215px + 20px);
    width: 38px; height: 38px;
    text-decoration: none; font-weight: 900;
  }
  .bouton-rond.jeu-admin {
    display: grid;
    position: fixed; z-index: 5;
    top: calc(50% - min(94dvh, 932px) / 2 + 48px);
    left: calc(50% + 215px + 20px);
    width: 38px; height: 38px;
    text-decoration: none;
  }
}

/* ---------------------------------------------------------------------------
   2. Typographie : la grasse italique des maquettes
   --------------------------------------------------------------------------- */
/* L'app n'utilise pas Bangers mais une grasse italique (RRF.Font.display).
   Redefinir le seul jeton `--display` suffit a aligner tout ce que /jeu
   herite de site.css : boutons, titres, enseignes. */
.jeu-app, .jeu-body {
  --display: "Barlow", system-ui, sans-serif;
  /* PAS DE FAUX ITALIQUE.
     Les boutons et les titres du jeu sont en italique, et l'italique est
     HERITE par tout ce qu'ils contiennent — y compris les emoji. Or la police
     des emoji (Noto Color Emoji sur Android, Apple Color Emoji sur iPhone)
     n'a pas de face italique : le navigateur en fabrique une en CISAILLANT le
     dessin. D'ou des parchemins, des zombies et des coupes qui penchent et
     qui bavent.
     Barlow, elle, a de VRAIES faces italiques (le lien de `jeu.html` charge
     `ital,wght@…;1,500;1,600;1,700;1,800`) : couper la synthese ne lui enleve
     donc rien, et redresse les emoji. Les deux ecritures sont la : la
     deuxieme pour les navigateurs recents, la premiere — qui omet `style` —
     pour les autres. */
  font-synthesis: weight small-caps;
  font-synthesis-style: none;
}
.jeu-app .btn,
.jeu-app .sign,
.jeu-app h1, .jeu-app h2, .jeu-app h3 {
  font-family: var(--display);
  font-weight: 800;
  font-style: italic;
  letter-spacing: .01em;
}

/* ---------------------------------------------------------------------------
   3. Les pieces dessinees
   --------------------------------------------------------------------------- */

/* --- L'enseigne en bois ---------------------------------------------------
   Cinq morceaux dans l'app : deux bouts cloutes, un losange au milieu, deux
   bordures qui s'etirent. En CSS, quatre couches de fond sur un seul element :
   la bordure etiree en dessous (c'est une planche unie), puis le losange
   centre, puis les deux bouts cales a gauche et a droite. Le resultat est le
   meme dessin sans cinq balises par titre. */
/* PIEGE : l'enseigne est faite de CINQ morceaux poses cote a cote, pas de
   quatre couches empilees. `EnseigneBois` (Components.swift) range
   gauche | bord-g | centre | bord-d | droite, chacun a la hauteur de
   l'enseigne, les deux bords seuls etires.
   En empilant un seul bord etire sur toute la largeur, il passait SOUS les
   embouts et remplissait de bois les encoches de leur silhouette : les bouts
   devenaient des angles droits, l'enseigne un rectangle. Le ciel doit se voir
   dans ces encoches.
   La largeur de chaque morceau se deduit de la hauteur (les dessins font
   299 px de haut), d'ou `--ens-h` — tenu egal a `min-height`. */
.enseigne {
  --ens-h: 2.3em;
  --ens-g: calc(var(--ens-h) * 122 / 299);
  --ens-d: calc(var(--ens-h) * 123 / 299);
  --ens-c: calc(var(--ens-h) * 85 / 299);
  position: relative;
  display: block;
  margin: 0;
  padding: .44em 2.4em .54em;
  min-height: var(--ens-h);
  text-align: center;
  color: var(--ink);
  font-size: clamp(1rem, 5cqi, 1.4rem);
  text-transform: uppercase;
  line-height: 1.15;
  text-shadow: 0 1px 0 rgba(255,255,255,.28);
  background:
    url("/assets/img/jeu/enseigne-gauche.webp") left   center / var(--ens-g) 100% no-repeat,
    url("/assets/img/jeu/enseigne-droite.webp") right  center / var(--ens-d) 100% no-repeat,
    url("/assets/img/jeu/enseigne-centre.webp") center center / var(--ens-c) 100% no-repeat,
    /* Un pixel de recouvrement de chaque cote : les embouts et le losange
       sont peints par-dessus, et l'arrondi des calculs ne laisse plus voir
       de trait de ciel a la jointure. */
    url("/assets/img/jeu/enseigne-bord-g.webp") left calc(var(--ens-g) - 1px) center /
      calc(50% - var(--ens-g) - var(--ens-c) / 2 + 2px) 100% no-repeat,
    url("/assets/img/jeu/enseigne-bord-d.webp") right calc(var(--ens-d) - 1px) center /
      calc(50% - var(--ens-d) - var(--ens-c) / 2 + 2px) 100% no-repeat;
  filter: drop-shadow(0 4px 6px rgba(0,0,0,.45));
}
.enseigne-petite {
  --ens-h: 2.1em;
  width: 200px; margin-left: auto; margin-right: auto;
  font-size: 1.05rem; padding: .34em 2.2em .42em;
}

/* --- La planche clouee ----------------------------------------------------
   Dessin de 720 x 157 px (240 x 52 pt) : coins et clous gardent leur taille,
   seul le milieu s'etire. C'est exactement ce que fait `border-image`. */
.planche {
  display: inline-block;
  margin: 0;
  padding: .3em 1.1em .35em;
  color: var(--ink);
  font-family: var(--display); font-weight: 800; font-style: italic;
  border: 17px solid transparent;
  border-width: 16px 26px;
  border-image: url("/assets/img/jeu/planche-bois.webp") 48 78 fill / 16px 26px / 0 stretch;
  filter: drop-shadow(0 3px 5px rgba(0,0,0,.4));
}

/* --- Le panneau parchemin -------------------------------------------------
   Le cadre aux bords dechires est une image a neuf tranches ; la texture est
   repetee dessous, rentree de 4 px pour ne pas depasser des dechirures. */
.jeu-app .panneau,
.jeu-app .panel.parchment {
  position: relative;
  z-index: 0;
  display: block;
  padding: 6px 8px 10px;
  color: var(--ink);
  background: none;
  border: 21px solid transparent;
  border-image: url("/assets/img/jeu/parchemin-cadre.webp") 63 / 21px / 0 stretch;
  border-radius: 0;
  box-shadow: none;
  filter: drop-shadow(0 6px 9px rgba(0,0,0,.45));
}
.jeu-app .panneau::before,
.jeu-app .panel.parchment::before {
  content: "";
  position: absolute;
  inset: -17px;                     /* -21 px de bordure + 4 px de retrait */
  z-index: -1;
  border-radius: 10px;
  background: url("/assets/img/jeu/parchemin-texture.webp") 0 0 / 190px auto repeat;
}

/* --- Les boutons ----------------------------------------------------------
   Meme recette que RRFPrimaryButtonStyle : degrade, trait d'encre de 3 px,
   coin de 8 px, ombre portee, texte blanc en grasse italique. */
.jeu-app .btn {
  border-radius: 8px;
  border: 3px solid var(--ink);
  box-shadow: 0 4px 6px rgba(0,0,0,.4);
  text-transform: uppercase;
  text-shadow: 0 2px 0 rgba(0,0,0,.3);
}
/* L'ombre sombre ci-dessus est pour les boutons a TEXTE BLANC (rouge, vert).
   Le bois a le texte en encre sombre, et site.css lui donne expres un rehaut
   clair ; l'ombre noire l'empatait et donnait ce relief embosse, plastique,
   qu'on voyait sur Android. Deux classes pour passer devant `.jeu-app .btn`. */
.jeu-app .btn.btn-wood,
.jeu-app .btn.btn-ghost-dark { text-shadow: 0 1px 0 rgba(255,255,255,.35); }
.jeu-app .btn:active { transform: scale(.97); box-shadow: 0 2px 4px rgba(0,0,0,.4); }
.jeu-app .btn-lg { transform: none; font-size: 1.35rem; padding: .5em 1.1em; }
.jeu-app .btn-lg:active { transform: scale(.97); }
.jeu-app .btn-sm { box-shadow: 0 3px 5px rgba(0,0,0,.35); }
/* Le vert dit « c'est payable », comme dans l'app. */
.jeu-app .btn-payable {
  background: linear-gradient(180deg, #54A97A, #2E6E4F 55%, #1C4A33);
}

/* --- Le bouton rond en parchemin ------------------------------------------ */
.bouton-rond {
  width: 44px; height: 44px; flex: none;
  display: grid; place-items: center;
  padding: 0; border: 0; cursor: pointer;
  color: #241A12; font-size: 1.15rem; line-height: 1;
  background: url("/assets/img/jeu/bouton-vide.webp") center / 100% 100% no-repeat;
  filter: drop-shadow(0 3px 4px rgba(0,0,0,.4));
}
.bouton-rond img { width: 66%; height: 66%; border-radius: 50%; object-fit: cover; }
/* Le portrait vit dans un `<span>` : laisse en `display: block` il collait a
   gauche et se posait sur la ligne de base, donc de travers dans le bois. */
.jeu-avatar > span {
  display: grid; place-items: center;
  width: 100%; height: 100%; line-height: 1;
}
.bouton-rond:active { transform: scale(.95); }

/* ---------------------------------------------------------------------------
   4. La barre du haut
   --------------------------------------------------------------------------- */
.jeu-app { --barre-haut: calc(65px + env(safe-area-inset-top)); }
.jeu-top {
  flex: none;
  position: relative; z-index: 10;
  display: flex; align-items: center; gap: 8px;
  padding: calc(15px + env(safe-area-inset-top)) 10px 6px;
  background: none;
  border: 0;
}
.jeu-logo { flex: none; line-height: 0; }
.jeu-logo img {
  height: 30px; width: auto;
  filter: drop-shadow(0 2px 3px rgba(0,0,0,.6));
}
.jeu-app .rrf-build {
  position: absolute; top: calc(2px + env(safe-area-inset-top)); left: 8px;
  background: rgba(0,0,0,.35); color: rgba(255,255,255,.7);
  font-size: 9px; padding: 2px 5px;
}

/* La pastille des chiffres DU JOUR : km courus, pas, VO2 gagne. C'est ce que
   l'application garde sous les yeux — le nom de la ville est deja sur
   l'enseigne, et sa reserve sur sa propre puce. */
.jeu-top-ville {
  margin-left: auto;
  display: flex; align-items: center; gap: 9px;
  padding: 3px 11px;
  border-radius: 999px;
  background: rgba(10,16,22,.62);
  border: 2px solid rgba(0,0,0,.45);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}
.jeu-top-ville span { display: inline-flex; align-items: center; gap: 4px; }
.jeu-top-ville i { font-style: normal; font-size: .95rem; }
.jeu-top-ville em {
  font-style: normal; font-size: .64rem; font-weight: 700; color: #9FB0BE;
  text-transform: lowercase;
}
.jeu-top-ville b {
  font-size: .98rem; font-weight: 900; color: #fff;
  font-variant-numeric: tabular-nums;
}
.jeu-top-ville img.vo2 { height: 1.3em; }
/* Pas encore connecte : rien a dire, donc pas de pastille vide. */
.jeu-top-ville:empty { display: none; }

.jeu-ville-nom {
  font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 1rem; line-height: 1.1; letter-spacing: .01em;
  max-width: 44vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  text-shadow: 0 1px 2px rgba(0,0,0,.7);
}
.jeu-ville-chiffres {
  font-size: .72rem; font-weight: 700; color: #CBD6DF;
  font-variant-numeric: tabular-nums; line-height: 1.2;
}
.jeu-ville-chiffres small { font-weight: 600; opacity: .7; }
.jeu-ville-chiffres img.vo2 { height: 1.3em; vertical-align: -.35em; }

/* ---------------------------------------------------------------------------
   5. L'ecran
   --------------------------------------------------------------------------- */
.jeu-ecran {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* Un ecran de telephone ne se tire pas de cote. Sans ca, `overflow-y: auto`
     rend `overflow-x` « auto » lui aussi, et le moindre debordement (le halo
     de la jauge sur un ecran etroit) laissait trainer le doigt a gauche et a
     droite. */
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-y: contain;
  padding: 4px 14px 18px;
  scrollbar-width: none;
}
.jeu-ecran::-webkit-scrollbar { width: 0; height: 0; }

.jeu-pane { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
.jeu-chargement {
  color: #D7E0E8; font-weight: 700; text-align: center; padding: 30px 0;
  text-shadow: 0 1px 3px rgba(0,0,0,.7);
}
/* Un titre d'onglet en enseigne, centre en haut de l'ecran. */
.jeu-titre { margin-top: 6px; }

.jeu-bloc { display: grid; gap: 10px; }
.jeu-bloc > h3 {
  font-size: 1.3rem; color: var(--rust-dark);
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  text-transform: uppercase;
}
.jeu-mot { margin: 0; font-size: .9rem; font-weight: 600; color: var(--ink-soft); }
.jeu-mot b { color: var(--ink); }
.jeu-mot-fin { font-size: .8rem; font-style: italic; }
.jeu-app .form-error { margin: 0; color: #8E1B10; font-weight: 800; font-size: .9rem; }

/* Les tuiles de chiffres, posees sur le parchemin. */
.jeu-app .kv { gap: 7px; }
.jeu-app .kv div {
  background: rgba(255,255,255,.42);
  border: 2px solid rgba(28,23,18,.22);
  border-radius: 7px;
}

/* ---------------------------------------------------------------------------
   6. La porte fermee : « telecharge l'application »
   --------------------------------------------------------------------------- */
.jeu-app .natif { text-align: center; }
.jeu-app .natif > * { justify-self: center; }
.natif-contenu { display: grid; gap: 8px; justify-items: center; }
.natif-icone { font-size: 2.1rem; line-height: 1; }
.jeu-app .natif h3 { color: var(--ink); font-size: 1.25rem; justify-content: center; }
.natif-mot { margin: 0; font-size: .9rem; font-weight: 600; color: var(--ink-soft); max-width: 42ch; }
.natif-repli {
  margin: 0; font-size: .8rem; font-weight: 700; color: var(--ink);
  background: rgba(255,255,255,.5); border: 2px dashed rgba(28,23,18,.3);
  border-radius: 8px; padding: 7px 10px;
}

/* ---------------------------------------------------------------------------
   6 bis. Onglet Courir : la semaine, la jauge des pas, les sorties
   --------------------------------------------------------------------------- */

/* --- La bande des sept jours --------------------------------------------- */
.courir-semaine { display: grid; gap: 8px; justify-items: center; margin-top: 4px; }
/* Mesure sur l'app : 252 x 50 pt. La notre faisait 248 x 73 — la largeur
   etait bonne, c'est la hauteur qui gonflait (32 px de bordure, 11 de marge
   et des fleches de 30). */
.semaine-planche {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  min-width: 250px; font-size: 1.05rem;
  padding: 2px 14px;
  border-width: 10px 26px;
  border-image-width: 10px 26px;
}
.semaine-fleche {
  width: 26px; height: 26px; flex: none;
  border: 0; background: none; padding: 0;
  color: var(--ink); font: inherit; font-size: 1.35rem; line-height: 1;
  cursor: pointer;
}
.semaine-fleche[disabled] { opacity: .25; cursor: default; }

.semaine-jours { display: grid; grid-template-columns: repeat(7, 1fr); width: 100%; }
.semaine-jour {
  display: grid; justify-items: center; gap: 5px;
  background: none; border: 0; padding: 2px 0; cursor: pointer;
}
.semaine-jour[disabled] { cursor: default; }
.semaine-lettre {
  font-size: .78rem; font-weight: 700; color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,.7);
}
.semaine-rond {
  width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center;
  border: 2px solid var(--ink);
  background: rgba(28,23,18,.45);
  color: #fff; font-size: .8rem; font-weight: 900;
  box-shadow: 0 2px 3px rgba(0,0,0,.4);
}
.semaine-jour.est-fait .semaine-rond { background: var(--defend); }
.semaine-jour.est-aujourdhui .semaine-rond { background: var(--ink-soft); }
.semaine-jour.est-a-venir .semaine-rond { background: rgba(28,23,18,.25); }
.semaine-jour.est-choisi .semaine-rond { border-color: #fff; border-width: 3px; }
.semaine-legende {
  margin: 0; font-size: .78rem; font-weight: 700; color: rgba(255,255,255,.92);
  text-shadow: 0 1px 3px rgba(0,0,0,.75);
}

/* --- La jauge des pas -----------------------------------------------------
   Pas de parchemin sous le cadran : dans l'app, la jauge est posée sur le
   chemin du décor. On garde cette idée, avec juste un halo beige pour que les
   chiffres se lisent quel que soit ce qu'il y a derrière. */
.jauge-boite { display: grid; justify-items: center; margin-top: 26px; }
/* Mesure sur l'app : le cadran occupe 65 % de la largeur de l'ecran, pas 82 %.
   Le reste est la marge dont les gouttes ont besoin — elles sortent de 6,9 %
   du cadran a gauche (le palier de 2 500 pas) plus la moitie de leur largeur. */
.jauge {
  position: relative;
  width: min(71%, 305px);
  aspect-ratio: 1;
  margin-bottom: 46px;
  /* `jauge-cadran.webp` n'est QUE l'anneau : son interieur est transparent.
     Le disque creme du cadran est peint ici, exactement a sa taille — avant,
     il venait du halo, et c'est pour ca que le halo etait si grand. */
  /* `closest-side` : le 100 % du degrade est le rayon du cadran. Sans lui le
     defaut est `farthest-corner` (0,707 fois la largeur) et le disque sortait
     bien trop petit. */
  background: radial-gradient(circle closest-side at 50% 50%,
    rgba(236,219,194,.97) 97%, rgba(236,219,194,0) 100%);
}
/* Le halo, mesure sur l'app : il serre le cadran sur les cotes (a peine un
   doigt de creme) et descend sous lui d'un tiers de sa hauteur, pour porter
   le nombre de pas. L'ancien formait un grand disque creme a bord net, plus
   voyant que le cadran. Une ellipse qui s'eteint exactement au bord de sa
   boite : plus aucun contour visible. */
.jauge::before {
  content: ""; position: absolute; inset: -3% -5% -40%;
  /* L'ellipse remplit exactement la boite et s'y eteint : decentrer son
     foyer laissait du creme a 55 % sur le bord haut, donc un trait net. */
  background: radial-gradient(ellipse 50% 50% at 50% 50%,
    rgba(236,219,194,.95), rgba(236,219,194,.9) 50%,
    rgba(236,219,194,.52) 76%, rgba(236,219,194,0) 100%);
}
.jauge > * { position: absolute; inset: 0; }
.jauge-cadran { width: 100%; height: 100%; object-fit: contain; }
.jauge-arc { width: 100%; height: 100%; overflow: visible; }
.jauge-zombie {
  width: auto; height: 44%; inset: auto;
  left: 50%; top: 53%; transform: translate(-50%, -50%);
  object-fit: contain;
  filter: drop-shadow(0 3px 4px rgba(0,0,0,.35));
}

.jauge-goutte {
  inset: auto; transform: translate(-50%, -50%);
  display: grid; justify-items: center; gap: 0;
  width: 56px;
}
.jauge-goutte img { width: 40px; height: auto; opacity: .9; }
.jauge-goutte.est-atteint img { opacity: 1; }
.jauge-goutte b {
  font-size: .82rem; font-weight: 900; color: var(--ink);
  text-shadow: 1px 1px 0 #fff, -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff;
}
.jauge-goutte.est-atteint b { color: #1878C4; }
.jauge-goutte { transform: translate(-50%, -50%) scale(.88); }
.jauge-goutte.est-atteint { transform: translate(-50%, -50%) scale(1); }
.jauge-coche {
  position: absolute; right: 6px; top: 16px;
  font-style: normal; font-size: .7rem; font-weight: 900; color: var(--defend);
  text-shadow: 0 0 2px #fff;
}

.jauge-compte {
  inset: auto; left: 50%; top: 100%; transform: translate(-50%, -46%);
  display: grid; justify-items: center; gap: 3px; width: 112%;
}
.jauge-compte b {
  font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 2.4rem; line-height: 1.08; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.jauge-compte small {
  font-size: .74rem; font-weight: 700; color: var(--ink-soft);
  text-align: center;
  text-shadow: 0 1px 0 rgba(255,255,255,.75);
}

/* --- Le ravitaillement ---------------------------------------------------- */
.courir-recolte { display: grid; gap: 8px; justify-items: center; margin-top: 6px; }
.courir-du {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 14px; border-radius: 999px;
  background: url("/assets/img/jeu/pastille-parchemin.webp") center / 100% 100% no-repeat;
  color: var(--ink); font-weight: 800; font-size: 1rem;
}
.courir-du img.vo2 { height: 1.4em; }
.courir-livre {
  margin: 4px 0 0; text-align: center;
  font-size: .85rem; font-weight: 700; color: #DCE7DF;
  text-shadow: 0 1px 3px rgba(0,0,0,.75);
}
.courir-source {
  margin: 2px 4px 0; text-align: center;
  font-size: .76rem; font-weight: 600; color: rgba(255,255,255,.82);
  text-shadow: 0 1px 3px rgba(0,0,0,.8);
}

/* --- Les sorties ---------------------------------------------------------- */
.sortie-ligne {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "titre fleche" "chiffres fleche";
  gap: 1px 8px; align-items: center;
  width: 100%; padding: 0; border: 0; background: none;
  text-align: left; cursor: pointer; color: inherit; font: inherit;
}
.sortie-ligne .jeu-liste-titre { grid-area: titre; }
.sortie-ligne .jeu-liste-chiffres { grid-area: chiffres; }
.sortie-fleche {
  grid-area: fleche;
  font-size: 1.3rem; color: var(--ink-soft); font-weight: 800;
}
.sortie-doute { color: #8E1B10; }
.sortie-carte { margin-top: 4px; }
.sortie-carte-vitre {
  height: 220px; border: 3px solid var(--ink); border-radius: 10px;
  background: #CBB994; overflow: hidden;
}
/* Masquee : le coureur voit encore SA trace, mais en gris — il doit savoir ce
   qu'il a cache. Les autres n'en recoivent meme pas les points. */
.sortie-carte-vitre.est-masquee { filter: grayscale(1); opacity: .45; }
.so-masquer { margin-top: 8px; }

/* La fiche d'une sortie : la distance d'abord, l'effort ensuite. */
.so-origine { margin: 0; font-size: .78rem; font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-soft); }
.so-km { margin: 2px 0 4px; font-family: var(--display); font-weight: 400;
  font-size: 2.4rem; line-height: 1; color: var(--ink); }
.so-effort { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 0 0 12px;
  font-size: .95rem; font-weight: 700; color: var(--ink-soft); }
.so-note { font-size: .82rem; color: var(--ink-soft); margin-top: 4px; }
.so-verse { margin-top: 10px; }
.jeu-alerte { color: #8E1B10; font-weight: 700; }

/* ---------------------------------------------------------------------------
   6 ter. La fenêtre (l'équivalent des `sheet` de l'application)
   --------------------------------------------------------------------------- */
/* Une fenetre restee dessous pendant qu'une feuille s'ouvre par-dessus : on la
   voit, elle ne repond plus. Son voile ne doit surtout pas avaler les clics
   destines a la feuille du dessus. */
.jeu-fenetre.est-dessous { pointer-events: none; }
.jeu-fenetre { position: absolute; inset: 0; z-index: 40; display: flex; flex-direction: column; }
.jeu-fenetre-voile {
  position: absolute; inset: 0;
  background: rgba(5,10,16,.6);
  opacity: 0; transition: opacity .18s ease;
}
.jeu-fenetre.est-ouverte .jeu-fenetre-voile { opacity: 1; }
.jeu-fenetre:has(.bat-cadre) .jeu-fenetre-voile { background: rgba(5,10,16,.38); }
.jeu-fenetre-feuille {
  position: absolute; left: 0; right: 0; bottom: 0;
  max-height: 88%;
  display: flex; flex-direction: column;
  padding: 0 12px calc(12px + env(safe-area-inset-bottom));
  transform: translateY(12%); opacity: 0;
  transition: transform .22s ease, opacity .18s ease;
}
.jeu-fenetre.est-ouverte .jeu-fenetre-feuille { transform: none; opacity: 1; }
.jeu-fenetre-tete {
  flex: none; display: flex; align-items: center; gap: 8px; padding: 0 0 6px;
}
.jeu-fenetre-tete .enseigne { flex: 1 1 auto; width: auto; margin: 0; }
.jeu-fenetre-fermer { width: 38px; height: 38px; font-size: 1rem; }
/* Une conversation est une PAGE empilee, pas une fenetre : on en revient par
   le bouton de gauche, comme dans l'app. */
.jeu-fenetre-retour {
  width: 38px; height: 38px; flex: none;
  background-image: url("/assets/img/jeu/bouton-retour.webp");
}

/* --- La feuille habillee (EnteteBois) ------------------------------------
   Dans l'app une feuille n'est pas un parchemin posé sur du noir : elle porte
   LE DÉCOR DU JEU, un écriteau suspendu au milieu, le bouton rouge « Fermer »
   à droite, et les cadres de parchemin se posent dessus les uns sous les
   autres — on voit le village entre eux. */
.jeu-fenetre-feuille.est-habillee {
  --ecr-w: min(190px, 44cqi);
  --ecr-h: calc(var(--ecr-w) * 380 / 778);
  --tete-h: calc(8px + 9px + var(--ecr-h) + 8px);
  border-radius: 22px 22px 0 0;
  border-top: 2px solid rgba(255,255,255,.12);
  box-shadow: 0 -12px 34px rgba(0,0,0,.55);
  overflow: hidden;                 /* pour les coins ; aucun parchemin ici */
  background:
    linear-gradient(180deg, rgba(0,0,0,.24), rgba(0,0,0,.5)),
    url("/assets/img/jeu/fond.webp") center / cover no-repeat,
    var(--night);
}
/* L'en-tete FLOTTE : c'est `safeAreaInset(edge: .top)` dans l'app. Les cadres
   passent DESSOUS l'ecriteau et le bouton rouge quand la page monte ; une
   barre en flux les aurait coupes net a sa hauteur. Les vides laissent passer
   le doigt, pour qu'on puisse faire defiler meme dans la bande du titre. */
.jeu-fenetre-haut {
  position: absolute; top: 8px; left: 12px; right: 12px; z-index: 5;
  pointer-events: none;
}
.jeu-fenetre-haut .ecriteau,
.jeu-fenetre-mains > * { pointer-events: auto; }
.jeu-fenetre-poignee {
  display: block; width: 44px; height: 5px; margin: 0 auto 4px;
  border-radius: 3px; background: rgba(255,255,255,.45);
}
/* Le defilement part du HAUT de la feuille et se reserve la hauteur de
   l'en-tete en marge : sans ca le premier cadre naitrait sous l'ecriteau. */
.jeu-fenetre-defile {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto; overflow-x: hidden;
  -webkit-overflow-scrolling: touch; overscroll-behavior-y: contain;
  padding: var(--tete-h) 0 4px;
  scrollbar-width: none;
}
.jeu-fenetre-defile::-webkit-scrollbar { width: 0; height: 0; }
/* Dans ce montage c'est le PARCHEMIN qui defile, pas son contenu : il reprend
   sa hauteur naturelle et rend le debordement au defilement. */
.jeu-app .jeu-fenetre-defile > .panneau.jeu-fenetre-cadre {
  flex: none; display: block; min-height: 0;
}
.jeu-fenetre-defile .jeu-fenetre-corps { flex: none; overflow: visible; }
/* L'ecriteau au milieu, les boutons par-dessus a hauteur de la planche :
   c'est le ZStack d'`EnteteBois`, pas une rangee. */
.jeu-fenetre-tete.est-bois {
  position: relative; display: block; height: var(--ecr-h);
}
.jeu-fenetre-tete.est-bois .ecriteau {
  position: absolute; left: 50%; top: 0; transform: translateX(-50%);
}
.jeu-fenetre-mains {
  position: absolute; left: 0; right: 0;
  top: calc(var(--ecr-h) * .66 - 22px);
  display: flex; align-items: center; justify-content: space-between;
  pointer-events: none;
}
.jeu-fenetre-mains > * { pointer-events: auto; }
.jeu-fenetre-vide { width: 1px; height: 44px; }
/* Un vide de la largeur du retour, pour que le titre reste centre. */
.jeu-fenetre-tete > .jeu-fenetre-vide { width: 38px; height: 38px; flex: none; }

/* L'ecriteau suspendu a deux chaines : le dessin fait 778 x 380, le bois
   sombre occupe 70 % de la largeur et commence a 48,5 % de la hauteur. */
.ecriteau {
  --ecr-w: min(190px, 44cqi);
  position: relative; flex: none; margin: 0;
  width: var(--ecr-w); height: calc(var(--ecr-w) * 380 / 778);
  background: url("/assets/img/jeu/ecriteau-chaines.webp") center / 100% 100% no-repeat;
  filter: drop-shadow(0 3px 4px rgba(0,0,0,.35));
}
.ecriteau span {
  position: absolute; left: 15%; width: 70%; top: 48.5%; height: 36%;
  display: grid; place-items: center;
  font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: calc(var(--ecr-w) * .115); line-height: 1;
  color: #F6E7C8; text-shadow: 0 1.5px 0 rgba(0,0,0,.7);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Le bouton rouge « Fermer » (423 x 216) et le retour en bois (286 x 267). */
.bouton-fermer {
  --h: 44px;
  flex: none; height: var(--h); width: calc(var(--h) * 423 / 216);
  padding: 0 0 2px; border: 0; cursor: pointer;
  background: url("/assets/img/jeu/bouton-fermer.webp") center / 100% 100% no-repeat;
  color: #FFF1D6; font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: calc(var(--h) * .36); line-height: 1;
  text-shadow: 0 1.5px 0 rgba(0,0,0,.65);
  filter: drop-shadow(0 2px 3px rgba(0,0,0,.35));
}
.bouton-fermer:active { transform: scale(.96); }
.bouton-bois {
  --h: 44px;
  flex: none; height: var(--h); width: calc(var(--h) * 286 / 267);
  padding: 0; border: 0; cursor: pointer;
  background: url("/assets/img/jeu/bouton-retour-bois.webp") center / 100% 100% no-repeat;
  filter: drop-shadow(0 2px 3px rgba(0,0,0,.35));
}
.bouton-bois:active { transform: scale(.96); }

/* --- Un corps en sections --------------------------------------------------
   Le corps cesse d'etre UN grand parchemin : chaque bloc porte le sien, et le
   decor se voit entre eux. Quatre classes pour passer devant `.jeu-app
   .panneau`, qui gagnerait a egalite. */
.jeu-app .panneau.jeu-fenetre-cadre.est-sections {
  border: 0; border-image: none; padding: 0; filter: none; background: none;
}
.jeu-app .panneau.jeu-fenetre-cadre.est-sections::before { content: none; }
.est-sections .jeu-fenetre-corps {
  display: grid; gap: 11px; align-content: start; padding: 2px 0 8px;
}
/* Ce qui n'est pas dans un parchemin est ecrit sur le decor : en creme. */
.est-sections .jeu-fenetre-corps > .jeu-mot,
.est-sections .jeu-fenetre-corps > .jeu-mot-fin {
  color: rgba(255,255,255,.88); text-shadow: 0 1px 3px rgba(0,0,0,.8);
}
.jeu-app .panneau.jeu-fenetre-section { margin: 0; padding: 8px 10px 12px; }
/* PIEGE : surtout pas d'`overflow` ici. La texture du parchemin est un
   `::before` en `inset: -17px`, qui deborde sous la bordure dechiree ; le
   moindre `overflow` le rogne au ras du contenu et laisse un liseré sombre
   tout autour. Le cadre ne defile pas parce que c'est le corps qui defile. */
.jeu-app .panneau.jeu-fenetre-cadre {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column;
}
.jeu-fenetre-corps {
  flex: 1 1 auto; min-height: 0;
  overflow-y: auto;                 /* ...c'est le contenu qui defile */
  scrollbar-width: none;
}
.jeu-fenetre-corps::-webkit-scrollbar { width: 0; }

/* ---------------------------------------------------------------------------
   6 quater. Onglet Ma ville
   --------------------------------------------------------------------------- */

/* --- L'en-tete : chiffres du jour, niveau, puces ------------------------- */
.puce img.vo2 { height: 1.2em; vertical-align: -.25em; }

/* L'enseigne de la ville porte le nombre de chantiers payables. */
.ville-enseigne { display: flex; align-items: center; justify-content: center; gap: 10px; }
/* Le rang suit le nom : a l'autre bout de l'enseigne, on ne faisait pas le
   lien entre les deux. */
.ville-rang {
  flex: none; min-width: 1.5em; height: 1.5em; padding: 0 .25em;
  display: grid; place-items: center; border-radius: 50%;
  background: var(--parchment); border: 2px solid #6B4A1E; color: var(--ink);
  font-family: var(--body); font-style: normal; font-weight: 900; font-size: .72rem;
  box-shadow: 0 2px 3px rgba(0,0,0,.4);
}
.jeu-pane[data-pane="ville"] .ville-enseigne,
.jeu-pane[data-pane="ville"] .ville-niveau,
.jeu-pane[data-pane="ville"] .puce { filter: drop-shadow(0 3px 6px rgba(0,0,0,.55)); }

/* Toute petite, comme dans l'application : elle ne doit pas pousser les trois
   puces sur le dessin. */
/* Mesure sur l'app : 95 x 36 pt, un cadre de bois mince autour d'un texte
   qui occupe la planche. La notre faisait 95 x 40 avec 10 px de bois en haut
   et en bas — plus epaisse que lisible. Le bois descend a 7 px, le texte
   gagne un point : 29 px de haut, et les trois capsules remontent d'autant. */
.ville-niveau {
  margin: -5px auto -3px; font-size: .76rem; letter-spacing: .02em;
  padding: 0 .55em; width: fit-content;
  border-width: 7px 16px;
  border-image-width: 7px 16px;
}

/* Les puces : FarRunners a gauche, la Forge a droite, le VO2 seul en dessous
   — la disposition de l'application. Sombres et translucides, pas en
   parchemin : elles flottent sur le decor. */
.ville-puces {
  display: flex; flex-wrap: wrap; align-items: flex-start;
  justify-content: space-between; gap: 6px;
}
.puce {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 11px; border: 1.5px solid rgba(255,255,255,.2); border-radius: 999px;
  background: rgba(0,0,0,.72);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  color: #fff; font-size: .78rem; line-height: 1.25;
  font-weight: 700; font-family: var(--body);
}
/* Le nombre est dans la meme taille que le mot : l'agrandir faisait grossir
   toute la capsule (c'est ce qui les faisait manger le dessin). */
.puce b { font-size: inherit; color: #fff; }
.ville-puces::before { content: ""; order: 1; flex-basis: 100%; height: 0; }
.puce-seule { order: 2; margin-right: auto; }
/* La puce du jour descend sur la deuxieme rangee, sous la Forge : `order: 2`
   la fait passer apres le saut de ligne, et le `margin-right: auto` de la
   pastille VO2 la pousse a droite. Sans cet ordre, elle se rangeait a cote
   de la Forge et la rangee du haut debordait. */
.puce-journee { order: 2; }

/* La journee de la ville reprend l'habillage des FarRunners (`cl-liste`) :
   portrait, pseudo touchable, kilometres. Seule la ligne des communes
   traversees lui est propre. */
.jour-ou { display: block; margin-top: 1px; font-size: .74rem; font-weight: 600; color: var(--ink-soft); }
.puce-bouton { cursor: pointer; }
.puce-bouton:active { transform: scale(.96); }
/* La pastille des nouveautes de la Forge : jaune a encre, comme dans l'app
   (`pastilleForge`), et « 9+ » au-dela de 9. */
.puce i {
  font-style: normal; min-width: 16px; height: 16px; padding: 0 4px;
  display: inline-grid; place-items: center; border-radius: 999px;
  background: #F5C431; color: var(--ink); font-size: .62rem; font-weight: 900;
  margin: -10px -6px -10px 1px;
}

/* --- La ville dessinee, ses pastilles de niveau -------------------------- */

.ville-pastille {
  position: absolute; left: 50%; top: -6px; transform: translate(-50%, -50%);
  min-width: 22px; height: 22px; padding: 0 4px;
  display: grid; place-items: center;
  border-radius: 999px; border: 2px solid #0E2238;
  background: linear-gradient(180deg, #4FA8F0, #1E6FBF);
  color: #fff; font-size: .72rem; font-weight: 900;
  box-shadow: 0 2px 3px rgba(0,0,0,.5);
  pointer-events: none;
}
.ville-pastille.est-vide { background: rgba(0,0,0,.75); }
.ville-pastille.est-payable {
  box-shadow: 0 2px 3px rgba(0,0,0,.5), 0 0 0 3px rgba(84,169,122,.75);
  animation: ville-pastille-bat 1.8s ease-in-out infinite;
}
@keyframes ville-pastille-bat { 50% { transform: translate(-50%, -50%) scale(1.14); } }

/* ---------------------------------------------------------------------------
   Le dessin de la ville EST la page « Ma ville ».
   fond-jour-N.jpg fait 853 x 1844, soit exactement le format d'un ecran de
   telephone : il remplit le plateau, et l'enseigne, les puces et le cadre
   d'attaque flottent dessus. Rien ne defile, et le decor general du jeu
   n'apparait pas ici. */
.ville-fond {
  position: absolute; inset: 0; z-index: 0; overflow: hidden;
}
.ville-fond .ville-vue {
  position: absolute; inset: 0;
  aspect-ratio: auto; width: auto;
  border: 0; border-radius: 0; background: none;
}
/* Le cadre garde son rapport 853/1844 — les emplacements sont en pourcentage
   de LUI — et se CALE EN HAUT du plateau.
   Il etait centre, et c'est ce qui mettait les puces sur le camp : 853/1844,
   c'est le format exact d'un iPhone, donc dans l'app le dessin tombe pile.
   Dans un navigateur la vitre est plus courte (la barre d'adresse mange une
   centaine de pixels), le dessin deborde, et le centrer remontait le camp
   d'autant. Cale en haut, le camp retrouve sa place sous l'enseigne ; c'est
   le bas — le sol et les zombies — qui sort du cadre, et le cadre des
   attaques le couvre deja. */
.ville-fond .ville-cadre {
  top: 0; left: 50%;
  width: 100%;
  transform: translateX(-50%);
}
.ville-fond .rv-piece[data-bat] { cursor: pointer; }

/* Sur cet onglet, la colonne ne defile pas et laisse passer les touchers :
   on touche un batiment la ou il se dresse. */
/* Le cadre des attaques est colle au menu : pas de bande de dessin entre
   les deux, comme dans l'app. */
.jeu-app[data-onglet="ville"] .jeu-ecran {
  overflow: hidden; pointer-events: none; padding-bottom: 0;
}
.jeu-app[data-onglet="ville"] .jeu-ecran,
.jeu-app[data-onglet="ville"] .jeu-tabs { position: relative; z-index: 1; }
/* L'enseigne colle au recap du jour, comme dans l'app : chaque pixel gagne
   ici est un pixel de camp degage sous les puces. */
.jeu-pane[data-pane="ville"] {
  height: 100%;
  grid-template-rows: auto auto auto minmax(0, 1fr) auto;
  gap: 5px;
}
.jeu-pane[data-pane="ville"] .jeu-titre { margin-top: 0; }
.jeu-app[data-onglet="ville"] .jeu-ecran { padding-top: 0; }
.jeu-pane[data-pane="ville"] > * { pointer-events: auto; }
/* La fenetre sur la ville : rien dedans, c'est par la qu'on la touche. */
.ville-fenetre { pointer-events: none !important; }

/* L'ecu de la Muraille, a la porte. */
/* La porte est a un endroit fixe du dessin (66 % de sa hauteur) : l'ecu y est
   pose dans le cadre, pas dans la vitre, pour ne pas bouger au recadrage. */
.ville-porte {
  /* 54 % et non 62 % : le dessin etant cale en haut, l'ouverture de la porte
     (62 %) passe derriere le cadre des attaques sur une vitre courte — celle
     d'un navigateur avec sa barre d'adresse. L'ecu se pose donc sur le rempart
     juste au-dessus de l'arche : toujours « a la porte », toujours touchable. */
  position: absolute; left: 50%; top: 54%; bottom: auto;
  transform: translate(-50%, -50%);
  width: 52px; height: 52px; padding: 0; border: 0; cursor: pointer;
  display: grid; place-items: center;
  border-radius: 50%; background: rgba(255,255,255,.22);
  box-shadow: inset 0 0 0 2px rgba(255,255,255,.35);
}
/* Un ecu blanc dessine, pas un emoji : l'emoji est rouge sur iPhone et gris
   ailleurs, alors que l'application en met un blanc, toujours le meme. */
.ville-porte-ecu {
  width: 24px; height: 28px; background: #fff;
  filter: drop-shadow(0 2px 3px rgba(0,0,0,.6));
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 28'%3E%3Cpath d='M12 0 0 4v10c0 7 5 12 12 14 7-2 12-7 12-14V4z'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 28'%3E%3Cpath d='M12 0 0 4v10c0 7 5 12 12 14 7-2 12-7 12-14V4z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.ville-porte .ville-pastille { left: auto; right: -4px; top: 2px; transform: none; }
@media (prefers-reduced-motion: reduce) { .ville-pastille.est-payable { animation: none; } }

/* --- Les deux onglets du cadre ------------------------------------------
   Ils sont DESSINÉS en haut du cadre : on ne refait pas de boutons, on pose
   deux zones transparentes par-dessus, aux mesures du dessin. */
.cadre-onglet { border: 0; background: none; cursor: pointer; padding: 0; }

/* --- Les cadres dessines (2048 x 768) ------------------------------------
   Tout est positionné en pourcentage du dessin, et les textes suivent la
   largeur du cadre (`cqi`) : c'est l'équivalent exact du facteur
   `f = largeur / 393` de l'application. */
.cadre {
  position: relative;
  container-type: inline-size;
  filter: drop-shadow(0 5px 8px rgba(0,0,0,.5));
}
.cadre-fond { width: 100%; height: auto; display: block; }
.cadre > :not(.cadre-fond) { position: absolute; }

.cadre-km {
  transform: translate(-50%, -50%);
  /* Sans cela la boite porte l'interligne par defaut : elle depasse les
     chiffres d'environ un cinquieme, et le centrage vertical tombe a cote. */
  line-height: 1;
  display: inline-flex; align-items: baseline; gap: .15em;
  font-size: 3.56cqi; font-weight: 900; font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 2px rgba(0,0,0,.75);
  white-space: nowrap;
}
.cadre-km small { font-size: 1.91cqi; font-weight: 800; color: rgba(255,255,255,.9); }
.cadre-km.est-vert { color: #5CE578; }
.cadre-km.est-rouge { color: #FA5E5E; }

.cadre-liste { overflow: hidden auto; scrollbar-width: none; }
.cadre-liste::-webkit-scrollbar { width: 0; }
.cadre-liste ul { list-style: none; margin: 0; padding: 0; }
.cadre-liste li {
  display: grid; grid-template-columns: auto 1fr auto; gap: .5em; align-items: center;
  height: 3.82cqi; font-size: 2.3cqi; font-weight: 700;
  color: #412A14; border-bottom: 1px solid rgba(65,42,20,.2);
}
.cadre-liste li span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cadre-liste li b { font-variant-numeric: tabular-nums; }
.cadre-liste i {
  width: 1.5cqi; height: 1.5cqi; border-radius: 50%;
  background: center / contain no-repeat;
}
.puce-verte { background-image: url("/assets/img/jeu/pastille-verte.webp"); }
.puce-rouge { background-image: url("/assets/img/jeu/pastille-rouge.webp"); }
.cadre-liste li.est-hors { opacity: .5; }
.cadre-liste li.cadre-hors-titre { display: block; font-style: italic; opacity: .6; font-size: 1.85cqi; font-weight: 700; color: #412A14; line-height: 3.82cqi; height: auto; border-bottom: 0; }
/* --- Le Hourra -----------------------------------------------------------
   Un habitant qui a couru chez nous aujourd'hui s'acclame : son pseudo
   scintille d'un bleu clair qui le traverse, lentement, puis se repose. Rien
   d'autre sur la ligne — pas de porte-voix : la ligne fait 3,82cqi de haut et
   trois colonnes, une image y décalait toute la liste, et le scintillement
   dit déjà qu'on peut toucher. */
.cadre-nom.est-hourrable {
  cursor: pointer; font-weight: 900; text-shadow: none;
  background: linear-gradient(100deg,
    #15618F 0%, #15618F 45%, #8AD4F2 55%, #15618F 66%, #15618F 100%);
  background-size: 300% 100%; background-position: 0 0;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  animation: hourra-brille 6s ease-in-out infinite;
}
.cadre-nom.est-hourrable:focus-visible { outline: 2px solid #15618F; outline-offset: 1px; border-radius: 4px; }
.cadre-nom.est-envoi { animation-play-state: paused; opacity: .55; }
/* Une onde lente qui traverse le pseudo (environ 1 s), puis cinq secondes de
   repos sur un bleu uni. Mesuré image par image : c'est tout l'écart avec la
   première version, qui clignotait deux dixièmes de seconde toutes les trois. */
@keyframes hourra-brille {
  0%        { background-position: 100% 0; }
  50%, 100% { background-position: 0 0; }
}

/* Le compte des Hourras reçus : une pastille plate, sans marge verticale —
   elle ne doit rien pouvoir décaler dans une ligne à hauteur fixe. */
.hourra-compte {
  margin-left: .5em; padding: 0 .45em; border-radius: 99px;
  background: rgba(21,97,143,.16); color: #15618F; -webkit-text-fill-color: #15618F;
  font-size: 1.75cqi; font-weight: 900; font-variant-numeric: tabular-nums;
  vertical-align: baseline;
}

/* Les bulles de VO₂ : elles montent du pseudo, puis filent vers la pastille
   « dispo » de la ville. Posées sur le document, au-dessus de tout. */
.hourra-calque { position: fixed; inset: 0; z-index: 9000; pointer-events: none; }
.hourra-bulle {
  position: fixed; width: 14px; height: 14px; border-radius: 50%;
  background: radial-gradient(circle at 32% 30%, #FFFFFF, #8FE3FF 55%, #2C8FC4);
  box-shadow: 0 0 8px rgba(143,227,255,.9);
  transform: translate(-50%, -50%) scale(.4); opacity: 0;
  animation: hourra-monte var(--t, 1.2s) cubic-bezier(.3, .05, .4, 1) forwards;
}
@keyframes hourra-monte {
  0%   { transform: translate(-50%, -50%) scale(.3); opacity: 0; }
  14%  { transform: translate(calc(-50% + var(--ex) * .25), calc(-50% - 14px)) scale(var(--r, 1)); opacity: 1; }
  52%  { transform: translate(calc(-50% + var(--ex)), calc(-50% - 52px)) scale(var(--r, 1)); opacity: 1; }
  100% { transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(.22); opacity: 0; }
}
.hourra-gain {
  position: fixed; display: inline-flex; align-items: center; gap: 4px;
  padding: 3px 10px; border-radius: 99px; white-space: nowrap;
  background: #15618F; color: #fff; font-weight: 900; font-size: .95rem;
  box-shadow: 0 3px 10px rgba(0,0,0,.4);
  transform: translate(-50%, -50%) scale(.6); opacity: 0;
  animation: hourra-gain 1.5s cubic-bezier(.3, .05, .4, 1) forwards;
}
.hourra-gain img { width: 1.1em; height: 1.1em; object-fit: contain; }
@keyframes hourra-gain {
  0%   { transform: translate(-50%, -50%) scale(.6); opacity: 0; }
  18%  { transform: translate(-50%, calc(-50% - 24px)) scale(1); opacity: 1; }
  58%  { transform: translate(-50%, calc(-50% - 44px)) scale(1); opacity: 1; }
  100% { transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(.45); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .cadre-nom.est-hourrable { animation: none; background-position: 50% 0; }
  .hourra-calque { display: none; }
}

.cadre-vide { margin: 0; font-size: 2.1cqi; font-weight: 700; color: rgba(65,42,20,.65); font-style: italic; }

.cadre-aiguille { transform-origin: 50% 50%; filter: drop-shadow(1px 2px 2px rgba(0,0,0,.45)); }

.cadre-etat {
  transform: translate(-50%, -50%);
  padding: .25em .9em; border-radius: 999px;
  border: 1px solid rgba(0,0,0,.5);
  font-size: 2.29cqi; font-weight: 900; color: #fff; white-space: nowrap;
  max-width: 45cqi; overflow: hidden; text-overflow: ellipsis;
}
.cadre-etat.ton-sombre { background: rgba(0,0,0,.72); }
.cadre-etat.ton-vert   { background: rgba(33,115,51,.92); }
.cadre-etat.ton-ambre  { background: rgba(140,97,26,.92); }
.cadre-etat.ton-rouge  { background: rgba(153,26,26,.92); }

/* Les deux barres de la semaine */
.cadre-barre { display: block; }
.cadre-remplissage {
  border-radius: .5cqi;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.25);
  transition: width .8s ease-out;
}
.cadre-remplissage.est-zombie { background: linear-gradient(0deg, #8C0D0A, #DB2E1A); }
.cadre-remplissage.est-coureurs { background: linear-gradient(0deg, #217329, #6BD14D); }
.cadre-barre-km {
  display: grid; align-items: center; justify-items: end;
  padding-right: .8cqi;
  font-size: 2.8cqi; font-weight: 900; color: #fff;
  font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 2px rgba(0,0,0,.8);
}
.cadre-vignette { transform: translate(-50%, -50%); height: auto; }
.cadre-habitants {
  transform: translate(-50%, -50%);
  font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 4.5cqi; color: #F0C44C;
  text-shadow: 0 0 2px #4A2A08, 1px 1px 0 #4A2A08, -1px 1px 0 #4A2A08;
}
.cadre-compte {
  display: flex; align-items: center; justify-content: space-between; gap: 1cqi;
  color: #52330F; font-weight: 800;
}
.cadre-compte span { font-size: 2.1cqi; line-height: 1.05; }
.cadre-compte b { font-size: 4.2cqi; white-space: nowrap; }
.cadre-prevision {
  display: grid; align-items: center;
  font-size: 2cqi; font-weight: 700; color: #52330F; text-align: right;
}
.cadre-rangee {
  display: grid; align-items: center; justify-items: end;
  padding-left: 42cqi; padding-right: 3cqi;
  border: 0; background: none; cursor: pointer;
}
/* `justify-items: end` dimensionne l'enfant a son contenu : sans plafond il
   debordait vers la gauche et l'ellipse ne se declenchait jamais. */
.cadre-rangee span {
  max-width: 100%;
  font-size: 2.29cqi; font-weight: 900; color: #99E673;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Sur le bois sombre, les teintes claires de l'app (`etatCourt`). */
.cadre-rangee span.ton-rouge { color: #FF8061; }
.cadre-rangee span.ton-creme { color: #FFD999; }

/* --- Le deroule de la ville --------------------------------------------- */
.journal { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.journal li {
  display: grid; grid-template-columns: 3.4em 1fr auto; gap: 8px; align-items: center;
  font-size: .82rem; font-weight: 700; color: var(--ink-soft);
}
.journal li.est-avenir { opacity: .45; }
.journal-jour { font-weight: 800; color: var(--ink); }
.journal-barres { display: grid; gap: 2px; }
.journal-barres i {
  display: block; height: 7px; border-radius: 3px; min-width: 2px;
  border: 1px solid rgba(28,23,18,.3);
}
.journal-barres i.est-coureurs { background: #2E6E4F; }
.journal-barres i.est-zombie { background: #B4291A; }
.journal-km { font-variant-numeric: tabular-nums; white-space: nowrap; }

.ville-boutons { display: grid; gap: 8px; }

/* --- Le panneau d'un batiment ------------------------------------------- */
.jeu-batiments .bld-ico {
  border: 0; background: none; padding: 0; cursor: pointer;
  font-size: 1.25rem; text-align: center; line-height: 1;
}
/* --- La planche des titres (PlancheTitre) --------------------------------
   Deux bouts cloutes (245 px pour 270 de haut) et un milieu qui s'etire a la
   longueur du texte. Meme recette que l'enseigne : seul le milieu bouge. */
.planche-titre {
  --h: 32px;
  display: inline-flex; align-items: center; justify-content: center;
  height: var(--h); margin: 0;
  --b: calc(var(--h) * 245 / 270);
  padding: 0 calc(var(--h) * .62) 2px;
  background:
    url("/assets/img/jeu/planche-gauche.webp") left center / var(--b) 100% no-repeat,
    url("/assets/img/jeu/planche-droite.webp") right center / var(--b) 100% no-repeat,
    url("/assets/img/jeu/planche-milieu.webp") left calc(var(--b) - 1px) center /
      calc(100% - 2 * var(--b) + 2px) 100% no-repeat;
  color: #F6E7C8; text-transform: none;
  font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: calc(var(--h) * .46); line-height: 1;
  text-shadow: 0 1.5px 0 rgba(0,0,0,.7);
  filter: drop-shadow(0 2px 3px rgba(0,0,0,.35));
  max-width: 100%;
}
.planche-titre > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Le panneau d'un batiment : il porte son nom et sa croix, et flotte sur la
   ville (feuille `nue`) — pas de barre de titre par-dessus. */
.bat-tete { display: flex; align-items: center; gap: 10px; }
.bat-icone {
  flex: none; width: 44px; height: 44px; display: grid; place-items: center;
  font-size: 1.6rem; line-height: 1;
  border-radius: 50%; border: 2px solid var(--ink); background: var(--parchment-deep);
}
/* La vignette : le DESSIN du batiment a son niveau, decoupe dans sa planche
   de stades (`ville-rendu.js`) — le meme qu'on voit dans la ville. */
.bat-vignette {
  flex: none; width: 58px; height: 58px; display: grid; place-items: center;
  border-radius: 50%; border: 2.5px solid var(--ink);
  background: radial-gradient(circle at 50% 42%, #F6E3BC, #DEC391);
  box-shadow: inset 0 -3px 6px rgba(0,0,0,.18);
  overflow: hidden;
}
.bat-vignette i {
  display: block; height: 42px; width: auto;
  background-repeat: no-repeat;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.35));
}

/* Le pied du cadre : il ne defile pas, le bouton principal reste visible. */
.jeu-fenetre-pied { flex: none; display: grid; gap: 2px; padding-top: 9px; }
.jeu-fenetre-pied .btn { margin: 0; }
.bat-histoire {
  position: relative; width: 100%; padding: 8px 22px 4px;
  border: 0; background: none; cursor: pointer;
  color: var(--rust-dark); font: inherit; font-weight: 800; font-size: .88rem;
}
.bat-histoire i {
  position: absolute; right: 8px; top: 50%; transform: translateY(-60%);
  font-style: normal; font-size: 1.2rem;
}
.bat-histoire:active { transform: scale(.98); }
/* Le panneau respire comme sur le dessin : des marges egales, et jamais plus
   haut que la vitre — le corps defile, le pied non. */
.jeu-fenetre-feuille:has(.bat-cadre) { padding-left: 16px; padding-right: 16px; }
.bat-cadre .jeu-fenetre-corps { display: grid; gap: 9px; align-content: start; }
.bat-titres { flex: 1 1 auto; min-width: 0; display: grid; gap: 3px; justify-items: start; }
.bat-titres .planche-titre { --h: 36px; }
/* Les flèches autour du nom : le bâtiment précédent ou suivant, en boucle.
   Le glissé du doigt sur la tête fait la même chose (`jeu-ville.js`). */
.bat-nav { display: flex; align-items: center; gap: 0; max-width: 100%; min-width: 0; }
.bat-nav .planche-titre { min-width: 0; flex: 0 1 auto; }
.bat-fleche {
  flex: none; width: 18px; height: 34px; padding: 0; cursor: pointer;
  display: grid; place-items: center;
  border: 0; border-radius: 8px; background: none;
  color: var(--rust-dark); font: inherit; font-size: 1.7rem; font-weight: 900; line-height: 1;
}
.bat-fleche:active { transform: scale(.88); }
.jeu-fenetre.sans-entree .jeu-fenetre-feuille,
.jeu-fenetre.sans-entree .jeu-fenetre-voile { transition: none; }
.bat-cadre .bat-tete { gap: 6px; }
.bat-tete { touch-action: pan-y; user-select: none; -webkit-user-select: none; }
.bat-cadre.est-vers-gauche .jeu-fenetre-corps { animation: bat-glisse-g .22s ease-out; }
.bat-cadre.est-vers-droite .jeu-fenetre-corps { animation: bat-glisse-d .22s ease-out; }
@keyframes bat-glisse-g { from { opacity: .3; transform: translateX(28px); } }
@keyframes bat-glisse-d { from { opacity: .3; transform: translateX(-28px); } }
@media (prefers-reduced-motion: reduce) {
  .bat-cadre.est-vers-gauche .jeu-fenetre-corps, .bat-cadre.est-vers-droite .jeu-fenetre-corps { animation: none; }
}
/* Ce que le bâtiment donne à son niveau : le chiffre d'aujourd'hui. */
.bat-avantage {
  padding: 8px 10px; border-radius: 10px;
  background: rgba(46,110,79,.10); border: 1.5px solid rgba(46,110,79,.35);
}
.bat-avantage .bat-ligne { color: var(--ink); }
.bat-avantage .bat-ligne b { color: #2E6E4F; }
.bat-tete b { display: block; font-size: 1rem; }
.bat-tete small { display: block; font-size: .78rem; font-weight: 600; color: var(--ink-soft); }
.bat-fermer {
  flex: none; width: 30px; height: 30px; padding: 0; cursor: pointer;
  display: grid; place-items: center; align-self: flex-start;
  border: 0; border-radius: 50%; background: var(--parchment-deep);
  color: var(--ink-soft); font-size: .8rem; font-weight: 900;
}
.bat-fermer:active { transform: scale(.94); }
.bat-sous-titre {
  margin: 0 0 6px; font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 1.1rem; color: var(--rust-dark); text-transform: uppercase;
}
.bat-podium { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; }
.bat-podium li {
  display: grid; grid-template-columns: 2em 1fr auto; gap: 8px; align-items: center;
  padding: 5px 8px; border-radius: 7px;
  background: rgba(255,255,255,.42); border: 2px solid rgba(28,23,18,.2);
}
.bat-niveaux { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 4px; }
.bat-niveaux li {
  display: flex; justify-content: space-between; gap: 10px;
  font-size: .82rem; font-weight: 700; color: var(--ink-soft);
  border-bottom: 1px dashed rgba(28,23,18,.2); padding-bottom: 3px;
}
.bat-niveaux b { color: var(--ink); }
.bat-niveaux small { opacity: .75; margin-left: 6px; }

/* --- La Forge ------------------------------------------------------------ */
/* Les objets seuls sont poses SUR LE DECOR, sans parchemin (ForgeView) :
   quatre par rangee meme sur un telephone de 360 px, des tuiles de 74 px. */
.forge-grille {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(76px, 1fr));
  gap: 14px 8px; padding: 2px 0 6px;
}
.forge-grille > p { grid-column: 1 / -1; }
.forge-retard {
  margin: -4px 0 0; font-size: .76rem; font-weight: 700;
  color: #F2C94C; text-shadow: 0 1px 3px rgba(0,0,0,.8);
}
.forge-vide { margin: 0; font-size: .88rem; font-weight: 600; color: var(--ink-soft); }

/* ---------------------------------------------------------------------------
   La tuile d'un objet (TuileRelique) : le cadre de l'etat, et ses cinq crans.

   Tout se derive de `--t`, la taille. Dans la grille elle vaut 92 px, pose en
   style par jeu-ville.js ; dans une ligne de triptyque, le CSS la remplace par
   `100cqw` et les quatre cases se partagent la largeur.

   Le cadre porte l'information AVANT le dessin : on lit « Rare » a la couleur
   du trait, et le niveau aux crans, sans un mot et sans toucher.
   --------------------------------------------------------------------------- */
.tuile-objet {
  position: relative; display: block; box-sizing: border-box;
  width: var(--t, 92px); height: var(--t, 92px);
  border-radius: calc(var(--t, 92px) * .16);
  background: radial-gradient(circle farthest-corner,
    color-mix(in srgb, var(--etat) 35%, #14110D) 0%, #14110D 100%);
  border: max(2px, calc(var(--t, 92px) * var(--epf, .028))) solid var(--etat);
}
/* Des « Rare », un filet clair a l'interieur du cadre, comme dans l'app. */
.tuile-objet.est-n3::after, .tuile-objet.est-n4::after, .tuile-objet.est-n5::after {
  content: ""; position: absolute; inset: 1px; pointer-events: none;
  border-radius: inherit; border: 1px solid rgba(255,255,255,.35);
}
.tuile-art {
  position: absolute; inset: calc(var(--t, 92px) * .12);
  width: calc(100% - var(--t, 92px) * .24); height: calc(100% - var(--t, 92px) * .24);
  object-fit: contain;
  filter: drop-shadow(0 2px 3px rgba(0,0,0,.6));
}
/* Un objet use est terne et chaud : l'app desature et teinte. */
.tuile-objet.est-n1 .tuile-art { filter: saturate(.35) sepia(.22) drop-shadow(0 2px 3px rgba(0,0,0,.6)); }
.tuile-vide {
  display: grid; place-items: center;
  font-size: calc(var(--t, 92px) * .34); color: color-mix(in srgb, var(--etat) 70%, transparent);
}
/* Les crans : cinq losanges dans une capsule sombre, au pied de la tuile. */
.tuile-crans {
  position: absolute; left: 50%; bottom: calc(var(--t, 92px) * -.04);
  transform: translateX(-50%);
  display: flex; gap: calc(var(--t, 92px) * .025);
  padding: calc(var(--t, 92px) * .03) calc(var(--t, 92px) * .06);
  border-radius: 999px; background: rgba(0,0,0,.55);
}
.tuile-crans i {
  width: calc(var(--t, 92px) * .075); height: calc(var(--t, 92px) * .075);
  transform: rotate(45deg); background: rgba(255,255,255,.18);
}
.tuile-crans i.est-plein { background: var(--etat); }

/* Le reflet : un voile clair qui balaie la tuile, puis une pause. Rare
   rarement, Exceptionnel plus souvent, Legendaire sans cesse — les memes
   cadences que l'app (`scintillement` et le reflet de TuileRelique). Il est
   dans son propre calque, rogne a l'arrondi : la tuile, elle, ne doit rien
   rogner, ses crans debordent en bas. */
.tuile-reflet {
  position: absolute; inset: 0; border-radius: inherit; overflow: hidden;
  pointer-events: none;
}
.tuile-reflet::before {
  content: ""; position: absolute; top: -50%; bottom: -50%; left: 0;
  width: 50%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.62), transparent);
  transform: translateX(-160%) rotate(22deg);
  mix-blend-mode: plus-lighter;
  animation: tuile-reflet var(--cycle, 5.4s) ease-in-out infinite;
}
.tuile-objet.est-n3 .tuile-reflet::before { --cycle: 5.4s; --part: 26%; }
.tuile-objet.est-n4 .tuile-reflet::before { --cycle: 3.6s; --part: 33%; }
.tuile-objet.est-n5 .tuile-reflet::before {
  --cycle: 2.2s; width: 35%; animation-delay: .6s; animation-timing-function: ease-in-out;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent);
  animation-name: tuile-reflet-continu;
}
@keyframes tuile-reflet {
  0% { transform: translateX(-160%) rotate(22deg); }
  30% { transform: translateX(260%) rotate(22deg); }
  100% { transform: translateX(260%) rotate(22deg); }
}
@keyframes tuile-reflet-continu {
  from { transform: translateX(-160%) rotate(20deg); }
  to { transform: translateX(330%) rotate(20deg); }
}
@media (prefers-reduced-motion: reduce) {
  .tuile-reflet::before { animation: none; opacity: 0; }
}

/* Les cinq etats : la palette de l'app (EtatRelique) et de l'admin (.rq-nN).
   `--epf` est le facteur d'epaisseur du cadre : il grossit avec l'etat. */
.est-n1 { --etat: #6B4A2B; --epf: .028; }
.est-n2 { --etat: #C07A3E; --epf: .034; }
.est-n3 { --etat: #C9D1D9; --epf: .040; }
.est-n4 { --etat: #A66BF0; --epf: .046; }
.est-n5 { --etat: #F2C94C; --epf: .052; }
/* La lueur, a partir de Rare — rien en dessous, l'app non plus. */
.tuile-objet.est-n3 { box-shadow: 0 0 calc(var(--t, 92px) * .09) rgba(127,184,255,.6); }
.tuile-objet.est-n4 { box-shadow: 0 0 calc(var(--t, 92px) * .09) rgba(166,107,240,.7); }
.tuile-objet.est-n5 { box-shadow: 0 0 calc(var(--t, 92px) * .09) rgba(242,201,76,.75); }

/* La case de la grille : la tuile, le nom sur deux lignes au plus, l'etat.
   Qui l'a rapporte ne s'y lit PAS — il faut toucher. */
.objet-case {
  margin: 0; display: grid; justify-items: center; gap: 5px;
  cursor: pointer; text-align: center;
}
.objet-case figcaption { display: grid; gap: 2px; }
/* Sur le decor : le nom en blanc, l'etat dans sa couleur vive. */
.objet-case figcaption b {
  font-size: .72rem; font-weight: 700; line-height: 1.15; color: #fff;
  text-shadow: 0 1px 3px rgba(0,0,0,.85);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.objet-case figcaption small {
  font-size: .66rem; font-weight: 800; color: var(--etat, #fff);
  text-shadow: 0 1px 3px rgba(0,0,0,.85);
}
.objet-case:hover .tuile-objet { transform: translateY(-2px); }
.tuile-objet { transition: transform .15s ease; }
/* La tuile porte ses pastilles (le sablier) : elle est leur repere. */
.objet-case-tuile { position: relative; display: block; }
.objet-case-tuile .sablier-tournant { position: absolute; top: -6px; right: -6px; z-index: 2; }

/* Le sablier d'un objet en amelioration (SablierTournant) : blanc, dans une
   pastille rouge sombre cerclee de blanc, et il se retourne — 1,2 s, sans
   revenir en arriere, comme dans l'app. */
.sablier-tournant {
  flex: none; display: inline-grid; place-items: center;
  width: var(--s, 26px); height: var(--s, 26px); box-sizing: border-box;
  border-radius: 50%; background: var(--rust-dark, #8E1B10);
  border: 1.5px solid rgba(255,255,255,.8); color: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.45);
  animation: sablier-tourne 1.2s ease-in-out infinite;
}
.sablier-tournant svg { width: 55%; height: 55%; }
@keyframes sablier-tourne { from { transform: rotate(0); } to { transform: rotate(180deg); } }
@media (prefers-reduced-motion: reduce) { .sablier-tournant { animation: none; } }

/* --- Une ligne de triptyque ----------------------------------------------
   Chaque triptyque a SON parchemin (LigneTriptyque) ; ils se suivent dans la
   grille du corps en sections, le decor visible entre eux. */
.jeu-app .panneau.heritage {
  /* `min-width: 0` n'est PAS decoratif : `.heritage` est un element de la
     grille du corps, donc il porte `min-width: auto` — le minimum automatique
     d'un element de grille, egal a son min-content. Le `<b>` du titre est en
     `white-space: nowrap` : sans ca, la ligne refuse de se compresser et la
     Forge deborde a droite sur un telephone de 360 px. */
  min-width: 0; margin: 0; padding: 0 2px 4px;
  /* Un bord dechire plus fin que celui des grands cadres : ParchmentPanel
     (padding 12) ne laisse que quelques points autour du triptyque, et les
     21 px du bord normal, plus sa marge, mangeaient la place des objets. */
  border-width: 14px; border-image-width: 14px;
}
.jeu-app .panneau.heritage::before { inset: -10px; }
.heritage-tete { display: flex; align-items: center; gap: 6px; font-weight: 900; font-size: 1rem; }
.heritage-tete > b { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.heritage-neuf {
  flex: none; padding: 1px 6px; border-radius: 999px;
  font-size: .62rem; font-weight: 900; letter-spacing: .04em;
  background: #F2C94C; color: #3A2610;
}
/* L'etat d'une relique obtenue : une pastille de sa couleur. */
.heritage-etat {
  flex: none; padding: 3px 10px; border-radius: 999px;
  font-size: .8rem; font-weight: 900;
  background: var(--etat); color: #3A2610; border: 1.5px solid rgba(90,58,18,.6);
}
.heritage-tete .forge-compte { padding: 3px 10px; font-size: .78rem; }
/* Quatre cases qui se partagent la largeur, et des signes minuscules entre
   elles — c'est la mesure de l'app (14 pt), et c'est ce qui laisse aux objets
   la place d'etre regardes. */
.heritage-equation {
  display: grid;
  grid-template-columns: minmax(0, 76px) 14px minmax(0, 76px) 14px minmax(0, 76px) 14px minmax(0, 76px);
  justify-content: center; align-items: center; margin-top: 7px;
}
.heritage-equation > i {
  font-style: normal; font-weight: 900; font-size: .95rem;
  text-align: center; color: rgba(28,23,18,.6);
}
.heritage-case {
  position: relative; container-type: inline-size;
  aspect-ratio: 1; display: block; border-radius: 16%;
}
.heritage-case .tuile-objet { --t: 100cqw; }
.heritage-case[role="button"] { cursor: pointer; }
.heritage-case.est-vide {
  border: 1.5px dashed rgba(28,23,18,.45);
  background: rgba(28,23,18,.06);
  box-sizing: border-box;
}
/* La relique au bout : fond brun sombre, le « ? » dore, et les trois filets
   d'or des Heritages. */
.heritage-case.est-relique {
  box-sizing: border-box; background: #3A2412; padding: 10%;
  box-shadow: 0 0 0 2px #7A5A18, 0 0 0 4px #3A2412, 0 0 0 6px rgba(242,201,76,.75);
}
.heritage-case.est-relique img { width: 100%; height: 100%; object-fit: contain; }
.heritage-case.est-relique b {
  display: grid; place-items: center; height: 100%;
  font-size: 1.6rem; color: #F2C94C;
}
.heritage-case.est-relique.est-obtenue {
  box-shadow: 0 0 0 2px #F2C94C, 0 0 0 4px #3A2412, 0 0 0 6px #F2C94C,
              0 0 14px rgba(242,201,76,.65);
}

/* --- Le suivi GPS (coque Android) ---------------------------------------- */
.gps-bloc .kv { margin-top: 8px; }
.gps-en-cours {
  margin: 0 0 6px; font-weight: 900; color: var(--rust-dark);
  animation: gps-pouls 1.6s ease-in-out infinite;
}
@keyframes gps-pouls { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
.jeu-app .gps-mesures { grid-template-columns: repeat(3, 1fr); }
.jeu-app .gps-mesures dd { font-size: 1rem; }
.gps-enplan { margin-top: 8px; border-style: dashed; }
.gps-enplan .btn + .btn { margin-top: 6px; }

/* --- Le Silo ------------------------------------------------------------- */
.silo-jauge {
  position: relative; height: 30px; border-radius: 8px;
  border: 3px solid var(--ink); background: rgba(28,23,18,.18); overflow: hidden;
}
.silo-jauge i { display: block; height: 100%; background: linear-gradient(180deg, #9BD9F7, #1878C4); }
.silo-jauge span {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-weight: 900; font-size: .9rem; color: #fff;
  text-shadow: 0 1px 2px rgba(0,0,0,.8);
}
.silo-jauge.est-plein i { background: linear-gradient(180deg, #F4573F, #8E1B10); }

/* ---------------------------------------------------------------------------
   7. Listes, batiments, classement
   --------------------------------------------------------------------------- */
.jeu-liste, .jeu-batiments, .jeu-classement {
  list-style: none; margin: 0; padding: 0; display: grid; gap: 7px;
}
.jeu-liste li, .jeu-batiments li, .jeu-classement li {
  background: rgba(255,255,255,.42);
  border: 2px solid rgba(28,23,18,.22);
  border-radius: 8px;
  padding: 8px 10px;
}
.jeu-liste li { display: grid; gap: 2px; }
.jeu-liste-titre { font-weight: 800; font-size: .95rem; }
.jeu-liste-titre small { font-weight: 700; font-size: .76rem; color: var(--ink-soft); margin-left: 6px; }
.jeu-liste-chiffres { font-size: .82rem; font-weight: 700; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
/* Une ligne qui porte un etat a droite : « Trouve N fois », le triptyque. */
.jeu-liste.est-deux li { grid-template-columns: 1fr auto; align-items: center; column-gap: 8px; }
.jeu-liste.est-deux li.est-vide { background: rgba(28,23,18,.07); border-style: dashed; }
.jeu-liste.est-deux li[role="button"] { cursor: pointer; }
.jeu-liste-titre small { display: block; margin: 0; }

.jeu-batiments li {
  display: grid; grid-template-columns: 1.8em 1fr auto; gap: 2px 9px; align-items: center;
}
.jeu-batiments li.is-vide { background: rgba(28,23,18,.07); border-style: dashed; }
.jeu-batiments li.is-vide .bld-ico, .jeu-batiments li.is-vide .bld-name { opacity: .6; }
.jeu-batiments .bld-name { display: grid; gap: 1px; }
.jeu-batiments .bld-name small { font-weight: 700; font-size: .76rem; color: var(--ink-soft); }
.jeu-batiments .btn[disabled] { opacity: .45; cursor: not-allowed; }
.jeu-batiments .btn[disabled]:active { transform: none; }
.jeu-batiments .btn img.vo2 { height: 1.1em; vertical-align: -.2em; }

.jeu-classement li {
  display: grid; grid-template-columns: 2.1em 1fr auto; gap: 2px 10px; align-items: center;
}
.jeu-classement li.is-moi { background: rgba(47,128,237,.18); border-color: #2F80ED; }
.jeu-rang {
  font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 1.25rem; line-height: 1; color: var(--rust-dark); text-align: center;
}
.jeu-classement li:nth-child(1) .jeu-rang { color: #B8860B; }
.jeu-nom { display: grid; gap: 1px; font-weight: 800; font-size: .95rem; min-width: 0; }
.jeu-nom small { font-weight: 700; font-size: .74rem; color: var(--ink-soft); }
.jeu-valeur { font-weight: 800; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---------------------------------------------------------------------------
   7 bis. Classement : le podium
   --------------------------------------------------------------------------- */
.cl-filtres { display: flex; gap: 8px; align-items: center; }
.cl-filtres .jeu-segments { flex: 1 1 auto; }
.cl-periode {
  flex: none; max-width: 48%;
  padding: .45em 1em; border: 0; border-radius: 999px;
  background: url("/assets/img/jeu/pastille-parchemin.webp") center / 100% 100% no-repeat;
  color: var(--ink); font: inherit; font-weight: 800; font-size: .85rem;
  filter: drop-shadow(0 2px 3px rgba(0,0,0,.45));
}

.cl-podium {
  display: flex; align-items: flex-end; justify-content: center; gap: 6px;
  margin-bottom: 4px;
}
.cl-marche {
  flex: 1 1 0; min-width: 0;
  display: grid; justify-items: center; gap: 1px;
  padding: 8px 4px; border-radius: 10px;
  background: rgba(255,255,255,.45); border: 2px solid rgba(28,23,18,.25);
  text-align: center;
}
.cl-marche-1 { padding-top: 14px; background: rgba(240,196,76,.35); border-color: #B8860B; }
.cl-marche-2 { background: rgba(200,200,200,.4); }
.cl-marche-3 { background: rgba(190,140,90,.32); }
.cl-medaille { font-size: 1.3rem; line-height: 1; }
.cl-marche b { font-size: .85rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.cl-marche small { font-size: .68rem; color: var(--ink-soft); font-weight: 700;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.cl-km { font-weight: 900; font-size: .9rem; font-variant-numeric: tabular-nums; }

.cl-portrait {
  width: 46px; height: 46px; border-radius: 50%; object-fit: cover;
  border: 2px solid var(--ink); background: var(--parchment-deep);
  display: grid; place-items: center; font-weight: 900; color: var(--ink-soft);
}
.cl-portrait.est-petit { width: 30px; height: 30px; font-size: .72rem; }
/* Le classement a un portrait en plus : quatre colonnes, et seulement lui.
   Les autres listes (Silo, bâtisseurs) en ont trois. */
/* --- La ligne d'un joueur, calquee sur `playerRow` ------------------------
   Trois colonnes et non quatre : le rang est passe EN PASTILLE sur le
   portrait (`PortraitClasse`). La colonne gagnee va au portrait, qui etait
   trop petit a 30 px pour qu'on reconnaisse quelqu'un. */
.cl-liste li { grid-template-columns: auto minmax(0, 1fr) auto; gap: 0 10px; padding: 6px 10px; }
.cl-liste li.cl-ville {
  grid-template-columns: auto auto minmax(0, 1fr) auto; cursor: pointer;
}
/* Le rang d'une ville : la pastille CARREE de `RankBadge`, la ou un joueur
   porte la sienne en rond sur son portrait. Memes trois metaux. */
.cl-rang-carre {
  flex: none; font-style: normal;
  min-width: 30px; height: 30px; padding: 0 4px;
  display: grid; place-items: center; border-radius: 8px;
  font-family: var(--display); font-weight: 800; font-size: 1rem; line-height: 1;
  color: var(--ink); border: 2px solid var(--ink-soft);
  background: linear-gradient(135deg, var(--parchment), var(--parchment-deep));
}
.cl-rang-carre.est-1 { background: linear-gradient(135deg, #FBE58A, #D9A521); border-color: var(--ink); }
.cl-rang-carre.est-2 { background: linear-gradient(135deg, #F1F3F5, #A8B0B8); border-color: var(--ink); }
.cl-rang-carre.est-3 { background: linear-gradient(135deg, #EDB884, #B0713A); border-color: var(--ink); }
.cl-badge { font-style: normal; margin-left: 4px; }

.cl-portrait-rang { position: relative; display: block; flex: none; }
/* La liste des FarRunners d'une ville reprend la ligne du classement, sans
   rang : ici le classement n'est qu'un ordre, pas une place a afficher. */
.fr-liste .cl-ligne-nom[role="button"] { cursor: pointer; }
.fr-liste .cl-ligne-nom[role="button"]:focus-visible { outline: 3px solid #FFD27A; outline-offset: 2px; }
/* Deux colonnes sur la LIGNE (portrait, pseudo) et surtout pas sur la LISTE :
   `.jeu-classement` est deja une grille, et lui donner des colonnes mettait
   les dormants cote a cote, deux par rangee. */
.fr-liste.est-dormants li { opacity: .72; grid-template-columns: auto minmax(0, 1fr); }
.fr-titre-dormants { margin-top: 18px; }
.cl-portrait-rang .cl-portrait.est-petit { width: 42px; height: 42px; font-size: .85rem; }
.cl-pastille-rang {
  position: absolute; right: -3px; bottom: -2px;
  min-width: 19px; height: 19px; padding: 0 3px;
  display: grid; place-items: center; border-radius: 999px;
  font-family: var(--display); font-weight: 800; font-style: normal;
  font-size: .72rem; line-height: 1; color: var(--ink);
  border: 1.5px solid var(--ink-soft);
  background: linear-gradient(135deg, var(--parchment), var(--parchment-deep));
  box-shadow: 0 1px 2px rgba(0,0,0,.35);
}
.cl-pastille-rang.est-1 { background: linear-gradient(135deg, #FBE58A, #D9A521); border-color: var(--ink); }
.cl-pastille-rang.est-2 { background: linear-gradient(135deg, #F1F3F5, #A8B0B8); border-color: var(--ink); }
.cl-pastille-rang.est-3 { background: linear-gradient(135deg, #EDB884, #B0713A); border-color: var(--ink); }

/* Le pseudo, ses distinctions et la bulle sur UNE ligne — c'est le `HStack`
   de l'app, pas un empilement. */
.cl-ligne-nom { display: flex; align-items: center; gap: 5px; min-width: 0; }
.cl-ligne-nom > b { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cl-ligne-nom img { flex: none; }
.cl-ecrire {
  flex: none; border: 0; background: none; padding: 0 2px; cursor: pointer;
  font-size: .82rem; line-height: 1; filter: saturate(.85);
}
.cl-toi {
  flex: none; font-style: normal; font-size: .6rem; font-weight: 900;
  color: #fff; background: #1878C4; border-radius: 999px; padding: 1px 6px;
}
/* Les deux mesures, avec la couleur de l'app : DEFENDRE vert, EXPLORER bleu. */
.cl-stats {
  /* `nowrap` et non `wrap` : avec `wrap`, « Val d'Yon et des Olonnes » passait
     a la ligne et la rangee grimpait de 59 a 79 px — justement ce qu'on
     voulait eviter. L'app tronque (`lineLimit(1)`), on tronque aussi. */
  display: flex; flex-wrap: nowrap; align-items: center; gap: 9px;
  min-width: 0; font-variant-numeric: tabular-nums;
}
.cl-stats i { font-style: normal; white-space: nowrap; flex: none; }
.cl-stats .cl-dedans { color: var(--defend); font-weight: 800; }
.cl-stats .cl-dehors { color: var(--explore); font-weight: 800; }
.cl-stats .cl-ou { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* Le titre tenait sur deux lignes et mangeait une ligne de classement. */
#cl-table > h3 { font-size: 1.05rem; line-height: 1.1; }

/* ---------------------------------------------------------------------------
   7 ter. Messages : les cartes de conversation
   --------------------------------------------------------------------------- */
.msg-pastille.est-mention { background: #F5C431; color: var(--ink); }
.msg-vide { padding: 2px 4px 6px; }
/* Les cartes se touchaient : avec un cadre de 21 px elles paraissaient
   espacees, a 11 px plus du tout. La liste porte donc sa gouttiere. */
#msg-liste { display: grid; gap: 8px; }
.msg-section {
  /* La marge basse etait NEGATIVE (-4 px) : elle remontait la premiere carte
     SOUS le titre, et la carte, posee par-dessus, volait les touchers
     destines a « Nouveau » — on ouvrait la premiere conversation. */
  margin: 12px 2px 0;
  position: relative; z-index: 1;
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: .9rem; letter-spacing: .04em; text-transform: uppercase;
  color: rgba(255,255,255,.88); text-shadow: 0 1px 3px rgba(0,0,0,.8);
}
/* « Nouveau » se range au bout du titre de la section, comme dans l'app —
   pas en gros bouton rouge tout en bas de la page. */
.msg-nouveau {
  flex: none; border: 0; background: none; cursor: pointer;
  /* De quoi viser au doigt, sans deborder sur la carte du dessous. */
  padding: 2px 4px; margin: -2px -4px;
  font: inherit; font-size: .88rem; text-transform: none; letter-spacing: 0;
  color: #fff; text-shadow: inherit;
}
.msg-nouveau:active { opacity: .7; }
/* `.jeu-app .panneau` impose `display: block` : il faut au moins deux classes
   pour le reprendre, sinon la carte s'empile au lieu de s'aligner. */
/* Une carte de conversation, c'est deux lignes de texte : 100 px de haut dont
   42 de cadre, c'etait un panneau pour une etiquette. Le parchemin descend a
   11 px (sa texture suit : -11 + 4), le portrait a 38, et la carte tient en
   66 px. Deux classes, sinon `.jeu-app .panneau` garde ses 21 px. */
.jeu-app .panneau.msg-carte {
  display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: center;
  /* Une carte citee ET non lue porte DEUX pastilles : sans ca la seconde
     passait a la ligne et rallongeait la carte d'un tiers. */
  grid-auto-flow: column; grid-auto-columns: auto;
  width: 100%; text-align: left; cursor: pointer; color: var(--ink); font: inherit;
  padding: 2px 4px 4px;
  border-width: 11px;
  border-image-width: 11px;
}
/* PIEGE : le retrait de 4 px du parchemin (`inset: -17px` pour 21 px de
   bordure) existe pour que la texture ne depasse pas des dechirures. A 11 px
   de bordure, la dechirure n'est plus assez epaisse pour couvrir ces 4 px :
   il restait un anneau plat tout autour de la carte, et du ciel dans les
   coins. Sur un cadre mince, la texture va donc jusqu'au bord. */
.jeu-app .panneau.msg-carte::before { inset: -11px; }
.msg-vignette {
  width: 38px; height: 38px; border-radius: 50%; overflow: hidden;
  border: 2px solid var(--ink); background: var(--parchment-deep);
  display: grid; place-items: center;
}
.msg-vignette img { width: 100%; height: 100%; object-fit: cover; }
.msg-lettres { font-weight: 900; color: var(--ink-soft); }
.msg-texte { display: grid; gap: 1px; min-width: 0; }
.msg-texte b { font-size: .95rem; }
.msg-texte small {
  font-size: .78rem; font-weight: 600; color: var(--ink-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.msg-pastille {
  font-style: normal; min-width: 22px; height: 22px; padding: 0 5px;
  display: grid; place-items: center; border-radius: 999px;
  background: #D62B1E; border: 2px solid #120C08; color: #fff;
  font-size: .72rem; font-weight: 900;
}
.msg-chevron { font-style: normal; font-size: 1.3rem; color: var(--ink-soft); font-weight: 800; }

.msg-smileys {
  display: grid; grid-template-columns: repeat(10, 1fr); gap: 3px;
  padding: 5px; border-radius: 8px; background: rgba(28,23,18,.1);
}
.msg-smileys button { border: 0; background: none; padding: 0; cursor: pointer; }
.msg-smileys img { width: 100%; height: auto; }
.msg-bouton-smiley {
  flex: none; width: 38px; height: 38px; border: 0; padding: 0;
  border-radius: 50%; background: rgba(28,23,18,.12); cursor: pointer; font-size: 1.1rem;
}
.zombicone { height: 1.45em; vertical-align: -.35em; }

/* ---------------------------------------------------------------------------
   7 quater. Carte : la barre de recherche et les fiches
   --------------------------------------------------------------------------- */
.carte-barre { display: flex; align-items: center; gap: 8px; }
/* Les deux boutons ronds a la hauteur du champ, comme dans l'app. */
.carte-barre .bouton-rond { width: 48px; height: 48px; }
.carte-recherche { position: relative; flex: 1 1 auto; min-width: 0; }
/* Mesure sur l'app : le champ fait 200 x 30 pt, soit un peu plus de la moitie
   de la largeur, avec sa loupe dedans. Il n'y a que deux boutons a cote —
   celui des regles n'a rien a faire sur une carte. */
.carte-recherche input {
  width: 100%; height: 48px; padding: 0 16px 0 42px; border: 0;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23584A3A' stroke-width='2.6' stroke-linecap='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M15.5 15.5 21 21'/%3E%3C/svg%3E")
      left 15px center / 18px 18px no-repeat,
    url("/assets/img/jeu/barre-recherche.webp") center / 100% 100% no-repeat;
  color: var(--ink); font: inherit; font-weight: 700; font-size: 1.02rem;
}
.carte-recherche input::placeholder { color: rgba(88,74,58,.75); }
.carte-resultats {
  position: absolute; z-index: 600; left: 0; right: 0; top: 52px;
  max-height: 260px; overflow-y: auto;
  border: 3px solid var(--ink); border-radius: 10px;
  background: var(--parchment); box-shadow: 0 6px 12px rgba(0,0,0,.5);
}
.carte-resultats button {
  display: block; width: 100%; text-align: left;
  padding: 7px 12px; border: 0; border-bottom: 1px solid rgba(28,23,18,.15);
  background: none; color: var(--ink); font: inherit; cursor: pointer;
}
.carte-resultats button:hover { background: rgba(28,23,18,.07); }
.carte-resultats b { display: block; font-size: .92rem; }
.carte-resultats small { font-size: .76rem; color: var(--ink-soft); font-weight: 700; }
.carte-boutons { display: grid; gap: 8px; }
.carte-legende { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px;
  font-size: .85rem; font-weight: 600; color: var(--ink-soft); }
.carte-legende li { display: grid; grid-template-columns: auto 1fr; gap: 8px; align-items: start; }
.carte-legende b { color: var(--ink); }
.carte-legende .pastille {
  width: 16px; height: 16px; border-radius: 4px; margin-top: 3px;
  border: 2px solid var(--ink); background: #3F9A63;
}
.carte-legende .est-ambre { background: #E08A22; }
.carte-legende .est-rouge { background: #D93B26; }
.carte-legende .est-ruine { background: #6C8F3A; border-style: dashed; }

/* ---------------------------------------------------------------------------
   7 quinquies. Mon espace
   --------------------------------------------------------------------------- */
.profil-tete { display: flex; align-items: center; gap: 12px; }
.profil-portrait {
  position: relative; width: 74px; height: 74px; flex: none;
  border-radius: 50%; border: 3px solid var(--ink); padding: 0;
  background: var(--parchment-deep); overflow: hidden; cursor: pointer;
}
.profil-portrait img { width: 100%; height: 100%; object-fit: cover; }
.profil-lettres { font-size: 2rem; }
.profil-stylo {
  position: absolute; right: 0; bottom: 0;
  width: 22px; height: 22px; display: grid; place-items: center;
  border-radius: 50%; background: var(--rust); color: #fff;
  border: 2px solid var(--ink); font-size: .7rem;
}
.profil-tete b { display: block; font-size: 1.15rem; }
.profil-tete small { display: block; font-size: .85rem; color: var(--ink-soft); font-weight: 700; }
.profil-grille {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(54px, 1fr)); gap: 6px;
  max-height: 210px; overflow-y: auto;
  padding: 6px; border-radius: 8px; background: rgba(28,23,18,.1);
}
.profil-grille button { border: 0; background: none; padding: 0; cursor: pointer; }
.profil-grille img {
  width: 100%; aspect-ratio: 1; border-radius: 50%; object-fit: cover;
  border: 2px solid rgba(28,23,18,.35);
}
/* Six boutons pleine largeur a 7 px d'ecart faisaient un empilement sans
   hierarchie. On les aere, et on separe ce qui touche au jeu de ce qui relie
   le telephone au monde exterieur. */
.profil-boutons { display: grid; gap: 10px; margin-top: 10px; }
.profil-boutons + .bat-sous-titre { margin-top: 18px; }
/* --- Compte et confidentialite -------------------------------------------
   La bascule des cartes, les trois liens legaux, et la suppression du compte.
   Apple (5.1.1(v)) et Google Play exigent que la suppression se fasse DANS
   l'application : c'est un motif de refus, pas un detail. */
.profil-compte { margin-top: 14px; }
.profil-compte .bat-sous-titre { margin-bottom: 4px; }
.profil-bascule {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 9px 2px; cursor: pointer;
  border-bottom: 1px solid rgba(58,44,31,.25);
}
.profil-bascule > span { flex: 1 1 auto; min-width: 0; }
.profil-bascule b { display: block; font-size: .95rem; color: var(--ink); }
.profil-bascule small {
  display: block; margin-top: 2px;
  font-size: .74rem; font-weight: 600; color: var(--ink-soft);
}
.profil-bascule input {
  flex: none; width: 46px; height: 27px; margin: 2px 0 0;
  appearance: none; cursor: pointer;
  border-radius: 999px; border: 2px solid var(--ink);
  background: rgba(28,23,18,.22); position: relative;
  transition: background .15s ease;
}
.profil-bascule input::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 19px; height: 19px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 2px rgba(0,0,0,.4);
  transition: transform .15s ease;
}
.profil-bascule input:checked { background: var(--rust); }
.profil-bascule input:checked::after { transform: translateX(19px); }
.profil-bascule input:disabled { opacity: .5; }
.profil-ligne {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 11px 2px; cursor: pointer;
  border: 0; border-bottom: 1px solid rgba(58,44,31,.25); background: none;
  color: var(--ink); font: inherit; font-weight: 700; font-size: .92rem;
  text-align: left; text-decoration: none;
}
.profil-ligne i { font-style: normal; font-weight: 900; color: var(--ink-soft); }
.profil-ligne:last-child { border-bottom: 0; }
.profil-ligne.est-grave { color: var(--rust-dark); font-weight: 800; }
.profil-ligne:active { opacity: .7; }

/* La fenetre de suppression. */
.profil-grave {
  margin: 0 0 6px; font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 1.35rem; color: var(--rust-dark);
}
.profil-pertes { margin: 2px 0 8px; padding-left: 20px; }
.profil-pertes li { font-size: .88rem; color: var(--ink); margin-bottom: 3px; }
.profil-champ {
  display: block; margin: 10px 0 4px;
  font-size: .78rem; font-weight: 800; color: var(--ink-soft);
}
.profil-saisie {
  width: 100%; box-sizing: border-box; padding: .5em .7em;
  border: 2px solid var(--ink); border-radius: 8px;
  background: rgba(255,255,255,.6); color: var(--ink); font: inherit;
}
.profil-titre {
  margin: 0 0 4px; font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 1.3rem; color: var(--ink);
}
/* La liste des montres : une planche par marque. */
.jeu-app .panneau.montre-ligne {
  display: flex; align-items: center; gap: 12px; padding: 8px 10px;
}
.montre-icone { font-size: 1.5rem; filter: grayscale(1); opacity: .7; }
.montre-ligne b {
  display: block; font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 1.15rem; color: var(--ink-soft);
}
.montre-ligne small { display: block; font-size: .8rem; font-weight: 700; color: var(--ink-soft); }

.profil-lien { display: flex; gap: 6px; }
.profil-lien input {
  flex: 1 1 auto; min-width: 0; padding: .4em .7em;
  border: 2px solid var(--ink); border-radius: 8px;
  background: rgba(255,255,255,.6); color: var(--ink); font: inherit; font-size: .82rem;
}
.jeu-fenetre-nu { border: 0 !important; padding: 0 !important; filter: none !important; }
.jeu-fenetre-nu::before { display: none; }

.regle { margin-bottom: 12px; }
.regle h4 {
  display: flex; align-items: center; gap: 8px; margin: 0 0 4px;
  font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 1.05rem; color: var(--rust-dark); text-transform: uppercase;
}
.regle h4 span {
  width: 22px; height: 22px; flex: none; display: grid; place-items: center;
  border-radius: 50%; background: var(--rust); color: #fff;
  font-size: .8rem; font-style: normal;
}
/* Comme sur le site : la regle est faite de paragraphes et de puces. */
.regle p { margin: 0 0 .6em; font-size: .88rem; font-weight: 600; color: var(--ink-soft); }
.regle ul { margin: 0 0 .6em; padding-left: 1.15em; font-size: .88rem; font-weight: 600; color: var(--ink-soft); }
.regle li { margin: 0 0 .25em; }
.regle p:last-child, .regle ul:last-child, .regle li:last-child { margin-bottom: 0; }
.regle .gab-tableau { width: auto; margin: 0 0 .6em; border-collapse: collapse; font-size: .88rem; font-weight: 600; color: var(--ink-soft); }
.regle .gab-tableau td { padding: .1em .8em .1em 0; vertical-align: baseline; white-space: nowrap; }
.regle .gab-tableau .gab-cle { font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ink); }

/* --- Les règles en parchemins (jeu-regles.js, comme RulesView dans l'app) --- */
.regle-carte { margin: 0; }
.regle-carte h4 { border-bottom: 1.5px solid rgba(65,42,20,.25); padding-bottom: 6px; margin-bottom: 8px; }
.regle-carte p, .regle-carte ul { color: var(--ink); }
.regle-courte { color: var(--rust-dark) !important; font-weight: 800 !important; }
.regle-courte b { color: var(--rust-dark); }
.regle-issue { display: flex; gap: 9px; align-items: flex-start; margin: 0 0 .55em; font-size: .84rem; font-weight: 600; color: var(--ink); }
.regle-issue small { display: block; font-family: var(--mono, monospace); font-size: .74rem; color: var(--ink-soft); }
.regle-issue b { display: block; }
.regle-pastille { flex: none; font-style: normal; font-size: .72rem; font-weight: 900; color: #fff;
  padding: 2px 8px; border-radius: 99px; white-space: nowrap; }
.regle-point { flex: none; width: 14px; height: 14px; margin-top: 2px; border-radius: 50%;
  border: 1px solid rgba(65,42,20,.4); }
.regle-pastille.ton-vert, .regle-point.ton-vert { background: #3F9A63; }
.regle-pastille.ton-ambre, .regle-point.ton-ambre { background: #E08A22; }
.regle-pastille.ton-rouge, .regle-point.ton-rouge { background: #D93B26; }
.regle-point.ton-bleu { background: #3BA7E8; }
.regle-batiments { list-style: none; padding: 0 !important; display: grid; gap: 7px; }
.regle-batiments li { display: flex; gap: 9px; align-items: flex-start; }
.regle-batiments li > span { flex: none; width: 22px; text-align: center; }
.regle-batiments li > span svg { width: 18px; height: 18px; }
.regle-batiments b { display: block; color: var(--ink); }
.regle-version { text-align: center; font-size: .75rem !important; }
/* Couché : cinq paliers sur deux lignes. L'écran du jeu est un téléphone,
   les libellés doivent donc pouvoir se replier. */
.regle .gab-tableau.est-couche { width: 100%; table-layout: fixed; font-size: .8rem; }
.regle .gab-tableau.est-couche td { padding: .1em .4em .1em 0; white-space: normal; overflow-wrap: anywhere; hyphens: auto; }
.regle .gab-tableau.est-couche td:last-child { padding-right: 0; }
.regle .gab-tableau:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------------------
   8. Les segments (classement, fils de messages)
   --------------------------------------------------------------------------- */
/* Le dessin de l'app : barre rouge cloutee pour l'actif, bois sombre sinon. */
.jeu-segments { display: flex; flex-wrap: wrap; gap: 6px; padding: 0; border: 0; background: none; }
.jeu-segments button {
  flex: 1 1 auto; min-width: 0;
  padding: .5em .7em; border: 0;
  background: url("/assets/img/jeu/segment-inactif.webp") center / 100% 100% no-repeat;
  color: #E7DCC6;
  font-family: var(--display); font-weight: 800; font-style: italic; font-size: .92rem;
  text-transform: uppercase; letter-spacing: .01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  cursor: pointer;
  filter: drop-shadow(0 3px 4px rgba(0,0,0,.4));
  text-shadow: 0 1px 2px rgba(0,0,0,.6);
}
.jeu-segments button.is-active {
  background-image: url("/assets/img/jeu/segment-actif.webp");
  color: #fff;
}
.jeu-segments button:active { transform: scale(.97); }
.jeu-segments .jeu-pastille {
  display: inline-block; margin-left: 5px; min-width: 17px; padding: 0 4px;
  border-radius: 999px; background: #D62B1E; border: 1.5px solid #120C08;
  color: #fff; font-style: normal; font-size: .68rem; font-weight: 800;
}

/* ---------------------------------------------------------------------------
   9. Carte
   --------------------------------------------------------------------------- */
/* PIEGE : la grille doit nommer AUTANT de rangees que l'onglet a d'enfants
   (enseigne, barre, bandeau, cadre, boutons). Avec trois rangees pour cinq
   enfants, le cadre tombait sur une rangee `auto` — et comme la carte est en
   `position: absolute` dedans, il n'avait plus RIEN pour se donner une
   hauteur : 0 px. L'onglet paraissait vide, et rien ne se chargeait, puisque
   l'`IntersectionObserver` qui declenche le premier appel ne voit jamais un
   element de hauteur nulle. */
/* --- L'onglet Carte : la carte EST l'ecran -------------------------------
   Comme dans l'app. La carte est un calque sur tout le plateau (`#carte-fond`,
   pose par jeu-carte.js), la barre du haut disparait, et il ne reste dans la
   colonne que l'enseigne, la recherche et le bandeau d'etat, qui flottent
   dessus. On gagne la bande du logo et celle du bouton du bas. */
.carte-fond { position: absolute; inset: 0; z-index: 0; }
.jeu-app[data-onglet="carte"] .map-frame {
  position: absolute; inset: 0;
  height: auto; min-height: 0;
  border: 0; border-radius: 0; box-shadow: none;
}
/* La barre du haut disparait sur les trois onglets qui ont besoin de toute
   la hauteur : la carte, le classement et les messages. On y perd l'acces a
   Mon espace, qui se prend depuis Courir ou Ma ville — c'est ce que fait
   l'app. La marge haute reprend l'encoche a son compte, sinon le contenu
   passerait sous la barre d'etat dans la coque Android. */
.jeu-app[data-onglet="carte"] .jeu-top,
.jeu-app[data-onglet="classement"] .jeu-top,
.jeu-app[data-onglet="messages"] .jeu-top { display: none; }
.jeu-app[data-onglet="classement"] .jeu-ecran,
.jeu-app[data-onglet="messages"] .jeu-ecran {
  padding-top: calc(10px + env(safe-area-inset-top));
}
/* La colonne laisse passer les touchers : on fait glisser la carte a travers
   elle, sauf sur ses propres elements. */
.jeu-app[data-onglet="carte"] .jeu-ecran {
  overflow: hidden; pointer-events: none;
  padding: calc(8px + env(safe-area-inset-top)) 14px 0;
}
.jeu-pane[data-pane="carte"] > * { pointer-events: auto; }
.jeu-app[data-onglet="carte"] .jeu-ecran,
.jeu-app[data-onglet="carte"] .jeu-tabs { position: relative; z-index: 1; }
.jeu-pane[data-pane="carte"] {
  height: 100%;
  grid-template-rows: auto auto auto;
  align-content: start;
}
/* Les boutons de zoom de Leaflet tombaient sur l'enseigne : ils descendent
   au-dessus des onglets. L'attribution OSM aussi, sinon elle passe derriere
   la barre d'onglets — et elle doit rester lisible. */
.jeu-app[data-onglet="carte"] .leaflet-top.leaflet-left {
  top: auto; bottom: calc(96px + env(safe-area-inset-bottom));
}
.jeu-app[data-onglet="carte"] .leaflet-bottom.leaflet-right {
  bottom: calc(80px + env(safe-area-inset-bottom));
}
/* Le bandeau d'etat flotte maintenant sur une carte claire : il lui faut sa
   capsule, comme aux puces de Ma ville. */
.jeu-app[data-onglet="carte"] .map-status:not(:empty) {
  justify-self: center; max-width: 100%;
  padding: 4px 11px; border-radius: 999px;
  border: 1.5px solid rgba(255,255,255,.2); background: rgba(0,0,0,.72);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  color: #fff; text-shadow: none;
}
.jeu-app .map-status {
  font-size: .82rem; color: #D7E0E8; text-shadow: 0 1px 3px rgba(0,0,0,.8);
}
.jeu-app .map-frame {
  /* `min-height` en ceinture : meme si la grille rechange, plus de cadre plat. */
  height: auto; min-height: 220px;
  border: 3px solid var(--ink); border-radius: 12px;
  box-shadow: 0 6px 10px rgba(0,0,0,.5);
}
/* Le bouton « ma ville la plus proche » reprend le bouton dessine de l'app. */
#map-locate.bouton-rond {
  font-size: 0;
  background-image: url("/assets/img/jeu/bouton-localiser.webp");
}
/* Le bouton du zonage : la grille 3x3 de l'app, dessinee en masque pour
   prendre l'encre du bouton (et la rouille quand il est enfonce). */
#map-zonage.bouton-rond { font-size: 0; }
#map-zonage::before {
  content: ""; width: 19px; height: 19px; background: #241A12;
  -webkit-mask: var(--grille-3) center / contain no-repeat;
  mask: var(--grille-3) center / contain no-repeat;
}
#map-zonage[aria-pressed="true"] {
  transform: scale(.94);
  box-shadow: inset 0 0 0 3px #F2B43A; border-radius: 50%;
  filter: drop-shadow(0 2px 2px rgba(0,0,0,.2));
}
#map-zonage[aria-pressed="true"]::before { background: var(--rust); }
.jeu-app {
  --grille-3: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 18'%3E%3Cg fill='none' stroke='%23000' stroke-width='1.7' stroke-linejoin='round'%3E%3Crect x='1' y='1' width='16' height='16' rx='2.5'/%3E%3Cpath d='M1 6.33h16M1 11.67h16M6.33 1v16M11.67 1v16'/%3E%3C/g%3E%3C/svg%3E");
}

/* --- « Qui la porte cette semaine », sur la page d'une ville etrangere --- */

/* ---------------------------------------------------------------------------
   10. Messages
   --------------------------------------------------------------------------- */
/* Cette regle datait du temps ou le fil vivait dans l'onglet : la derniere
   rangee etirait « Joueurs bloques » sur 229 px de haut, bouton transparent
   et invisible sur le decor. Le fil est une fenetre depuis, l'onglet n'a plus
   besoin de remplir la hauteur — il defile. */
.jeu-pane[data-pane="messages"] { align-content: start; }
.jeu-fil { grid-template-rows: auto minmax(0, 1fr) auto auto; min-height: 0; }
.jeu-bulles {
  display: grid; gap: 8px; align-content: start;
  min-height: 0; overflow-y: auto;
  padding: 2px; margin: 0 -2px;
  overscroll-behavior-y: contain;
  scrollbar-width: none;
}
.jeu-bulles::-webkit-scrollbar { width: 0; }
.jeu-bulle {
  justify-self: start; max-width: 85%;
  display: grid; gap: 2px;
  padding: 7px 11px; border-radius: 12px 12px 12px 3px;
  background: rgba(255,255,255,.6); border: 2px solid rgba(28,23,18,.25);
}
.jeu-bulle.is-moi {
  justify-self: end; border-radius: 12px 12px 3px 12px;
  background: linear-gradient(180deg, #E34033, #C4261A);
  border-color: #6E1109; color: #fff;
}
.jeu-bulle-qui { font-weight: 800; font-size: .74rem; color: var(--rust-dark); }
.jeu-bulle.is-moi .jeu-bulle-quand { color: rgba(255,255,255,.8); }
.jeu-bulle.is-moi .bulle-coeur { color: rgba(255,255,255,.75); }
.jeu-bulle.is-moi .bulle-coeur.est-aime,
.jeu-bulle.is-moi .bulle-coeur.est-compte { color: #FFD7D2; }
.jeu-bulle p { margin: 0; font-size: .93rem; font-weight: 600; white-space: pre-wrap; word-break: break-word; }
.jeu-bulle-quand { font-size: .68rem; font-weight: 700; color: var(--ink-soft); justify-self: end; }

.jeu-ecrire { display: flex; gap: 8px; align-items: center; }
.jeu-ecrire input {
  flex: 1 1 auto; min-width: 0; height: 40px;
  padding: 0 16px; border: 0;
  background: url("/assets/img/jeu/barre-recherche.webp") center / 100% 100% no-repeat;
  color: var(--ink); font: inherit; font-weight: 600;
}
.jeu-ecrire input::placeholder { color: rgba(88,74,58,.75); }
.jeu-ecrire input:focus-visible { outline: 3px solid #FFD27A; outline-offset: 1px; }
.jeu-ecrire .btn { flex: none; }

/* ---------------------------------------------------------------------------
   11. L'ecran d'accueil, non connecte (AuthFlowView)
   --------------------------------------------------------------------------- */
/* L'écran d'accueil n'a pas de barre du haut : il n'y a ni ville ni portrait
   à montrer, et le logo est déjà au milieu. */
.jeu-app[data-etat="invite"] .jeu-top > :not(.rrf-build) { display: none; }
.jeu-app[data-etat="invite"] .jeu-top { padding-bottom: 0; }
/* Deconnecte, les cinq onglets n'ont plus rien a montrer : chaque ecran
   rappellerait l'API sans jeton, se ferait renvoyer un 401 et ramenerait ici.
   On les retire plutot que de laisser cliquer dans le vide. */
.jeu-app[data-etat="invite"] .jeu-tabs { display: none; }
.jeu-accueil { display: grid; gap: 16px; justify-items: center; padding: 10px 0 30px; }
.jeu-accueil-logo { width: min(74%, 250px); height: auto;
  filter: drop-shadow(0 4px 8px rgba(0,0,0,.7)); }
.jeu-accueil .enseigne { width: 100%; }
.jeu-accueil .panneau { width: 100%; }
.jeu-accueil-version {
  margin: 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .72rem; color: rgba(255,255,255,.6);
}
/* Les formulaires viennent du site : ils gardent leurs champs, on retire
   seulement ce qui n'a de sens que dans une fenêtre. */
.jeu-accueil .modal-card { border: 0; padding: 0; box-shadow: none; background: none; }
.jeu-accueil .modal-card::before { display: none; }
.jeu-accueil .modal-sub { margin-top: 0; }

/* ---------------------------------------------------------------------------
   11 bis. L'écran d'attente, le compte rendu d'invasion, les fenêtres du site
   --------------------------------------------------------------------------- */
.jeu-attente {
  display: grid; justify-items: center; gap: 14px;
  padding: 22vh 20px 0; text-align: center;
}
.jeu-attente img { width: min(70%, 240px); height: auto;
  filter: drop-shadow(0 4px 8px rgba(0,0,0,.7)); }
.jeu-attente p { margin: 0; font-size: .85rem; font-weight: 700; color: rgba(255,255,255,.88);
  text-shadow: 0 1px 3px rgba(0,0,0,.8); }
.jeu-attente-barre {
  width: 200px; height: 8px; border-radius: 999px;
  background: rgba(255,255,255,.18); overflow: hidden;
}
.jeu-attente-barre i {
  display: block; width: 40%; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--rust-light), var(--rust));
  animation: jeu-attente-glisse 1.1s ease-in-out infinite;
}
@keyframes jeu-attente-glisse {
  0% { transform: translateX(-100%); } 100% { transform: translateX(250%); }
}
@media (prefers-reduced-motion: reduce) { .jeu-attente-barre i { animation: none; width: 100%; } }

.rapport-issue {
  margin: 0; padding: 8px 12px; border-radius: 8px;
  font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 1.15rem; text-align: center; color: #fff;
}
.rapport-issue.est-bon { background: var(--defend); }
.rapport-issue.est-mauvais { background: var(--rust-dark); }

/* Les fenêtres du site (connexion, inscription) dans le dessin du jeu :
   un parchemin, pas une carte blanche posée sur le plateau. */
.jeu-body .modal-card {
  position: relative; z-index: 0;
  background: none;
  border: 21px solid transparent;
  border-image: url("/assets/img/jeu/parchemin-cadre.webp") 63 / 21px / 0 stretch;
  border-radius: 0; box-shadow: none;
  color: var(--ink);
}
.jeu-body .modal-card::before {
  content: ""; position: absolute; inset: -17px; z-index: -1; border-radius: 10px;
  background: url("/assets/img/jeu/parchemin-texture.webp") 0 0 / 190px auto repeat;
}
.jeu-body .modal-card .sign { margin-bottom: 14px; }

/* PIEGE, et il a coute : `.jeu-accueil .modal-card` plus haut retire deja ce
   decor — mais `.jeu-body .modal-card` est ecrit APRES, avec exactement la
   meme specificite, donc c'est lui qui gagnait. L'ecran d'inscription
   affichait DEUX parchemins imbriques : celui du panneau qui accueille le
   formulaire, et celui de la carte. Sur l'ecran d'accueil, le panneau suffit.
   Regle posee ici, apres, et plus specifique : les deux conditions. */
.jeu-body .jeu-accueil .modal-card {
  border: 0; border-image: none; padding: 0; box-shadow: none; background: none;
  max-height: none; overflow: visible;
}
.jeu-body .jeu-accueil .modal-card::before { display: none; }

/* Dans la coque Android, « Sur iPhone ? Inscris-toi plutot dans l'app » n'a
   aucun sens : on EST l'application, et le lien emmenerait vers TestFlight,
   c'est-a-dire nulle part. `jeu.js` pose `data-coque` sur <html>. */
html[data-coque] .modal-iphone { display: none; }
.jeu-body .field { background: rgba(255,255,255,.55); }

/* ---------------------------------------------------------------------------
   11 ter. Messages : coeurs, menu d'un message, mot de passage
   --------------------------------------------------------------------------- */
.jeu-bulle { cursor: pointer; }
.jeu-bulle-pied { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.bulle-coeur {
  border: 0; background: none; padding: 0 2px; cursor: pointer;
  font-size: .78rem; font-weight: 800; color: rgba(88,74,58,.6);
}
.bulle-coeur.est-aime { color: #D62B1E; }
.bulle-coeur.est-compte { cursor: default; color: #D62B1E; }

.msg-actions { display: grid; gap: 7px; margin-top: 6px; }
/* Seul bouton de la page depuis que « Nouveau » est monte dans le titre : en
   fantome sur un decor charge il ne se lisait plus. */
.msg-actions .btn-ghost-dark {
  background: rgba(0,0,0,.6);
  border: 1.5px solid rgba(255,255,255,.22);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  color: var(--cream);          /* l'encre sombre du site, sur du noir… */
  text-shadow: 0 1px 2px rgba(0,0,0,.6);
}

.msg-menu { position: absolute; inset: 0; z-index: 50; display: flex; align-items: flex-end; }
.msg-menu-voile { position: absolute; inset: 0; background: rgba(5,10,16,.6); }
/* Deux classes : `.jeu-app .panneau` impose `display: block` (même piège que
   la carte de conversation). */
.jeu-app .msg-menu-liste {
  position: relative; width: 100%;
  margin: 12px; padding: 6px 8px;
  display: grid; gap: 4px;
}
.msg-menu-liste button {
  padding: .6em .8em; border: 0; border-radius: 8px;
  background: rgba(255,255,255,.45);
  color: var(--ink); font: inherit; font-weight: 700; font-size: .95rem;
  text-align: left; cursor: pointer;
}
.msg-menu-liste button:hover { background: rgba(255,255,255,.7); }
.msg-menu-liste .est-annuler { text-align: center; font-weight: 800; color: var(--rust-dark); }
.bloque-ligne { display: flex; align-items: center; justify-content: space-between; gap: 10px; }

.jeu-toast {
  position: absolute; z-index: 60; left: 50%; bottom: 90px; transform: translateX(-50%);
  margin: 0; padding: 8px 16px; max-width: 86%;
  border-radius: 999px; border: 2px solid rgba(0,0,0,.5);
  background: rgba(10,16,22,.92); color: #fff;
  font-size: .85rem; font-weight: 700; text-align: center;
}

/* La carte d'un indice : une VRAIE carte, dessinee par Leaflet.
   Les tuiles sont desaturees et assombries pour que le rouge du triangle soit
   la seule chose qu'on regarde — c'est l'allure qu'elle a dans l'application.
   La bordure doree dit que c'est une piece du jeu, pas un plan. */
.indice-carte {
  position: relative; height: 190px; margin: 8px 0 4px;
  border-radius: 10px; overflow: hidden;
  border: 3px solid #B8860B;
  background: #cfc6b6;
}
.indice-carte .leaflet-tile {
  filter: grayscale(1) contrast(.92) brightness(.82) sepia(.18);
}
.indice-carte .leaflet-container { background: #cfc6b6; }

/* --- La fiche d'un objet et celle d'une relique --------------------------
   Deux feuilles EMPILEES par-dessus la Forge (`options.empile`) : on y entre
   d'une tuile, on en revient par le bouton de gauche, et la liste est restee
   derriere, a sa place et a son defilement. */
/* Comme ReliqueDetailView : pas d'en-tete de bois, le decor assombri, le
   bouton retour en haut a gauche ; l'objet et son nom sont poses sur le
   decor, seuls les tableaux sont sur parchemin, ecrits petit. */
.jeu-fenetre-feuille:has(> .objet-cadre) {
  padding-top: 10px;
  border-radius: 22px 22px 0 0;
  border-top: 2px solid rgba(255,255,255,.12);
  box-shadow: 0 -12px 34px rgba(0,0,0,.55);
  overflow: hidden;
  background:
    linear-gradient(180deg, rgba(0,0,0,.5), rgba(0,0,0,.62)),
    url("/assets/img/jeu/fond.webp") center / cover no-repeat,
    var(--night);
}
.jeu-fenetre-feuille:has(> .objet-cadre) > .jeu-fenetre-tete { padding: 0; }
.objet-entete-vide { flex: 1 1 auto; }
.objet-cadre .jeu-fenetre-corps { gap: 12px; padding-bottom: 14px; }
.objet-tete {
  display: grid; justify-items: center; gap: 6px; padding: 10px 6px 0;
  text-align: center; color: #fff;
}
.objet-tete .tuile-objet { margin-bottom: 4px; }
.objet-vignette {
  position: relative; width: 150px; height: 150px; display: grid; place-items: center;
  border-radius: 24px; overflow: hidden; margin-bottom: 4px;
}
.objet-vignette img { width: 86%; height: 86%; object-fit: contain; }
.objet-vignette.est-relique {
  background: #3A2412;
  box-shadow: 0 0 0 3px #7A5A18, 0 0 0 6px #3A2412, 0 0 0 9px rgba(242,201,76,.75);
}
.objet-vignette.est-relique.est-obtenue {
  box-shadow: 0 0 0 3px #F2C94C, 0 0 0 6px #3A2412, 0 0 0 9px #F2C94C,
              0 0 22px rgba(242,201,76,.65);
}
.objet-nom {
  margin: 0; font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 1.55rem; line-height: 1.1; color: #fff;
  text-shadow: 0 2px 4px rgba(0,0,0,.7);
}
.objet-etat {
  margin: 0; font-weight: 900; font-size: .76rem; letter-spacing: .06em;
  text-transform: uppercase; color: var(--etat, #fff);
  text-shadow: 0 1px 3px rgba(0,0,0,.8);
}
.objet-mot, .objet-amelio {
  margin: 0; max-width: 34em; font-size: .9rem; font-weight: 500; line-height: 1.4;
  color: rgba(255,255,255,.86); text-shadow: 0 1px 3px rgba(0,0,0,.8);
}
.objet-amelio {
  display: flex; align-items: center; gap: 8px; text-align: left;
  font-weight: 700; color: #fff;
}
.objet-legende {
  margin: -4px 0 0; text-align: center; font-size: .76rem; font-weight: 600;
  color: rgba(255,255,255,.85); text-shadow: 0 1px 3px rgba(0,0,0,.8);
}
.objet-etat-petit {
  font-weight: 900; font-size: .75rem; letter-spacing: .04em;
  color: var(--etat, var(--ink-soft)); white-space: nowrap;
}
/* Les couleurs vives (plus haut, `.est-nN`) se lisent sur le decor ; sur
   parchemin, l'argent et l'or disparaissent : l'encre de leur etat. */
.est-n1 { --encre: #6B4A2B; }
.est-n2 { --encre: #A0602A; }
.est-n3 { --encre: #4E6478; }
.est-n4 { --encre: #7A3FC0; }
.est-n5 { --encre: #8A6A0A; }
.panneau .objet-etat-petit { color: var(--encre, var(--ink-soft)); }
.objet-carte { margin: 0; }
/* Le parchemin des details : des LIGNES, libelle a gauche, petit et pale,
   valeur a droite — `ligne()` de ReliqueDetailView. */
.jeu-app .objet-kv { display: grid; grid-template-columns: 1fr; gap: 0; margin: 0; }
.jeu-app .objet-kv div {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  padding: 4px 0; background: none; border: 0; border-radius: 0;
}
.objet-kv dt {
  display: flex; align-items: baseline; gap: 6px;
  text-transform: none; letter-spacing: 0;
  font-size: .76rem; font-weight: 600; color: var(--ink-soft);
}
.objet-kv dt i { font-style: normal; font-size: .72rem; width: 1.2em; text-align: center; }
.objet-kv dd { margin: 0; font-size: .88rem; font-weight: 700; color: var(--ink); text-align: right; }
/* « Trouvé une fois » et « Le triptyque » : un titre, des lignes. */
.objet-trouvailles h4, .objet-triptyque h4 {
  margin: 0 0 6px; font-size: .9rem; font-weight: 900; color: var(--ink);
}
.objet-trouvailles ul, .objet-triptyque ul {
  list-style: none; margin: 0; padding: 0; display: grid; gap: 8px;
}
.objet-trouvailles li, .objet-triptyque li {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.objet-trouvailles li > span:first-child, .objet-triptyque li > span:last-child {
  display: grid; gap: 1px; min-width: 0;
}
.objet-trouvailles b, .objet-triptyque b { font-size: .88rem; font-weight: 700; color: var(--ink); }
.objet-trouvailles small, .objet-triptyque small { font-size: .7rem; font-weight: 600; color: var(--ink-soft); }
.objet-triptyque li { justify-content: flex-start; }
.objet-triptyque li[role="button"] { cursor: pointer; }
.objet-triptyque .heritage-case.est-vide { width: 46px; height: 46px; flex: none; }
.objet-triptyque .tuile-objet { flex: none; }
.objet-legende-encre { margin: 8px 0 0; font-size: .76rem; font-weight: 600; color: var(--ink-soft); }


/* ---------------------------------------------------------------------------
   11 quater. Le fil de discussion, en plein écran
   --------------------------------------------------------------------------- */
/* Dans l'application, une conversation occupe tout l'écran et flotte sur le
   décor de la ville : pas de parchemin sous les bulles. */
/* Le cadre se retracte de la hauteur du clavier : la barre de saisie remonte
   au-dessus de lui, et c'est la zone des bulles qui se raccourcit — donc on
   voit ce qu'on ecrit ET le dernier message. Deux classes, parce que
   `.jeu-app .panneau` bat une classe seule (piege deja paye cinq fois). */
.jeu-app .panneau.msg-fil-cadre { padding-bottom: env(keyboard-inset-height, 0px); }
.jeu-fenetre-cadre.msg-fil-cadre {
  border: 0; padding: 0; filter: none; background: none;
  /* Une colonne souple plutôt qu'une grille à rangées comptées : la bannière
     n'existe que dans un privé, et la grille décalait tout quand elle
     manquait. */
  display: flex; flex-direction: column; gap: 8px;
  overflow: hidden;                 /* ce sont les bulles qui défilent */
}
/* PIÈGE : le corps d'une fenêtre est un `.jeu-bloc`, donc une GRILLE. Ses
   rangées automatiques se partagent la hauteur restante : avec peu de messages,
   la rangée de la barre d'écriture recevait sa part, et la barre (étirée sur
   sa rangée) devenait un grand cadre noir en bas du fil. Une colonne souple :
   les bulles prennent tout ce qui reste, le reste garde sa taille. */
.msg-fil-cadre > .jeu-fenetre-corps {
  display: flex; flex-direction: column; gap: 8px;
  overflow: hidden;                 /* ce sont les bulles qui défilent */
}
.msg-fil-corps .jeu-bulles { flex: 1 1 auto; min-height: 0; }
.msg-fil-corps .msg-bandeau, .msg-fil-corps .msg-smileys,
.msg-fil-corps .msg-barre { flex: none; }
.jeu-fenetre-cadre.msg-fil-cadre::before { display: none; }
.jeu-fenetre-feuille:has(.msg-fil-cadre) {
  max-height: 100%; height: 100%;
  padding-top: calc(8px + env(safe-area-inset-top));
  background:
    linear-gradient(180deg, rgba(0,0,0,.42), rgba(0,0,0,.58)),
    url("/assets/img/jeu/fond.webp") center / cover no-repeat,
    var(--night);
}
.msg-fil .jeu-bulles { max-height: none; }

.msg-entete {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: 9px;
  padding: 4px 10px; border-radius: 999px;
  background: rgba(10,16,22,.6); border: 2px solid rgba(0,0,0,.45);
}
.msg-entete-portrait {
  width: 34px; height: 34px; flex: none; border-radius: 50%; overflow: hidden;
  border: 2px solid var(--ink); background: var(--parchment-deep);
  display: grid; place-items: center; font-weight: 900; font-size: .72rem; color: var(--ink);
}
.msg-entete-portrait img { width: 100%; height: 100%; object-fit: cover; }
.msg-entete-nom {
  flex: 1 1 auto; min-width: 0;
  font-family: var(--display); font-weight: 800; font-style: italic; font-size: 1rem;
  color: var(--cream); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.msg-entete-nom small {
  display: block; font-family: var(--body); font-style: normal; font-weight: 700;
  font-size: .68rem; color: #B9C4CD;
}
.msg-entete-menu { width: 34px; height: 34px; font-size: .8rem; letter-spacing: -1px; }

.msg-bandeau {
  margin: 0 0 6px; padding: 7px 12px; border-radius: 10px;
  background: rgba(10,16,22,.62); border: 1px solid rgba(255,255,255,.12);
  color: #CBD6DF; font-size: .76rem; font-weight: 600;
}

/* Un à trois autocollants seuls : en grand, sans bulle. */
.msg-collants {
  justify-self: start; display: grid; justify-items: start; gap: 2px;
  cursor: pointer;
}
.msg-collants.is-moi { justify-self: end; justify-items: end; }
.msg-collants-rang { display: flex; gap: 4px; }
.msg-collants-rang img { width: 56px; height: 56px; filter: drop-shadow(0 3px 4px rgba(0,0,0,.5)); }
.msg-collants .jeu-bulle-quand { color: rgba(255,255,255,.8); text-shadow: 0 1px 3px rgba(0,0,0,.8); }
.msg-collants .bulle-coeur { color: #FF6B5E; }

/* La barre d'écriture : un champ sombre, le smiley, le pouce zombie. */
.msg-barre {
  flex: none; align-items: center; gap: 7px;
  padding: 6px; border-radius: 999px;
  background: rgba(10,16,22,.75); border: 2px solid rgba(0,0,0,.5);
}
.msg-barre input {
  flex: 1 1 auto; min-width: 0; height: 36px; padding: 0 14px;
  border: 0; border-radius: 999px;
  background: rgba(255,255,255,.1); color: var(--cream); font: inherit; font-weight: 600;
}
.msg-barre input::placeholder { color: rgba(255,255,255,.45); }
.msg-bouton-smiley {
  flex: none; width: 34px; height: 34px; border: 2px solid #6E1109; padding: 0;
  border-radius: 50%; background: var(--rust); color: #fff; cursor: pointer; font-size: 1rem;
}
.msg-pouce { flex: none; border: 0; background: none; padding: 0; cursor: pointer; }
.msg-pouce img { width: 38px; height: 38px; filter: drop-shadow(0 2px 3px rgba(0,0,0,.5)); }
/* Le bouton « Envoyer » ne sert que si quelque chose est écrit : au repos
   c'est le pouce qui part, comme dans l'application. */
.msg-barre:has(input:placeholder-shown) .msg-envoyer { display: none; }
.msg-barre:has(input:not(:placeholder-shown)) .msg-pouce { display: none; }
/* Le texte saisi fait apparaître « Envoyer » : la barre ne doit pas s'élargir
   pour autant (sur un écran étroit, tout le fil débordait à droite). */
.msg-fil-corps, .msg-fil-corps .msg-barre { box-sizing: border-box; width: 100%; max-width: 100%; min-width: 0; }
.msg-barre input { width: 0; }
.msg-barre .msg-envoyer { flex: none; height: 36px; padding: 0 .75em; font-size: .95rem; }

/* ---------------------------------------------------------------------------
   11 quinquies. Le panneau d'un bâtiment, et qui l'a construit
   --------------------------------------------------------------------------- */
.bat-ligne, .bat-paye {
  margin: 0; font-size: .82rem; font-weight: 600; color: var(--ink-soft);
}
.bat-ligne b { color: var(--ink); }
.bat-paye { font-size: .76rem; }
.bat-resume { margin: 0; font-size: .88rem; }
.bat-max { margin: 0; font-weight: 800; color: #2E6E4F; }

/* Le filet a losange entre deux blocs, comme sur le dessin. */
.bat-trait {
  position: relative; height: 1px; margin: 11px 2px; border: 0;
  background: linear-gradient(90deg, transparent, rgba(107,74,30,.5) 10%,
    rgba(107,74,30,.5) 90%, transparent);
  overflow: visible;
}
.bat-trait::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 9px; height: 9px; border-radius: 1px;
  transform: translate(-50%, -50%) rotate(45deg);
  background: #6B4A1E;
}

.bat-bloc { display: grid; gap: 6px; }
.bat-bloc-tete {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-size: .92rem; font-weight: 800; color: var(--ink);
}
.bat-bloc-tete > span { display: inline-flex; align-items: center; gap: 7px; }
.bat-bloc-tete img.vo2 { height: 1.5em; width: auto; }
.bat-stock { font-size: 1.05rem; font-weight: 900; font-variant-numeric: tabular-nums; }
/* La pastille de prix est en parchemin, pas en bleu plein : c'est `VO2Pill`. */
.bat-prix {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 12px; border-radius: 999px;
  background: var(--parchment-deep); border: 2px solid rgba(28,23,18,.3);
  color: var(--ink); font-weight: 900; font-size: .95rem;
  font-variant-numeric: tabular-nums;
}
.bat-prix img.vo2 { height: 1.4em; width: auto; }
.bat-prix i { font-style: normal; font-size: .72em; color: var(--ink-soft); }
.bat-mesure { display: flex; align-items: center; gap: 9px; }
.bat-mesure .bat-barre { flex: 1 1 auto; }
.bat-pourcent {
  flex: none; font-size: .82rem; font-weight: 900; color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}
.bat-barre {
  position: relative; height: 16px; border-radius: 8px;
  border: 2px solid rgba(28,23,18,.35); background: rgba(28,23,18,.12); overflow: hidden;
}
.bat-barre i { display: block; height: 100%; background: linear-gradient(180deg, #9BD9F7, #1878C4); }
.bat-barre.est-plein i { background: linear-gradient(180deg, #F4573F, #8E1B10); }
.bat-barre span {
  position: absolute; right: 7px; top: 50%; transform: translateY(-50%);
  font-size: .68rem; font-weight: 900; color: var(--ink-soft);
}
.bat-manque { margin: 0; font-size: .78rem; font-weight: 700; color: #8E1B10; }
.bat-ligne-action {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.bat-ligne-action > p { flex: 1 1 auto; min-width: 0; }
.bat-verrou {
  background: linear-gradient(180deg, #3A3129, #221C16);
  border-color: #120C08; color: rgba(255,255,255,.8); opacity: 1; cursor: not-allowed;
}
.bat-verrou:active { transform: none; }
/* Un lien d'action : pastille claire a liseré d'encre, texte bleu. */
.bat-lien {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  margin: 8px 0 0; padding: 7px 13px; width: 100%;
  border: 2px solid rgba(28,23,18,.28); border-radius: 10px; cursor: pointer;
  background: rgba(255,255,255,.5);
  color: #1565A8; font: inherit; font-weight: 800; font-size: .85rem;
  box-shadow: 0 2px 0 rgba(0,0,0,.12);
}
.bat-lien:active { transform: translateY(1px); box-shadow: none; }
.bat-lien img { height: 22px; width: auto; }
.bat-ligne-action .bat-lien { margin: 0; width: auto; flex: none; }

.batisseurs { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.batisseurs li {
  display: grid; grid-template-columns: 1.7em minmax(0, 1fr) auto; gap: 9px; align-items: center;
}
.batisseur-rang { font-size: 1.1rem; text-align: center; }
.batisseur-nom {
  position: relative; min-width: 0;
  padding: 4px 9px; border-radius: 7px;
  background: rgba(255,255,255,.45); border: 2px solid rgba(28,23,18,.22);
  font-weight: 800; font-size: .88rem; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* La barre est DANS la pastille, derrière le nom : une ligne de moins, et on
   compare les parts d'un coup d'œil. */
.batisseur-nom i {
  position: absolute; left: 0; top: 0; bottom: 0; z-index: -1;
  background: rgba(59,167,232,.3);
}
.batisseur-nom { isolation: isolate; }
.batisseur-vo2 {
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
  font-weight: 900; font-size: .85rem; color: #1878C4;
}

/* Chaque niveau est son PROPRE parchemin : deux classes pour passer devant
   `.jeu-app .panneau` et sa marge. */
.jeu-app .panneau.bat-niveau { margin: 0; }
.bat-niveau-tete b { font-size: 1.25rem; }
.bat-niveau-tete {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-family: var(--display); font-weight: 800; font-style: italic; font-size: 1.05rem;
  color: var(--ink);
}
.bat-parts { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 2px; }
.bat-parts li {
  display: flex; justify-content: space-between; gap: 10px;
  font-size: .8rem; font-weight: 700; color: var(--ink-soft);
  border-bottom: 1px dashed rgba(28,23,18,.18); padding-bottom: 2px;
}
.bat-parts b { color: var(--ink); }

/* ---------------------------------------------------------------------------
   11 sexies. L'assaut du dimanche, déplié
   Il emprunte tout a la fiche d'une ville ennemie — `.etr-bloc`, les planches
   a icone, les jauges peintes, le journal des jours. Ne restent ici que les
   paliers et les deux lignes du pillage.
   --------------------------------------------------------------------------- */
.paliers { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 5px; }
.palier {
  display: grid; grid-template-columns: 10px minmax(0, 1fr) auto; gap: 7px; align-items: baseline;
  font-size: .78rem; font-weight: 700; color: var(--ink-soft);
}
.palier i { width: 9px; height: 9px; border-radius: 50%; }
.palier.ton-vert i { background: #217329; }
.palier.ton-ambre i { background: #8C611A; }
.palier.ton-rouge i { background: #991A1A; }
.palier b {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .74rem; white-space: nowrap; color: var(--ink);
}

.dim-vole, .dim-butin { margin: 4px 0; font-size: .82rem; line-height: 1.35; }
.dim-vole { font-weight: 700; color: #991A1A; }
.dim-butin { font-weight: 600; color: var(--ink); }

/* ---------------------------------------------------------------------------
   11 septies. La Forge et le Silo
   --------------------------------------------------------------------------- */
.jeu-app .panneau.forge-entete { display: flex; gap: 12px; align-items: center; margin: 0; }
.forge-marteaux { flex: none; width: 46px; height: 46px; filter: drop-shadow(0 1px 1px rgba(0,0,0,.35)); }
.forge-entete b { display: block; font-size: 1.05rem; font-weight: 900; }
.forge-entete small { display: block; font-size: .74rem; font-weight: 600; color: var(--ink-soft); }
.forge-compteurs { display: flex; flex-wrap: wrap; gap: 10px; margin: 2px 0 3px; }
.forge-compteurs i {
  display: inline-flex; align-items: center; gap: 4px;
  font-style: normal; font-size: .76rem; font-weight: 800; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
/* Les deux icones de l'app : la relique (cadre d'or, etincelle) et l'objet. */
.icone-relique {
  width: 15px; height: 15px; display: inline-grid; place-items: center;
  border-radius: 3px; background: #14110D; border: 1.5px solid #F2C94C;
  color: #F2C94C; font-size: 8px; line-height: 1;
}
.icone-objet { width: 17px; height: 17px; object-fit: contain; }
.forge-titre {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin: 6px 0 0;
}
.forge-titre .planche-titre { --h: 30px; max-width: calc(100% - 70px); }
/* « 1 / 5 » : la pastille sombre au bout de la planche (PastilleCompte). */
.forge-compte {
  flex: none; font-style: normal; min-width: 1.9em; padding: 4px 11px;
  border-radius: 999px; background: rgba(0,0,0,.75);
  border: 1.5px solid rgba(201,163,90,.7); color: #fff;
  font-weight: 900; font-size: .8rem; text-align: center;
  font-variant-numeric: tabular-nums;
}


.silo-tete {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-size: .85rem; font-weight: 700; color: var(--ink-soft);
}
.silo-niveau { font-size: .8rem; }
.silo-chiffre {
  margin: 0; font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 2.6rem; line-height: 1; color: var(--ink); font-variant-numeric: tabular-nums;
}
.silo-chiffre small {
  font-family: var(--body); font-style: normal; font-weight: 700;
  font-size: .85rem; color: var(--ink-soft); margin-left: 6px;
}
.silo-jauge {
  position: relative; height: 18px; border-radius: 9px;
  border: 2px solid var(--ink); background: rgba(28,23,18,.18); overflow: hidden;
}
.silo-jauge i { display: block; height: 100%; background: linear-gradient(180deg, #9BD9F7, #1878C4); }
.silo-jauge.est-plein i { background: linear-gradient(180deg, #F4573F, #8E1B10); }

/* --- La carte epinglee du Classement : « Toi » et « Ma ville » ------------
   Elle donne le rang reel sur l'ensemble, meme quand on est deja dans le
   tableau. Deux classes : `.jeu-app .panneau` impose `display: block`. */
.jeu-app .panneau.cl-epingle { display: grid; gap: 8px; margin-top: 12px; }
.cl-epingle > h4 {
  margin: 0; font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: .95rem; text-transform: uppercase; color: var(--rust-dark);
}
.cl-epingle-corps { display: flex; align-items: center; gap: 8px; }
.cl-epingle-corps .jeu-nom { flex: 1 1 auto; min-width: 0; }
.cl-epingle-corps .jeu-nom b {
  display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cl-epingle-corps .cl-tresors { flex-wrap: wrap; font-size: .72rem; }
.cl-epingle-corps .btn { flex: none; padding: .35em .7em; font-size: .8rem; }
.cl-laurier {
  flex: none; display: grid; justify-items: center; line-height: 1.05;
  padding: 2px 8px; border-radius: 8px;
  border: 2px solid rgba(28,23,18,.35); background: var(--parchment-deep);
}
.cl-laurier b { font-size: 1.05rem; font-family: var(--display); font-style: italic; }
.cl-laurier small { font-size: .62rem; font-weight: 700; color: var(--ink-soft); }
.cl-ville:focus-visible { outline: 3px solid #FFD27A; outline-offset: 2px; }

/* ---------------------------------------------------------------------------
   11 octies. La fiche d'une ville sur la carte, et sa page
   --------------------------------------------------------------------------- */
.carte-fiche {
  position: absolute; z-index: 35; left: 0; right: 0; bottom: 0;
  padding: 0 12px calc(78px + env(safe-area-inset-bottom));
  pointer-events: none;
}
/* Deux classes : `.jeu-app .panneau` impose `display: block`. Et, meme piege
   que la fenetre, le defilement est sur le corps, jamais sur le parchemin. */
.jeu-app .panneau.carte-fiche-cadre {
  position: relative; pointer-events: auto;
  display: grid;
}
.carte-fiche-corps {
  max-height: 62vh; overflow-y: auto;
  display: grid; gap: 7px;
  scrollbar-width: none;
}
.carte-fiche-corps::-webkit-scrollbar { width: 0; }
.carte-fiche-fermer {
  position: absolute; top: 2px; right: 4px;
  width: 26px; height: 26px; border: 0; border-radius: 50%;
  background: rgba(28,23,18,.15); color: var(--ink);
  font-size: .8rem; font-weight: 900; cursor: pointer;
}
.fiche-tete { display: flex; align-items: center; gap: 10px; padding-right: 26px; }
.fiche-tete b { display: block; font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 1.15rem; text-transform: uppercase; }
.fiche-tete small { display: block; font-size: .76rem; font-weight: 700; color: var(--ink-soft); }
.crest.ecusson-fiche { width: 54px; height: 42px; flex: none; }
.crest.ecusson-petit { width: 34px; height: 27px; flex: none; }
.crest.ecusson-moyen { width: 48px; height: 38px; flex: none; }

.fiche-assaut { display: grid; gap: 5px; }
.fiche-assaut-tete { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.fiche-assaut-tete b { font-size: .9rem; }
.fiche-menace {
  font-style: normal; padding: 2px 9px; border-radius: 999px;
  border: 2px solid var(--ink); color: #fff; font-size: .72rem; font-weight: 900;
}
.fiche-menace.ton-vert { background: #3F9A63; }
.fiche-menace.ton-ambre { background: #E08A22; }
.fiche-menace.ton-rouge { background: #D93B26; }
.fiche-menace.ton-bleu { background: #1878C4; }
/* La medaille de podium de la semaine, collee au nom. */
.fiche-medaille { height: 1em; width: auto; vertical-align: -.12em; margin-left: 6px; }
/* Les petites icones dessinees de l'app (coureur, horloge). */
.fiche-icone { height: 1.15em; width: auto; vertical-align: -.2em; flex: none; }
.fiche-verdict { margin: 2px 0 0; font-size: .84rem; font-weight: 800; }
.fiche-verdict.ton-vert { color: #2E6E4F; }
.fiche-verdict.ton-ambre { color: #9A5B10; }
.fiche-verdict.ton-rouge { color: #9E2415; }
.fiche-quand { display: flex; align-items: center; gap: 6px; font-weight: 800; }
/* --- Une ville detruite, sur la carte ------------------------------------
   Le chateau en flammes coiffe la fiche, la vignette de la ruine se met a
   GAUCHE du nom, et les trois chiffres tiennent sur une rangee : la fiche
   reste courte. En colonne elle prenait tout l'ecran. */
.ruine-chateau {
  /* Bornee en HAUTEUR (92 px, comme dans l'app) : a largeur libre le dessin
     montait a 300 px et poussait la fiche sous les onglets. */
  display: block; width: calc(100% - 48px); height: 92px;
  object-fit: contain; margin: 0 auto -10px;
  position: relative; z-index: 1; pointer-events: none;
  filter: drop-shadow(0 3px 5px rgba(0,0,0,.5));
}
.ruine.ruine-fiche { width: 84px; flex: none; margin: 0; }
.fiche-tete-ruine { align-items: flex-start; }
.fiche-bandeau-img { display: block; height: 28px; width: auto; margin-top: 3px; }
.fiche-alerte {
  margin: 0; display: flex; align-items: center; gap: 6px;
  font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: .98rem; color: var(--rust-dark);
}
/* Trois chiffres sur une rangee, separes d'un filet : c'est la rangee de
   `CityMapCard`, pas des cases. */
.fiche-stats {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  margin: 2px 0; text-align: center;
}
.fiche-stats > div {
  display: grid; justify-items: center; gap: 1px; padding: 0 4px;
  border-left: 1px solid rgba(28,23,18,.22);
}
.fiche-stats > div:first-child { border-left: 0; }
.fiche-stats img { height: 24px; width: auto; }
.fiche-stats dd {
  margin: 0; font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 1.15rem; color: var(--ink); line-height: 1.1;
}
.fiche-stats dt {
  font-size: .64rem; font-weight: 700; color: var(--ink-soft);
  text-transform: none; letter-spacing: 0;
}
.fiche-regle {
  height: 1.5px; border: 0; margin: 4px 0;
  background: rgba(28,23,18,.28);
}
.fiche-pied { display: flex; align-items: center; gap: 10px; }
.fiche-pied .jeu-mot { flex: 1 1 auto; margin: 0; font-size: .76rem; }
.fiche-pied .btn {
  flex: none; width: 150px; padding: .45em .5em;
  font-size: .9rem; white-space: nowrap;
}
.fiche-bandeau {
  margin: 0; justify-self: center; padding: 3px 14px;
  font-family: var(--display); font-weight: 800; font-style: italic;
  text-transform: uppercase; color: #fff; background: #8E1B10;
  border: 2px solid var(--ink); border-radius: 999px; width: fit-content;
}
.fiche-barre {
  position: relative; height: 14px; border-radius: 7px;
  border: 2px solid rgba(28,23,18,.35); background: rgba(28,23,18,.12); overflow: hidden;
}
.fiche-barre i { display: block; height: 100%; }
.fiche-barre i.ton-vert { background: #3F9A63; }
.fiche-barre i.ton-ambre { background: #E08A22; }
.fiche-barre i.ton-rouge { background: #D93B26; }
.fiche-barre span {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  font-size: .66rem; font-weight: 900; color: var(--ink-soft);
}
.fiche-chiffres {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 5px; margin: 0;
}
.fiche-chiffres div {
  padding: 5px 3px; border-radius: 7px; text-align: center;
  background: rgba(255,255,255,.42); border: 2px solid rgba(28,23,18,.2);
}
.fiche-chiffres dt { font-size: .62rem; font-weight: 800; color: var(--ink-soft);
  text-transform: uppercase; letter-spacing: .02em; }
.fiche-chiffres dd { margin: 0; font-weight: 900; font-size: 1rem; font-variant-numeric: tabular-nums; }

/* --- L'ecran d'une ville etrangere (ForeignCityView) ----------------------
   Ce n'est pas une fenetre : dans l'app c'est un `fullScreenCover`, un ecran
   entier pose par-dessus le plateau, onglets compris, dont on ne sort que par
   la planche « retour » en haut a gauche. Meme montage que Ma ville : le
   dessin de la ville est un calque de fond (`.etr-decor`), l'en-tete flotte
   dessus, et les cartes defilent par-dessus le dessin.
   z-index 30 : au-dessus des onglets (10), en dessous des fenetres (40) —
   la Forge et les passages s'ouvrent donc par-dessus cet ecran. */
.etr-ecran {
  position: absolute; inset: 0; z-index: 30;
  display: flex; flex-direction: column;
  background: #0E1720;
  opacity: 0; transition: opacity .18s ease;
}
.etr-ecran.est-ouverte { opacity: 1; }

/* Le dessin de la ville, cale en haut comme sur Ma ville (meme raison : le
   cadre a le format d'un ecran de telephone, une vitre de navigateur est plus
   courte). Desature : on regarde chez quelqu'un d'autre. Rien n'y est
   touchable — pas de `+` vert, pas de chantier. */
.etr-decor {
  position: absolute; inset: 0; z-index: 0; overflow: hidden;
  filter: saturate(.85);
  pointer-events: none;
}
.etr-decor .ville-vue {
  position: absolute; inset: 0;
  aspect-ratio: auto; width: auto;
  border: 0; border-radius: 0; background: none;
}
.etr-decor .ville-cadre { top: 0; left: 50%; width: 100%; transform: translateX(-50%); }
.etr-decor.est-illustre {
  background: url("/assets/img/jeu/ville-jour.webp") top center / cover no-repeat;
}
.etr-porte { cursor: default; }
/* Le voile de l'app : sombre en haut (sous l'en-tete) et en bas (sous les
   cartes), transparent au milieu, pour que le camp reste lisible. */
.etr-voile {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg,
    rgba(0,0,0,.52), rgba(0,0,0,0) 26%, rgba(0,0,0,0) 58%, rgba(0,0,0,.58));
}

.etr-entete {
  flex: none; position: relative; z-index: 3;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: calc(8px + env(safe-area-inset-top)) 12px 2px;
}
/* Le retour a gauche, le blason au milieu, et a droite un vide de la meme
   largeur : sans lui le blason n'est pas centre. */
.etr-barre { display: flex; align-items: center; width: 100%; }
.etr-barre .etr-blason { flex: 1 1 auto; display: grid; place-items: center; }
.etr-vide { width: 46px; height: 46px; flex: none; }
.bouton-rond.etr-retour {
  width: 46px; height: 46px;
  background-image: url("/assets/img/jeu/bouton-retour.webp");
}
.planche.etr-nom {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  max-width: 100%; padding: .1em .9em .15em;
  font-size: 1.15rem; text-transform: uppercase;
}
.planche.etr-nom .fiche-medaille { height: 20px; width: auto; }
.etr-sous { display: grid; justify-items: center; gap: 8px; width: 100%; }
/* Ses FarRunners a gauche, sa Forge a droite — jamais son VO2 ni sa Defense
   (regle de confidentialite du cahier des charges). */
.etr-capsules { display: flex; align-items: center; width: 100%; gap: 8px; }
.etr-puce { display: inline-flex; align-items: center; gap: 5px; }
.etr-puce-droite { margin-left: auto; }
.etr-ico { height: 1.15em; width: auto; flex: none; }

/* Les cartes defilent par-dessus le dessin ; les 36 % du haut restent vides
   pour laisser voir le camp, comme dans l'app. */
.etr-defile {
  flex: 1 1 auto; min-height: 0; position: relative; z-index: 2;
  overflow-y: auto; overflow-x: hidden;
  -webkit-overflow-scrolling: touch; overscroll-behavior-y: contain;
  padding: 0 12px calc(14px + env(safe-area-inset-bottom));
  scrollbar-width: none;
}
.etr-defile::-webkit-scrollbar { width: 0; height: 0; }
.etr-espace { height: 36%; flex: none; }
.etr-cartes { display: grid; gap: 10px; }
.etr-cartes > :empty { display: none; }
.etr-pile { display: grid; gap: 10px; }
/* Deux classes : `.jeu-app .panneau` gagnerait a egalite. Pas d'`overflow`
   ici — la texture du parchemin vit sur un `::before` qui sort du cadre. */
.jeu-app .panneau.etr-bloc { margin: 0; padding: 8px 10px 12px; }
.etr-bloc .jeu-mot { margin: 4px 0; }
.etr-note { margin: 3px 0; font-size: .74rem; font-weight: 600; color: var(--ink-soft); }

/* La planche de titre et, a sa droite, l'horloge du compte a rebours. */
.etr-ligne-titre {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; margin-bottom: 6px;
}
.etr-ligne-titre .etr-titre { margin: 0; }
.etr-ligne-titre .etr-horloge { margin: 0 0 0 auto; flex: none; }

/* La planche dessinee ne sait pas maigrir : elle tronque. L'application, elle,
   reduit le titre (`minimumScaleFactor(0.7)`), et « Assaut du dimanche » tient.
   Mesure a 300 px de carte : le texte veut 167 px, la planche ne lui en offre
   que 98 — ses trois morceaux dessines en mangent 71 a eux seuls. Reduire la
   police ne rattrape pas 69 px. Deux parades, dans cet ordre.

   1. L'horloge passe SOUS la planche plutot que de lui prendre sa moitie.
      C'est la rangee qui se replie, la planche recupere toute la largeur.

   2. Et sous 300 px de rangee, planche et horloge maigrissent ensemble — il
      reste 19 px a trouver sur « Deroule de la semaine », qui n'a pas
      d'horloge a renvoyer a la ligne. Cette regle-la est plus bas, APRES la
      definition de `.etr-titre` : a specificite egale c'est l'ordre qui
      tranche, et posee ici elle perdait. */
.etr-ligne-titre { container-type: inline-size; flex-wrap: wrap; }

/* --- Les jauges dessinees -------------------------------------------------
   La piste grise (36 / 200 / 36 d'un dessin haut de 59) et, par-dessus, le
   remplissage peint (bouts de 38 sur 64 de haut ; 34 sur 55 pour le feu).
   Les bouts gardent leur taille, seul le milieu s'etire. */
.jauge-d {
  position: relative; display: block; flex: 1 1 auto; min-width: 40px;
  height: var(--jh, 16px);
  --g: calc(var(--jh, 16px) * 36 / 59);
  background:
    url("/assets/img/jeu/piste-grise-g.webp") left center / var(--g) 100% no-repeat,
    url("/assets/img/jeu/piste-grise-d.webp") right center / var(--g) 100% no-repeat,
    url("/assets/img/jeu/piste-grise-m.webp") left calc(var(--g) - 1px) center /
      calc(100% - 2 * var(--g) + 2px) 100% no-repeat;
}
.jauge-d i {
  position: absolute; top: 0; bottom: 0; left: 0; display: block;
  --g: calc(var(--jh, 16px) * 38 / 64);
  min-width: calc(2 * var(--g));
  max-width: 100%;
  background:
    var(--img-g) left center / var(--g) 100% no-repeat,
    var(--img-d) right center / var(--g) 100% no-repeat,
    var(--img-m) left calc(var(--g) - 1px) center /
      calc(100% - 2 * var(--g) + 2px) 100% no-repeat;
  transition: width .5s ease-out;
}
.jauge-d i.jauge-d-rouge {
  --img-g: url("/assets/img/jeu/barre-rouge-g.webp");
  --img-m: url("/assets/img/jeu/barre-rouge-m.webp");
  --img-d: url("/assets/img/jeu/barre-rouge-d.webp");
}
.jauge-d i.jauge-d-verte {
  --img-g: url("/assets/img/jeu/barre-verte-g.webp");
  --img-m: url("/assets/img/jeu/barre-verte-m.webp");
  --img-d: url("/assets/img/jeu/barre-verte-d.webp");
}
.jauge-d i.jauge-d-feu {
  --g: calc(var(--jh, 16px) * 34 / 55);
  --img-g: url("/assets/img/jeu/barre-feu-g.webp");
  --img-m: url("/assets/img/jeu/barre-feu-m.webp");
  --img-d: url("/assets/img/jeu/barre-feu-d.webp");
}

/* --- L'attaque de 21 h : la frise peinte et sa jauge de feu --------------- */
.etr-frise { position: relative; margin: 2px 0 4px; }
.etr-frise-fond { display: block; width: 100%; height: auto; border-radius: 6px; }
.etr-frise-jauge {
  position: absolute; left: 14%; width: 72%; bottom: 6%;
  height: 24px; display: grid; align-items: center;
}
.etr-curseur {
  position: absolute; top: 50%; width: 24px; height: 24px;
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.45));
  transition: left .5s ease-out;
}

/* Le verdict : la coche peinte quand la ville tient, le crane sinon. */
.etr-verdict {
  display: flex; align-items: center; gap: 8px; margin: 4px 0 6px;
  font-weight: 900; font-size: .9rem;
}
.etr-verdict img { height: 1.55em; width: auto; flex: none; }
.etr-verdict.ton-vert { color: #216F33; }
.etr-verdict.ton-ambre { color: #9E6B14; }
.etr-verdict.ton-rouge { color: #9E1A1A; }
.etr-verdict.ton-gris { color: var(--ink-soft); }

/* --- L'assaut du dimanche : zombies contre FarRunners, a la meme echelle -- */
.etr-barres { display: grid; gap: 10px; margin: 6px 0; }
.etr-barre-l { display: flex; align-items: center; gap: 8px; }
.etr-barre-l .etr-ico { height: 22px; width: 24px; object-fit: contain; }
.etr-barre-nom { flex: none; width: 66px; font-size: .74rem; font-weight: 700; color: var(--ink); }
.etr-barre-km {
  flex: none; width: 66px; text-align: right;
  font-size: .84rem; font-weight: 900; font-variant-numeric: tabular-nums;
}
.etr-scene { display: block; width: min(100%, 300px); height: auto; margin: 6px auto 0; }

/* --- Le deroule de la semaine : le panneau peint et le tableau des jours -- */
.etr-deroule { display: flex; align-items: flex-start; gap: 6px; }
.etr-panneau-peint { flex: none; width: 92px; height: auto; margin-top: 6px; }
.etr-journal {
  flex: 1 1 auto; min-width: 0;
  background: rgba(255,255,255,.18); border-radius: 8px; overflow: hidden;
}
.etr-journal-tete, .etr-journal-l {
  display: grid; grid-template-columns: minmax(0, 1fr) 66px 62px;
  align-items: center; gap: 6px; padding: 4px 6px;
}
.etr-journal-tete {
  font-size: .66rem; font-weight: 800; color: var(--ink-soft);
}
.etr-journal-tete span, .etr-journal-l span { white-space: nowrap; }
.etr-journal-tete span + span, .etr-journal-l span + span { justify-self: end; }
.etr-journal-tete img { height: 12px; width: auto; vertical-align: -.1em; }
.etr-journal-l {
  font-size: .76rem; color: var(--ink); font-variant-numeric: tabular-nums;
}
.etr-journal-l:nth-child(even) { background: rgba(255,255,255,.35); }
.etr-journal-l.est-enCours { font-weight: 900; }
.etr-journal-l.est-avenir { color: rgba(44,34,24,.42); }
.etr-journal-l small {
  grid-column: 1 / -1; justify-self: end;
  font-size: .64rem; font-weight: 700; color: #9E1A1A;
}

/* --- Qui la porte cette semaine : les medailles peintes et le drapeau ----- */
.etr-podium { display: flex; align-items: flex-end; gap: 4px; }
.etr-porteurs { flex: 1 1 auto; min-width: 0; display: grid; gap: 6px; }
.etr-porteur { display: flex; align-items: center; gap: 8px; }
.etr-medaille { flex: none; width: 34px; height: 34px; }
.etr-porteur-fiche {
  flex: 1 1 auto; min-width: 0;
  display: flex; align-items: center; gap: 8px;
  padding: 4px 8px; border-radius: 8px; background: rgba(255,255,255,.4);
}
.etr-avatar { flex: none; width: 30px; height: 30px; border-radius: 50%; object-fit: cover; }
.etr-avatar.est-lettres {
  display: grid; place-items: center;
  background: var(--rust); color: #fff; font-size: .7rem; font-weight: 800;
}
.etr-porteur-fiche b {
  flex: 1 1 auto; min-width: 0; font-size: .92rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.etr-porteur-fiche i {
  font-style: normal; font-weight: 700; font-size: .8rem;
  font-variant-numeric: tabular-nums;
}
.etr-drapeau { flex: none; width: 78px; height: auto; }

/* --- Une ville infestee ---------------------------------------------------
   Personne n'y habite : pas de camp, mais LA grande illustration de siege en
   fond de tout le plateau. Le bilan tient en un cadre court, pose en bas —
   pas de vide de 36 % a garder, il n'y a pas de camp a laisser voir. */
.etr-decor.est-infestee {
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  filter: none;
}
.etr-ecran.est-infestee .etr-espace { display: none; }
.etr-ecran.est-infestee .etr-defile { display: flex; flex-direction: column; }
.etr-ecran.est-infestee .etr-cartes { margin-top: auto; }
/* La ruine remplace le blason dans l'en-tete. */
.ruine.etr-ruine { width: 66px; height: auto; flex: none; }
.etr-bandeau { display: block; height: 38px; width: auto; margin: 0 auto 6px; }
.etr-infestee .jeu-mot { text-align: center; }
.etr-infestee .fiche-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Le bouton tient sur UNE ligne : en capitales il passait a deux. */
.jeu-app .btn.etr-inviter {
  text-transform: none; font-size: .98rem; padding: .42em .6em;
  white-space: nowrap; margin-top: 6px;
}

/* Les titres des quatre cartes : trois morceaux dessines cote a cote, le
   milieu seul s'etire — meme recette que l'enseigne. L'icone est DANS le
   morceau de gauche, d'ou sa largeur. */
.etr-bloc h4.etr-titre, .etr-titre {
  --h: 2.4em;
  position: relative; z-index: 1; flex: 0 1 auto; min-width: 0;
  display: flex; align-items: center;
  height: var(--h); margin: 0;
  /* Le texte commence APRES le morceau de gauche, qui porte l'icone. */
  padding-left: calc(var(--g) + 4px); padding-right: calc(var(--d) + 6px);
  color: #fff; text-transform: none;
  text-shadow: 0 2px 3px rgba(0,0,0,.75), 0 0 2px rgba(0,0,0,.6);
  font-family: var(--display); font-weight: 800; font-style: italic;
  font-size: 1.02rem; text-transform: none;
  background:
    var(--img-g) left center / var(--g) 100% no-repeat,
    var(--img-d) right center / var(--d) 100% no-repeat,
    var(--img-m) left calc(var(--g) - 1px) center /
      calc(100% - var(--g) - var(--d) + 2px) 100% no-repeat;
  filter: drop-shadow(0 3px 5px rgba(0,0,0,.4));
}
.etr-titre > span {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.etr-titre-feu {
  --g: calc(var(--h) * 265 / 199); --d: calc(var(--h) * 60 / 199);
  --img-g: url("/assets/img/jeu/titre-feu-g.webp");
  --img-m: url("/assets/img/jeu/titre-feu-m.webp");
  --img-d: url("/assets/img/jeu/titre-feu-d.webp");
}
.etr-titre-lune {
  --g: calc(var(--h) * 230 / 193); --d: calc(var(--h) * 70 / 193);
  --img-g: url("/assets/img/jeu/titre-lune-g.webp");
  --img-m: url("/assets/img/jeu/titre-lune-m.webp");
  --img-d: url("/assets/img/jeu/titre-lune-d.webp");
}
.etr-titre-calendrier {
  --g: calc(var(--h) * 205 / 150); --d: calc(var(--h) * 60 / 150);
  --img-g: url("/assets/img/jeu/titre-calendrier-g.webp");
  --img-m: url("/assets/img/jeu/titre-calendrier-m.webp");
  --img-d: url("/assets/img/jeu/titre-calendrier-d.webp");
}
.etr-titre-trophee {
  --g: calc(var(--h) * 335 / 212); --d: calc(var(--h) * 60 / 212);
  --img-g: url("/assets/img/jeu/titre-trophee-g.webp");
  --img-m: url("/assets/img/jeu/titre-trophee-m.webp");
  --img-d: url("/assets/img/jeu/titre-trophee-d.webp");
}
.etr-horloge {
  display: flex; align-items: center; gap: 6px; margin: 0;
  font-weight: 800; font-size: .86rem; color: var(--ink);
}

/* Voir plus haut, `.etr-ligne-titre` : la parade 2 contre les titres tronques. */
@container (max-width: 300px) {
  .etr-bloc h4.etr-titre, .etr-ligne-titre .etr-titre { --h: 2.1em; font-size: .88rem; }
  .etr-ligne-titre .etr-horloge { font-size: .76rem; gap: 4px; }
  .etr-ligne-titre .etr-horloge img { height: 1.2em; }
}
.etr-horloge img { height: 1.3em; width: auto; }

/* ---------------------------------------------------------------------------
   11 nonies. Le classement des villes
   --------------------------------------------------------------------------- */
.cl-explication {
  margin: 0 2px; font-size: .76rem; font-weight: 600; color: rgba(255,255,255,.85);
  text-shadow: 0 1px 3px rgba(0,0,0,.8);
}
.cl-ecusson { display: grid; place-items: center; }
.cl-tresors { display: flex; flex-wrap: wrap; gap: 8px; }
.cl-tresors i { font-style: normal; font-size: .72rem; font-weight: 700; }
/* Dans la liste, les quatre tresors ne passent PAS a la ligne : une rangee de
   ville doit faire la meme hauteur qu'une rangee de joueur. */
/* Mesure : les quatre tresors veulent 144 px a 7 px d'ecart, la colonne du
   nom en offre 141 — il manquait 3 px et le compteur de FarRunners se faisait
   rogner. A 5 px ils tiennent, et c'est le NOM qui se tronque, comme dans
   l'app (`minimumScaleFactor`). Un chiffre coupe ne veut rien dire ; un nom
   coupe se devine. */
.cl-liste .cl-tresors { flex-wrap: nowrap; gap: 5px; overflow: hidden; }
/* `minimumScaleFactor(0.8)` de `StatsVilleClassement`, traduit en CSS — il n'a
   pas d'equivalent direct. Mesure : a .72rem les quatre tresors depassent de
   19 px a 360 px de large (la largeur Android la plus courante) et le compteur
   de FarRunners se faisait rogner. A .60rem — 83 %, soit le facteur de l'app —
   ils tiennent a 360 comme a 390. Sous 340 px rien ne les fait tenir sur une
   ligne : on les laisse passer a la ligne plutot que de couper un chiffre, un
   nombre tronque ne voulant rien dire. */
@container (max-width: 380px) {
  .cl-liste .cl-tresors i { font-size: .60rem; }
}
@container (max-width: 340px) {
  .cl-liste .cl-tresors { flex-wrap: wrap; }
}
.cl-menace {
  padding: 3px 8px; border-radius: 7px; border: 2px solid var(--ink);
  color: #fff; font-size: .7rem; font-weight: 900; white-space: nowrap;
}
.cl-menace.ton-vert { background: #3F9A63; }
.cl-menace.ton-ambre { background: #E08A22; }
.cl-menace.ton-rouge { background: #D93B26; }
.jeu-segments button[disabled] { opacity: .4; cursor: default; }

/* ---------------------------------------------------------------------------
   12. Les cinq onglets
   --------------------------------------------------------------------------- */
/* Chaque dalle est un dessin complet, icone et nom compris : le CSS ne fait
   que les poser cote a cote sur la pierre du socle. L'espacement negatif fait
   se toucher les contours sombres, comme dans l'app. */
.jeu-tabs {
  flex: none;
  position: relative; z-index: 10;
  display: grid; grid-template-columns: repeat(5, 1fr);
  gap: 0;
  padding: 11px 2px calc(9px + env(safe-area-inset-bottom));
  background: url("/assets/img/jeu/socle-menu.webp") top center / 100% auto repeat-y;
  box-shadow: 0 -4px 12px rgba(0,0,0,.5);
}
.jeu-tab {
  position: relative;
  aspect-ratio: 218 / 150;
  margin: 0 -2px;
  border: 0; padding: 0;
  background: center / 100% 100% no-repeat;
  cursor: pointer;
  font-size: 0;
}
.jeu-tab:active { transform: translateY(1px); }
.jeu-tab:focus-visible { outline: 3px solid #FFD27A; outline-offset: -4px; border-radius: 8px; }
.jeu-tab[data-onglet="courir"]     { background-image: url("/assets/img/jeu/onglet-courir.webp"); }
.jeu-tab[data-onglet="ville"]      { background-image: url("/assets/img/jeu/onglet-ville.webp"); }
.jeu-tab[data-onglet="carte"]      { background-image: url("/assets/img/jeu/onglet-carte.webp"); }
.jeu-tab[data-onglet="classement"] { background-image: url("/assets/img/jeu/onglet-classement.webp"); }
.jeu-tab[data-onglet="messages"]   { background-image: url("/assets/img/jeu/onglet-messages.webp"); }
.jeu-tab[data-onglet="courir"].is-active     { background-image: url("/assets/img/jeu/onglet-courir-actif.webp"); }
.jeu-tab[data-onglet="ville"].is-active      { background-image: url("/assets/img/jeu/onglet-ville-actif.webp"); }
.jeu-tab[data-onglet="carte"].is-active      { background-image: url("/assets/img/jeu/onglet-carte-actif.webp"); }
.jeu-tab[data-onglet="classement"].is-active { background-image: url("/assets/img/jeu/onglet-classement-actif.webp"); }
.jeu-tab[data-onglet="messages"].is-active   { background-image: url("/assets/img/jeu/onglet-messages-actif.webp"); }

.jeu-tab-pastille {
  position: absolute; top: -2px; right: 4px;
  min-width: 18px; height: 18px; padding: 0 4px;
  border: 1.5px solid #120C08; border-radius: 999px;
  background: #D62B1E; color: #fff;
  font-size: 10px; font-weight: 800; line-height: 15px; text-align: center;
  font-style: normal;
}

/* ---------------------------------------------------------------------------
   13. Les fenetres (connexion, inscription, mon espace)
   --------------------------------------------------------------------------- */
/* Posees sur le plateau et non sur la page : dans la fenetre du telephone,
   une modale pleine page casserait l'illusion. */
.jeu-body .modal { max-width: 430px; }

/* ---------------------------------------------------------------------------
   14. Petits ecrans
   --------------------------------------------------------------------------- */
/* En dessous de 400 px (iPhone SE, la plupart des Android), la barre du haut
   reclamait 382 px et sortait du cadre : l'avatar passait par-dessus bord.
   Les mots « km » et « pas » partent — les icones les disent deja — et tout
   se resserre. Mesure : 382 px -> 318 px. */
@media (max-width: 400px) {
  .jeu-app { --barre-haut: calc(59px + env(safe-area-inset-top)); }
  .jeu-top { gap: 6px; padding-left: 8px; padding-right: 8px; }
  .jeu-logo img { height: 26px; }
  .jeu-top-ville { gap: 7px; padding: 3px 8px; }
  .jeu-top-ville em { display: none; }
  .jeu-top-ville b { font-size: .9rem; }
  .jeu-top-ville i { font-size: .85rem; }
  .jeu-avatar.bouton-rond { width: 38px; height: 38px; }
}

@media (max-width: 380px) {
  .jeu-logo img { height: 26px; }
  .jeu-ville-nom { font-size: .9rem; }
  .jeu-ecran { padding-left: 10px; padding-right: 10px; }
  .jeu-app .panneau, .jeu-app .panel.parchment { border-width: 17px; border-image-width: 17px; }
  .jeu-app .panneau::before, .jeu-app .panel.parchment::before { inset: -13px; }
}
@media (prefers-reduced-motion: reduce) {
  .jeu-tab:active, .jeu-app .btn:active, .jeu-segments button:active { transform: none; }
}

/* Les distinctions : médailles à côté du pseudo, et tableau d'honneur des bâtiments. */
.medailles { display: inline-flex; gap: 2px; margin-left: 5px; vertical-align: middle; flex: none; }
.medailles img { width: 1.25em; height: 1.25em; object-fit: contain; filter: drop-shadow(0 1px 1px rgba(0,0,0,.35)); }
.jeu-bulle-qui .medailles img { width: 1.1em; height: 1.1em; }
.bat-honneur { display: inline-flex; align-items: center; gap: 6px; }
.bat-honneur img { width: 26px; height: 26px; object-fit: contain; }
.honneur-niveaux { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 4px; margin: 8px 0 14px; text-align: center; }
.honneur-niveaux span { display: flex; flex-direction: column; align-items: center; gap: 2px; min-width: 0; }
.honneur-niveaux img { height: 46px; width: auto; max-width: 100%; object-fit: contain; }
.honneur-niveaux b { font-size: .64rem; line-height: 1.15; overflow-wrap: anywhere; }
.honneur-niveaux small { font-size: .72rem; opacity: .75; }
.honneur-liste { list-style: none; margin: 0; padding: 0; }
.honneur-liste li { display: flex; align-items: center; gap: 10px; padding: 7px 6px; border-top: 1px solid rgba(58,44,31,.15); }
.honneur-liste li:first-child { border-top: 0; }
.honneur-liste li.is-moi { background: rgba(154,59,31,.10); border-radius: 8px; }
.honneur-portrait { width: 38px; height: 38px; border-radius: 50%; object-fit: cover; flex: none; }
.honneur-portrait.est-lettres { display: grid; place-items: center; background: #9a3b1f; color: #fff; font-weight: 800; }
.honneur-nom { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.honneur-nom small { opacity: .75; }
/* Le corps de la fenêtre est une grille : sans min-width 0, une ligne longue l'élargit. */
.honneur-liste, .honneur-niveaux { min-width: 0; }
.honneur-medaille { width: 36px; height: 36px; object-fit: contain; flex: none; }
.honneur-medaille.est-vide { width: 26px; height: 26px; margin: 0 5px; border: 1.5px dashed rgba(58,44,31,.35); border-radius: 50%; }

/* ---------------------------------------------------------------------------
   Le didacticiel (jeu-didacticiel.js) : au-dessus de tout, fenêtres comprises.
   --------------------------------------------------------------------------- */
.didacticiel { position: absolute; inset: 0; z-index: 100; cursor: pointer; }
.didac-voile { position: absolute; inset: 0; width: 100%; height: 100%; }
.didac-liseres span {
  position: absolute; border: 3px solid #FFC83D; border-radius: 14px; pointer-events: none;
  animation: didac-pulse 1.6s ease-in-out infinite;
}
@keyframes didac-pulse {
  0%, 100% { box-shadow: 0 0 4px rgba(255, 200, 61, .6); }
  50% { box-shadow: 0 0 18px rgba(255, 200, 61, .95); }
}
.didac-guide {
  position: absolute; left: 14px; right: 14px; bottom: 92px;
  display: flex; flex-direction: column; align-items: flex-start;
  transition: top .4s ease, bottom .4s ease;
}
.didac-guide.est-en-haut { bottom: auto; top: 10px; }
.didac-pose {
  width: 118px; height: 118px; margin: 0 0 -6px 14px; object-fit: contain;
  filter: drop-shadow(0 3px 6px rgba(0, 0, 0, .45));
}
.didac-pose.est-nouvelle { animation: didac-entree .3s ease-out; }
@keyframes didac-entree { from { transform: scale(.85); opacity: 0; } to { transform: none; opacity: 1; } }
.didac-bulle {
  position: relative; align-self: stretch;
  background: #E9D5B9; border: 2.5px solid #1C1712; border-radius: 18px;
  padding: 16px; box-shadow: 0 6px 18px rgba(0, 0, 0, .45); cursor: default;
}
/* La pointe, vers le guide. */
.didac-bulle::before, .didac-bulle::after {
  content: ""; position: absolute; left: 58px; border: solid transparent;
}
.didac-bulle::before { top: -17px; border-width: 0 13px 17px; border-bottom-color: #1C1712; }
.didac-bulle::after { top: -13px; left: 61px; border-width: 0 10px 14px; border-bottom-color: #E9D5B9; }
.didac-texte {
  margin: 0 0 12px; color: #1C1712; font: 600 17px/1.35 ui-rounded, "Barlow", system-ui, sans-serif;
}
.didac-reste { color: transparent; }
.didac-pied { display: flex; align-items: center; gap: 10px; }
.didac-passer {
  background: none; border: 0; padding: 0; color: #584A3A; font: 600 12px "Barlow", sans-serif;
  text-decoration: underline; cursor: pointer;
}
.didac-points { display: flex; gap: 4px; margin-left: auto; }
.didac-points i { width: 6px; height: 6px; border-radius: 50%; background: rgba(88, 74, 58, .3); }
.didac-points i.est-ici { background: #E0301E; }
.didac-suivant {
  background: #E0301E; color: #fff; border: 2px solid #8E1B10; border-radius: 999px;
  padding: 7px 14px; font: 800 14px "Barlow", sans-serif; cursor: pointer; opacity: .45;
}
.didac-suivant.est-pret { opacity: 1; }

/* ---------------------------------------------------------------------------
   Les écussons (sql/54) : la bulle de l'appui long, le choix du Profil,
   l'Hôtel de ville.
   --------------------------------------------------------------------------- */
.medailles img[data-insigne] { cursor: help; -webkit-touch-callout: none; user-select: none; }
.insigne-bulle {
  position: absolute; z-index: 90; width: 270px; display: flex; gap: 10px; align-items: flex-start;
  background: #E9D5B9; color: #1C1712; border: 2px solid #1C1712; border-radius: 14px;
  padding: 10px 12px; box-shadow: 0 6px 18px rgba(0,0,0,.45); pointer-events: none;
}
.insigne-bulle img { width: 52px; height: 52px; object-fit: contain; flex: none; }
.insigne-bulle b { display: block; font-size: 15px; }
.insigne-bulle small { display: block; color: #8E1B10; font-size: 11px; font-weight: 700; }
.insigne-bulle p { margin: 3px 0 0; font-size: 13px; color: #584A3A; line-height: 1.3; }
.profil-ecussons-bouton { margin-top: 6px; }
#profil-ecussons .medailles img { width: 1.1em; height: 1.1em; }
.ecusson-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(88px, 1fr)); gap: 10px; margin-bottom: 12px; }
.ecusson-tuile {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 10px 6px; border-radius: 12px; border: 3px solid transparent; background: rgba(233,213,185,.95);
  font: 700 12px "Barlow", sans-serif; color: #1C1712; cursor: pointer;
}
.ecusson-tuile img { width: 52px; height: 52px; object-fit: contain; }
.ecusson-tuile.est-choisi { border-color: #E0301E; }
.ecusson-tuile.est-absent { opacity: .5; cursor: default; }
.ecusson-tuile.est-absent img { filter: grayscale(1); }
.ecusson-tuile i {
  position: absolute; top: -6px; right: -6px; width: 22px; height: 22px; border-radius: 50%;
  background: #E0301E; color: #fff; font: 900 12px/22px "Barlow", sans-serif; font-style: normal;
}
.rares-liste li { display: flex; align-items: center; gap: 10px; }
.rares-liste li img { width: 40px; height: 40px; object-fit: contain; }
.rares-liste li.est-vide img { filter: grayscale(1); opacity: .5; }
.rares-liste li small { display: block; }

.insigne-bulle.est-courte { width: 220px; padding: 8px 10px; }
.insigne-bulle.est-courte img { width: 36px; height: 36px; }
.insigne-bulle.est-courte b { font-size: 14px; }
.jeu-bulle-lien {
  display: inline-block; align-self: flex-start; width: auto; margin: 4px 0 2px; padding: 4px 10px; border: 0; border-radius: 999px;
  background: #E0301E; color: #fff; font: 800 12px "Barlow", sans-serif; cursor: pointer;
}

/* ---------------------------------------------------------------------------
   15. Strava
   ---------------------------------------------------------------------------
   L'orange n'est pas de la palette du jeu : c'est justement ce qui fait qu'on
   reconnait le bouton sans lire son texte. Le dessin « Connect with Strava »
   est pose tel quel — la charte de Strava interdit de le redessiner. */
.strava-connect {
  display: block; width: 100%; max-width: 280px; margin: 10px auto 0;
  padding: 0; border: 0; background: none; cursor: pointer;
  filter: drop-shadow(0 3px 5px rgba(0,0,0,.35));
}
.strava-connect img { display: block; width: 100%; height: auto; }
.strava-connect:active { transform: scale(.97); }
.strava-connect[disabled] { opacity: .5; cursor: default; }

.strava-compte { display: flex; align-items: center; gap: 10px; }
.strava-coche { font-size: 1.4rem; line-height: 1; }
.strava-compte b { display: block; font-size: 1.05rem; color: var(--ink); }
.strava-compte small { display: block; font-size: .78rem; font-weight: 700; color: var(--ink-soft); }
.strava-invite .jeu-mot { text-align: center; }

.strava-tete {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.bouton-rond.strava-recharger { width: 34px; height: 34px; font-size: 1.05rem; }

.strava-courses { list-style: none; margin: 4px 0 0; padding: 0; display: grid; gap: 6px; }
.strava-courses li {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 7px 9px; border-radius: 8px;
  background: rgba(255,255,255,.42); border: 2px solid rgba(28,23,18,.2);
}
.strava-courses li.est-sans-trace { opacity: .68; border-style: dashed; }
.strava-nom {
  flex: 1 1 auto; min-width: 0;
  font-weight: 800; font-size: .92rem; color: var(--ink);
}
.strava-nom small {
  display: block; font-size: .74rem; font-weight: 700; color: var(--ink-soft);
}
.strava-sans { flex: none; font-size: .7rem; font-weight: 700; color: var(--ink-soft); }
.strava-courses .btn { flex: none; padding: .32em .8em; font-size: .78rem; }

.strava-exemple {
  margin: 6px 0 0; padding: 8px 10px; border-radius: 6px;
  background: rgba(28,23,18,.07);
  font: inherit; font-size: .7rem; font-weight: 600; color: var(--ink-soft);
  white-space: pre-wrap; overflow-wrap: anywhere;
}
.strava-dernier {
  margin: 8px 0 0; font-size: .76rem; font-weight: 600; color: var(--ink);
}
.strava-dernier b { display: block; font-size: .68rem; color: var(--ink-soft); }
.strava-dernier.est-rate { color: var(--rust-dark); }
/* L'apercu d'une course reprise : la meme chaine que l'import d'un fichier,
   dans son propre parchemin — pose sur le decor il etait illisible. */
#strava-import:empty { display: none; }
#strava-import .import-fichier {
  margin: 0 0 6px; font-size: .76rem; font-weight: 800; color: var(--ink-soft);
}
#strava-import .kv { margin: 0 0 8px; }

/* Répondre à un message (sql/59) : l'extrait cité dans la bulle, la barre au-dessus du champ. */
.msg-citation { display: block; width: 100%; text-align: left; margin: 2px 0 6px; padding: 5px 8px;
  border: 0; border-left: 3px solid #C2410C; border-radius: 6px; background: rgba(65, 42, 20, .10);
  font: inherit; font-size: .86em; color: inherit; cursor: pointer; }
.msg-citation b { display: block; color: #9A3412; font-size: .95em; }
.msg-citation span { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; opacity: .85; }
.msg-citation.est-absente { font-style: italic; opacity: .7; cursor: default; }
.is-moi .msg-citation { background: rgba(255, 255, 255, .22); border-left-color: #FFD27A; }
.is-moi .msg-citation b { color: inherit; }
.msg-collants .msg-citation { max-width: 240px; }
.msg-reponse-barre[hidden] { display: none; }
.msg-fil-corps .msg-reponse-barre { flex: none; margin: 0; }
.msg-reponse-barre { box-sizing: border-box; width: 100%; max-width: 100%; min-width: 0; overflow: hidden; }
.msg-reponse-barre { display: flex; align-items: center; gap: 8px; margin: 0 0 6px; padding: 6px 8px;
  border-left: 3px solid #C2410C; border-radius: 8px; background: #FBF1DE; color: #412A14; }
.msg-reponse-texte { flex: 1; min-width: 0; font-size: .88em; }
.msg-reponse-texte b { display: block; color: #9A3412; }
.msg-reponse-texte span { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; opacity: .8; }
.msg-reponse-annuler { flex: none; border: 0; background: none; font-size: 1.1em; cursor: pointer; color: #412A14; }
.jeu-bulle.est-cible, .msg-collants.est-cible { animation: msg-cible 1.4s ease; }
@keyframes msg-cible { 0%, 60% { box-shadow: 0 0 0 3px #FFD27A; } 100% { box-shadow: 0 0 0 0 transparent; } }

/* Strava : « Retirer » l'accord au partage, en lien discret. */
.lien-bouton { background: none; border: 0; padding: 0; font: inherit; color: var(--rust-dark, #8E1B10); text-decoration: underline; cursor: pointer; }

/* ---------------------------------------------------------------------------
   L'ecran de course, porte de `Features/Run/CourseView.swift`
   La carte dessous, trois couches par-dessus : la barre du haut, le cadre
   noir des chiffres, les commandes. Rien ne defile : tout tient a l'ecran,
   parce qu'on le regarde en courant.
   --------------------------------------------------------------------------- */
.crs {
  position: fixed; inset: 0; z-index: 60;
  display: grid; grid-template-rows: auto 1fr auto auto;
  background: #0E0E0E; color: #fff;
}
.crs-carte { position: absolute; inset: 0; z-index: 0; background: #1B2A24; }
.crs-haut, .crs-cadre, .crs-commandes { position: relative; z-index: 1; }

.crs-haut { grid-row: 1; display: flex; align-items: center; gap: 10px;
  padding: calc(8px + env(safe-area-inset-top)) 14px 0; }
.crs-rond {
  width: 40px; height: 40px; flex: none; border: 0; border-radius: 999px;
  background: rgba(0,0,0,.75); color: #fff; font-size: 1.1rem; font-weight: 900;
  line-height: 1; cursor: pointer;
}
.crs-vide { background: none; }
.crs-zone {
  flex: 1 1 auto; text-align: center; max-width: 24em; margin: 0 auto;
  padding: 7px 12px; border-radius: 999px;
  font-family: var(--condensed); font-weight: 800; font-size: .92rem;
  background: rgba(0,0,0,.6); transition: background .25s ease;
}
.crs-zone.est-maison { background: rgba(76,154,42,.92); }
.crs-zone.est-dehors { background: rgba(43,122,184,.92); }

.crs-cadre {
  grid-row: 3; margin: 0 14px 10px; padding: 18px 10px;
  border-radius: 22px; background: rgba(0,0,0,.92); text-align: center;
}
.crs-titre { margin: 0 0 12px; font-size: 1.15rem; font-weight: 800; color: rgba(255,255,255,.8); }
.crs-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.crs-stats b {
  display: block; font-size: clamp(1.7rem, 9vw, 2.4rem); font-weight: 900;
  line-height: 1; font-variant-numeric: tabular-nums;
}
.crs-stats span { display: block; margin-top: 6px; font-size: .8rem; font-weight: 700; color: rgba(255,255,255,.75); }
.crs-split { display: flex; justify-content: center; gap: 18px; margin: 14px 0 0;
  font-size: .85rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.crs-maison { color: #99E673; }
.crs-dehors { color: #7CC4F0; }

.crs-commandes {
  grid-row: 4; display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 18px 14px calc(26px + env(safe-area-inset-bottom));
  background: #141414; border-radius: 24px 24px 0 0;
}
.crs-paire { display: flex; gap: 44px; }
.crs-paire > span { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.crs-bouton {
  width: 96px; height: 96px; border: 0; border-radius: 999px; cursor: pointer;
  font-size: 2rem; line-height: 1; color: #fff; background: var(--rust);
  box-shadow: 0 0 18px rgba(224,48,30,.45);
}
.crs-paire .crs-bouton { width: 84px; height: 84px; font-size: 1.7rem; }
.crs-finir { background: #fff; color: #141414; box-shadow: 0 0 18px rgba(255,255,255,.3); }
.crs-bouton[disabled] { opacity: .5; }
.crs-legende { font-size: 1.05rem; font-weight: 800; color: var(--rust-light, #FF8061); }
.crs-legende-claire { color: #fff; }

/* Pendant une sortie, le jeu dessous ne defile pas sous l'ecran plein. */
body.est-en-course { overflow: hidden; }

/* ---------- Les reglages de notifications (jeu-notifications.js) ----------
   Les lignes sont des `.profil-bascule`, comme le reste de Mon espace : seuls
   l'entete d'une famille et le bandeau de l'appareil ont besoin d'un dessin. */
.pn-famille { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.pn-famille-boutons { display: flex; gap: 6px; flex: none; }
.pn-tout { display: flex; gap: 8px; }
.pn-ok { color: var(--defend); font-weight: 700; }

/* Montre : la ligne Suunto est un vrai bouton (jeu-suunto.js). */
.jeu-app .panneau.montre-ligne.est-active { width: 100%; text-align: left; cursor: pointer; font: inherit; color: inherit; }
.montre-ligne.est-active .montre-icone { filter: none; opacity: 1; }
.montre-chevron { margin-left: auto; font-size: 1.6rem; font-weight: 900; color: var(--ink-soft); }
