@charset "utf-8";

/* LotR II · Map Editor — l'outil.
 *
 * Suit DESIGN.md, y compris ses trois partis-pris non négociables :
 *   1. angle vif, ombre décalée PLEINE (aucun border-radius, aucun flou)
 *   2. la trame est la matière (demi-teintes en damier, jamais une opacité)
 *   3. densité de manuel technique, aligné à gauche
 * Le rouge #c00000 est le SEUL signal d'interaction — jamais décoratif.
 *
 * Une seule dérogation au parti-pris 3, assumée : la landing est en colonne
 * unique de 64ch, l'éditeur est un OUTIL et prend toute la fenêtre. Le contrat
 * fixe la mesure du texte au fil, pas celle d'un plan de travail — et c'est
 * précisément la contrainte que ce projet lève par rapport au jeu. */

/* ---------- fontes ----------
 *
 * Deux gothiques de Google Fonts, HÉBERGÉES ICI (24 Kio de woff2) et non
 * appelées par @import : DESIGN.md exige que le rendu ne dépende d'aucune
 * requête tierce, et un @import vers fonts.googleapis.com le violerait tout
 * en ajoutant deux allers-retours avant le premier pixel de texte.
 *
 * Trois rôles, et la séparation n'est pas cosmétique :
 *   --font-title    Pirata One  — la plus lourde, réservée aux grands titres
 *   --font-display  Germania One — libellés, boutons, en-têtes de section
 *   --font-mono     Courier New — les CHIFFRES et les marqueurs techniques
 *
 * Le monospace reste parce que la mise en page en dépend : la valeur de zoom
 * est calée sur 5ch, le résumé de carte aligne ses nombres en colonne, et les
 * marqueurs [ok] / [!] / [lock] tirent leur lisibilité de leur chasse fixe.
 * Une blackletter y serait illisible ET casserait l'alignement. */

@font-face {
  font-family: "Germania One";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../../fonts/germania-one-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Pirata One";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../../fonts/pirata-one-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Pirata One";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../../fonts/pirata-one-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  --bg: #e8dfc4;
  --surface: #f1ead2;
  --ink: #1c1208;
  --ink-2: #3f2d18;
  /* 4,70:1 contre le premier centile du parchemin (l'ancien #6f6845 n'y tenait
   * que 2,88:1 — et déjà seulement 4,66:1 sur l'aplat qu'il remplace). */
  --muted: #4e4830;
  --accent: #c00000;
  --accent-deep: #8e231c;
  --border: #8f7440;
  --moss: #51492f;
  --font-title: "Pirata One", "Germania One", serif;
  --font-display: "Germania One", "Pirata One", serif;
  --font-mono: "Courier New", ui-monospace, monospace;
  --font-body: system-ui, -apple-system, sans-serif;

  --lift: 4px 4px 0 var(--ink);
  --lift-pressed: 2px 2px 0 var(--ink);

  --bar-h: 52px;
  --rail: 200px;
  --side: 272px;
}

* { box-sizing: border-box; margin: 0; }

/* L'attribut `hidden` doit gagner : sans cela une règle de classe qui pose un
 * `display` l'emporte sur la feuille du navigateur et l'élément masqué reste
 * affiché. */
[hidden] { display: none !important; }

html, body { height: 100%; overflow: hidden; }

body {
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.45;
  color: var(--ink);
  background-color: var(--bg);
  /* Même matière que la landing : le parchemin SEUL. Il ne se voit que là où
   * aucun panneau ne le couvre — démarrage, écran vide de la conversion
   * d'image, marges du canevas. */
  /* Une seule couche : le parchemin de `root/texture.png`. En `cover` et non
   * répété — la source ne boucle pas, une répétition afficherait ses coutures
   * (mesuré : 1,8x le grain naturel). La trame héraldique `bg-pattern.png` qui
   * se posait par-dessus a été retirée, et avec elle le `multiply` : il n'avait
   * de sens que pour marier DEUX couches ; sur une seule il ne ferait que la
   * teinter de la couleur de repli. */
  background-image: url(../../texture.webp);
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center;
  background-attachment: fixed;
}

/* Parti-pris 2 : le demi-ton se fabrique en damier, pas en alpha. */
.rule,
.doc-sep {
  height: 6px;
  background-image: repeating-conic-gradient(var(--border) 0% 25%, transparent 0% 50%);
  background-size: 4px 4px;
}

kbd {
  font-family: var(--font-mono);
  font-size: 11px;
  border: 1px solid var(--ink);
  background: var(--surface);
  padding: 0 3px;
}

/* ---------- démarrage ---------- */

.boot {
  position: fixed;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: start;
  gap: 14px;
  padding: 24px;
  background-color: var(--bg);
  background-image: url(../../texture.webp);
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center;
}
.boot-brand { font-family: var(--font-display); }
.boot-brand .main { font-size: 20px; font-weight: 700; letter-spacing: 0.08em; }
.boot-brand .sub {
  font-size: 12px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--muted);
}
.boot h1 {
  font-family: var(--font-title);
  font-size: clamp(22px, 4vw, 28px);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.boot p { color: var(--ink-2); max-width: 56ch; }
.boot-bar {
  width: 280px; height: 10px;
  border: 2px solid var(--ink);
  background: var(--surface);
}
.boot-bar i { display: block; height: 100%; width: 0; background: var(--accent); }
.boot-error { color: var(--accent); font-weight: 700; }

/* ---------- ossature ---------- */

.app { display: grid; grid-template-rows: var(--bar-h) 1fr; height: 100%; }

/* Le parchemin, et pas un aplat. `root/texture.png` est la matière du site ;
 * la barre et les panneaux couvraient toute la fenêtre de `--surface`, si bien
 * qu'on ne la voyait nulle part. Elle est posée en FEUILLE CONTINUE :
 *
 *   `fixed`  ancre l'image à la fenêtre, pas à l'élément — deux panneaux
 *            voisins montrent donc la même feuille, séparés par leur seul
 *            filet d'encre, et le grain ne glisse pas quand un panneau défile.
 *   `cover`  plutôt qu'un carrelage : mesuré sur la source, la couture d'un
 *            carrelage vaut 1,8x le grain naturel — elle se verrait.
 *
 * `--surface` reste dessous : c'est la couleur qui tient tant que l'image
 * n'est pas chargée, et celle des petits objets (boutons, puces, kbd) qui
 * doivent au contraire se détacher À PLAT sur la feuille. */
.parchment,
.bar,
.panel {
  background-color: var(--surface);
  /* Voile de 30 % de `--surface` par-dessus le grain. Mesuré sur la texture :
   * les encres principales tiennent sans voile (7,5:1 au pire contre le premier
   * centile du fond), mais le premier centile est à 187,162,117 — trop sombre
   * pour du texte secondaire. À 30 % il remonte à 203,184,145, et le grain
   * reste franchement visible. */
  background-image:
    linear-gradient(rgba(241, 234, 210, 0.3), rgba(241, 234, 210, 0.3)),
    url(../../texture.webp);
  background-size: cover;
  background-position: center;
  background-attachment: fixed;
}

.bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 12px;
  border-bottom: 2px solid var(--ink);
}

