/*
 * game.css — le HUD, en DOM et CSS, sans framework (`rules/architecture.md` §2).
 *
 * La direction artistique est celle du terrain : du **bois clair**, des encres
 * brunes, rien de néon. Un panneau de HUD est une plaque de bois posée sur le
 * plateau, pas une fenêtre de logiciel — c'est la même règle que la page d'essai
 * du rendu, reprise telle quelle pour que les deux se ressemblent.
 */

:root {
  --bois: linear-gradient(178deg, #efdfc0, #dcc59a);
  --encre: #463625;
  --encre-pale: #7a5a34;
  --titre: #6a3d12;
  --bord: rgba(84, 56, 26, .55);
  --ombre: 0 14px 30px rgba(0, 0, 0, .55), inset 0 1px 0 rgba(255, 255, 255, .6),
           inset 0 -2px 7px rgba(116, 80, 38, .3);
  --serif: ui-serif, Georgia, "Times New Roman", serif;

  /*
   * ⚠️ **Les trois mesures du socle de commandement, et l'égalité qui les tient :**
   *
   *     --socle = --mini + 32       (10 px de marge en haut et en bas + 12 px de cadre)
   *
   * La minimap est carrée et pleine hauteur : c'est elle qui commande la hauteur du socle. Son
   * cadre ajoute 2 × 5 px de marge intérieure et 2 × 1 px de bordure, d'où les 12. **Si tu
   * changes l'une des deux valeurs, refais l'addition** — sinon la plaque de la minimap dépasse
   * du socle et retombe sur le terrain, ou elle flotte au milieu d'un socle trop haut.
   *
   * La même hauteur donne les rangées du pupitre : `(--mini + 2) / 3` par case, soit 43 px au
   * plus serré — de quoi loger un nom sur deux lignes et sa ligne de coût, pas davantage.
   *
   * `--socle` est lu **deux fois** ailleurs : `hud.js#_basEcran` mesure la hauteur rendue du
   * socle pour couper le cadre de vue de la minimap, et le message éphémère s'y adosse.
   */
  --socle: 188px;
  --mini: 156px;
  --haut: 44px;         /* le bandeau des ressources */
}

/* Grand écran : le socle respire, la minimap se lit. */
@media (min-width: 1600px) {
  :root { --socle: 210px; --mini: 178px; }
}
/* Écran étroit : on serre, mais on ne superpose rien — le socle reste un bloc. */
@media (max-width: 1240px) {
  :root { --socle: 172px; --mini: 140px; }
}
/*
 * Écran **court** : c'est la contrainte la plus dure, donc elle est écrite en dernier et elle
 * gagne. Un socle de 210 px sur une fenêtre de 700 mangerait près d'un tiers du terrain. On
 * descend aussi la typographie des cases : à 43 px de rangée, « Hôtel de ville » tient sur deux
 * lignes **et** garde sa ligne de coût.
 */
@media (max-height: 820px) {
  :root { --socle: 160px; --mini: 128px; }
  .cmd b { font-size: 11px; }
  .cmd small { font-size: 9.5px; }
  .aide { font-size: 10.5px; }
}

html, body {
  margin: 0; height: 100%; background: #0b0805; overflow: hidden;
  font-family: var(--serif); color: var(--encre);
  user-select: none; -webkit-user-select: none;
}
/*
 * ⚠️ **Le `crosshair` est le REPLI, pas le curseur.** `curseurs.js` pose un dessin en `data:`
 * URI dans `canvas.style.cursor` selon ce que le prochain clic ferait — et chacune de ses
 * valeurs finit par `, crosshair`. Cette ligne-ci sert donc deux fois : avant la première image,
 * et si jamais une image de curseur refusait de se charger. Ne la remplace pas par `default` :
 * une flèche de bureau sur un plateau de jeu se remarque immédiatement.
 */
canvas { display: block; width: 100vw; height: 100vh; cursor: crosshair; }

/*
 * ⚠️ **Le HUD garde son propre curseur, et chaque plaque le déclare chez elle.**
 *
 * Un geste armé ne doit pas donner l'impression qu'on peut creuser un bouton : le curseur du
 * canevas s'arrête au bord du plateau. La déclaration est répétée dans `.bandeau`, `.socle` et
 * `.menu-jeu` plutôt que groupée en tête de fichier — un sélecteur groupé `.socle, …` posé plus
 * haut devient *la première règle `.socle` du fichier*, et les gardes de `hud.test.js` lisent
 * la première. Une règle de style qui déplace ce que lisent les tests est une règle mal placée.
 */

.hud { position: fixed; inset: 0; pointer-events: none; }
.hud > * { pointer-events: auto; }

/* ---- bandeau du haut : les ressources ---------------------------------- */

.bandeau {
  position: fixed; top: 0; left: 0; right: 0; height: var(--haut);
  display: flex; align-items: center; gap: 22px; padding: 0 18px;
  background: var(--bois); border-bottom: 1px solid var(--bord);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .45);
  font-size: 14.5px; box-sizing: border-box; z-index: 8;
  cursor: default;                      /* le curseur de jeu s'arrête au bord du plateau */
}
/* L'insigne ferme le bandeau à gauche. `gap` du bandeau = 22 px, trop large ici :
   on le rattrape par une marge négative pour qu'il colle aux ressources. */