.brand { display: flex; align-items: baseline; gap: 8px; font-family: var(--font-display); text-decoration: none; color: var(--ink); }
.brand .main { font-size: 15px; font-weight: 700; letter-spacing: 0.08em; }
.brand .sub { font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted); }

.bar-group { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

.bar-title { flex: 1; display: flex; align-items: baseline; justify-content: center; gap: 10px; min-width: 0; }

.map-name {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--ink);
  background: transparent;
  border: 2px solid transparent;
  padding: 3px 8px;
  text-align: center;
  min-width: 10ch;
  max-width: 34ch;
}
.map-name:hover { border-color: var(--border); }
.map-name:focus { outline: none; border-color: var(--ink); background: var(--bg); }

.map-meta { font-family: var(--font-mono); font-size: 11px; color: var(--muted); white-space: nowrap; }

.stage { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr) var(--side); min-height: 0; }

.panel {
  overflow-y: auto;
  padding: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.panel-left { border-right: 2px solid var(--ink); }
.panel-right { border-left: 2px solid var(--ink); }

/* En-têtes numérotés, comme les sections de la landing. */
.panel h2 {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding-top: 10px;
  border-top: 2px solid var(--ink);
}
.panel h2:first-child { padding-top: 0; border-top: 0; }
.panel h2 .num { color: var(--muted); margin-right: 6px; }
.panel h2 .count { color: var(--muted); font-weight: 400; letter-spacing: 0; }

.hint { font-size: 12px; color: var(--muted); }
.hint b { color: var(--ink-2); font-weight: 400; }

/* Ce que la carte a perdu en chemin. Même taille qu'une indication — ce n'est
 * pas une erreur, la carte existe — mais le filet rouge du bord la sort de la
 * grisaille : elle se voit sans se lire, ce qui est exactement son rôle. */
.ai-note {
  font-size: 12px;
  color: var(--ink-2);
  border-left: 3px solid var(--accent);
  padding-left: 8px;
}

/* ---------- boutons : la profondeur est mécanique ---------- */

.btn {
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink);
  background: var(--surface);
  border: 2px solid var(--ink);
  padding: 6px 10px;
  cursor: pointer;
  box-shadow: var(--lift);
  transition: transform 100ms cubic-bezier(0.2, 0, 0, 1),
              box-shadow 100ms cubic-bezier(0.2, 0, 0, 1);
}
.btn:hover,
.btn:focus-visible { color: var(--accent); transform: translate(2px, 2px); box-shadow: var(--lift-pressed); }
.btn:active { transform: translate(4px, 4px); box-shadow: 0 0 0 var(--ink); }
.btn.primary { background: var(--accent); color: var(--surface); }
.btn.primary:hover, .btn.primary:focus-visible { background: var(--accent-deep); color: var(--surface); }
.btn.small { padding: 4px 7px; font-size: 11px; box-shadow: var(--lift-pressed); }
.btn.small:hover, .btn.small:focus-visible { transform: translate(2px, 2px); box-shadow: 0 0 0 var(--ink); }
.btn[disabled] { color: var(--muted); border-color: var(--border); box-shadow: none; cursor: default; transform: none; }

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

.toggle { display: flex; align-items: center; gap: 7px; color: var(--ink-2); cursor: pointer; }
.toggle input { accent-color: var(--accent); }

.zoom-value { font-family: var(--font-mono); min-width: 5ch; text-align: center; color: var(--ink-2); }

/* ---------- rail gauche : mini-carte, compteurs, palette ----------
 *
 * Architecture reprise de l'éditeur amont. Ce qui change, c'est que le rail
 * n'est plus une colonne de 162 pixels : les cases de la palette respirent, et
 * la mini-carte occupe la largeur disponible au lieu de ses 130×129 figés. */

.mini-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 132 / 124;
  border: 2px solid var(--ink);
  background: var(--moss);
  box-shadow: var(--lift-pressed);
  /* État de départ seulement : `mini-map.js` remplace ce curseur par la MAIN
   * dès que le pointeur entre dans un comté. */
  cursor: crosshair;
}
/* Sélecteur de projection, dans le coin du cadre : une lettre, comme la
 * gouttière de l'éditeur amont (A/O/C/I). Il ne masque presque rien. */
.mini-projection {
  position: absolute;
  top: 3px;
  left: 3px;
  z-index: 1;
  width: 18px;
  height: 18px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--ink);
  padding: 0;
  cursor: pointer;
}
.mini-projection:hover { color: var(--accent); }

.mini-frame canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  image-rendering: pixelated;
}

/* Compteurs de CARTE : fiefs de départ et marchands. Ce sont des propriétés de
 * la carte, pas du comté choisi — d'où leur place sous la mini-carte et non
 * dans le panneau de comté. */
.badges { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.badge {
  display: flex;
  align-items: center;
  gap: 6px;
  border: 1px solid var(--border);
  background: var(--bg);
  padding: 3px 6px;
}
.badge-icon { width: 20px; height: 20px; object-fit: contain; image-rendering: pixelated; }
.badge-value {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
}
/* Sous deux fiefs, le DOS renvoie au menu principal au lancement : c'est un
 * défaut de la carte, pas une préférence — marqueur d'alerte. */
.badge.warn { border-color: var(--accent); }
.badge.warn .badge-value { color: var(--accent); }

.brush-label {
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink);
  min-height: 1.2em;
}

/* ---------- taille de pinceau ----------
 *
 * Dix crans, en cercles croissants : la barre se lit d'un coup d'oeil, sans
 * avoir à déchiffrer dix chiffres. Elle n'apparaît que pour les pinceaux de
 * terrain — les seuls qu'il ait un sens d'étaler. */

.brush-sizes {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2px;
  padding: 3px 4px;
  border: 2px solid var(--ink);
  background: var(--bg);
}

.brush-size-discs {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  gap: 2px;
}

.mountain-sizes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  width: 100%;
  gap: 4px;
}

.mountain-size {
  min-height: 26px;
  padding: 1px 8px;
  border: 2px solid var(--ink);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
.mountain-size:hover { color: var(--accent); }
.mountain-size[aria-pressed="true"] {
  color: var(--surface);
  background: var(--accent);
  box-shadow: inset 0 0 0 1px var(--surface);
}

.brush-size {
  display: grid;
  place-items: center;
  width: 100%;
  height: 26px;
  padding: 0;
  background: transparent;
  border: 0;
  cursor: pointer;
}
.brush-size-dot {
  width: var(--dot);
  height: var(--dot);
  border-radius: 50%;
  background: var(--ink-2);
}
.brush-size:hover .brush-size-dot { background: var(--accent); }
/* L'actif est plein rouge, cerclé : le seul signal d'interaction du design. */
.brush-size[aria-pressed="true"] .brush-size-dot {
  background: var(--accent);
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 3px var(--ink);
}

.brush-grid {
  display: grid;
  grid-template-columns: repeat(var(--brush-columns, 4), 1fr);
  gap: 4px;
}

.brush {
  position: relative;
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  padding: 2px;
  background: var(--bg);
  border: 2px solid var(--ink);
  cursor: pointer;
  overflow: hidden;
}
.brush:hover { border-color: var(--accent); }
/* L'actif est cerclé de rouge plein — le seul signal d'interaction du design.
 * L'amont pose un cadre brun ; ici le rouge tient ce rôle partout ailleurs. */
.brush[aria-pressed="true"] { border-color: var(--accent); box-shadow: inset 0 0 0 2px var(--accent); }
.brush-icon {
  display: block;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  image-rendering: pixelated;
}
/* « Nouvelle capitale » partage le tableau de la ville : le « + » les sépare. */
.brush-plus {
  position: absolute;
  top: 1px;
  right: 1px;
  width: 13px;
  height: 13px;
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--ink);
}
/* Même tableau que Prairie : le D gravé signale la variante hors comté. */
.brush-badge {
  position: absolute;
  top: 1px;
  right: 1px;
  min-width: 13px;
  height: 13px;
  padding: 0 1px;
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-size: 10px;
  line-height: 1;
  color: var(--surface);
  background: var(--ink);
  border: 1px solid var(--surface);
}
/* Manque dans le comté choisi : marqueur TEXTE, pas de pastille (DESIGN.md). */
.brush.warn::after {
  content: "!";
  position: absolute;
  bottom: 0;
  left: 2px;
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 700;
  color: var(--accent);
  text-shadow: 0 0 2px var(--surface), 0 0 2px var(--surface);
}