.bandeau .insigne {
  flex: 0 0 auto; width: 28px; height: 28px; margin-right: -10px; opacity: .92;
}
.res { display: flex; align-items: center; gap: 7px; }
.res b { font-size: 16px; color: var(--titre); min-width: 40px; text-align: right; }
.res span { color: var(--encre-pale); font-variant: small-caps; letter-spacing: .05em; }
.pastille {
  width: 11px; height: 11px; border-radius: 2px; display: inline-block;
  box-shadow: inset 0 -1px 2px rgba(0, 0, 0, .35);
}
.pastille.r0 { background: #7c9c54; }   /* bois */
.pastille.r1 { background: #9aa3ad; }   /* pierre */
.pastille.r2 { background: #d7a13a; }   /* énergie */
.pastille.r3 { background: #c2683f; }   /* nourriture */

.etat {
  margin-left: auto; display: flex; gap: 18px; align-items: center;
  color: var(--encre-pale); font-size: 13px;
}
.etat .faction { font-weight: 700; font-size: 15px; }
/*
 * La file d'ordres du client. Vide 99 % du temps — et une boîte vide ne doit pas décaler ses
 * voisines : `:empty { display: none }` la retire du flux au lieu de laisser un blanc qui
 * bougerait l'heure et la faction d'un cran chaque fois qu'un ordre se met en attente.
 */
.etat .file { color: var(--titre); font-variant: small-caps; letter-spacing: .04em; }
.etat .file:empty { display: none; }

/* ---- LE SOCLE DE COMMANDEMENT -------------------------------------------- */

/*
 * ⚠️ **Le HUD n'est plus une volée d'éléments posés sur le plateau, c'est un socle.**
 *
 * Ce qu'il y avait avant : une barre de commandes centrée en bas, un panneau de sélection en
 * bas à gauche, une minimap en bas à droite, une ligne d'aide en haut à gauche. Trois défauts,
 * tous mesurés, et aucun réglage ne les rattrapait :
 *
 *  · **ça se recouvrait.** Deux corrections successives sur la seule paire aide / barre de
 *    commandes — à 1280×800 « Creuser » se posait sur « 1-5 bâtir », à 1500 pile la barre
 *    passait à deux rangs et repassait sur l'aide. Une condition de largeur ne pouvait pas
 *    marcher : ce n'est pas la largeur qui décide du nombre de rangs, c'est la sélection ;
 *  · **72 des 327 cellules de sol visibles (22 %) tombaient sous un élément qui capte le
 *    clic**, et rien ne le disait : les boutons flottaient sans fond, on croyait viser de
 *    l'herbe entre eux ;
 *  · **les boutons bougeaient de place** selon la sélection, donc aucune mémoire musculaire.
 *
 * Le socle règle les trois d'un coup, et c'est la forme du genre depuis 1997 : **un bloc plein
 * d'un bord à l'autre**, trois zones qui ne se croisent jamais (flex, `min-width: 0` sur la
 * seule colonne élastique), et le terrain jouable est tout ce qui est au-dessus. Le joueur
 * **voit** la limite : bord franc, ombre portée sur le terrain, bois opaque.
 */
.socle {
  position: fixed; left: 0; right: 0; bottom: 0; height: var(--socle);
  box-sizing: border-box; display: flex; align-items: stretch; gap: 12px;
  padding: 10px 14px; z-index: 8;
  background: var(--bois);
  border-top: 2px solid rgba(52, 35, 16, .92);
  box-shadow: 0 -14px 30px rgba(0, 0, 0, .5), inset 0 1px 0 rgba(255, 255, 255, .55);
  cursor: default;                      /* le curseur de jeu s'arrête au bord du plateau */
}
/* Le liseré qui pose le socle SUR le terrain : sans lui, la limite se devine au lieu de se voir. */
.socle::before {
  content: ''; position: absolute; left: 0; right: 0; top: -14px; height: 14px;
  background: linear-gradient(180deg, rgba(10, 7, 4, 0), rgba(10, 7, 4, .42));
  pointer-events: none;
}

/* ---- colonne du centre : la fiche de sélection, puis l'aide --------------- */

.centre {
  flex: 1 1 auto; min-width: 0; overflow: hidden;
  display: flex; flex-direction: column; gap: 6px;
}
.panneau {
  flex: 1 1 auto; min-height: 0; overflow: hidden;
  width: 100%; max-width: 760px; margin: 0 auto;
  padding: 8px 14px 9px; box-sizing: border-box;
  background: rgba(94, 66, 32, .13); border: 1px solid rgba(84, 56, 26, .32);
  border-radius: 3px; box-shadow: inset 0 1px 4px rgba(70, 46, 20, .2);
}
.fiche { display: flex; flex-direction: column; gap: 5px; }
.fiche .tete { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
.fiche strong {
  color: var(--titre); font-size: 15px; letter-spacing: .04em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Une pièce d'en face : la fiche le dit, et de la couleur de son camp. */
.fiche .camp { font-size: 11.5px; font-variant: small-caps; letter-spacing: .06em; }
.fiche.rien strong { color: var(--encre-pale); font-weight: 400; font-style: italic; }
.vie {
  position: relative; height: 13px; background: rgba(70, 46, 20, .28);
  border-radius: 2px; overflow: hidden;
}
.vie i { display: block; height: 100%; background: #6fc25a; }
.vie span {
  position: absolute; inset: 0; text-align: center; font-size: 10.5px; line-height: 13px;
  color: #2f2416; letter-spacing: .05em;
}
/* Le travail en cours : un chantier qui monte, une production qui finit. */
.travail { height: 6px; background: rgba(70, 46, 20, .28); border-radius: 2px; overflow: hidden; }
.travail i { display: block; height: 100%; background: #a8631f; }
.travail.chantier i { background: #8a6a3a; }
.info {
  font-size: 12.5px; color: #5c4a34; font-style: italic;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.groupes { display: flex; flex-wrap: wrap; gap: 5px; overflow: hidden; max-height: 44px; }
.groupe {
  font-size: 12px; padding: 1px 7px; border: 1px solid var(--bord); border-radius: 2px;
  color: #5c4a34; white-space: nowrap;
}

/* ---- LE PUPITRE : 5 colonnes × 3 rangées, à position FIXE ----------------- */

/*
 * ⚠️ **Une case ne bouge jamais.** C'est la seule raison d'être d'une grille : la main apprend
 * l'endroit d'une commande, pas son rang d'apparition. Une commande qui ne s'applique pas à la
 * sélection **laisse sa case vide** (`.cmd.vide`) — elle ne décale pas ses voisines. L'ancienne
 * barre, elle, se reconstruisait : « Attaquer » n'était jamais deux fois au même pixel.
 *
 * Cinq colonnes, parce que la rangée du haut porte les cinq bâtiments des touches 1 à 5.
 * `hud.js` refuse de démarrer si quelqu'un en ajoute un sixième sans venir ici.
 */
/*
 * ⚠️ **La largeur vient d'une addition, pas d'un goût.** La case la plus chargée du jeu est le
 * Monument, et il coûte **quatre** ressources (`1200 · 1200 · 900 · 600`) : ~106 px de contenu à
 * 9,5 px de corps. À `29vw` sur une fenêtre de 1500, une case en offrait 73 et le prix était
 * coupé au milieu d'un chiffre. `33vw` en donne 89 — pas assez pour une ligne, mais assez pour
 * **deux moitiés lisibles** : c'est `.cmd small` qui se replie, voir plus bas.
 *
 * Si quelqu'un ajoute un bâtiment à cinq coûts, il faudra refaire l'addition ici — et le
 * garde-fou de `capture.mjs` le dira avant lui, ce qui n'a pas été le cas la première fois.
 */
.commandes {
  flex: 0 0 auto; width: clamp(400px, 33vw, 600px);
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  grid-template-rows: repeat(3, minmax(0, 1fr)); gap: 5px;
}
.cmd {
  position: relative; overflow: hidden; padding: 5px 4px 2px 6px;
  background: var(--bois); border: 1px solid var(--bord); border-radius: 2px;
  box-shadow: 0 2px 5px rgba(0, 0, 0, .35), inset 0 1px 0 rgba(255, 255, 255, .55);
  font-family: var(--serif); color: var(--encre);
  cursor: pointer; text-align: left; line-height: 1.12;
  display: flex; flex-direction: column; justify-content: center; gap: 1px;
  transition: filter .08s linear, transform .08s linear;
}
/* La case creuse : elle tient la place, et elle a l'air de ce qu'elle est — un logement vide. */
.cmd.vide {
  background: rgba(58, 40, 20, .17); border-color: rgba(84, 56, 26, .26);
  box-shadow: inset 0 2px 6px rgba(48, 32, 14, .3); cursor: default;
}
.cmd:not(.vide):hover { filter: brightness(1.08); transform: translateY(-1px); }
.cmd:not(.vide):active { filter: brightness(.95); transform: translateY(0); }
.cmd:focus-visible { outline: 2px solid #a8631f; outline-offset: -2px; }
/*
 * ⚠️ **Le français accentue ses capitales, et rien ne doit rogner l'accent.**
 *
 * On lisait « Energie » — pas « Énergie » mal placé, pas « Ãnergie » : un E nu. Le DOM, lui,
 * portait bien le point de code 201. C'était **`overflow: hidden` posé sur ce `b`** : sa boîte
 * de contenu *est* la boîte de ligne, et l'accent d'une capitale monte quelques dixièmes de
 * pixel au-dessus de la ligne d'ascendante de la fonte. À 12 px, l'accent fait un pixel de haut ;
 * en perdre le sommet, c'est le perdre tout entier.
 *
 * Le piège, c'est que ça ne frappe **que les capitales** : « Hôtel » et « Arrêt » s'affichaient
 * parfaitement, leurs accents minuscules retombant bien à l'intérieur. On cherchait donc une
 * faute d'encodage sur un seul mot — il n'y en avait pas.
 *
 * Le `overflow` allait avec un `text-overflow: ellipsis` qui **n'a jamais rien fait** : l'ellipse
 * demande `white-space: nowrap`, absent ici, et le nom a le droit de passer sur deux lignes
 * (« Hôtel de ville » le fait). Deux propriétés mortes, dont une nuisible. Les 5 px de marge
 * haute de `.cmd` suffisent à contenir l'accent, et `.cmd` garde son `overflow: hidden`.
 *
 * ⚠️ `padding-right` réserve la pastille de touche (`.cmd kbd`, en absolu en haut à droite) :
 * sans lui, « Hôtel de ville » passait **sous** le « 4 » et les deux se superposaient.
 */
.cmd b {
  display: block; font-size: 12px; color: var(--titre); line-height: 1.32;
}
/*
 * ⚠️ **La réserve n'est due qu'aux cases qui portent une pastille.** Réservée à toutes, elle
 * coûtait 17 px à « Abandonner », qui n'a pas de raccourci — et qui débordait alors de 13 px sur
 * une fenêtre de 1280. Une marge payée par une case qui n'en profite pas est une marge de trop.
 */
.cmd:has(kbd) b { padding-right: 17px; }
/*
 * ⚠️ **La ligne de coût se replie, et ce n'est pas un détail de mise en forme.**
 *
 * Elle était en `nowrap`, au motif qu'une seconde ligne pousserait le nom hors d'une rangée de
 * 43 px. Le raisonnement partait d'un compte faux : le Monument ne coûte pas trois ressources
 * mais **quatre** (`1200 · 1200 · 900 · 600`), soit ~106 px de contenu. Aucune largeur de case
 * raisonnable ne les met sur une ligne, et `nowrap` ne faisait donc pas tenir la ligne — il la
 * **coupait au milieu d'un chiffre**, en silence, ce qui est le pire des deux mondes : le joueur
 * lisait un prix faux.
 *
 * L'addition en hauteur, refaite : rangée la plus serrée 43 px (socle 160, minimap 128) ; nom
 * 11 px × 1,32 = 14,5 ; deux lignes de coût 9,5 × 1,2 × 2 = 22,8. Total 37,3 — ça tient, et
 * `capture.mjs` le vérifie à quatre tailles de fenêtre.
 */
.cmd small {
  display: flex; align-items: center; gap: 3px; flex-wrap: wrap; row-gap: 0;
  line-height: 1.2;
  font-size: 9.5px; color: #7a5a34; letter-spacing: .01em; overflow: hidden;
}
.cmd small .pastille { width: 7px; height: 7px; margin-left: 2px; }
.cmd small .pastille:first-child { margin-left: 0; }
/* Le compteur d'une file de production : « Ouvrier ×3 ». */
.cmd .file { font-style: normal; color: #a8631f; font-weight: 700; }
.cmd kbd {
  position: absolute; top: 2px; right: 3px; font: 10px ui-monospace, monospace;
  color: #8a6a3a; border: 1px solid rgba(120, 90, 50, .5); border-radius: 2px;
  padding: 0 3px; background: rgba(255, 250, 238, .5);
}
/* Trop cher : la case reste là et reste cliquable — c'est la simulation qui refuse, pas nous. */
.cmd.cher { opacity: .55; }
.cmd.cher small { color: #8d3a1f; }
/* Armée : le geste est en cours, le prochain clic sur le terrain le pose. */
.cmd.arme {
  outline: 2px solid #6a3d12; outline-offset: -2px; filter: brightness(1.12);
  box-shadow: 0 0 0 1px rgba(255, 236, 190, .5), 0 2px 9px rgba(168, 99, 31, .55);
}
.cmd.abandon:not(.vide) b { color: #8d3a1f; }

/* ---- journal, message ---------------------------------------------------- */

/*
 * ⚠️ **`align-items: flex-end` — sans lui, chaque entrée était une barre vide de 260 px.**
 *
 * La colonne fait 260 px de large, et un enfant de `flex-direction: column` s'étire par défaut
 * sur toute la largeur du conteneur. « Ouvrier prêt. » — treize caractères — se dessinait donc
 * dans une plaque sombre de 260 px avec le texte tassé contre le bord droit, en haut de l'écran.
 * On ne lisait pas une nouvelle du jeu, on lisait une console de mise au point.
 *
 * `text-align: right` reste : il aligne le texte d'une entrée qui, elle, passerait sur deux
 * lignes. C'est l'un **et** l'autre, pas l'un ou l'autre.
 */
.journal {
  position: fixed; right: 18px; top: calc(var(--haut) + 12px); width: 260px;
  display: flex; flex-direction: column; align-items: flex-end; gap: 3px; text-align: right;
  pointer-events: none; z-index: 7;
}
.journal div {
  max-width: 100%; box-sizing: border-box;
  background: rgba(20, 14, 8, .58); border: 1px solid rgba(120, 90, 50, .45);
  color: #e6d5b4; font-size: 12.5px; padding: 3px 8px; border-radius: 2px;
}
/* Une alerte n'a pas la même voix qu'une nouvelle : on attaque ta base, ça se voit de loin. */
.journal .alerte {
  background: rgba(72, 18, 10, .78); border-color: rgba(214, 96, 62, .8); color: #ffcdb8;
  font-weight: 700;
}
.journal .perte { color: #cbb08c; }
/*
 * Le message éphémère s'adosse au socle. Il flottait à 100 px du bas, c'est-à-dire **dans** la
 * barre de commandes dès qu'elle passait à deux rangs.
 */
.message {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--socle) + 16px); z-index: 7;
  background: rgba(20, 14, 8, .78); border: 1px solid rgba(160, 110, 50, .6);
  color: #f0d9ac; font-size: 13.5px; padding: 6px 14px; border-radius: 2px;
  pointer-events: none;
}

/* ---- rectangle de sélection, barres de vie ------------------------------- */

/*
 * ⚠️ Ces deux calques sont **sous** le bandeau et le socle (z-index 8), et c'est voulu : une
 * barre de vie d'unité qui passe derrière le socle s'y arrête net, comme au bord de l'écran.
 * Les remonter ferait flotter des jauges par-dessus les commandes.
 */
.rect {
  position: fixed; left: 0; top: 0; border: 1px solid #f2e2bd;
  background: rgba(242, 226, 189, .13); pointer-events: none; z-index: 4;
}
.barres { position: fixed; inset: 0; pointer-events: none; z-index: 3; }
.pv {
  position: absolute; left: 0; top: 0; width: 30px; height: 4px;
  background: rgba(12, 8, 4, .72); border: 1px solid rgba(0, 0, 0, .5); border-radius: 1px;
}
.pv i { display: block; height: 100%; background: #6fc25a; }

/* ---- minimap, à gauche du socle -------------------------------------------- */

/*
 * **Pourquoi à gauche.** C'est la place qu'elle occupe dans Age of Empires II comme dans
 * StarCraft — les deux jeux dont ce socle reprend la forme —, et un joueur du genre y va sans
 * regarder. Le corollaire compte autant : la fiche de sélection, qui change à chaque clic,
 * occupe le **centre**, là où l'œil revient ; et le pupitre, qu'on vise sans le lire, est au
 * bout du geste, à droite.
 */
.minimap {
  flex: 0 0 auto; align-self: center; padding: 5px; line-height: 0;
  background: #1a1209; border: 1px solid rgba(52, 35, 16, .9); border-radius: 2px;
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, .7), 0 1px 0 rgba(255, 255, 255, .28);
}
/*
 * ⚠️ `touch-action: none` n'est pas de la décoration : sans lui, le navigateur confisque le
 * balayage de la minimap pour faire défiler la page et les `pointermove` s'arrêtent au premier
 * pixel — exactement le défaut qu'on vient de corriger, réintroduit par le style. Et le curseur
 * est celui du terrain (`crosshair`), parce qu'on y **vise** : la main d'un lien laissait croire
 * qu'il n'y avait qu'à cliquer, alors qu'on y glisse et qu'on y donne des ordres.
 */
.minimap canvas {
  width: var(--mini); height: var(--mini); image-rendering: pixelated;
  cursor: crosshair; touch-action: none;
}

/* ---- aide, sous la fiche ---------------------------------------------------- */

/*
 * ⚠️ **L'aide a quitté le terrain, et c'est son troisième déménagement — le dernier.**
 *
 * Elle a d'abord partagé le bas de l'écran avec la barre de commandes (elles se recouvraient
 * dès que la barre passait à deux rangs, ce qui dépend de la **sélection** et pas seulement de
 * la largeur : aucune condition de taille ne pouvait le régler), puis elle s'est réfugiée en
 * haut à gauche, par-dessus le plateau. Elle est maintenant **dans l'interface**, sous la
 * fiche, dans une colonne qui ne peut structurellement rien recouvrir.
 *
 * Et elle a maigri de moitié : les touches de geste (`1-5`, `E`, `V`, `F`, `X`) sont gravées
 * sur leur case du pupitre, à côté. Une aide ne répète pas l'écran.
 */
.aide {
  flex: 0 0 auto; font-size: 11px; line-height: 1.5; color: #6d5836;
  max-width: 760px; margin: 0 auto; width: 100%;
  overflow: hidden; max-height: 4.4em;   /* trois lignes au plus : la colonne les tient */
}
.aide b { color: var(--titre); font-weight: 700; }

/* ---- LE MENU D'ÉCHAP ---------------------------------------------------------- */

/*
 * ⚠️ **Il passe au-dessus de tout, y compris de l'écran de fin ?** Non — `.fin` est à 15, la
 * plaque du menu à 14. Une partie terminée n'a plus de menu à offrir : c'est l'écran de fin qui
 * doit rester lisible, et le menu qui doit passer dessous s'ils se croisent.
 *
 * ⚠️ **Le voile capte les clics** (`pointer-events` hérité du `.hud > *`, mais le menu n'est pas
 * dans `.hud` : il est posé directement sur `body`, donc il les capte de naissance). C'est ce
 * qui empêche un clic destiné au bouton « Reprendre » de traverser et d'envoyer l'armée marcher.
 */
.menu-jeu {
  position: fixed; inset: 0; z-index: 14;
  display: flex; align-items: center; justify-content: center;
  background: rgba(8, 6, 4, .68); backdrop-filter: blur(2px);
  cursor: default;                      /* le curseur de jeu s'arrête au bord du plateau */
}
.menu-plaque {
  background: var(--bois); border: 1px solid var(--bord); box-shadow: var(--ombre);
  border-radius: 2px; padding: 22px 26px; width: min(460px, 92vw);
  max-height: 92vh; overflow-y: auto;
  display: flex; flex-direction: column; gap: 10px;
}
.menu-plaque h2 {
  margin: 0; font-size: 22px; color: var(--titre); letter-spacing: .05em;
  font-variant: small-caps;
}
.menu-plaque h3 {
  margin: 2px 0 0; font-size: 12px; color: var(--encre-pale);
  font-variant: small-caps; letter-spacing: .08em; font-weight: 400;
}
.menu-bouton {
  font: 15px var(--serif); padding: 8px 14px; border: 1px solid var(--bord);
  background: #f0e0c1; color: var(--titre); border-radius: 2px; cursor: pointer;
  text-align: left;
}
.menu-bouton:hover { background: #f7ead0; }
.menu-reglages {
  display: flex; flex-direction: column; gap: 8px;
  border-top: 1px solid rgba(84, 56, 26, .28);
  border-bottom: 1px solid rgba(84, 56, 26, .28);
  padding: 10px 0;
}
/*
 * ⚠️ **`min-width: 0` sur la colonne de texte, et ce n'est pas décoratif.** Sans lui, un libellé
 * d'aide un peu long pousse la ligne au-delà de la plaque au lieu de revenir à la ligne : c'est
 * le même défaut, à la lettre, que celui qui a coupé les quatre coûts du Monument dans le
 * pupitre. Une boîte flex ne rétrécit pas en dessous de son contenu tant qu'on ne le lui dit pas.
 */
.menu-ligne {
  display: flex; align-items: flex-start; gap: 10px; cursor: pointer;
}
.menu-ligne .menu-champ { flex: 0 0 auto; margin-top: 3px; accent-color: #7a5a34; }
.menu-ligne input[type="range"] { width: 96px; }
.menu-texte { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.menu-texte b { font-size: 14px; color: var(--encre); font-weight: 600; }
.menu-texte small { font-size: 11px; color: var(--encre-pale); line-height: 1.35; }
.menu-valeur {
  flex: 0 0 auto; font-style: normal; font-size: 12px; color: var(--encre-pale);
  min-width: 64px; text-align: right; font-variant: small-caps;
}
.menu-remise { font-size: 12px; padding: 5px 10px; align-self: flex-start; }
.menu-abandon { color: #8d3a24; }
/* Armé : le second clic confirme. La couleur change **avec** le libellé, jamais seule. */
.menu-abandon.menu-arme { background: #e9c2b3; color: #6d2413; font-weight: 700; }
.menu-note { margin: 0; font-size: 11.5px; color: var(--encre-pale); line-height: 1.4; }
.menu-gestes { margin: 0; font-size: 11.5px; color: #6d5836; line-height: 1.5; }
.menu-gestes b { color: var(--titre); font-weight: 700; }

/* ---- fin de partie ---------------------------------------------------------- */

.fin {
  position: fixed; inset: 0; display: grid; place-items: center; z-index: 15;
  background: rgba(8, 6, 4, .72); backdrop-filter: blur(2px); text-align: center;
}
.fin > div {
  background: var(--bois); border: 1px solid var(--bord); box-shadow: var(--ombre);
  padding: 28px 54px; border-radius: 2px;
}
.fin .marque { display: block; width: 64px; height: 64px; margin: 0 auto 10px; }
.fin h1 { margin: 0 0 8px; font-size: 34px; color: var(--titre); letter-spacing: .06em; }
.fin p { margin: 4px 0; font-size: 15px; }
.fin .g { color: #7a5a34; font-size: 12.5px; }

/* ---- vestiaire (mode réseau) -------------------------------------------------- */

.vestiaire {
  position: fixed; inset: 0; display: grid; place-items: center; z-index: 20;
  background: #120d09;
}
.vestiaire .boite {
  background: var(--bois); border: 1px solid var(--bord); box-shadow: var(--ombre);
  padding: 24px 30px; border-radius: 2px; min-width: 460px; max-width: 720px;
  max-height: 94vh; overflow-y: auto;
}
/*
 * ⚠️ **La carte du monde n'est pas un formulaire, elle n'a pas la largeur d'un formulaire.**
 * `max-width: 720px` est la bonne mesure pour s'identifier — une ligne de saisie n'a rien à
 * gagner à faire 1 400 px de large — et la pire possible pour un monde de 25 territoires : elle
 * enfermait l'atlas dans un carré de 543 px au milieu du parchemin. Le `:has()` distingue les
 * deux écrans **sans que le JS ait à poser une classe**, donc sans qu'on puisse oublier de la
 * retirer en revenant au salon.
 */
.vestiaire .boite:has(.monde) { max-width: min(1560px, 96vw); }
.vestiaire h1 { margin: 0 0 12px; font-size: 24px; color: var(--titre); }
/* Le logo tient l'écran pendant que le titre d'étape change à côté de lui. */
.vestiaire .tete { display: flex; align-items: center; gap: 13px; margin: 0 0 14px; }
.vestiaire .tete .marque { flex: 0 0 auto; width: 46px; height: 46px; }
.vestiaire .tete h1 { margin: 0; }
.vestiaire .form { display: flex; flex-direction: column; gap: 8px; }
.vestiaire input, .vestiaire select {
  font: 14px var(--serif); padding: 6px 9px; border: 1px solid var(--bord);
  background: #f6ead1; color: var(--encre); border-radius: 2px;
}
.vestiaire button, .fin button {
  font: 14px var(--serif); padding: 6px 14px; border: 1px solid var(--bord);
  background: #f0e0c1; color: var(--titre); border-radius: 2px; cursor: pointer;
}
.vestiaire button.secondaire, .fin button.secondaire { color: var(--encre-pale); }
.vestiaire button[disabled] { opacity: .45; cursor: default; }
/* Le vestiaire et l'écran de fin sont les deux bouts de la même boucle : même bouton. */
.vestiaire .ligne, .fin .ligne { display: flex; gap: 8px; align-items: center; margin: 10px 0; flex-wrap: wrap; }
.fin .ligne { justify-content: center; margin: 18px 0 0; }
/*
 * ⚠️ **Ici vivaient `.vestiaire .grille` et `.vestiaire .case`** — la grille de fiches 5×5 qui
 * servait de carte du monde avant l'atlas. Plus une ligne de JS ne les produit depuis le
 * 2026-08-13, et elles sont restées : quatre règles qui ne s'appliquaient à rien, mais qui
 * décrivaient encore un écran disparu. Elles ont fait perdre du temps deux fois — une fois en
 * lecture (« il y a donc encore une grille quelque part ? ») et une fois pour de bon, quand
 * `essai-reseau.mjs` a continué de chercher `.vestiaire .grille .case` : le banc échouait dès
 * la création du compte, donc **plus rien ne vérifiait la boucle réseau de bout en bout**, et
 * les captures `shots/menu-*.png` montraient l'écran d'avant pendant des jours.
 */
.vestiaire .g { color: #7a5a34; font-size: 12.5px; }
.vestiaire .err { color: #8d3a1f; font-size: 12.5px; }

/* ---- écran d'échec ------------------------------------------------------------ */

.oups {
  position: fixed; inset: 0; display: grid; place-items: center; padding: 40px;
  color: #e6d5b4; background: #12100c; text-align: center;
  font: 15px/1.7 var(--serif); z-index: 30;
}
.oups code { color: #f0c98a; }
/* Les modèles se téléchargent pendant la partie ; le HUD et le terrain restent accessibles. */
.suivi-modeles { position:fixed; top:52px; left:50%; transform:translateX(-50%); z-index:25; width:max-content; max-width:min(680px,92vw); display:flex; align-items:center; gap:10px; padding:9px 12px; background:#211b14ee; color:#edddbd; border:1px solid #a78b57; border-radius:5px; font:13px/1.4 system-ui,sans-serif; }
.suivi-modeles[hidden] { display:none; }
.suivi-modeles button { flex-shrink:0; border:1px solid #8e754d; border-radius:3px; background:#332a1e; color:inherit; padding:3px 8px; cursor:pointer; }
.suivi-modeles button[hidden] { display:none; }
.suivi-modeles span { min-width:0; }