/* ---------- canevas ---------- */

.canvas-wrap { position: relative; min-width: 0; min-height: 0; overflow: hidden; background: var(--moss); }
#map-canvas { display: block; touch-action: none; cursor: crosshair; }
#map-canvas.panning { cursor: grabbing; }

/* Le coin haut-gauche de la carte porte deux choses : le bandeau transitoire
 * et l'aide de la mini-carte. Elles s'EMPILENT dans ce conteneur au lieu d'être
 * posées chacune en absolu au même point, où la seconde masquerait la
 * première. */
.canvas-notes {
  position: absolute;
  left: 12px;
  top: 12px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
  max-width: calc(100% - 24px);
  pointer-events: none;
}

.readout,
.message,
.map-hint,
.draw-help,
.confirm {
  position: absolute;
  font-family: var(--font-mono);
  font-size: 12px;
  background: var(--surface);
  border: 2px solid var(--ink);
  padding: 5px 9px;
  box-shadow: var(--lift);
  pointer-events: none;
}
.readout { left: 12px; bottom: 12px; color: var(--ink-2); }
.readout:empty { display: none; }

/* Le comté qu'on TRAÎNE dans la liste, et le trait qui montre où il tombera.
 * Le trait est PLEIN et sans flou, comme tout ce qui marque une position dans
 * cet éditeur : une ombre portée aurait deux côtés à nu. */
.county-item.dragging { opacity: 0.45; }
.county-item.drop-before { box-shadow: inset 0 2px 0 var(--accent); }
.county-item.drop-after { box-shadow: inset 0 -2px 0 var(--accent); }

/* Les SAISONS, posées sur la carte comme le zoom : quatre tuiles de blé, une
 * par saison, au-dessus de la lecture de tuile. C'est la tuile elle-même qui
 * dit la saison (le blé du printemps est vert, celui d'hiver est gelé) et le
 * clic la change. Pas de plaque sous les tuiles — leur losange est transparent
 * aux coins, une plaque se verrait autour — et la saison REGARDÉE est cernée
 * d'un trait PLEIN, sans flou, comme le blason des fiefs. */
.season-dock {
  position: absolute;
  left: 12px;
  bottom: 44px;
  display: flex;
  align-items: flex-end;
  gap: 2px;
}
.season-dock button {
  padding: 0;
  border: 0;
  background: none;
  line-height: 0;
  cursor: pointer;
}
.season-dock canvas { display: block; }
.season-dock button[aria-pressed="true"] canvas {
  filter: drop-shadow(2px 0 0 var(--accent)) drop-shadow(-2px 0 0 var(--accent))
    drop-shadow(0 2px 0 var(--accent)) drop-shadow(0 -2px 0 var(--accent));
}

/* Le zoom, posé sur la carte en pendant de la lecture de tuile : même bord,
 * même hauteur, l'autre coin. Il ne porte PAS de plaque à lui — chaque bouton
 * a déjà la sienne, et une plaque sur des plaques ferait un cadre dans un
 * cadre. La valeur, elle, en a une : sans fond elle serait posée à même la
 * carte, où le bleu de la mer et le vert de la prairie passent sous le même
 * texte. */
.zoom-dock {
  position: absolute;
  right: 12px;
  bottom: 12px;
  display: flex;
  align-items: center;
  gap: 6px;
}
.zoom-dock .zoom-value {
  background: var(--surface);
  border: 2px solid var(--ink);
  box-shadow: var(--lift);
  padding: 4px 6px;
  font-size: 12px;
}
/* Placés par la pile ci-dessus, pas par leurs propres coordonnées. */
.message,
.map-hint { position: static; }
.message { max-width: 60ch; color: var(--ink); }
/* L'aide de la mini-carte : montrée seulement pendant qu'on la survole, là où
 * le geste se fait — sur la carte — et non dans la colonne d'en face. */
.map-hint {
  max-width: 62ch;
  line-height: 1.55;
  color: var(--ink-2);
}
.map-hint b { color: var(--ink); font-weight: 400; }

/* L'aide de la planche à dessin. Coin HAUT-DROIT : les pastilles de comté et
 * leur infobulle vivent au milieu du tracé, la lecture de coordonnées en bas —
 * ce coin-là est le seul que rien n'occupe. Elle ne paraît que pendant qu'on
 * survole l'aperçu, qui est justement dans ce coin de la colonne d'à côté : le
 * regard n'a pas à traverser l'écran. */
.draw-help {
  right: 12px;
  top: 12px;
  max-width: 46ch;
  line-height: 1.55;
  color: var(--ink-2);
}
.draw-help p { margin: 0; }
.draw-help p + p { margin-top: 7px; }
.draw-help b { color: var(--ink); font-weight: 400; }
/* L'aperçu est la poignée de l'aide : il se prend aussi au clavier. */
.draw-preview:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.confirm {
  left: 50%;
  top: 12px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  pointer-events: auto;
}

/* ---------- liste des comtés ---------- */

/* Le retrait de 40 px etait celui du <ul> lui-meme : la feuille du navigateur
 * pose un padding-inline-start sur toute liste, et le reset global ne remet a
 * zero que les marges. */
/* Mode d'emploi d'un pinceau, sous son nom. Discret : il ne parle que pour
 * les pinceaux dont la règle ne se devine pas. */
.brush-hint {
  font-size: 11px;
  line-height: 1.35;
  color: var(--muted);
  border-left: 2px solid var(--border);
  padding-left: 6px;
}

/* La clé du climat : cinq bandes de numéros, leur valeur et ce qu'elle vaut.
 * Une grille et non une phrase — les cinq lignes se lisent en colonne, et une
 * légende qui se lit une fois ne mérite pas un paragraphe par bande. */
.climate-legend {
  display: grid;
  gap: 2px;
  padding: 4px 0;
  font-size: 11px;
  line-height: 1.3;
}

.climate-row {
  display: grid;
  grid-template-columns: 10px auto 3ch auto;
  align-items: center;
  gap: 6px;
}

/* La pastille est la teinte EXACTE posée sur la carte : c'est elle qui fait le
 * lien avec la surimpression, pas la couleur du texte. */
.climate-swatch {
  width: 10px;
  height: 10px;
  border: 1px solid var(--ink-2);
}

.climate-range { color: var(--ink-2); }

/* Monospace et aligné à droite : les cinq valeurs se comparent en colonne
 * (+4, +2, −8, 0, −12), et c'est la comparaison qui dit l'ordre de l'échelle. */
.climate-value {
  font-family: var(--font-mono);
  text-align: right;
  color: var(--ink);
}

.climate-effect { color: var(--muted); }

/* Calque de fond de l'écran de dessin : la photo sous le tracé. */
/* Infobulle des pastilles de comte, sur la planche a dessin. */
.county-hint {
  position: absolute;
  z-index: 5;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.4;
  white-space: pre;
  color: var(--ink);
  background: var(--surface);
  border: 2px solid var(--ink);
  box-shadow: var(--lift);
  padding: 5px 8px;
  pointer-events: none;
}
.county-action { display: flex; flex-direction: column; gap: 9px; }
.county-action-targets { display: flex; flex-wrap: wrap; gap: 6px; }

/* « Verser dans » : les voisins d'un comté, dans sa fiche. */
/* Modale « Claim land » : la mini-carte situe la case, le reste choisit. */
.claim-dialog { display: flex; flex-direction: column; gap: 9px; min-width: 260px; }
/* La ligne d'aide d'une modale de choix garde une place FIXE. Elle change de
 * texte au survol — le comté visé à la place du mode d'emploi — et le texte
 * neuf, plus court, faisait redescendre la modale d'une ligne EN MÊME TEMPS
 * qu'il en rétrécissait la largeur : survoler la mini-carte faisait sauter
 * tout ce qui est dessous. Sa DOUBLURE (`.hint-ghost`, invisible) porte le plus
 * long des textes possibles ; les deux occupent la même cellule d'une grille,
 * donc la boîte prend la hauteur ET la largeur du plus grand — à toute largeur
 * de fenêtre, sans un calcul en JavaScript à refaire au redimensionnement. */
.hint-slot { display: grid; }
.hint-slot > .hint { grid-area: 1 / 1; }
.hint-ghost { visibility: hidden; }

.claim-map {
  align-self: center;
  border: 2px solid var(--ink);
  box-shadow: var(--lift);
  line-height: 0;
}
.claim-map canvas { width: 264px; height: 248px; image-rendering: pixelated; }

.county-merge { display: flex; flex-wrap: wrap; align-items: center; gap: 5px; }
/* Une cible qui ne TOUCHE pas le comté : la fusion y donnera un comté en
 * plusieurs morceaux. Le trait pointillé le dit sans rien interdire — c'est une
 * forme que le format porte (50 des 434 comtés livrés sont déjà morcelés), pas
 * une faute. Pas de rouge : DESIGN.md le réserve au seul signal d'interaction. */
.county-merge-far { border-style: dashed; }
.county-merge-label {
  font-family: var(--font-display);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.backdrop-controls { display: flex; flex-direction: column; gap: 5px; }
.backdrop-opacity { display: flex; align-items: center; gap: 7px; color: var(--ink-2); }
.backdrop-opacity span {
  font-family: var(--font-display);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.backdrop-opacity input { flex: 1; min-width: 0; accent-color: var(--accent); }
.backdrop-opacity input:disabled { opacity: 0.45; }

.county-list { list-style: none; display: flex; flex-direction: column; padding: 0; }

.county-item {
  display: flex;
  align-items: center;
  gap: 5px;
  width: 100%;
  font: inherit;
  text-align: left;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--border);
  /* Trois pixels à gauche : la pastille respire sans quitter le bord. */
  padding: 5px 2px 5px 3px;
  cursor: pointer;
}
.county-item:last-child { border-bottom: 0; }
.county-item:hover { color: var(--accent); }
/* Le comté choisi se signale par son FOND seul. Le filet rouge en retrait
 * intérieur passait sous la pastille de couleur, à trois pixels d'elle : deux
 * traits verticaux collés, dont un qui n'appartenait pas à la ligne. Et le
 * comté choisi est déjà celui dont la fiche est ouverte juste dessous. */
.county-item[aria-current="true"] { background: var(--bg); }
.county-swatch {
  position: relative;
  width: 10px;
  height: 10px;
  flex: none;
  border: 1px solid var(--ink);
}
.county-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Blason du fief de départ. UNE image pour dix-neuf teintes : le PNG n'est
 * qu'un masque (blanc, alpha = relief), et c'est la couleur de fond — celle du
 * comté, posée en ligne — qui le traverse. Sans masque il aurait fallu
 * dix-neuf fichiers, ou renoncer à ce que le blason réponde à la pastille. */
/* DEUX éléments, et ce n'est pas un caprice : le masque vit sur l'ENFANT, le
 * cerne sur le PARENT. En CSS le `filter` s'applique AVANT le `mask` — les
 * quatre ombres portées étaient donc calculées sur le rectangle plein de
 * l'élément, puis découpées par le masque avec tout le reste. On ne voyait
 * aucun cerne. En filtrant le parent d'un enfant déjà masqué, l'ombre suit la
 * silhouette du blason.
 *
 * La couleur du comté arrive par `--county`, posée en ligne : `background` sur
 * le parent y peindrait un carré que le masque de l'enfant ne couvrirait pas. */
.county-shield {
  /* Sept sur neuf : la SURFACE est divisée par deux (63 px2 contre 120), et le
   * blason reste plus petit que la pastille de couleur qui ouvre la ligne.
   *
   * Ne pas descendre plus bas. Mesure a huit fois la taille reelle : a 6x7 la
   * pointe basse commence a se perdre, et a 5x6 — la moitie de chaque cote —
   * le cerne d un pixel mange 40 % de la largeur, il ne reste qu une pastille
   * sombre de trois pixels sur quatre, moins lisible que le carre de couleur
   * qu elle jouxte. */
  /* POSÉ SUR la pastille, débordant de son coin haut-droit. Les deux disent la
   * même couleur ; les superposer en fait un seul objet — la pastille du comté,
   * marquée d'un écusson quand un noble y commence — au lieu de deux carrés
   * voisins de même teinte. Et le nom récupère les douze pixels du créneau. */
  position: absolute;
  /* Deux pixels de debord seulement : a quatre, l ecusson venait toucher la
   * premiere lettre du nom, qui n est qu a cinq pixels de la pastille. */
  right: -2px;
  top: -3px;
  width: 7px;
  height: 9px;
  /* Cerne d'un pixel qui ÉPOUSE la forme : quatre ombres PLEINES, décalées
   * d'un pixel dans les quatre directions. Aucun flou — c'est la gravure du
   * site, la même qu'en note de bannière sur la landing. */
  filter:
    drop-shadow(1px 0 0 var(--ink)) drop-shadow(-1px 0 0 var(--ink))
    drop-shadow(0 1px 0 var(--ink)) drop-shadow(0 -1px 0 var(--ink));
}
.county-shield::before {
  content: "";
  display: block;
  width: 100%;
  height: 100%;
  background: var(--county, var(--muted));
  -webkit-mask-image: url(../assets/icons/county-shield.png);
  mask-image: url(../assets/icons/county-shield.png);
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

/* Industries : les silhouettes d'ouvrier du jeu, à hauteur de ligne. */
.county-works { display: flex; align-items: center; gap: 2px; flex: none; }
/* Treize pixels : a dix-huit, les ressources ecrasaient le nom du comte et le
 * tronquaient des le premier. */
.county-work { height: 13px; width: auto; image-rendering: pixelated; }

/* Champs : le losange de blé et son compte. min-width en chasse fixe pour
 * que les nombres s'alignent d'une ligne à l'autre. */
.county-fields {
  display: flex;
  align-items: center;
  gap: 3px;
  flex: none;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-2);
}
.county-fields b { min-width: 2ch; text-align: right; }
.county-grain { width: 22px; height: 11px; image-rendering: pixelated; }

.county-flag { font-family: var(--font-mono); font-size: 11px; flex: none; }
.county-flag { color: var(--accent); font-weight: 700; }

.county-detail { display: flex; flex-direction: column; gap: 8px; border: 2px solid var(--ink); background: var(--bg); padding: 9px; }
.county-detail h3 { font-family: var(--font-display); font-size: 13px; text-transform: uppercase; letter-spacing: 0.06em; }
.county-detail .rename {
  width: 100%;
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 2px solid var(--ink);
  padding: 4px 6px;
}
.county-detail .rename:focus { outline: none; border-color: var(--accent); }

/* Tableau d'état : monospace, marqueurs texte. */
.stat-row { display: flex; flex-wrap: wrap; gap: 3px 12px; font-family: var(--font-mono); font-size: 12px; color: var(--muted); }
.stat b { color: var(--ink); }
.stat.bad b { color: var(--accent); }
.stat.good b { color: var(--moss); }

.issues { list-style: none; font-size: 12px; padding: 0; }
.issues li { padding: 3px 0; border-bottom: 1px solid var(--border); color: var(--ink); }
.issues li:last-child { border-bottom: 0; }
.issues li::before { content: "[!] "; font-family: var(--font-display); font-weight: 700; color: var(--accent); }
.issues span { color: var(--muted); }

/* Repli du lien de partage : le presse-papier peut être refusé, le lien doit
 * alors rester lisible ET sélectionnable d'un bloc. */
.share-body { display: flex; flex-direction: column; gap: 8px; }
.share-field {
  width: 100%;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink);
  background: var(--surface);
  border: 2px solid var(--ink);
  padding: 6px;
  resize: vertical;
  word-break: break-all;
}

.traders { display: flex; flex-wrap: wrap; gap: 4px; }
.trader {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink);
  background: var(--surface);
  border: 2px solid var(--ink);
  padding: 2px 6px;
  cursor: pointer;
}
.trader:hover:not([disabled]) { color: var(--accent); }
.trader[aria-pressed="true"] { background: var(--accent); color: var(--surface); }
.trader[disabled] { color: var(--muted); border-color: var(--border); cursor: default; }

.summary { font-family: var(--font-mono); font-size: 12px; display: flex; flex-direction: column; }
.summary div { display: flex; justify-content: space-between; gap: 12px; padding: 2px 0; border-bottom: 1px solid var(--border); color: var(--muted); }
.summary div:last-child { border-bottom: 0; }
.summary b { color: var(--ink); }

/* ---------- fenêtres étroites ---------- */

@media (max-width: 900px) {
  .stage { grid-template-columns: 1fr; grid-template-rows: 1fr auto; }
  .panel { flex-direction: row; flex-wrap: wrap; align-items: flex-start; border: 0; border-top: 2px solid var(--ink); max-height: 36vh; }
  .panel-left { order: 2; }
  .panel-right { order: 3; }
  .canvas-wrap { order: 1; }
  .bar-title { display: none; }
}

/* ---------- écrans ----------
 *
 * Quatre écrans dans une page, un seul visible (boot.js). Ils partagent
 * l'ossature de l'éditeur : une barre de 52 px, puis le reste de la hauteur.
 * C'est ici que se voit la contrainte levée par le site — le jeu compose ces
 * mêmes écrans dans 640×480 fixes, avec un ascenseur de douze lignes et un
 * aperçu de 132×124. */

.screen { display: grid; grid-template-rows: var(--bar-h) 1fr; height: 100%; }

.screen-title {
  font-family: var(--font-title);
  font-size: 15px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* ---------- Create a map ---------- */

.create {
  display: grid;
  grid-template-columns: minmax(240px, 1fr) 320px;
  grid-template-rows: minmax(0, 1fr) auto;
  min-height: 0;
}
.create-library { grid-row: 1; grid-column: 1; border-right: 2px solid var(--ink); }
.create-preview { grid-row: 1; grid-column: 2; }
.create-actions { grid-row: 2; grid-column: 1 / -1; border-top: 2px solid var(--ink); }

.map-list { display: flex; flex-direction: column; min-height: 0; overflow-y: auto; }

.map-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: baseline;
  gap: 10px;
  width: 100%;
  font: inherit;
  text-align: left;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--border);
  padding: 7px 4px;
  cursor: pointer;
}
.map-item:hover { color: var(--accent); }
/* Sélection : le jeu passe la ligne en vidéo inversée. Ici la barre rouge en
 * bord d'élément dit la même chose sans repeindre un aplat noir. */
.map-item[aria-current="true"] {
  /* Une ombre INTERNE creuse la ligne dans la feuille sans la repeindre : un
   * aplat `--bg` posait une tache pâle au milieu du grain. */
  box-shadow: inset 3px 0 0 var(--accent), inset 0 0 0 999px rgba(63, 45, 24, 0.09);
  padding-left: 10px;
}
.map-item-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 700; }
.map-item-meta {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
}
.map-item-tag {
  font-family: var(--font-display);
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--moss);
  border: 1px solid var(--border);
  padding: 0 4px;
  white-space: nowrap;
}

/* ---------- liste groupée par provenance ---------- */

/* Le jeu d'origine, le Siege Pack et les cartes de l'utilisateur ne se mêlent
 * pas : trois blocs, en-têtes collants pour rester lisibles au défilement. */
.map-group {
  position: sticky;
  top: 0;
  z-index: 1;
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--muted);
  background: var(--surface);
  border-bottom: 2px solid var(--ink);
  padding: 8px 2px 4px;
}
.map-group:first-child { padding-top: 0; }

/* Cadenas des cartes livrées : marqueur TEXTE, pas de pastille (DESIGN.md). */
.map-item-lock {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  color: var(--muted);
  white-space: nowrap;
}
.map-item[aria-current="true"] .map-item-lock { color: var(--ink-2); }

.map-search {
  font: inherit;
  color: var(--ink);
  background: var(--bg);
  border: 2px solid var(--ink);
  padding: 5px 8px;
  flex: none;
}
.map-search:focus { outline: none; border-color: var(--accent); }
.map-search::placeholder { color: var(--muted); }

.thumb-frame {
  width: 288px;
  border: 2px solid var(--ink);
  background: var(--moss);
  box-shadow: var(--lift);
  width: fit-content;
  max-width: 100%;
  line-height: 0;
}
.thumb-frame canvas { display: block; width: 100%; height: auto; image-rendering: pixelated; }
.thumb-name {
  font-family: var(--font-title);
  font-size: 15px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.thumb-meta { font-family: var(--font-display); font-size: 12px; color: var(--muted); }

.action-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 8px; }

.action {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font: inherit;
  text-align: left;
  color: var(--ink);
  background: var(--bg);
  border: 2px solid var(--ink);
  padding: 9px 11px;
  cursor: pointer;
  box-shadow: var(--lift);
  transition: transform 100ms cubic-bezier(0.2, 0, 0, 1),
              box-shadow 100ms cubic-bezier(0.2, 0, 0, 1);
}
.action:hover, .action:focus-visible { transform: translate(2px, 2px); box-shadow: var(--lift-pressed); }
.action:active { transform: translate(4px, 4px); box-shadow: 0 0 0 var(--ink); }
.action b {
  font-family: var(--font-display);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}
.action:hover b, .action:focus-visible b { color: var(--accent); }
.action span { font-size: 12px; color: var(--muted); }
.action span b { font-family: var(--font-display); font-size: 11px; letter-spacing: 0; color: var(--ink-2); }

/* ---------- Draw a map / Create from image ---------- */

.workspace { display: grid; grid-template-columns: minmax(0, 1fr) var(--side); min-height: 0; }
.workspace .canvas-wrap { display: grid; place-items: center; padding: 10px; }
.workspace canvas {
  display: block;
  touch-action: none;
  border: 2px solid var(--ink);
  box-shadow: var(--lift);
}
#image-canvas { cursor: move; }
#draw-canvas {
  transform-origin: 0 0;
  will-change: transform;
}
#draw-canvas.panning { cursor: grabbing !important; }
.draw-marker-layer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 2;
}
.draw-county-marker {
  position: absolute;
  display: grid;
  place-items: center;
  box-sizing: border-box;
  transform: translate(-50%, -50%);
  border: 1px solid #ffe9a6;
  border-radius: 50%;
  background: rgba(24, 33, 15, 0.72);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1;
}
.draw-county-marker.invalid {
  border-width: 2px;
  background: rgba(152, 15, 8, 0.94);
}
.draw-county-marker.selected {
  border-color: #ffe9a6;
  box-shadow: 0 0 0 2px var(--accent), 3px 3px 0 var(--ink);
}
.draw-selection-help {
  margin: 2px 0 0;
  padding-left: 7px;
  border-left: 2px solid var(--border);
  color: var(--muted);
  font-size: 11px;
  line-height: 1.35;
}
.draw-selection {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding-top: 7px;
  border-top: 1px solid var(--border);
}
.draw-selection[hidden] { display: none; }
.draw-selection > span {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--ink-2);
}
.draw-zoom-dock { z-index: 4; }

.dialog-source-retouch { width: min(900px, 100%); max-width: min(900px, 100%); }
.source-retouch { display: flex; flex-direction: column; gap: 10px; min-height: 0; }
.source-retouch-tools { display: flex; flex-wrap: wrap; align-items: end; gap: 8px; }
.source-retouch-color { display: flex; align-items: center; gap: 6px; }
.source-retouch-swatch {
  width: 28px;
  height: 28px;
  border: 2px solid var(--ink);
  box-shadow: var(--lift-pressed);
}
.source-retouch-color input {
  width: 74px;
  height: 28px;
  padding: 3px 5px;
  font-family: var(--font-mono);
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--ink);
}
.source-retouch-color input[aria-invalid="true"] { border-color: var(--accent); }
.source-retouch-canvas {
  position: relative;
  height: min(58vh, 620px);
  min-height: 160px;
  overflow: auto;
  display: block;
  padding: 8px;
  background: var(--moss);
  border: 2px solid var(--ink);
  box-shadow: var(--lift-pressed);
}
.source-retouch-canvas canvas {
  display: block;
  margin: auto;
  max-width: 100%;
  max-height: min(58vh, 620px);
  width: auto;
  height: auto;
  touch-action: none;
  box-shadow: var(--lift);
}
.source-retouch-canvas canvas[data-tool="pick"] { cursor: crosshair; }
.source-retouch-canvas canvas[data-tool="paint"] { cursor: none; }
.source-retouch-canvas canvas[data-tool="fill"] { cursor: cell; }
.source-retouch-canvas canvas[data-tool="contrast"] { cursor: none; }
.source-retouch-canvas.is-panning canvas { cursor: grabbing; }
.source-retouch-brush-preview {
  position: absolute;
  z-index: 1;
  box-sizing: border-box;
  border: 1px solid var(--surface);
  border-radius: 50%;
  box-shadow: 0 0 0 1px var(--ink);
  pointer-events: none;
  transform: translate(-50%, -50%);
}

.empty {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: start;
  gap: 10px;
  padding: 24px;
  background-color: var(--bg);
  background-image: url(../../texture.webp);
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center;
}
.empty h3 {
  font-family: var(--font-title);
  font-size: 20px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.empty p { max-width: 48ch; color: var(--ink-2); }

.issues li.ok { color: var(--moss); }
.issues li.ok::before { content: "[ok] "; color: var(--moss); }

/* ---------- outils de l'écran de dessin ----------
 *
 * Comme l'amont : crayon, gomme, puis deux pots de peinture qui portent la
 * TEXTURE qu'ils versent — la photo de mer et celle de prairie, les mêmes
 * tableaux que la palette de l'éditeur. Un pot de peinture montrant ce qu'il
 * verse se passe de mode d'emploi. */

.draw-tools { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; }

.draw-tool {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 5px 3px;
  font: inherit;
  color: var(--ink);
  background: var(--bg);
  border: 2px solid var(--ink);
  cursor: pointer;
}
.draw-tool img {
  display: block;
  width: 38px;
  height: 30px;
  object-fit: cover;
  image-rendering: pixelated;
  border: 1px solid var(--ink);
}
/* Le crayon et la gomme sont des SVG au trait : les encadrer comme une photo
 * de terrain les ferait passer pour un troisième pot. */
.draw-tool img[src$=".svg"] {
  object-fit: contain;
  border-color: transparent;
  background: transparent;
}
.draw-tool span {
  font-family: var(--font-display);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.draw-tool:hover { border-color: var(--accent); }
.draw-tool:hover span { color: var(--accent); }
.draw-tool[aria-pressed="true"] { background: var(--accent); border-color: var(--ink); }
.draw-tool[aria-pressed="true"] span { color: var(--surface); }

/* L'aperçu projeté n'est pas cliquable, contrairement à la mini-carte de
 * l'éditeur : pas de curseur qui le laisse croire. */
.draw-preview { cursor: default; }

/* ---------- réglages : curseurs, champs, choix exclusifs ---------- */

.slider { display: grid; grid-template-columns: 1fr auto; align-items: baseline; gap: 2px 8px; }
.slider-label {
  font-family: var(--font-display);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.slider-value {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink);
  text-align: right;
  min-width: 5ch;
}
.slider input[type="range"] { grid-column: 1 / -1; width: 100%; accent-color: var(--accent); }
#image-controls { display: flex; flex-direction: column; gap: 8px; }

/* ---------- Describe a realm ----------
 *
 * Un écran de FORMULAIRE, contrairement à ses deux voisins qui sont des plans
 * de travail : le canevas n'y sert qu'à montrer le résultat, et tout ce qu'on
 * y fait se passe dans la colonne. D'où des champs pleine largeur — la colonne
 * fait 272 px, une clé d'API en fait cent de plus, et un champ qui déborde
 * empêche de vérifier ce qu'on a collé. */

.ai-field,
.ai-prompt {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink);
  background: var(--bg);
  border: 2px solid var(--ink);
  padding: 5px 7px;
  width: 100%;
  min-width: 0;
}
.ai-field:focus,
.ai-prompt:focus { outline: none; border-color: var(--accent); }
.ai-field::placeholder,
.ai-prompt::placeholder { color: var(--muted); }

.ai-prompt {
  font-family: var(--font-body);
  font-size: 13px;
  resize: vertical;
  min-height: 68px;
}

/* Le champ de modèle et son bouton de listage sur une ligne : le nom reste
 * saisissable à la main, « Models » ne fait que le remplir. */
.ai-model-row { display: flex; gap: 6px; align-items: stretch; }
.ai-model-row .btn { flex: none; }
/* Le bouton mange 70 px des 248 de la colonne. En 12 px le champ coupait
 * `gemini-3.1-pro-preview` à vingt caractères ; en 11 px il l'affiche entier,
 * et le nom du modèle en cours se lit sans cliquer dedans. */
.ai-model-row .ai-field { flex: 1; font-size: 11px; }

/* La liste des modèles d'un compte : une colonne défilante dans la modale.
 * Le catalogue d'OpenAI compte des dizaines d'entrées — la borner en hauteur
 * est ce qui garde le bouton « Close » atteignable. */
.ai-model-list {
  display: flex;
  flex-direction: column;
  gap: 3px;
  max-height: min(52vh, 420px);
  overflow-y: auto;
  min-width: min(420px, 76vw);
}
.ai-model-item {
  font: inherit;
  font-size: 12px;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 1px;
  color: var(--ink-2);
  background: transparent;
  border: 1px solid var(--border);
  padding: 5px 7px;
  cursor: pointer;
}
.ai-model-item b { font-family: var(--font-mono); color: var(--ink); font-weight: 400; }
.ai-model-item span { color: var(--muted); }
.ai-model-item:hover,
.ai-model-item:focus-visible { border-color: var(--accent); }
.ai-model-item:hover b,
.ai-model-item:focus-visible b { color: var(--accent); }
.ai-model-item[aria-current="true"] { background: var(--bg); border-color: var(--ink); }

/* Les exemples sont des amorces, pas des boutons d'action : filet fin, pas
 * d'ombre portée, et le rouge n'arrive qu'au survol. Ils ne doivent pas peser
 * autant que « Draw it », qui est le seul geste de l'écran. */
.ai-examples { display: flex; flex-direction: column; gap: 4px; }
.ai-example {
  font: inherit;
  font-size: 12px;
  text-align: left;
  color: var(--ink-2);
  background: transparent;
  border: 1px solid var(--border);
  padding: 4px 6px;
  cursor: pointer;
}
.ai-example:hover,
.ai-example:focus-visible { color: var(--accent); border-color: var(--accent); }

/* Le voile d'attente couvre le canevas : c'est la carte qu'on attend, et une
 * réponse peut prendre une minute sur un modèle à raisonnement. */
.ai-busy {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 14px;
  background: rgba(28, 18, 8, 0.72);
  color: var(--surface);
  font-family: var(--font-display);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-size: 13px;
}
.ai-spinner {
  width: 26px;
  height: 26px;
  border: 3px solid var(--surface);
  border-top-color: var(--accent);
  animation: ai-turn 900ms linear infinite;
}
@keyframes ai-turn { to { transform: rotate(360deg); } }
/* Le temps écoulé, en retrait : il ne se lit que si on le cherche, mais il
 * transforme « ça ne finit jamais » en une durée qu'on peut rapporter. */
.ai-busy-elapsed {
  margin: -6px 0 0;
  font-size: 11px;
  letter-spacing: 0.08em;
  opacity: 0.7;
}
/* Un carré qui tourne indéfiniment est une gêne pour qui y est sensible ; la
 * bordure rouge suffit alors à distinguer le voile d'un écran figé. */
@media (prefers-reduced-motion: reduce) {
  .ai-spinner { animation: none; }
}

.form { display: flex; flex-direction: column; gap: 12px; min-width: min(340px, 70vw); }
.field { display: flex; flex-direction: column; gap: 4px; }
.field-label {
  font-family: var(--font-display);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.field-input {
  font: inherit;
  color: var(--ink);
  background: var(--surface);
  border: 2px solid var(--ink);
  padding: 5px 7px;
}
.field-input:focus { outline: none; border-color: var(--accent); }

.choice { display: flex; flex-wrap: wrap; gap: 4px; }
.choice-item {
  font-family: var(--font-display);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ink);
  background: var(--surface);
  border: 2px solid var(--ink);
  padding: 5px 9px;
  cursor: pointer;
}
.choice-item:hover { color: var(--accent); }
.choice-item[aria-pressed="true"] { background: var(--accent); color: var(--surface); }
/* La flèche du décalage de carte : centrée dans sa case, et solidaire de la
 * couleur du bouton — crème sur le rouge du bouton choisi. */
.choice-item svg { display: block; }

/* Un bouton d'outil actif est plein rouge, comme un pinceau de la palette. */
.btn[aria-pressed="true"] { background: var(--accent); color: var(--surface); }
.btn[aria-pressed="true"]:hover { background: var(--accent-deep); color: var(--surface); }

/* ---------- modales et bandeau ---------- */

/* Le voile absorbe les clics : c'est sa vraie fonction dans le jeu aussi. Il
 * est plein, jamais flouté — DESIGN.md interdit le flou. */
.veil {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgba(28, 18, 8, 0.44);
}
.dialog {
  max-width: min(520px, 100%);
  max-height: 100%;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
  background: var(--surface);
  /* Le filet d'encre est remplacé plus bas par le cadre de pierre du jeu. */
  box-shadow: var(--lift);
  padding: 16px 18px;
}
.dialog-title {
  font-family: var(--font-title);
  font-size: 15px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding-bottom: 9px;
  border-bottom: 2px solid var(--ink);
}
.dialog-body { display: flex; flex-direction: column; gap: 10px; color: var(--ink-2); }
/* Les actions PASSENT À LA LIGNE. « Claim land » peut en aligner dix-neuf —
 * une par comté de la carte quand la case visée n'en touche aucun. Sur une
 * seule ligne, les boutons se comprimaient jusqu'à rogner leur texte
 * (« MILANO » réduit à « ANO ») et débordaient par la GAUCHE, hors d'atteinte :
 * un alignement en fin de ligne pousse le débordement du côté du bord de
 * départ, que rien ne peut faire défiler. */
.dialog-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
  padding-top: 4px;
}
/* Un bouton garde sa taille : c'est la LIGNE qui cède, pas le mot. */
.dialog-actions > .btn { flex: 0 0 auto; }

.toast {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  z-index: 50;
  max-width: min(70ch, calc(100% - 32px));
  font-family: var(--font-display);
  font-size: 12px;
  color: var(--ink);
  background: var(--surface);
  border: 2px solid var(--ink);
  box-shadow: var(--lift);
  padding: 7px 12px;
}

/* ---------- corrections relevées sur preview-home.png ---------- */

/* Sans carte choisie, le cadre n'a rien à encadrer : il ne doit pas laisser un
 * carré sombre de 4 px au-dessus du texte. */
.thumb-frame:empty { display: none; }

/* Un bouton rouge désactivé ment : il annonce l'action principale de l'écran
 * alors qu'il ne répond pas. `.btn[disabled]` ne reprenait que la couleur du
 * texte, et `.primary` gardait son fond. */
.btn.primary[disabled],
.btn.primary[disabled]:hover {
  color: var(--muted);
  background: var(--surface);
  border-color: var(--border);
  box-shadow: none;
  transform: none;
}

/* Bibliothèque vide : l'avis prend la forme d'une note du document plutôt que
 * de flotter en pleine largeur au-dessus d'un vide de 600 px. */
#library-empty {
  max-width: 62ch;
  border-left: 2px solid var(--border);
  padding-left: 12px;
  margin-top: 4px;
}

/* ---------- fenêtres étroites ---------- */

@media (max-width: 900px) {
  .create { grid-template-columns: 1fr; grid-template-rows: auto auto auto; }
  .create-library {
    grid-row: 2;
    grid-column: 1;
    border-right: 0;
    border-top: 2px solid var(--ink);
    max-height: 40vh;
  }
  .create-preview { grid-row: 1; grid-column: 1; }
  .create-actions { grid-row: 3; }
  .workspace { grid-template-columns: 1fr; grid-template-rows: 1fr auto; }
  .workspace .panel-right { border-left: 0; border-top: 2px solid var(--ink); max-height: 40vh; }
}

/* ---------- modales « carte entière » ----------
 *
 * Comtés de départ et routes marchandes : les deux seuls réglages qui
 * appartiennent à la CARTE et non à un comté. D'où une modale à chacun, ouverte
 * depuis son compteur, avec la grande mini-carte cliquable de l'amont — on
 * désigne un comté sur la silhouette du royaume, pas dans une liste de noms.
 *
 * La colonne de droite garde un nombre de lignes FIXE : la liste ne saute pas
 * quand on ajoute ou retire un fief, et les rangs vides annoncent la place
 * qui reste. */

.dialog-wide { max-width: min(660px, 100%); }

.wm-grid {
  display: grid;
  grid-template-columns: 264px minmax(0, 1fr);
  gap: 16px;
  align-items: start;
}

/* Le creux de parchemin de l'amont, dans la matière du site : un cadre net et
 * une ombre PORTÉE VERS L'INTÉRIEUR, sans flou (DESIGN.md). */
.wm-mini {
  border: 2px solid var(--ink);
  background: var(--bg);
  padding: 3px;
  line-height: 0;
}
/* Dessinée en 132x124 — la taille native, pour laquelle le lissage des côtes
 * est calibré — et AGRANDIE ici. `pixelated` garde les marches nettes plutôt
 * que de les fondre : c'est ce que fait le zoom de l'amont. */
.wm-mini-canvas {
  width: 258px;
  height: auto;
  display: block;
  /* État de départ seulement : `whole-map-dialogs.js` pose la MAIN sur les
   * comtés, seuls endroits où le clic fait quelque chose. */
  cursor: default;
  image-rendering: pixelated;
}

.wm-side { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.wm-count {
  font-family: var(--font-title);
  font-size: 22px;
  line-height: 1.1;
  color: var(--ink);
}
.wm-count.warn { color: var(--accent); }
.wm-list-title {
  font-family: var(--font-display);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  border-bottom: 1px solid var(--border);
  padding-bottom: 3px;
}
.wm-list { display: flex; flex-direction: column; }
.wm-row {
  font-family: var(--font-display);
  font-size: 14px;
  text-align: left;
  color: var(--ink);
  background: none;
  border: 0;
  border-bottom: 1px solid var(--border);
  padding: 4px 2px;
  cursor: pointer;
}
.wm-row:hover:not([disabled]) { color: var(--accent); }
/* Le marchand en cours d'édition, en rouge plein : le seul signal
 * d'interaction du design, et le même qu'à la palette de pinceaux. */
.wm-row[aria-pressed="true"] {
  background: var(--accent);
  color: var(--surface);
  padding-left: 6px;
}
.wm-row[disabled] { color: var(--muted); cursor: default; }
.wm-warn { font-size: 12px; color: var(--accent); min-height: 1.1em; }
.wm-note { font-size: 12px; color: var(--muted); }

.wm-tools { display: flex; gap: 8px; }
.wm-hint {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-2);
  border-top: 1px solid var(--border);
  padding-top: 8px;
  min-height: 1.2em;
}

/* Le compteur EST un bouton : il doit le montrer au survol, comme tout ce qui
 * répond au clic dans l'éditeur. */
.badge { cursor: pointer; text-align: left; font: inherit; }
.badge:hover { border-color: var(--accent); }
.badge:hover .badge-value { color: var(--accent); }

@media (max-width: 620px) {
  .wm-grid { grid-template-columns: minmax(0, 1fr); }
  .wm-mini-canvas { width: 100%; }
}

/* ---------- cadre de pierre du jeu ----------
 *
 * VILLBORD.PL8 : le cadre qui entoure l'écran de village du DOS, décodé et
 * redécoupé en planche neuf-tranches par `tools/extract-village-border.js` de
 * l'amont (montants de 12 px, motif de 32 px, coins distincts des bords).
 *
 * `round` et non `repeat` : le motif se termine ainsi sur un bloc entier au
 * lieu d'être coupé en son milieu. Pas de mot-clé `fill` — le centre reste
 * transparent et le panneau garde son parchemin.
 *
 * `image-rendering: pixelated` n'a pas d'effet sur un border-image ; à 12 px
 * natifs il n'y a de toute façon aucune mise à l'échelle. */

/* Il encadre les MODALES, et elles seules. Sur les colonnes de l'éditeur il
 * faisait un bandeau de 12 px sur toute la hauteur de l'écran : trop lourd pour
 * un plan de travail qu'on regarde en continu. Une modale, on la regarde le
 * temps d'un réglage — un cadre y a sa place, et il remplace exactement ce que
 * faisait le filet d'encre de 2 px. */
.dialog {
  border: 12px solid transparent;
  border-image: url(../assets/village-border.png) 12 round;
}

/* Status on the preview only; pointer gestures still reach the canvas. */
.image-busy {
  position: absolute;
  top: 16px;
  left: 16px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
  border: 2px solid var(--ink);
  background: var(--surface);
  color: var(--ink);
  box-shadow: 3px 3px 0 var(--ink);
  pointer-events: none;
  font-family: var(--font-display);
}
.image-spinner {
  width: 12px;
  height: 12px;
  border: 2px solid var(--ink);
  border-top-color: var(--surface);
  animation: ai-turn 900ms steps(4) infinite;
}
@media (prefers-reduced-motion: reduce) {
  .image-spinner { animation: none; }
}
