@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@500;600;700&display=swap');

:root {
    --antiqua-bg: #fbf6ec;
    --antiqua-panel: #ffffff;
    --antiqua-border: #e3d5b8;
    --antiqua-text: #3a2f1e;
    /* Assombri le 20/07 (#7a684a -> #6b5a3d, audit UX/UI du 19/07, P1.4 :
       "renforcer les textes secondaires brun clair sur crème") -- l'ancienne
       valeur passait déjà le seuil AA (~5:1) mais de justesse vu le nombre
       de textes en 11-13px qui l'utilisent ; la nouvelle vaut ~6,2:1 sur
       fond crème et ~6,7:1 sur fond blanc, une seule variable pour tout le
       site (des dizaines d'usages, y compris en style inline). */
    --antiqua-text-muted: #6b5a3d;
    --antiqua-accent: #c9a468;
    --antiqua-accent-dark: #8a6a3f;
    --antiqua-header-bg: #241c14;
    --antiqua-header-text: #f3e6cf;
    --antiqua-danger: #993c1d;
    --antiqua-danger-bg: #fbe6df;

    /* Palette du manifeste visuel (étape V3) -- points de départ pour les éléments
       du monde et les états (pictogrammes, illustrations, accents), pas des
       remplacements des couleurs de thème ci-dessus. */
    --palette-encre: #241a13;
    --palette-ivoire: #f4e9d3;
    --palette-bleu-nil: #24779a;
    --palette-turquoise: #1b9a93;
    --palette-vert-roseau: #4f7a4c;
    --palette-terre-cuite: #c7633f;
    --palette-or-vieilli: #b68a45;
    --palette-indigo: #17345d;
}

/* Règle transverse anti-débordement (P1.6, audit UX/UI du 19/07) : les pages
   admin les plus denses (paramètres, joueurs, monuments) débordaient
   horizontalement sous 400px -- box-sizing appliqué au coup par coup ailleurs
   dans ce fichier ne couvrait pas tout, et un <select>/<input> pouvait
   s'étirer à la largeur de son contenu dans un conteneur flex sans jamais se
   réduire. Générique et sans effet visuel sur les pages déjà correctes. */
*, *::before, *::after {
    box-sizing: border-box;
}

main, section, article, form, fieldset {
    min-width: 0;
}

input, select, textarea, button {
    max-width: 100%;
}

/* Un <select> refuse de rétrécir sous la largeur de sa plus longue <option>
   dans un conteneur flex, même avec max-width:100% -- c'est ce qui poussait
   la ligne "Donner" (admin/joueurs) hors de son <li> malgré la règle
   ci-dessus (noms de ressources longs, ex. "Plantes médicinales sauvages"). */
select {
    min-width: 0;
}

/* Focus clavier par défaut, dans la palette Antiqua (audit UX/UI du 19/07 :
   "styliser le focus-visible... tout en gardant un contraste fort"). Sans
   règle globale, la plupart des éléments retombaient sur l'anneau bleu par
   défaut du navigateur -- visible, mais hors charte. Les règles plus
   spécifiques déjà en place (formulaire de connexion, plateau de manœuvres,
   onglets Caserne) restent prioritaires pour leurs propres contextes. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
    outline: 2px solid var(--antiqua-accent-dark);
    outline-offset: 2px;
}

body {
    margin: 0;
    min-height: 100vh;
    background-color: var(--antiqua-bg);
    background-image:
        radial-gradient(ellipse 900px 500px at 50% 0%, rgba(201, 164, 104, 0.14), transparent 70%),
        /* Lavis quasi-opaque qui atténue la texture à ~15% de son intensité d'origine
           (audit 4.1 : "trop jaune, contrastée et omniprésente") sans toucher au
           fichier image ni à la lueur radiale au-dessus. */
        linear-gradient(rgba(251, 246, 236, 0.85), rgba(251, 246, 236, 0.85)),
        url("/images/texture-papyrus.png");
    background-repeat: no-repeat, no-repeat, repeat;
    color: var(--antiqua-text);
    font-family: Georgia, "Times New Roman", serif;
    line-height: 1.6;
}

/* Réservé au menu principal, à la barre Admin et aux nav minimales qui leur
   ressemblent (mémorial) -- corrige une fuite (23/07, retour de ChatGPT sur
   l'audit du 22/07) : ces règles ciblaient tout élément <nav> du site, y
   compris le sommaire du Guide et la barre de catégories de Paramètres
   admin, qui héritaient alors d'un fond sombre sticky et d'un texte clair
   sans le vouloir (le titre "Sommaire", pas un lien, devenait illisible en
   texte muet sur fond sombre ; la pagination d'Admin Joueurs devenait une
   deuxième barre sombre en bas de page). */
.site-nav {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 20px;
    background-color: var(--antiqua-header-bg);
    padding: 14px 24px;
}

.site-nav a {
    color: var(--antiqua-header-text);
    text-decoration: none;
    font-size: 14px;
    padding: 10px 2px;
    display: inline-flex;
    align-items: center;
}

/* Les liens de la nav sont groupés pour pouvoir devenir une rangée
   défilable sur mobile (voir plus bas) ; en desktop le groupe est
   transparent (mêmes espacements que la nav elle-même). */
.nav-liens {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 20px;
}

/* La déconnexion est un formulaire POST (CSRF requis, voir security.yaml)
   mais doit se lire comme un lien parmi les autres entrées de la nav. */
.form-deconnexion {
    display: inline-flex;
    margin: 0;
}

.lien-deconnexion {
    background: none;
    border: none;
    cursor: pointer;
    color: var(--antiqua-header-text);
    font-size: 14px;
    font-family: inherit;
    /* line-height hérité explicitement : les boutons ne l'héritent pas par
       défaut, ce qui décalait « Se déconnecter » verticalement par rapport
       aux liens de la nav (revue design du 18/07). */
    line-height: 1.6;
    padding: 10px 2px;
    display: inline-flex;
    align-items: center;
}

/* Page active de la nav : soulignement discret couleur accent. */
.site-nav a.nav-actif {
    box-shadow: inset 0 -2px 0 var(--antiqua-accent);
    color: var(--antiqua-accent);
}

/* Point "nouveau" du menu (23/07, retour de ChatGPT sur l'audit du 22/07) :
   prolonge le digest déjà calculé pour la Place publique (voir
   NouveauteExtension) jusque dans le menu, pour donner envie d'y retourner
   sans devoir cliquer pour vérifier. */
.nav-point-nouveau {
    display: inline-block;
    width: 7px;
    height: 7px;
    margin-left: 5px;
    border-radius: 50%;
    background-color: var(--antiqua-accent);
    vertical-align: middle;
}

/* État du personnage dans le header (revue design du 18/07) : l'énergie et
   les PV pilotent toutes les décisions mais n'étaient visibles que sur
   Personnage/Accueil, jamais sur les écrans où on les dépense. Le bloc est
   un lien vers la fiche du personnage. */
.nav-etat {
    margin-left: auto;
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    gap: 3px;
    padding: 4px 2px;
    text-decoration: none;
}

.nav-etat-ligne {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    color: var(--antiqua-header-text);
    line-height: 1;
}

.nav-etat-libelle {
    width: 22px;
    text-align: right;
    opacity: 0.8;
}

.nav-mini-jauge {
    width: 64px;
    height: 6px;
    border-radius: 3px;
    background-color: rgba(255, 255, 255, 0.18);
    overflow: hidden;
}

.nav-mini-remplissage {
    display: block;
    height: 100%;
    border-radius: 3px;
}

.nav-etat-valeur {
    min-width: 44px;
    font-variant-numeric: tabular-nums;
}

/* Jauge à zéro : la barre vide ne peut plus « colorer » l'alerte, c'est le
   rail et la valeur qui la portent (famine imminente). */
.nav-mini-jauge.jauge-rail-danger {
    background-color: rgba(153, 60, 29, 0.55);
}

.jauge.jauge-rail-danger {
    box-shadow: inset 0 0 0 1px #993c1d;
    background-color: rgba(153, 60, 29, 0.15);
}

.nav-etat-ligne .jauge-valeur-danger,
.jauge-valeur-danger {
    color: #993c1d;
    font-weight: bold;
}

.nav-amphore {
    padding: 0;
    margin-right: 4px;
}

.nav-amphore img {
    display: block;
    border-radius: 4px;
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.nav-bouton-menu {
    display: none;
    background: none;
    border: 1px solid rgba(243, 230, 207, 0.35);
    border-radius: 4px;
    color: var(--antiqua-header-text);
    font-size: 16px;
    line-height: 1;
    padding: 8px 12px;
    cursor: pointer;
}

/* Nav mobile (P0.1, audit UX/UI du 19/07) : huit entrées ne tiennent pas en
   375 px -- l'ancien défilement horizontal sans indice visuel les rendait
   de fait inatteignables (Caserne/Temple/Guide jamais vus). Remplacé par un
   panneau déroulant classique (bouton Menu, voir nav_controller.js) : rangée
   du haut logo + Menu + état vital + déconnexion, panneau plein largeur en
   liste verticale sous la nav quand ouvert. */
@media (max-width: 700px) {
    .site-nav {
        padding: 10px 16px;
        gap: 4px 12px;
    }

    .nav-bouton-menu {
        display: inline-flex;
        align-items: center;
    }

    .nav-liens {
        order: 5;
        flex-basis: 100%;
        flex-direction: column;
        align-items: stretch;
        flex-wrap: nowrap;
        gap: 0;
        max-height: 0;
        overflow: hidden;
    }

    .nav-liens.est-ouvert {
        max-height: 480px;
        margin-top: 8px;
        padding-top: 8px;
        border-top: 1px solid rgba(243, 230, 207, 0.15);
    }

    .nav-liens a {
        padding: 12px 4px;
        width: 100%;
    }
}

@media (hover: hover) and (pointer: fine) {
    .site-nav a:hover {
        color: var(--antiqua-accent);
    }
}

h1, h2, h3 {
    font-family: "Cormorant Garamond", Georgia, serif;
    color: var(--antiqua-text);
    font-weight: 600;
}

h1 {
    position: relative;
    padding-bottom: 12px;
    font-size: 40px;
}

.entete-connexion {
    display: flex;
    align-items: center;
    gap: 14px;
}

.entete-connexion h1 {
    padding-bottom: 0;
}

h1::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 60px;
    height: 2px;
    background-color: var(--antiqua-accent);
}

/* Titre "encré" : remplace le trait statique par un tracé animé au premier affichage */
.titre-encre::after {
    display: none;
}

.titre-encre svg {
    display: block;
    width: 160px;
    max-width: 100%;
    height: 12px;
    margin-top: 2px;
    overflow: visible;
}

.titre-encre path {
    fill: none;
    stroke: var(--antiqua-accent-dark);
    stroke-width: 2.5;
    stroke-linecap: round;
    stroke-dasharray: 400;
    stroke-dashoffset: 400;
    transition: stroke-dashoffset 1.1s cubic-bezier(0.22, 1, 0.36, 1);
}

.titre-encre.in-view path {
    stroke-dashoffset: 0;
}

@media (prefers-reduced-motion: reduce) {
    .titre-encre path {
        stroke-dashoffset: 0;
        transition: none;
    }
}

main, body > *:not(nav) {
    max-width: 840px;
    margin: 0 auto;
    padding: 0 24px;
}

/* Issue #27 (28/07) : la règle ci-dessus vise la colonne de lecture d'une page
   ordinaire -- 840px centrés, la largeur confortable pour du texte courant.
   Mais son sélecteur attrape `main` PARTOUT, y compris un `<main>` employé
   comme colonne à l'intérieur d'une grille large.

   Mesuré en production sur Place publique à 1920px : la colonne des
   conversations occupait une cellule de 962px et s'y trouvait bornée à 840px,
   donc centrée -- (962 − 840) ÷ 2 = 61px de vide à gauche. Le titre du hero
   commençait à 217px, la colonne à 278px. Exactement le décalage décrit par
   l'issue, et exactement ce que ses critères interdisent : un contenu utile
   « artificiellement recentré ou rétréci ».

   La règle est donc désarmée pour tout enfant direct de `.page-large`, le
   conteneur large partagé par les pages à hero. Écrit ainsi plutôt qu'en
   ciblant Place publique : c'est le gabarit commun qui doit porter
   l'invariant -- le titre du hero et le premier contenu utile commencent sur
   le même axe -- et non chaque page qui redresse son propre bord. Toute page
   qui placera demain un `main`, un `aside` ou une `section` dans ce conteneur
   héritera du bon comportement sans le savoir. */
.page-large > main,
.page-large > aside,
.page-large > section {
    max-width: none;
    margin-inline: 0;
}

/* Sans ça, le dernier bloc de chaque page touche le bord de la fenêtre --
   aucune règle du site n'ajoutait de marge verticale en bas de page. */
body > *:not(nav):last-child {
    padding-bottom: 48px;
}

nav {
    max-width: none;
}

table {
    border-collapse: collapse;
    margin: 12px 0;
}

td {
    padding: 4px 12px 4px 0;
    color: var(--antiqua-text-muted);
}

ul {
    padding-left: 0;
    list-style: none;
}

/* Ligne de liste plate par défaut (audit UX/UI du 19/07, P1.3 -- "presque
   chaque ligne devient une carte blanche avec bordure et ombre : ressources,
   savoir-faire, statistiques, journaux, manœuvres, paramètres"). Avant
   cette règle, TOUT <li> du site (y compris ceux qui n'ajoutent qu'un
   display:block/flex par-dessus, comme .liste-guide, .liste-reponses ou les
   listes d'Admin Mesures/Paramètres) héritait d'un fond blanc + bordure +
   ombre, quelle que soit son importance réelle. Un simple séparateur suffit
   pour une liste ; la carte pleine (fond + bordure + ombre) est réservée
   aux modules qui la méritent via la classe .carte ci-dessous. */
li {
    padding: 10px 14px;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: 6px 12px;
    border-bottom: 1px solid var(--antiqua-border);
}

li:last-child {
    border-bottom: none;
}

/* Carte autonome (audit UX/UI du 19/07, P1.3) : réservée aux <li> qui
   représentent un module indépendant et manipulable (ex. .carte-parcelle
   sur /zone), pas une simple ligne de données. */
.carte {
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 6px;
    margin-bottom: 8px;
    box-shadow: 0 1px 4px rgba(58, 47, 30, 0.06);
}

@media (hover: hover) and (pointer: fine) {
    .carte:hover {
        box-shadow: 0 3px 10px rgba(58, 47, 30, 0.12);
    }
}

form {
    margin: 12px 0;
}

label {
    display: block;
    font-size: 13px;
    color: var(--antiqua-text-muted);
    margin-top: 10px;
}

input {
    display: block;
    width: 100%;
    max-width: 320px;
    padding: 8px 10px;
    margin-top: 4px;
    border: 1px solid var(--antiqua-border);
    border-radius: 6px;
    font-size: 14px;
    box-sizing: border-box;
}

button {
    background-color: var(--antiqua-accent-dark);
    color: var(--antiqua-header-text);
    border: none;
    border-radius: 6px;
    padding: 8px 16px;
    font-size: 13px;
    cursor: pointer;
    margin-top: 10px;
}

/* Taille tactile minimale (audit UX/UI du 19/07, P1.4) : sans ça, un bouton
   ou un <select> retombait sur ~32px de haut, sous les 44px recommandés
   pour une cible tactile. Les cases à cocher/radio gardent leur taille
   native -- leur cible cliquable inclut déjà le <label> associé. */
button,
select,
input:not([type="checkbox"]):not([type="radio"]) {
    min-height: 44px;
}

@media (hover: hover) and (pointer: fine) {
    button:hover:not(:disabled) {
        background-color: var(--antiqua-header-bg);
    }
}

a {
    color: var(--antiqua-accent-dark);
}

.flash-success, .flash-error {
    padding: 10px 14px;
    border-radius: 6px;
    margin: 12px auto;
    font-size: 14px;
}

.flash-success {
    background-color: #eef3df;
    color: #3b6d11;
}

.flash-error, .alert {
    background-color: #fbe6df;
    color: #993c1d;
}

/* Patron d'action standardisé (Lot 5 #35, révision desktop du 22/07) --
   voir templates/_action_production.html.twig. */
.action-titre {
    font-weight: 600;
    margin: 10px 0 4px;
}

.action-disponibilite {
    font-size: 13px;
    margin: 0 0 2px;
}

.action-disponibilite--ok {
    color: #3b6d11;
}

.action-disponibilite--non {
    color: var(--antiqua-danger);
}

.action-resultat {
    font-size: 13px;
    color: var(--antiqua-text-muted);
    margin: 0 0 4px;
}

.toasts {
    box-sizing: border-box;
    position: fixed;
    top: 16px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1000;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    width: 100%;
    max-width: 420px;
    padding: 0 12px;
    pointer-events: none;
}

.toast {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    box-sizing: border-box;
    padding: 12px 16px;
    border-radius: 8px;
    font-size: 14px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
    opacity: 0;
    transform: translateY(-12px);
    transition: opacity 0.3s ease, transform 0.3s ease;
    pointer-events: auto;
    cursor: pointer;
}

.toast--visible {
    opacity: 1;
    transform: translateY(0);
}

.toast--success {
    background-color: #eef3df;
    color: #3b6d11;
}

.toast--error {
    background-color: #fbe6df;
    color: #993c1d;
}

.toast svg {
    flex-shrink: 0;
}

@media (prefers-reduced-motion: reduce) {
    .toast {
        transition: none;
    }
}

/* Système de boutons (revue design du 18/07, variante destructive du 20/07
   -- audit UX/UI P1.2, "Réinitialiser un monument et Prendre la récolte de
   quelqu'un ne doivent pas ressembler à Enregistrer ou Manger") :
   - action primaire  : .bouton-principal / .lien-bouton (fond brun plein) ;
   - action secondaire: .bouton-contour (contour, fond transparent, taille au
     contenu) -- distincte de .bouton-secondaire (plein-largeur, page
     connexion/inscription, définie plus bas) : même esprit contour, mais
     .bouton-secondaire impose width:100% qui ne convient pas à un bouton
     inline au milieu d'une ligne. Un nom partagé aurait fait gagner la
     règle définie le plus bas dans ce fichier (cascade), écrasant
     silencieusement le bouton "Terminer mon tour" en pleine largeur --
     constaté et corrigé le 18/07 avant que ça n'atteigne la prod ;
   - action discrète  : .lien-discret (texte souligné, sans fond) ;
   - action destructive: .bouton-destructif (terre cuite, ⚠ devant le
     libellé) -- réservée aux actions irréversibles ou hostiles à un autre
     joueur (réinitialisation admin, vol de récolte, suspension de compte),
     toujours doublée d'un onsubmit="return confirm(...)" ;
   - indisponible     : button:disabled, appliqué automatiquement (dont les
     cooldowns via cooldown_controller.js) -- l'état doit se VOIR, pas
     seulement s'ignorer au clic. */
button:disabled {
    background-color: var(--antiqua-border);
    color: var(--antiqua-text-muted);
    cursor: not-allowed;
    opacity: 0.6;
    font-style: italic;
}

/* Autonome (ne dépend pas des styles du <button> nu) : utilisée aussi bien
   sur un bouton que sur un lien (ex. "Regarder" vers une manoeuvre). */
.bouton-contour {
    display: inline-block;
    background: transparent;
    border: 1px solid var(--antiqua-accent-dark);
    border-radius: 6px;
    padding: 8px 16px;
    font-size: 13px;
    color: var(--antiqua-accent-dark);
    text-decoration: none;
    cursor: pointer;
}

.bouton-destructif {
    background-color: var(--antiqua-danger);
    color: var(--antiqua-header-text);
    border: none;
    border-radius: 6px;
    padding: 8px 16px;
    font-size: 13px;
    cursor: pointer;
}

.bouton-destructif::before {
    content: "⚠ ";
}

@media (hover: hover) and (pointer: fine) {
    .bouton-destructif:hover:not(:disabled) {
        background-color: var(--antiqua-header-bg);
    }
}

/* Recomposition desktop de la Caserne (23/07, Lot 5 #29) : deux grandes
   cartes d'action côte à côte plutôt que deux lignes empilées avec
   beaucoup de vide à droite sur grand écran -- même patron que
   .recolte-sauvage-choix sur /zone. */
.caserne-actions {
    display: grid;
    gap: 16px;
    grid-template-columns: 1fr;
    align-items: stretch;
    margin: 16px 0 24px;
}

@media (min-width: 700px) {
    .caserne-actions {
        grid-template-columns: 1fr 1fr;
    }
}

.caserne-actions .bloc-tableau-bord {
    display: flex;
    flex-direction: column;
}

.caserne-actions p {
    flex: 1;
}

/* Badges de statut (liste des manœuvres). */
.badge {
    display: inline-block;
    font-size: 11px;
    line-height: 1;
    padding: 4px 9px;
    border-radius: 10px;
    white-space: nowrap;
}

.badge-attente {
    border: 1px solid var(--antiqua-border);
    color: var(--antiqua-text-muted);
}

.badge-en-cours {
    border: 1px solid var(--antiqua-accent-dark);
    color: var(--antiqua-accent-dark);
}

.badge-terminee {
    background-color: var(--antiqua-border);
    color: var(--antiqua-text-muted);
}

.badge-a-toi {
    background-color: #639922;
    color: #fff;
}

/* Onglets Caserne (P1.5, audit UX/UI du 19/07) : radios cachés + labels,
   sans JS -- même logique "pas de SPA" que le reste du prototype. Les
   radios doivent précéder la barre d'onglets et les panneaux en DOM (le
   sélecteur ~ ne cible que les frères suivants). */
.onglet-radio {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

.caserne-onglets-boutons {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 16px;
}

.caserne-onglets-boutons label {
    display: inline-flex;
    padding: 8px 14px;
    border: 1px solid var(--antiqua-border);
    border-radius: 999px;
    font-size: 13px;
    color: var(--antiqua-text-muted);
    background-color: var(--antiqua-panel);
    cursor: pointer;
}

.onglet-radio:focus-visible ~ .caserne-onglets-boutons label {
    outline: none;
}

#onglet-a-toi:focus-visible ~ .caserne-onglets-boutons label[for="onglet-a-toi"],
#onglet-attente:focus-visible ~ .caserne-onglets-boutons label[for="onglet-attente"],
#onglet-rejoindre:focus-visible ~ .caserne-onglets-boutons label[for="onglet-rejoindre"],
#onglet-regarder:focus-visible ~ .caserne-onglets-boutons label[for="onglet-regarder"],
#onglet-terminees:focus-visible ~ .caserne-onglets-boutons label[for="onglet-terminees"] {
    outline: 2px solid var(--antiqua-accent-dark);
    outline-offset: 2px;
}

.caserne-onglet-panneau {
    display: none;
}

#onglet-a-toi:checked ~ .caserne-onglet-panneau[data-onglet="a-toi"],
#onglet-attente:checked ~ .caserne-onglet-panneau[data-onglet="attente"],
#onglet-rejoindre:checked ~ .caserne-onglet-panneau[data-onglet="rejoindre"],
#onglet-regarder:checked ~ .caserne-onglet-panneau[data-onglet="regarder"],
#onglet-terminees:checked ~ .caserne-onglet-panneau[data-onglet="terminees"] {
    display: block;
}

#onglet-a-toi:checked ~ .caserne-onglets-boutons label[for="onglet-a-toi"],
#onglet-attente:checked ~ .caserne-onglets-boutons label[for="onglet-attente"],
#onglet-rejoindre:checked ~ .caserne-onglets-boutons label[for="onglet-rejoindre"],
#onglet-regarder:checked ~ .caserne-onglets-boutons label[for="onglet-regarder"],
#onglet-terminees:checked ~ .caserne-onglets-boutons label[for="onglet-terminees"] {
    background-color: var(--antiqua-accent-dark);
    border-color: var(--antiqua-accent-dark);
    color: #fff;
}

/* Formulaire en ligne (Publier une offre, Donner) : champs sur une rangée
   en desktop, empilés pleine largeur sur mobile. */
.formulaire-inline {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}

.formulaire-inline > * {
    margin: 0;
}

.formulaire-inline input[type="number"] {
    width: 62px;
}

.formulaire-inline select {
    width: auto;
}

@media (max-width: 700px) {
    .formulaire-inline {
        flex-direction: column;
        align-items: stretch;
    }

    .formulaire-inline input[type="number"],
    .formulaire-inline select {
        width: 100%;
    }
}

/* Cibles tactiles : 44 px minimum au doigt (revue design du 18/07). Les
   cases du plateau de manœuvre (grille 12×12 volontairement dense) et les
   boutons-liens textuels gardent leur taille propre. */
@media (pointer: coarse) {
    button:not(.case-maneuver):not(.lien-deconnexion):not(.lien-discret),
    .lien-bouton,
    select,
    input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]) {
        min-height: 44px;
    }
}

@media (hover: hover) and (pointer: fine) {
    .bouton-contour:hover:not(:disabled) {
        background-color: var(--antiqua-accent-dark);
        color: var(--antiqua-header-text);
    }
}

/* Harmonisé à 1520px (23/07, retour de ChatGPT sur l'audit du 22/07 ; ajusté
   le même jour, retour direct de Gwendal -- 1200px restait visiblement plus
   étroit que le reste sur Place publique/Caserne/Chez moi/Guide). Plusieurs
   largeurs concurrentes cohabitaient sans raison (840/1100/1200/1480/1520/
   1600px) -- convergence sur une seule largeur "page applicative" (ici,
   même valeur que .tableau-bord-accueil/.tableau-zone/.page-large--temple/
   .tableau-personnage), et ~840px à part pour la lecture (.prose).
   .page-large--maneuver (1600px) reste une exception assumée : le plateau à
   trois colonnes a réellement besoin de cette largeur (voir son propre
   commentaire), ce n'est pas une divergence accidentelle. */
.page-large {
    max-width: 1520px;
}

/* Largeur de lecture confortable pour les textes longs (P2.1, audit UX/UI
   du 19/07) : les guides utilisaient toute la largeur de .page-large
   (1100px), une ligne bien trop longue pour du texte courant. ~70ch est la
   fourchette recommandée (60-75 caractères). Un tableau ou un exemple qui a
   vraiment besoin de plus de place reste libre de déborder (aucune règle
   ici ne l'en empêche, .prose ne contraint que sa propre largeur). */
.prose {
    max-width: 70ch;
    line-height: 1.55;
}

.guide-sommaire {
    font-size: 14px;
    margin: 12px 0 4px;
    color: var(--antiqua-text-muted);
    scroll-margin-top: 16px;
}

.guide-sommaire-titre {
    display: inline;
}

/* Par défaut (mobile, tablette, et desktop en dessous du seuil de la colonne
   latérale ci-dessous) : liste en ligne, séparateurs « · » -- rendu identique
   à l'ancien sommaire texte. */
.guide-sommaire-liste {
    display: inline;
    list-style: none;
    margin: 0;
    padding: 0;
}

.guide-sommaire-liste li {
    display: inline;
}

.guide-sommaire-liste li:not(:last-child)::after {
    content: " · ";
}

/* Réutilisation de l'espace laissé vide de chaque côté du texte sur un grand
   écran (retour de Gwendal du 21/07, capture à l'appui : la colonne de
   lecture à 70ch restait justifiée -- lisibilité -- mais tout l'espace
   libéré autour ne servait à rien, jamais recomposé pour le desktop).
   `.page-large--guide` hérite maintenant directement de `.page-large`
   (1520px, harmonisé le 23/07) pour tenir une vraie colonne de sommaire,
   sans jamais réduire la largeur de la colonne de texte elle-même (toujours
   70ch via .prose). */
@media (min-width: 1200px) {
    .guide-mise-en-page {
        display: grid;
        grid-template-columns: 220px 1fr;
        gap: 40px;
        align-items: start;
    }

    .guide-sommaire {
        position: sticky;
        top: 84px;
        margin: 0;
        max-height: calc(100vh - 104px);
        overflow-y: auto;
    }

    .guide-sommaire-titre {
        display: block;
        margin-bottom: 8px;
        color: var(--antiqua-text);
    }

    .guide-sommaire-liste {
        display: flex;
        flex-direction: column;
        gap: 8px;
    }

    .guide-sommaire-liste li {
        display: block;
    }

    .guide-sommaire-liste li:not(:last-child)::after {
        content: none;
    }

    /* Le bouton de retour flottant n'a plus lieu d'être : le sommaire reste
       visible en permanence dans sa colonne fixe. */
    .bouton-sommaire-flottant {
        display: none !important;
    }
}

/* Bouton flottant vers le sommaire (P2.2, audit UX/UI du 19/07) : les
   guides les plus longs (jusqu'à 8275px sur mobile) n'avaient aucun moyen
   rapide d'y revenir sans tout remonter à la main. Desktop : le sommaire
   inline suffit, pas besoin du bouton flottant. */
.bouton-sommaire-flottant {
    display: none;
}

@media (max-width: 767px) {
    .bouton-sommaire-flottant {
        display: inline-flex;
        position: fixed;
        bottom: 16px;
        right: 16px;
        z-index: 25;
        background-color: var(--antiqua-accent-dark);
        color: #fff;
        padding: 10px 16px;
        border-radius: 999px;
        text-decoration: none;
        font-size: 13px;
        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
    }
}

/* Présentation visuelle du cycle de vie d'une parcelle (guide, section
   "Comprendre les parcelles" -- retour bêta de Shirasda) : une simple rangée
   d'étapes plutôt qu'un schéma, cohérente avec la sobriété du reste du site.
   role="img" + aria-label portent la description complète pour les lecteurs
   d'écran ; les flèches et étapes elles-mêmes sont décoratives. */
.cycle-parcelle {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 4px;
    margin: 12px 0;
}

.cycle-etape {
    padding: 6px 12px;
    border-radius: 999px;
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    font-size: 13px;
    font-weight: 600;
    white-space: nowrap;
}

.cycle-etape--alerte {
    background-color: color-mix(in srgb, var(--palette-terre-cuite) 18%, var(--antiqua-panel));
    border-color: var(--palette-terre-cuite);
}

.cycle-fleche {
    color: var(--antiqua-text-muted);
    font-size: 14px;
}

/* Petites captures recadrées du guide (npm run guide:captures, voir
   docs/GUIDE-MAINTENANCE.md) : jamais l'explication principale, seulement de
   quoi savoir où regarder ou cliquer -- d'où une largeur volontairement
   modeste plutôt qu'une image pleine largeur. */
.guide-capture {
    margin: 12px 0;
    text-align: center;
}

.guide-capture img {
    max-width: min(360px, 100%);
    width: 100%;
    height: auto;
    border: 1px solid var(--antiqua-border);
    border-radius: 8px;
    box-shadow: 0 2px 8px rgba(58, 47, 30, 0.12);
}

.guide-capture figcaption {
    font-size: 12px;
    color: var(--antiqua-text-muted);
    margin-top: 6px;
}

/* Vignettes illustratives du Guide (lot d'assets du 25/07) : distinctes des
   captures d'écran ci-dessus (.guide-capture, cadrées/ombrées comme une
   photo d'interface) -- ces illustrations n'ont jamais de cadre, l'image
   entière est montrée telle quelle (object-fit:contain, consignes du lot).
   Flottent à côté du texte sur les largeurs qui le permettent ; empilées en
   dessous du texte sous 700px pour ne jamais couper une phrase en deux. */
.guide-vignette {
    max-width: 240px;
    width: 100%;
    height: auto;
    object-fit: contain;
    margin: 4px auto 12px;
    display: block;
}

@media (min-width: 700px) {
    .guide-vignette--droite {
        float: right;
        margin: 4px 0 12px 24px;
    }

    .guide-vignette--gauche {
        float: left;
        margin: 4px 24px 12px 0;
    }
}

/* Issue #65 (29/07) : 525 px morts à droite du guide, mesurés en production à
   1920 px (conteneur 1472, grille 220|1212, colonne de lecture 687). Plus du
   tiers de la largeur utile, et une page longue pour la même raison : les
   vignettes 1024x1024 étaient à l'étroit dans ces 687 px, le texte se pliait
   en colonnes d'environ 420 px autour d'elles pendant que la place attendait
   juste à côté.

   CORRECTIF DU MÊME JOUR, sur retour de Gwendal. La première version suivait
   l'issue à la lettre -- « ce n'est pas la colonne de lecture qu'il faut
   élargir, c'est l'espace à côté qu'il faut employer » -- et sortait les
   vignettes dans la gouttière par une marge négative. Résultat mesuré
   conforme (0 px mort, page raccourcie de 1 318 px), résultat VU mauvais :
   des illustrations décrochées à 200 px de leur texte, qui n'illustrent plus
   rien. « En regard de la section », ce n'était pas ça.

   La consigne de l'issue était une hypothèse, et le rendu l'a démentie. On
   fait donc l'inverse, qui est ce qu'il fallait faire : **la colonne de
   lecture s'élargit jusqu'au bord droit du bloc central**, et les vignettes
   restent HABILLÉES PAR LE TEXTE, à leur place d'origine dans le flux. Le
   flottement d'origine n'a jamais eu besoin d'être remplacé -- il manquait
   seulement de largeur pour respirer.

   Ce que ça coûte, assumé : au-delà de 1200 px la ligne dépasse les ~70
   caractères recommandés (P2.1 de l'audit du 19/07). Les vignettes cassent
   cette longueur là où elles sont, et le décrochage visuel coûtait plus cher
   que la longueur de ligne. */
@media (min-width: 1200px) {
    .page-large--guide .prose {
        max-width: none;
    }

    /* Elles ont enfin la place d'exister : 240 px dans une colonne de 687
       donnaient une vignette-timbre à côté d'un texte à l'étroit. Le texte
       les habille toujours, des deux côtés en alternance -- c'est le rythme
       d'origine, conservé. */
    .page-large--guide .guide-vignette {
        max-width: 340px;
    }

    .page-large--guide .guide-vignette--droite {
        margin: 4px 0 16px 32px;
    }

    .page-large--guide .guide-vignette--gauche {
        margin: 4px 32px 16px 0;
    }
}

/* Aide contextuelle ciblée (retour bêta de Shirasda, /propriete) : distincte
   des textes muets environnants pour signaler qu'elle répond directement à
   une confusion connue, sans reproduire toute la section du guide. */
.fiche-note-delais {
    font-size: 13px;
    color: var(--antiqua-text);
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 8px;
    padding: 10px 12px;
    margin-top: 12px;
}

.table-delais {
    width: 100%;
    border-collapse: collapse;
    margin-top: 8px;
}

.table-delais th, .table-delais td {
    text-align: left;
    padding: 4px 8px 4px 0;
    border-bottom: 1px solid var(--antiqua-border);
    font-size: 13px;
}

.table-delais th {
    color: var(--antiqua-text-muted);
    font-weight: 600;
}

.table-delais tr:last-child td {
    border-bottom: none;
}

/* Admin (retour du 21/07, même logique que le reste du site) : la liste de
   tuiles du tableau de bord et les longues listes label/valeur (paramètres,
   mesures de bêta) restaient sur une seule colonne étroite, quelle que soit
   la largeur d'écran -- gênant en particulier pour Gwendal, qui édite ces
   pages souvent. */
.grille-admin-dashboard {
    list-style: none;
    margin: 16px 0 0;
    padding: 0;
    display: grid;
    gap: 12px;
}

.carte-admin-section {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    border: 1px solid var(--antiqua-border);
    border-radius: 10px;
    padding: 14px 16px;
    background-color: var(--antiqua-panel);
}

.grille-parametres {
    list-style: none;
    margin: 8px 0;
    padding: 0;
}

@media (min-width: 900px) {
    .grille-admin-dashboard {
        grid-template-columns: repeat(2, 1fr);
    }

    .grille-parametres {
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        gap: 0 24px;
    }
}

/* Sommaire de catégories + recherche + indicateur persistant (Lot 5,
   révision desktop du 22/07) : /admin/parametres atteignait 3495px sans
   point de repère pour naviguer ni savoir si une modification restait à
   enregistrer sans redescendre section par section. Sommaire empilé au-
   dessus du contenu sous 1100px (une colonne fixe latérale n'apporterait
   rien sur un écran étroit) ; devient une vraie colonne fixe au-delà. */
.admin-parametres-sommaire {
    margin-bottom: 20px;
    padding: 14px 16px;
    border: 1px solid var(--antiqua-border);
    border-radius: 10px;
    background-color: var(--antiqua-panel);
}

.admin-parametres-sommaire nav ul {
    list-style: none;
    margin: 8px 0 0;
    padding: 0;
}

.admin-parametres-sommaire nav li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 4px 0;
}

.admin-parametres-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    padding: 1px 5px;
    border-radius: 999px;
    background-color: var(--antiqua-danger);
    color: #fff;
    font-size: 11px;
}

.parametres-ligne-masquee {
    display: none;
}

.admin-parametres-resume-total {
    margin: 12px 0 0;
    padding-top: 10px;
    border-top: 1px solid var(--antiqua-border);
    font-size: 13px;
    color: var(--antiqua-danger);
    font-weight: 600;
}

@media (min-width: 1100px) {
    .admin-parametres-mise-en-page {
        display: flex;
        align-items: flex-start;
        gap: 24px;
    }

    .admin-parametres-sommaire {
        flex: 0 0 220px;
        position: sticky;
        /* 71px = hauteur réelle de .nav-admin (mesurée), elle-même sticky à
           top:0 juste au-dessus -- même valeur que .admin-joueurs-filtre. */
        top: 71px;
        margin-bottom: 0;
    }

    .admin-parametres-contenu {
        flex: 1;
        min-width: 0;
    }
}

/* Chronique des Anciens : grille de cartes plutôt qu'une colonne unique
   (retour du 21/07 -- cette liste s'allonge indéfiniment au fil des morts et
   n'avait jusque-là aucun traitement de largeur particulier). */
.grille-chronique {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
    list-style: none;
    margin: 24px 0 0;
    padding: 0;
}

.carte-epitaphe {
    display: block;
    padding: 14px 16px;
    border: 1px solid var(--antiqua-border);
    border-radius: 10px;
    background-color: var(--antiqua-panel);
}

.carte-epitaphe-texte {
    margin: 0;
    font-style: italic;
}

.carte-epitaphe-date {
    margin: 8px 0 0;
    font-size: 12px;
    color: var(--antiqua-text-muted);
}

/* Corps de la page Temple plus large que le .page-large générique (1100px) --
   même largeur que .tableau-bord-accueil (1520px), pour le confort de lecture
   sur cette page à deux colonnes. N'a plus de lien avec la bannière depuis le
   passage de celle-ci en .page-hero (22/07) : elle est désormais pleine
   largeur (100vw) et ne sert plus de référence de largeur au contenu. */
.page-large--temple {
    max-width: 1520px;
}

/* Recomposition du Temple (Lot 2, 24/07) : la Chronique des Anciens (mémoire
   des morts) et le jeu du passage (senet) étaient empilés en une seule
   colonne malgré la largeur de 1520px -- le senet, contenu le plus dense et
   le plus actif de la page, restait à l'étroit dans la même colonne que la
   liste d'épitaphes. 1/3-2/3 à partir de 1200px (la Chronique, plus courte,
   n'a pas besoin d'autant de place que le plateau) ; empilés en dessous,
   avec la même frise qu'avant comme séparateur puisque la grille perd son
   sens en une seule colonne. */
.temple-layout {
    display: flex;
    flex-direction: column;
    gap: 32px;
}

.temple-layout > .temple-chronique::after {
    content: '';
    display: block;
    height: 16px;
    margin: 28px auto 0;
    max-width: 840px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='16' viewBox='0 0 20 16'%3E%3Cpath d='M0 16 L0 4 L4 4 L4 12 L12 12 L12 4 L16 4 L16 16' fill='none' stroke='%238a6a3f' stroke-width='2'/%3E%3C/svg%3E");
    background-repeat: repeat-x;
    background-position: center;
    opacity: 0.45;
}

@media (min-width: 1200px) {
    .temple-layout {
        display: grid;
        grid-template-columns: 1fr 2fr;
        align-items: start;
        gap: 40px;
    }

    .temple-layout > .temple-chronique::after {
        content: none;
    }
}

/* Place pour le sommaire de catégories latéral (Lot 5, révision desktop
   du 22/07) -- sinon le sommaire (220px) grignote la largeur déjà limitée
   du contenu à deux colonnes. */
.page-large--parametres {
    max-width: 1520px;
}

/* La manoeuvre est une grille tactique, pas du texte : le panneau d'actions
   (300px), le plateau (12 cases de 44px + marge, ~570px) et la fiche
   d'unité (280px) tiennent mal dans les 1100px génériques de .page-large
   sur grand écran (retour du 20/07 : "colonnes vides sur les côtés").
   Voir .maneuver-plateau-layout pour la disposition en trois colonnes. */
.page-large--maneuver {
    max-width: 1600px;
}

@media (min-width: 880px) {
    .page-large.deux-colonnes,
    .bloc-tableau-bord.deux-colonnes {
        display: grid;
        grid-template-columns: minmax(300px, 380px) 1fr;
        align-items: start;
        gap: 28px;
    }

    .page-large.deux-colonnes-egales {
        display: grid;
        grid-template-columns: 1fr 1fr;
        align-items: start;
        gap: 28px;
    }
}

/* Recomposition de l'Accueil (Lot 2, 23/07, retour de ChatGPT sur l'audit
   du 22/07) : Nouveautés (annonces) intégrées à la grille plutôt qu'en
   bloc plein largeur séparé au-dessus -- 2/3 annonces + 1/3 "depuis ta
   dernière visite" en première rangée (ce qui a changé pendant ton absence,
   le plus large car le plus narratif), état du personnage + zone en
   coup d'œil en deuxième rangée (où tu en es, ce que tu peux faire). Grille
   à 6 colonnes en desktop pour permettre le ratio 2/3-1/3 en rangée 1 tout
   en gardant une moitié-moitié stricte en rangée 2 (spans entiers). */
.tableau-bord-accueil {
    max-width: 1520px;
    display: grid;
    gap: 24px;
    grid-template-columns: 1fr;
    grid-template-areas:
        "annonces"
        "journal"
        "etat"
        "zone";
}

@media (min-width: 768px) and (max-width: 1199px) {
    .tableau-bord-accueil {
        grid-template-columns: 1fr 1fr;
        grid-template-areas:
            "annonces annonces"
            "journal journal"
            "etat zone";
    }
}

@media (min-width: 1200px) {
    .tableau-bord-accueil {
        grid-template-columns: repeat(6, 1fr);
        grid-template-areas:
            "annonces annonces annonces annonces journal journal"
            "etat etat etat zone zone zone";
    }
}

.tableau-bord-accueil .bloc-annonces { grid-area: annonces; }
.tableau-bord-accueil .bloc-etat { grid-area: etat; }
.tableau-bord-accueil .bloc-zone { grid-area: zone; }
.tableau-bord-accueil .bloc-journal { grid-area: journal; }

.bloc-tableau-bord {
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 10px;
    padding: 20px 24px;
    box-shadow: 0 2px 10px rgba(58, 47, 30, 0.08);
}

/* Bloc « Nouveautés » : même carte que le tableau de bord, mais posée dans
   la grille de l'Accueil (voir .tableau-bord-accueil .bloc-annonces
   ci-dessus) plutôt qu'en bloc plein largeur séparé. */
.bloc-annonces {
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 10px;
    padding: 20px 24px;
    box-shadow: 0 2px 10px rgba(58, 47, 30, 0.08);
}

.bloc-annonces .annonce + .annonce {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--antiqua-border);
}

.bloc-journal--vide {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 20px 24px;
    background-color: transparent;
    border-style: dashed;
    box-shadow: none;
    text-align: center;
}

.journal-vide-titre {
    margin: 0;
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--antiqua-text-muted);
}

.journal-vide-message {
    margin: 0;
    color: var(--antiqua-text-muted);
}

/* État vide générique (P2.3, audit UX/UI du 19/07) : même patron discret
   que .bloc-journal--vide (Accueil), réutilisable hors d'une carte
   .bloc-tableau-bord -- chronique, marché, etc. */
.etat-vide {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 20px 24px;
    border: 1px dashed var(--antiqua-border);
    border-radius: 10px;
    text-align: center;
}

/* Illustrations d'état vide (lot d'assets du 25/07) : 120-220px conseillé par
   les consignes d'intégration, opacité réduite pour rester discrète (jamais
   une pièce maîtresse de l'écran -- ce bloc reste avant tout un message). */
.etat-vide-illustration {
    width: auto;
    height: 140px;
    max-width: 100%;
    object-fit: contain;
    opacity: 0.85;
    margin-bottom: 4px;
}

/* P0.2 (audit UX/UI du 19/07) : sous 768px, priorité à ce que le joueur doit
   comprendre puis faire avant la profondeur du système -- fiche vitale (avec
   l'alerte de famine), ressources/Manger tout de suite après (l'action que
   l'alerte réclame), puis histoire et savoir-faire, illustration/stats en
   dernier.

   Correctif du 20/07 : une première version utilisait un seul grid à 8 zones
   avec grid-template-areas partagé entre les 3 colonnes -- les lignes de
   grille étant globales, le bloc Savoir-faire (très long) forçait un
   alignement qui laissait un vide énorme sous Statistiques en desktop
   (colonnes qui ne sont plus vraiment indépendantes dès qu'elles partagent
   des lignes). Remplacé par la technique display:contents : les 3 colonnes
   d'origine (identite/centre/droite) redeviennent de vrais conteneurs
   indépendants (flex-direction:column, hauteur libre) à partir de 768px ;
   en dessous, elles s'effacent (display:contents) et les 8 zones qu'elles
   contiennent deviennent des éléments directs du grid, réordonnées
   individuellement -- sans jamais dupliquer le contenu. */
.tableau-personnage {
    max-width: 1520px;
    display: grid;
    gap: 24px;
    grid-template-columns: 1fr;
}

.tableau-personnage .colonne-identite,
.tableau-personnage .colonne-centre,
.tableau-personnage .colonne-droite {
    display: contents;
}

.tableau-personnage .zone-fiche { order: 1; }
.tableau-personnage .zone-ressources { order: 2; }
.tableau-personnage .zone-histoire { order: 3; }
.tableau-personnage .zone-specialisation { order: 4; }
.tableau-personnage .zone-savoir-faire { order: 5; }
.tableau-personnage .zone-jets { order: 6; }
.tableau-personnage .zone-illustration { order: 7; }
.tableau-personnage .zone-stats { order: 8; }

@media (min-width: 768px) {
    /* Au-delà du mobile, les colonnes redeviennent de vrais conteneurs :
       l'ordre mobile ci-dessus ne doit plus s'appliquer (chaque colonne
       reprend l'ordre naturel de ses propres zones). */
    .tableau-personnage .zone-fiche,
    .tableau-personnage .zone-ressources,
    .tableau-personnage .zone-histoire,
    .tableau-personnage .zone-specialisation,
    .tableau-personnage .zone-savoir-faire,
    .tableau-personnage .zone-jets,
    .tableau-personnage .zone-illustration,
    .tableau-personnage .zone-stats {
        order: initial;
    }

    .tableau-personnage .colonne-identite,
    .tableau-personnage .colonne-centre,
    .tableau-personnage .colonne-droite {
        display: flex;
        flex-direction: column;
        gap: 24px;
    }
}

@media (min-width: 768px) and (max-width: 1199px) {
    .tableau-personnage {
        grid-template-columns: 1fr 1fr;
        grid-template-areas:
            "identite centre"
            "droite   droite";
    }
}

@media (min-width: 1200px) {
    .tableau-personnage {
        grid-template-columns: repeat(3, 1fr);
        grid-template-areas: "identite centre droite";
    }
}

.tableau-personnage .colonne-identite { grid-area: identite; }
.tableau-personnage .colonne-centre { grid-area: centre; }
.tableau-personnage .colonne-droite { grid-area: droite; }

.illustration-personnage {
    width: 100%;
    aspect-ratio: 16 / 9;
    background-size: cover;
    background-position: center;
    border-radius: 10px;
    border: 1px solid var(--antiqua-border);
    box-shadow: 0 2px 10px rgba(58, 47, 30, 0.08);
    margin-bottom: 16px;
}

.illustration-etat {
    width: 100%;
    aspect-ratio: 4 / 3;
    background-size: cover;
    background-position: center;
    border-radius: 10px;
    border: 1px solid var(--antiqua-border);
    box-shadow: 0 2px 10px rgba(58, 47, 30, 0.08);
    margin-bottom: 16px;
}

/* Propriété sans terre : l'illustration pleine largeur reléguait le message
   essentiel sous le pli — moitié de taille, sous le texte. */
.illustration-etat--compacte {
    max-width: 400px;
    margin: 16px 0 0;
}

/* Refonte "Chez moi" (D-030, sous-lot 1 ; recomposition desktop Lot 2, 24/07 ;
   fusion des ateliers dans les terres, issue #16, 26/07) : TROIS sections,
   chacune sa propre carte. "Mes terres et bâtiments" garde sa pleine largeur
   (elle a déjà sa propre mise en page à deux colonnes au-delà de 880px,
   .terres-layout -- la rétrécir dans une cellule de grille l'écraserait) ;
   "Mon abri"
   (purement visuel, contenu court) et "Mes biens" (liste) se partagent la
   première rangée en 1/3-2/3 à partir de 1200px, plutôt qu'empilés sans
   raison sur un écran large (retour sur l'usage de la largeur desktop). */
.chez-moi-sections {
    display: grid;
    gap: 24px;
    grid-template-columns: 1fr;
    grid-template-areas:
        "abri"
        "biens"
        "terres";
}

/* Repli pour toute section n'ayant pas d'aire nommée : pleine largeur.
   Sans lui, une section ajoutée sans penser à la grille est placée
   automatiquement dans une cellule libre -- c'est-à-dire un TIERS de large
   sur desktop, en dessous de tout (bévue réelle de l'issue #7 : « Ma terre en
   cours de mise en valeur » y a passé une journée). Les règles nommées
   ci-dessous l'emportent sur ce repli. */
.chez-moi-sections > * {
    grid-column: 1 / -1;
}

@media (min-width: 768px) and (max-width: 1199px) {
    .chez-moi-sections {
        grid-template-columns: 1fr 1fr;
        grid-template-areas:
            "abri biens"
            "terres terres";
    }
}

@media (min-width: 1200px) {
    .chez-moi-sections {
        grid-template-columns: repeat(3, 1fr);
        grid-template-areas:
            "abri biens biens"
            "terres terres terres";
    }
}

.chez-moi-sections .bloc-abri { grid-area: abri; }
.chez-moi-sections .bloc-biens { grid-area: biens; }
.chez-moi-sections .bloc-terres { grid-area: terres; }

/* Mon abri : composition VERTICALE (issue #14, 26/07). La carte occupe déjà
   un tiers de la première rangée sur desktop ; la redécouper en deux colonnes
   à l'intérieur donnait une illustration trop petite pour être regardée et un
   texte comprimé sur huit lignes -- deux divisions successives de la même
   largeur. L'image prend maintenant toute la largeur utile, le texte et le
   sommeil se lisent dessous, à toutes les tailles d'écran. */
.bloc-abri-contenu {
    display: flex;
    flex-direction: column;
    gap: 14px;
}

/* Ratio plus panoramique que le 4/3 des illustrations d'état : à pleine
   largeur de carte, un 4/3 poussait les commandes de sommeil sous le pli en
   1440x900. Ratio FIXE (jamais dépendant de la largeur) + `cover` : le
   cadrage est le même partout, seule l'échelle change. */
.bloc-abri-illustration {
    aspect-ratio: 3 / 2;
    margin: 0;
}

.bloc-abri-texte {
    margin: 0;
}

.bloc-abri-lien-guide {
    font-size: 12px;
    margin: 8px 0 0;
}

/* Aperçu de la conversion en boulangerie (confirmation du lancement de
   chantier, "Mes ateliers") : réutilise l'asset bakery_complete déjà livré
   avec un traitement de projection -- jamais un cinquième fichier "fantôme".
   Voile de transparence + désaturation légère, bordure en tirets comme
   l'ancien repli d'illustration manquante (même intention : signaler "ceci
   n'existe pas encore réellement"). */
.illustration-projetee {
    opacity: 0.55;
    filter: grayscale(35%) saturate(80%);
    border-style: dashed;
}

/* Mes terres et bâtiments : même répartition à deux colonnes qu'avant la
   refonte (voir .page-large.deux-colonnes / .bloc-tableau-bord.deux-colonnes
   ci-dessus), portée ici par un conteneur dédié puisque la section entière
   vit maintenant dans sa propre carte .bloc-tableau-bord. */
@media (min-width: 880px) {
    .terres-layout.deux-colonnes {
        display: grid;
        grid-template-columns: minmax(300px, 380px) 1fr;
        align-items: start;
        gap: 28px;
    }
}

/* Page Parcelle (issue #21, 26/07) : l'illustration de la case à gauche, la
   colonne d'information à droite -- même répartition que .terres-layout, mais
   portée par un conteneur qui ENVELOPPE les cartes existantes au lieu de
   vivre dedans. Chaque carte garde ainsi son .bloc-tableau-bord, son fond et
   sa bordure ; l'image se pose à côté, pas sur le papier.

   La colonne de droite prend TOUT le reste de la page (synthèse, conditions,
   action, activité récente), pas seulement la première carte : en face de la
   seule synthèse -- trois lignes de texte --, l'image laissait un vide de
   130px de haut sur toute la largeur restante en 1440.

   Le grand écran est la cible de l'issue ; en dessous de 880px la grille
   retombe en pile, et l'illustration est bornée juste en dessous -- un 4:3
   pleine largeur ferait un mur de 660px de haut à 879px de large. */
@media (min-width: 880px) {
    .parcelle-entete {
        display: grid;
        grid-template-columns: minmax(300px, 380px) 1fr;
        align-items: start;
        gap: 28px;
    }
}

@media (max-width: 879px) {
    .illustration-parcelle {
        max-width: 420px;
    }
}

/* Projet foncier : la colonne d'action ne porte que quelques lignes de prose.
   Étalée sur toute la largeur de la carte, la mesure dépassait 130 caractères
   -- illisible. On la borne, quitte à laisser de l'air à droite : une ligne
   confortable vaut mieux qu'une colonne remplie. */
.bloc-projet-foncier .colonne-inventaire {
    max-width: 760px;
}

/* « <Cité> en un coup d'œil » (issue #17, lot 1, 26/07) : un bloc qui INFORME
   et ne porte aucun formulaire. Quatre signaux courts, en colonnes sur
   desktop pour qu'ils se lisent d'un balayage plutôt qu'en liste verticale
   qui rallongerait encore la page. */
.zone-synthese {
    max-width: 1100px;
    margin: 0 auto 24px;
}

.zone-synthese-liste {
    list-style: none;
    margin: 8px 0 0;
    padding: 0;
    display: grid;
    gap: 8px 24px;
    grid-template-columns: 1fr;
    font-size: 14px;
    color: var(--antiqua-text-muted);
}

/* La règle globale sur `li` est un flex à `space-between` (pensée pour les
   lignes « libellé — action » des inventaires) : elle écartelait « 5 / 5 cases
   occupées » et « — 5 exploitations actives » aux deux bouts de la colonne.
   Ici, une ligne de synthèse est une PHRASE, pas deux colonnes. */
.zone-synthese-liste li {
    display: block;
    padding: 6px 0;
}

@media (min-width: 760px) {
    .zone-synthese-liste {
        grid-template-columns: 1fr 1fr;
    }
}

/* `.ateliers-layout` a disparu avec la section « Mes ateliers » (issue #16,
   26/07) : l'occupation bâtie d'une case se rend désormais dans la section
   des terres, donc avec `.terres-layout.deux-colonnes` -- une seule règle de
   répartition pour une seule notion, au lieu de deux règles jumelles. */

.banniere-page {
    box-sizing: border-box;
    width: 100%;
    max-width: 1100px;
    height: 280px;
    margin: 16px auto 24px;
    border-radius: 10px;
    background-size: cover;
    background-position: center;
    border: 1px solid var(--antiqua-border);
    box-shadow: 0 2px 10px rgba(58, 47, 30, 0.1);
}

.fiche-perso {
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 10px;
    padding: 20px 24px;
    margin: 16px auto;
    box-shadow: 0 2px 10px rgba(58, 47, 30, 0.08);
}

.fiche-perso-entete {
    display: flex;
    align-items: center;
    gap: 18px;
    margin-bottom: 18px;
}

.fiche-perso-entete h1 {
    margin: 0 0 4px;
}

.avatar {
    width: 72px;
    height: 72px;
    border-radius: 50%;
    overflow: hidden;
    border: 2px solid var(--antiqua-accent-dark);
    flex-shrink: 0;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    background-color: var(--antiqua-panel);
}

.banniere {
    box-sizing: border-box;
    width: 100%;
    max-width: 840px;
    height: 220px;
    margin: 16px auto 24px;
    border-radius: 10px;
    background-size: cover;
    background-position: center;
    border: 1px solid var(--antiqua-border);
    box-shadow: 0 2px 10px rgba(58, 47, 30, 0.1);
}

/* Modificateur pour les bannières servies en <picture>/<img> (WebP + repli PNG)
   plutôt qu'en div à background-image -- .banniere/.banniere-page restent
   inchangées pour les pages qui utilisent encore l'ancienne approche
   (inscription, zone). Remplace la hauteur fixe par un ratio d'aspect
   qui s'adapte à la largeur réelle de l'image. */
.banniere-media {
    display: block;
    height: auto;
}

.banniere-media img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 1;
    object-fit: cover;
    object-position: center;
    border-radius: 10px;
}

@media (max-width: 700px) {
    .banniere-media img {
        aspect-ratio: 16 / 7;
    }
}

/* Bannières hero pleine largeur (lot "bannieres-retenues-v1", 22/07) --
   remplace l'ancien .accueil-hero (contenu dans la largeur éditoriale,
   3:1, recadré) par le patron demandé pour ce nouveau lot d'images,
   livrées nativement en 1920×480 (4:1) comme bandeau panoramique complet,
   à ne jamais recadrer sur ordinateur (voir GUIDE-INTEGRATION.md fourni
   avec les assets). Sort volontairement de tout conteneur éditorial via
   100vw/-50vw ; seul le texte superposé reste recentré sur une largeur de
   lecture (.page-hero__content). */
.page-hero {
    position: relative;
    box-sizing: border-box;
    /* Défait `body > *:not(nav) { max-width:840px; margin:0 auto; padding:0 24px }`
       (règle générique de mise en page, plus haut dans ce fichier) qui
       s'appliquait sinon à ce <header> comme à n'importe quel autre enfant
       direct de <body> -- constatée en vérifiant les styles calculés après
       un rendu à 1920px qui donnait un bandeau de 840px avec 24px de marge
       intérieure au lieu du plein écran. */
    max-width: none;
    width: 100vw;
    margin: 16px 0 24px calc(50% - 50vw);
    padding: 0;
    aspect-ratio: 4 / 1;
    overflow: hidden;
    background-color: var(--antiqua-accent);
}

/* Banniere Marche et Chronique (lot d'assets du 25/07 x2) : livrees en
   2560x700 (~3.66:1), pas le 4:1 natif du lot precedent -- aspect-ratio
   propre pour eviter les bandes vides que produirait object-fit:contain
   dans un cadre 4:1. */
.page-hero--marche,
.page-hero--chronique {
    aspect-ratio: 2560 / 700;
}

.page-hero__image {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.page-hero__overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: flex-end;
    pointer-events: none;
    background: linear-gradient(to top, rgba(40, 27, 14, 0.42) 0%, rgba(40, 27, 14, 0.1) 42%, transparent 70%);
}

/* Aligné sur la largeur réelle du contenu de chaque page (retour de ChatGPT
   sur l'audit du 22/07 ; toutes les pages à Hero partagent maintenant la
   même largeur -- 23/07, .page-large harmonisée à 1520px).
   Corrigé le 25/07 (retour de Gwendal, constaté sur toutes les pages à Hero,
   pas seulement les plus récentes) : `width: min(100% - 2rem, 1520px)` sans
   padding donnait un bord gauche à 16px du viewport en dessous de 1568px de
   large, alors que .page-large (max-width 1520px + padding 24px, hérité de
   `body > *:not(nav)`) place son propre contenu à 24px -- 8px d'écart entre
   le titre et le bloc en dessous sur toutes les largeurs d'écran usuelles.
   Même formule que .page-large (max-width + padding-inline, box-sizing
   border-box global) au lieu de soustraire une marge à la largeur :
   garantit un bord gauche identique à n'importe quelle largeur. */
.page-hero__content {
    width: 100%;
    max-width: 1520px;
    margin-inline: auto;
    padding-inline: 24px;
    padding-block: 1.25rem;
    color: #fff;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.55);
}

.page-hero__content h1 {
    margin: 0 0 8px;
    color: inherit;
}

.page-hero__content .titre-encre path {
    stroke: #fff;
}

.page-hero__content p {
    margin: 0;
    max-width: 640px;
    font-size: 15px;
    color: inherit;
}

.page-hero__content a {
    color: var(--antiqua-accent);
}

/* Sous 768px, un panorama 4:1 complet devient trop bas pour rester lisible
   -- recadrage contrôlé (hauteur bornée, object-position choisi par page
   pour garder le sujet principal plutôt que le centre géométrique). */
@media (max-width: 767px) {
    .page-hero {
        width: 100%;
        margin-left: 0;
        aspect-ratio: auto;
        height: clamp(180px, 36vw, 260px);
    }

    .page-hero__image {
        object-fit: cover;
        object-position: center;
    }

    .page-hero__content {
        padding-block: 0.75rem;
    }

    /* Sans ça, un titre qui passe sur deux lignes à cette largeur (ex. "Le
       Temple garde les noms") dépasse la hauteur bornée du bandeau et se
       fait couper en haut par l'overflow:hidden -- constaté par capture. */
    .page-hero__content h1 {
        font-size: 24px;
        padding-bottom: 6px;
    }

    .page-hero__content p {
        font-size: 13px;
    }
}

.icone-ressource {
    width: 40px;
    height: 40px;
    border-radius: 6px;
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    flex-shrink: 0;
}

.icone-ressource-inline {
    position: relative;
    display: inline-flex;
    width: 56px;
    height: 56px;
    border-radius: 8px;
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    vertical-align: middle;
    flex-shrink: 0;
}

.icone-ressource-inline .badge-quantite {
    position: absolute;
    bottom: -6px;
    right: -8px;
    min-width: 20px;
    padding: 2px 6px;
    border-radius: 10px;
    border: 1px solid var(--antiqua-bg);
    background-color: var(--antiqua-accent-dark);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    line-height: 1.4;
    text-align: center;
}

.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
    gap: 10px;
    margin-bottom: 20px;
}

.stat-tooltip {
    position: relative;
    background-color: var(--antiqua-bg);
    border: 1px solid var(--antiqua-border);
    border-radius: 6px;
    padding: 8px 10px;
    cursor: help;
    text-align: center;
}

.stat-label {
    display: block;
    font-size: 12px;
    color: var(--antiqua-text-muted);
    letter-spacing: 1px;
}

.stat-valeur {
    display: block;
    font-size: 20px;
    color: var(--antiqua-text);
}

.tooltip-text {
    visibility: hidden;
    opacity: 0;
    position: absolute;
    bottom: 105%;
    left: 50%;
    transform: translateX(-50%);
    background-color: var(--antiqua-header-bg);
    color: var(--antiqua-header-text);
    padding: 8px 12px;
    border-radius: 6px;
    font-size: 12px;
    width: 200px;
    line-height: 1.4;
    transition: opacity 0.15s ease;
    z-index: 10;
    pointer-events: none;
}

/* Parité clavier (audit UX/UI du 19/07, P24) : ces info-bulles ne
   s'ouvraient qu'au survol -- invisibles au clavier (les <div>/<li> qui
   les portent n'étaient pas focusables). tabindex="0" ajouté sur ces
   éléments dans les gabarits ; :focus-within couvre aussi .stat-tooltip
   quand il enveloppe un vrai bouton (ex. "Manger") plutôt qu'un tabindex
   direct. Un `title` dupliquant le texte est aussi posé dans les gabarits
   pour les lecteurs d'écran, indépendamment de cette bascule visuelle. */
.stat-tooltip:hover .tooltip-text,
.stat-tooltip:focus .tooltip-text,
.stat-tooltip:focus-within .tooltip-text,
.jauge-tooltip:hover .tooltip-text,
.jauge-tooltip:focus .tooltip-text,
.savoir-faire-item:hover .tooltip-text,
.savoir-faire-item:focus .tooltip-text,
.libelle-info:hover .tooltip-text,
.libelle-info:focus .tooltip-text {
    visibility: visible;
    opacity: 1;
}

/* Savoir-faire (P1 Lot 1). */
.fiche-perso-titre-repliable {
    font-family: Georgia, "Times New Roman", serif;
    font-size: 22px;
    color: var(--antiqua-text);
    cursor: pointer;
    margin-bottom: 8px;
}

/* Réponses d'une prise de parole repliées par défaut (retour de Gwendal du
   20/07) : un fil très répondu transformait la colonne de Place publique en
   défilement sans fin. */
.liste-reponses-repliable summary {
    cursor: pointer;
    font-size: 13px;
    color: var(--antiqua-text-muted);
}

/* Indicateur "nouveau depuis ton dernier passage" (retour de Gwendal du
   21/07, Place publique) : ton or plutôt que le vert de .badge-a-toi
   (« à toi de jouer ») -- signale un contenu à découvrir, pas une action
   requise. Réutilisable partout où ce même besoin se représente. */
.badge-nouveau {
    display: inline-block;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    padding: 1px 7px;
    border-radius: 999px;
    border: 1px solid var(--palette-or-vieilli);
    background-color: rgba(182, 138, 69, 0.16);
    color: var(--antiqua-text);
    vertical-align: middle;
}

/* Repère visuel discret sur chaque réponse nouvelle, une fois le fil déplié
   (le badge du <summary> suffit replié -- voir .liste-reponses-repliable
   summary ci-dessus). */
.reponse-nouvelle {
    border-left: 2px solid var(--palette-or-vieilli);
    padding-left: 8px;
}

/* Journal social (P1.3/audit UX/UI du 19/07) : la règle générique
   li{display:flex;justify-content:space-between} (pensée pour les listes
   formulaire/valeur) espaçait le texte de façon illisible sur une liste de
   lecture courante -- repasse en alignement à gauche, heure dans une
   colonne stable à droite plutôt qu'écartée par le space-between. */
.liste-journal li {
    display: flex;
    justify-content: flex-start;
    align-items: baseline;
    gap: 10px;
    text-align: left;
}

.liste-journal-heure {
    flex-shrink: 0;
    margin-left: auto;
    white-space: nowrap;
    font-size: 12px;
    color: var(--antiqua-text-muted);
}

/* Domaines de savoir-faire repliés par défaut (audit UX/UI du 19/07) :
   résumé (nombre, meilleure compétence) visible même fermé, pour ne pas
   perdre l'information en repliant. */
.savoir-faire-domaine {
    margin-bottom: 10px;
}

.savoir-faire-domaine summary {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 4px 12px;
    cursor: pointer;
}

.savoir-faire-domaine summary h3 {
    margin: 0;
}

.savoir-faire-domaine-resume {
    font-size: 12px;
    color: var(--antiqua-text-muted);
    white-space: nowrap;
}

.liste-savoir-faire {
    list-style: none;
    margin: 0 0 16px;
    padding: 0;
    display: grid;
    gap: 6px;
}

.savoir-faire-item {
    position: relative;
    cursor: help;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    padding: 6px 10px;
    border: 1px solid var(--antiqua-border);
    border-radius: 6px;
    background-color: var(--antiqua-bg);
}

.savoir-faire-score {
    font-size: 12px;
    color: var(--antiqua-text-muted);
    white-space: nowrap;
}

.libelle-info {
    position: relative;
    display: inline-block;
    cursor: help;
    border-bottom: 1px dotted var(--antiqua-text-muted);
}

.libelle-info .tooltip-text {
    bottom: auto;
    top: 100%;
    left: 0;
    transform: none;
    margin-top: 6px;
}


@media (max-width: 600px) {
    .tooltip-text {
        width: 120px;
    }
}

/* Liste des bâtisseurs du monument (25/07) : une énumération de noms est
   illisible dans les 200px (120px en mobile) de .tooltip-text, taillés pour
   une phrase d'explication. Sélecteur à deux classes pour l'emporter sur la
   media query ci-dessus quelle que soit la position dans le fichier. */
.tooltip-text.tooltip-batisseurs {
    width: 260px;
}

@media (max-width: 600px) {
    .tooltip-text.tooltip-batisseurs {
        width: 190px;
    }
}

.jauge-bloc {
    margin-bottom: 14px;
}

.jauge-tooltip {
    position: relative;
    display: flex;
    justify-content: space-between;
    cursor: help;
    font-size: 14px;
    margin-bottom: 4px;
}

.jauge {
    height: 10px;
    background-color: var(--antiqua-bg);
    border: 1px solid var(--antiqua-border);
    border-radius: 5px;
    overflow: hidden;
}

.jauge-remplissage {
    height: 100%;
    border-radius: 5px;
}

.jauge-energie {
    background-color: var(--antiqua-accent);
}

.jauge-pv {
    background-color: #639922;
}

.jauge-reputation {
    background-color: #3d7a8c;
}

.section-titre {
    display: flex;
    align-items: center;
    gap: 10px;
}

.section-titre h2 {
    margin: 0;
}

.icone-rond {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background-color: var(--antiqua-bg);
    border: 1px solid var(--antiqua-border);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.icone-rond svg {
    width: 20px;
    height: 20px;
}

.carte-terre {
    display: flex;
    align-items: center;
    gap: 12px;
}

/* Carte de parcelle (Zone) : le <li> global est un flex horizontal, ce qui
   écrasait titre, conditions et bouton sur une seule ligne chaotique --
   ici la carte s'empile : entête (icône + titre + action), puis conditions. */
li.carte-parcelle {
    display: block;
}

/* Ressource possédée (fiche personnage) : même souci que carte-parcelle --
   le <li> global écrasait icône/nom et actions (Manger, Mettre en vente)
   sur une seule ligne. La carte s'empile : entête, puis actions
   (correctif du 22/07, retour "webdesign moche"). */
li.carte-ressource-possedee {
    display: block;
}

.carte-ressource-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 6px;
}

.carte-terre-action {
    margin-left: auto;
}

/* La carte Violence se distingue des autres actions : fond assombri et
   liseré terracotta -- grave sans être criard (revue design du 18/07). */
.fiche-violence {
    background-color: #f4ead6;
    border-left: 3px solid #993c1d;
}

.carte-terre-icone {
    width: 40px;
    height: 40px;
    border-radius: 6px;
    background-color: #ece0c4;
    border: 1px solid var(--antiqua-border);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.carte-terre-icone svg {
    width: 26px;
    height: 26px;
}

.carte-terre-texte {
    flex-grow: 1;
}

.carte-terre-texte strong {
    display: block;
    font-size: 15px;
}

.barre-progres {
    height: 14px;
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 7px;
    overflow: hidden;
    margin: 6px auto 4px;
    box-shadow: inset 0 1px 3px rgba(58, 47, 30, 0.1);
}

.barre-progres-remplissage {
    height: 100%;
    background-color: var(--antiqua-accent);
    transition: width 0.3s ease;
}

.barre-progres-remplissage.acheve {
    background-color: #639922;
}

.barre-sante {
    height: 8px;
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 4px;
    overflow: hidden;
    margin: 8px auto;
    box-shadow: inset 0 1px 3px rgba(58, 47, 30, 0.1);
}

.barre-sante-remplissage {
    height: 100%;
}

.nav-admin {
    background-color: #1a1410;
}

.badge-admin {
    background-color: var(--antiqua-accent-dark);
    color: var(--antiqua-header-text);
    font-size: 11px;
    letter-spacing: 1px;
    text-transform: uppercase;
    padding: 3px 8px;
    border-radius: 4px;
}

/* Admin Joueurs : filtre fixe pendant le défilement (Lot 5, révision
   desktop du 22/07) -- l'action la plus fréquente sur une page de
   plusieurs dizaines de lignes ne devrait jamais nécessiter de remonter.
   71px correspond à la hauteur réelle de .nav-admin (mesurée, ~70,4px),
   elle-même sticky à top:0 juste au-dessus. */
.admin-joueurs-filtre {
    position: sticky;
    top: 71px;
    z-index: 10;
    background-color: var(--antiqua-panel);
}

/* Tables denses admin (Lot 5, révision desktop du 22/07) : Admin Joueurs
   remplace le mur de cartes (3830px pour 25 comptes dans l'audit) par une
   vraie table -- Compte/rôle/état/IP/activité toujours visibles, le reste
   (7 groupes de formulaires par ligne dans l'ancienne version) replié dans
   le <details> "Actions" ci-dessous. Admin Ressources partage le même
   patron (icône, identité, valeur, groupe, poids, actions). */
.table-admin-joueurs,
.table-admin-ressources,
.table-caserne {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

.table-admin-joueurs th,
.table-admin-ressources th,
.table-caserne th {
    text-align: left;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--antiqua-text-muted);
    padding: 8px 12px;
    border-bottom: 2px solid var(--antiqua-border);
    white-space: nowrap;
}

.table-admin-joueurs td,
.table-admin-ressources td,
.table-caserne td {
    padding: 10px 12px;
    border-bottom: 1px solid var(--antiqua-border);
    vertical-align: top;
    color: var(--antiqua-text);
}

.admin-joueurs-actions summary {
    cursor: pointer;
    font-size: 13px;
    color: var(--antiqua-accent-dark);
    margin-top: 4px;
}

.lien-bouton {
    display: inline-block;
    background-color: var(--antiqua-accent-dark);
    color: var(--antiqua-header-text);
    border: none;
    border-radius: 6px;
    padding: 8px 16px;
    font-size: 13px;
    text-decoration: none;
}

.carte, .fiche-perso {
    transition: box-shadow 0.15s ease;
}

@media (hover: hover) and (pointer: fine) {
    .lien-bouton:hover {
        background-color: var(--antiqua-header-bg);
    }
}

.liste-guide li {
    display: block;
}

.liste-guide li strong {
    display: inline;
}

.liste-reponses li {
    display: block;
}

.frise {
    height: 16px;
    margin: 28px auto;
    max-width: 840px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='16' viewBox='0 0 20 16'%3E%3Cpath d='M0 16 L0 4 L4 4 L4 12 L12 12 L12 4 L16 4 L16 16' fill='none' stroke='%238a6a3f' stroke-width='2'/%3E%3C/svg%3E");
    background-repeat: repeat-x;
    background-position: center;
    opacity: 0.45;
}

/* Mémorial (/deces, lot d'assets du 25/07) : composition en deux colonnes
   desktop -- texte + formulaire de renaissance à gauche, illustration du
   passage à droite (ratio natif 4:5, jamais recadrée). Empilés sous 880px,
   image APRÈS le texte : "Renaître" reste l'action prioritaire sur petit
   écran, jamais reléguée sous une illustration. */
.deces-layout {
    display: flex;
    flex-direction: column;
    gap: 28px;
}

@media (min-width: 880px) {
    .deces-layout {
        display: grid;
        grid-template-columns: 1fr minmax(280px, 380px);
        align-items: start;
        gap: 32px;
    }
}

.deces-layout-illustration {
    width: 100%;
    height: auto;
    aspect-ratio: 1400 / 1750;
    object-fit: contain;
    border-radius: 10px;
    margin: 0 auto;
    display: block;
}

/* Pictogrammes du journal (étape V2 — recoloration par masque, currentColor) */
.event-icon {
    width: 1.25rem;
    height: 1.25rem;
    display: inline-block;
    vertical-align: -0.3em;
    flex-shrink: 0;
    background: currentColor;
    mask-position: center;
    mask-size: contain;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    -webkit-mask-size: contain;
    -webkit-mask-repeat: no-repeat;
}

.event-icon--recolte {
    color: #4F7A4C;
    mask-image: url("/images/ui/icons/recolte.svg");
    -webkit-mask-image: url("/images/ui/icons/recolte.svg");
}

.event-icon--echange {
    color: #24779A;
    mask-image: url("/images/ui/icons/echange.svg");
    -webkit-mask-image: url("/images/ui/icons/echange.svg");
}

.event-icon--don {
    color: #1B9A93;
    mask-image: url("/images/ui/icons/don.svg");
    -webkit-mask-image: url("/images/ui/icons/don.svg");
}

.event-icon--propriete {
    color: #B68A45;
    mask-image: url("/images/ui/icons/propriete.svg");
    -webkit-mask-image: url("/images/ui/icons/propriete.svg");
}

.event-icon--monument {
    color: #17345D;
    mask-image: url("/images/ui/icons/monument.svg");
    -webkit-mask-image: url("/images/ui/icons/monument.svg");
}

.event-icon--delit {
    color: #C7633F;
    mask-image: url("/images/ui/icons/delit.svg");
    -webkit-mask-image: url("/images/ui/icons/delit.svg");
}

/* Réseau des cités V0 (lot 2) : départs et arrivées entre cités. La couleur
   lui est PROPRE (bleu du Nil) pour que la famille se distingue au premier
   coup d'œil.

   Le pictogramme empruntait celui des échanges faute d'icône de barque, si
   bien qu'un départ de voyage et un troc affichaient la même image -- limite
   assumée et documentée ici depuis le lot 2. `voyage.svg` est livré (lot A du
   brief visuel, 28/07) : la dette est soldée. */
.event-icon--voyage {
    color: #2E6F8E;
    mask-image: url("/images/ui/icons/voyage.svg");
    -webkit-mask-image: url("/images/ui/icons/voyage.svg");
}

/* Secourisme (issue #49, 28/07) : le soin porté a d'abord emprunté le
   pictogramme du don -- même registre, mais rien ne distinguait un geste qui
   répare d'un cadeau. `soin.svg` arrive avec le même lot que `voyage.svg`.
   Couleur propre : le vert des gestes qui réparent, jamais le rouge des
   incidents. */
.event-icon--soin {
    color: #4F7A4C;
    mask-image: url("/images/ui/icons/soin.svg");
    -webkit-mask-image: url("/images/ui/icons/soin.svg");
}

/* « Qui est ici » (cohérence V0, 27/07) : une ligne d'ambiance, jamais un
   élément d'action. Discrète mais lisible — le premier essai la noyait dans
   un bandeau photographique, où elle était illisible et coupée. */
.presents-ici {
    font-size: 13px;
    color: var(--antiqua-text-muted);
    margin: 0 0 12px;
}

/* Médaillon d'une cité dans une carte de destination (Réseau des cités V0,
   lot 5). Une IMAGE, pas un masque : ces illustrations sont détourées, avec
   leurs propres valeurs — les réduire à une silhouette monochrome leur ferait
   perdre ce qui les distingue. Le conteneur ne fixe donc ni couleur ni
   masque, seulement une place et un cadrage. */
.carte-destination__icone--medaillon {
    background: none;
}

.carte-destination__icone--medaillon img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}

/* Naissance : révélation des sept valeurs tirées puis répartition. La
   palette du manifeste (V3, jusqu'ici seulement enregistrée en variables)
   sert enfin à quelque chose : colorer les tessons du dégradé chaud (bas)
   au froid (haut), sans code de rareté ni effet de loot-box. */
.naissance-scene {
    max-width: 1100px;
    margin: 24px auto 48px;
}

.inscription-etapes {
    font-size: 13px;
    color: var(--antiqua-text-muted);
}

.naissance-carte {
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 14px;
    box-shadow: 0 4px 24px rgba(58, 47, 30, 0.12);
    padding: 32px;
    display: grid;
    gap: 28px;
    grid-template-columns: 1fr;
}

@media (min-width: 860px) {
    .naissance-revelee .naissance-carte {
        grid-template-columns: minmax(320px, 1.2fr) minmax(280px, 1fr);
        grid-template-areas: "scene assignation";
    }

    .naissance-revelee .naissance-scene-stage {
        grid-area: scene;
        /* La colonne de gauche (amphore + tessons) est structurellement plus
           courte que la liste des 7 caractéristiques à droite -- centrer son
           contenu sur la hauteur de la carte répartit le vide au lieu de le
           laisser entier sous l'amphore (audit UX/UI du 19/07). */
        justify-content: center;
        height: 100%;
    }
}

.naissance-introduction {
    text-align: center;
    max-width: 480px;
    margin: 0 auto;
}

.naissance-introduction p {
    color: var(--antiqua-text-muted);
}

.naissance-scene-stage {
    display: flex;
    flex-direction: column;
    align-items: center;
}

/* [hidden] seul ne suffit pas ici : la règle ci-dessus fixe déjà `display`,
   et une règle d'auteur l'emporte toujours sur le [hidden] de la feuille
   navigateur (même piège déjà rencontré sur .temple-senet-jeu). */
.naissance-scene-stage[hidden] {
    display: none;
}

/* Stade Ancrage (P1 Lot 1) : mêmes proportions que .naissance-introduction,
   pas de display propre -- [hidden] natif suffit. */
.naissance-ancrage {
    text-align: center;
    max-width: 480px;
    margin: 0 auto;
}

.naissance-ancrage p {
    color: var(--antiqua-text-muted);
}

/* Stade Finalisation (P1 Lot 1) : récapitulatif calculé côté serveur avant
   confirmation définitive. */
.naissance-recapitulatif {
    margin-top: 16px;
    padding: 16px;
    border: 1px solid var(--antiqua-border);
    border-radius: 10px;
    background-color: var(--antiqua-bg);
}

.naissance-recap-grille {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px 16px;
    margin: 8px 0;
}

.naissance-recap-grille dt {
    font-size: 12px;
    color: var(--antiqua-text-muted);
}

.naissance-recap-grille dd {
    margin: 0;
    font-weight: 600;
}

.naissance-recap-competences {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 4px;
    font-size: 13px;
}

.naissance-recap-domaine {
    color: var(--antiqua-text-muted);
    font-size: 12px;
}

.naissance-recap-note {
    font-size: 12px;
    color: var(--antiqua-text-muted);
    margin: 8px 0 0;
}

/* Stade Finalisation, personnalisation narrative (P1 Lot 1, correctif de
   périmètre du 18/07) : textarea non stylée globalement ailleurs dans
   l'appli (seul input l'est) -- largeur pleine et redimensionnement vertical
   seul, cohérent avec la sobriété des autres formulaires. */
.naissance-recit {
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--antiqua-border);
}

/* Piste d'apparence dérivée des caractéristiques (retour du 18/07) : une
   suggestion, pas une consigne -- distinguée en italique du reste des aides. */
.naissance-suggestion {
    font-style: italic;
}

.naissance-recit textarea {
    display: block;
    width: 100%;
    max-width: 480px;
    padding: 8px 10px;
    margin-top: 4px;
    border: 1px solid var(--antiqua-border);
    border-radius: 6px;
    font-size: 14px;
    font-family: inherit;
    box-sizing: border-box;
    resize: vertical;
}

.naissance-amphore {
    width: min(140px, 32vw);
    transform-origin: 50% 35%;
    margin-bottom: 8px;
}

.naissance-amphore img {
    width: 100%;
    height: auto;
    display: block;
    filter: drop-shadow(0 10px 10px rgba(58, 47, 30, 0.18));
}

.naissance-tessons {
    display: grid;
    grid-template-columns: repeat(7, minmax(40px, 56px));
    justify-content: center;
    align-items: end;
    gap: clamp(6px, 1.5vw, 12px);
    min-height: 100px;
    padding: 8px 4px 16px;
}

@media (max-width: 560px) {
    .naissance-tessons {
        grid-template-columns: repeat(4, minmax(44px, 56px));
    }
}

.tesson {
    --tesson-fill: var(--antiqua-accent);
    appearance: none;
    font: inherit;
    font-weight: 600;
    color: var(--antiqua-header-text);
    background: radial-gradient(circle at 34% 28%, color-mix(in srgb, var(--tesson-fill) 82%, white 18%), var(--tesson-fill));
    border: 1px solid color-mix(in srgb, var(--tesson-fill) 70%, black 15%);
    border-radius: 48% 52% 43% 57% / 56% 40% 60% 44%;
    min-height: 56px;
    min-width: 44px;
    display: grid;
    place-items: center;
    position: relative;
    cursor: pointer;
    opacity: 0;
    box-shadow: 0 6px 12px rgba(58, 47, 30, 0.18);
}

.tesson.est-pose {
    opacity: 1;
}

.tesson[aria-pressed="true"] {
    outline: 4px solid var(--palette-bleu-nil);
    outline-offset: 3px;
    box-shadow: 0 0 0 6px color-mix(in srgb, var(--palette-bleu-nil) 25%, transparent), 0 6px 12px rgba(58, 47, 30, 0.18);
    transform: scale(1.12);
    z-index: 1;
}

@media (prefers-reduced-motion: no-preference) {
    .tesson {
        transition: transform 0.15s ease;
    }
}

.tesson.est-saisi {
    opacity: 0.5;
}

.tesson:disabled {
    cursor: default;
    opacity: 0.28;
    filter: grayscale(0.5);
}

.naissance-assignation {
    display: none;
}

.naissance-revelee .naissance-assignation {
    display: grid;
    gap: 12px;
    align-content: start;
}

@media (min-width: 860px) {
    .naissance-revelee .naissance-assignation {
        grid-area: assignation;
    }
}

.naissance-assignation-guide p {
    margin: 0 0 4px;
    font-size: 13px;
    color: var(--antiqua-text-muted);
}

.naissance-etapes {
    margin: 4px 0;
    padding-left: 20px;
    font-size: 13px;
}

.naissance-etapes li {
    margin-bottom: 2px;
}

.naissance-note-rassurante,
.naissance-note-secondaire {
    font-size: 12px;
    color: var(--antiqua-text-muted);
}

.naissance-note-secondaire {
    font-style: italic;
}

/* Réserve la hauteur d'une ligne même vide, pour que son apparition à la
   sélection d'un tesson ne fasse pas sauter le reste de la mise en page. */
.naissance-selection-info {
    min-height: 1.2em;
    font-size: 13px;
    font-weight: 600;
    color: var(--palette-bleu-nil);
    margin: 4px 0 0;
}

.naissance-aide-lien {
    text-align: center;
    margin-top: 16px;
    font-size: 13px;
}

.naissance-caracteristiques {
    display: grid;
    gap: 8px;
}

.caracteristique {
    appearance: none;
    font: inherit;
    /* Un <button> sans appearance:none garde parfois une couleur de texte
       grise par défaut (contraste jugé faible par l'audit UX/UI du 19/07,
       "noms de caractéristiques très pâles sur fond crème") -- explicite,
       ne dépend plus des styles par défaut du navigateur. */
    color: var(--antiqua-text);
    text-align: left;
    background-color: var(--antiqua-bg);
    border: 1px solid var(--antiqua-border);
    border-radius: 8px;
    padding: 8px 12px;
    cursor: pointer;
    display: grid;
    grid-template-columns: 2.6rem 1fr auto;
    align-items: center;
    gap: 10px;
}

@media (hover: hover) and (pointer: fine) {
    /* :not(:disabled) nécessaire pour au moins égaler la spécificité du
       button:hover:not(:disabled) global (même fuite CSS déjà rencontrée et
       corrigée sur .temple-senet-fermer) -- sans lui, une caractéristique
       survolée à la souris passait en brun sombre (--antiqua-header-bg) au
       lieu du survol clair prévu ici, découvert en générant les captures du
       guide joueur du 21/07. */
    .caracteristique:hover:not(:disabled) {
        background-color: var(--antiqua-panel);
        border-color: var(--antiqua-accent);
    }
}

.caracteristique.est-survolee {
    background-color: var(--antiqua-panel);
    border-color: var(--palette-bleu-nil);
    outline: 2px solid var(--palette-bleu-nil);
    outline-offset: 1px;
}

.caracteristique-code {
    font-weight: 700;
    letter-spacing: 0.05em;
    color: var(--antiqua-accent-dark);
}

.caracteristique-nom {
    display: block;
    font-weight: 600;
}

.caracteristique-effet {
    display: block;
    font-size: 12px;
    color: var(--antiqua-text-muted);
}

.caracteristique-valeur-groupe {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
}

.caracteristique-valeur {
    min-width: 2.2rem;
    min-height: 2.2rem;
    border-radius: 999px;
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
}

/* Indice visuel purement décoratif (le vrai libellé accessible vient de
   l'aria-label posé dynamiquement en JS) -- rappelle qu'une caractéristique
   déjà remplie se vide d'un clic, sans bouton dédié imbriqué dans le
   <button> englobant (invalide en HTML). */
.caracteristique-retirer-hint {
    display: none;
    font-size: 10px;
    color: var(--antiqua-text-muted);
    white-space: nowrap;
}

.caracteristique.est-assignee .caracteristique-retirer-hint {
    display: inline;
}

.caracteristique.est-assignee {
    border-color: var(--antiqua-accent);
}

/* Emplacement vide (P2.6, audit UX/UI du 19/07) : un simple tiret dans un
   rond plein se lisait comme une valeur ambiguë plutôt qu'un
   emplacement à remplir -- bordure en pointillé (même langage visuel que
   .etat-vide) et texte explicite plutôt qu'un "—" isolé. */
.caracteristique-valeur:empty {
    border-style: dashed;
    background-color: transparent;
}

.caracteristique-valeur:empty::before {
    content: "Vide";
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--antiqua-text-muted);
    font-weight: 400;
}

.naissance-pied {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-top: 8px;
}

.naissance-progression {
    display: grid;
    gap: 6px;
    font-size: 13px;
    color: var(--antiqua-text-muted);
}

.naissance-progression-barre {
    width: 180px;
    max-width: 100%;
    height: 6px;
    border-radius: 999px;
    background-color: var(--antiqua-border);
    overflow: hidden;
}

.naissance-progression-remplissage {
    height: 100%;
    width: 0%;
    background-color: var(--palette-bleu-nil);
    border-radius: 999px;
    transition: width 0.2s ease;
}

/* Lisibilité à 360px (retour bêta : aucun palier sous 560px n'existait) --
   resserre la carte et les tessons sans changer la mise en page à deux
   colonnes, qui ne s'active de toute façon qu'à partir de 860px. */
@media (max-width: 400px) {
    .naissance-carte {
        padding: 20px 16px;
        gap: 20px;
    }

    .naissance-tessons {
        grid-template-columns: repeat(4, minmax(48px, 1fr));
    }

    .caracteristique {
        grid-template-columns: 2.2rem 1fr auto;
        padding: 8px;
    }

    .caracteristique-effet {
        font-size: 11px;
    }
}

/* Connexion : seuil d'entrée dans Antiqua -- grande carte centrale reprenant
   les couleurs/rayons/ombres de la refonte de l'Accueil (étape V4), plutôt
   que le formulaire isolé et le fond parchemin de l'ancienne version. */
.connexion-scene {
    box-sizing: border-box;
    max-width: 1300px;
    min-height: calc(100vh - 96px);
    margin: 0 auto;
    padding: 48px 24px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.connexion-carte {
    box-sizing: border-box;
    width: 100%;
    display: grid;
    grid-template-columns: 1fr;
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 14px;
    box-shadow: 0 4px 24px rgba(58, 47, 30, 0.14);
    overflow: hidden;
}

.connexion-carte-visuel {
    position: relative;
    aspect-ratio: 16 / 9;
    max-height: 260px;
    background-color: var(--antiqua-header-bg);
}

.connexion-carte-visuel picture,
.connexion-carte-visuel img {
    display: block;
    width: 100%;
    height: 100%;
}

.connexion-carte-visuel img {
    object-fit: cover;
    object-position: 55% center;
}

.connexion-carte-visuel-texte {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: flex-end;
    padding: 20px 24px;
    background: linear-gradient(to top, rgba(36, 26, 19, 0.78), rgba(36, 26, 19, 0.2) 60%, transparent 100%);
}

.connexion-carte-visuel-texte p {
    margin: 0;
    max-width: 420px;
    color: var(--antiqua-header-text);
    font-family: "Cormorant Garamond", Georgia, serif;
    font-size: 19px;
    font-style: italic;
}

.connexion-carte-formulaire {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding: 32px 28px 40px;
}

.connexion-carte-formulaire .entete-connexion {
    margin-bottom: 8px;
}

.connexion-carte-formulaire .entete-connexion img {
    border-radius: 8px;
}

.badge-beta {
    display: inline-block;
    margin-top: 4px;
    font-size: 11px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--antiqua-text-muted);
    border: 1px solid var(--antiqua-border);
    border-radius: 999px;
    padding: 2px 10px;
}

.formulaire-connexion {
    margin: 12px 0 0;
}

.formulaire-connexion input {
    max-width: none;
    width: 100%;
    min-height: 44px;
    padding: 10px 14px;
    margin-top: 6px;
    font-size: 15px;
    border-radius: 8px;
}

.formulaire-connexion input:focus-visible {
    outline: 2px solid var(--palette-bleu-nil);
    outline-offset: 1px;
    border-color: var(--palette-bleu-nil);
}

.formulaire-connexion input:user-invalid {
    border-color: var(--palette-terre-cuite);
}

.formulaire-connexion input[aria-invalid="true"] {
    border-color: var(--palette-terre-cuite);
}

.formulaire-connexion input:-webkit-autofill {
    -webkit-text-fill-color: var(--antiqua-text);
    box-shadow: 0 0 0 1000px var(--antiqua-panel) inset;
}

.bouton-principal {
    width: 100%;
    box-sizing: border-box;
    min-height: 48px;
    margin-top: 22px;
    font-size: 15px;
    border-radius: 8px;
}

.connexion-actions {
    margin-top: 22px;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
}

.bouton-secondaire {
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 44px;
    background-color: transparent;
    color: var(--antiqua-accent-dark);
    border: 1px solid var(--antiqua-accent-dark);
    border-radius: 8px;
    padding: 8px 16px;
    font-size: 14px;
    text-decoration: none;
    text-align: center;
}

@media (hover: hover) and (pointer: fine) {
    .bouton-secondaire:hover {
        background-color: var(--antiqua-bg);
    }
}

.bouton-secondaire:focus-visible,
.lien-discret:focus-visible {
    outline: 2px solid var(--palette-bleu-nil);
    outline-offset: 2px;
}

.lien-discret {
    align-self: center;
    font-size: 13px;
    color: var(--antiqua-text-muted);
    text-decoration: underline;
    text-underline-offset: 2px;
}

@media (min-width: 880px) {
    .connexion-carte {
        grid-template-columns: 3fr 2fr;
        min-height: 560px;
    }

    .connexion-carte-visuel {
        aspect-ratio: auto;
        max-height: none;
    }

    .connexion-carte-formulaire {
        padding: 48px 44px;
    }
}

/* Zone (Abydos) : la cueillette gagne une illustration dédiée, à côté du
   bouton plutôt qu'un simple lien perdu dans le texte (audit du 12/07).
   Même max-width que .accueil-hero et .tableau-zone -- direct enfant du
   body, pas de wrapper .page-large qui la rendrait plus étroite que la
   bannière au-dessus (audit du 12/07, 2e passe). */
.zone-cueillette {
    max-width: 1520px;
    display: grid;
    gap: 24px;
    grid-template-columns: 1fr;
    align-items: center;
    margin: 16px auto 24px;
}

@media (min-width: 700px) {
    .zone-cueillette {
        grid-template-columns: 1fr 2fr;
    }
}

/* Un tiers colonne image / deux tiers texte : l'image garde son format
   natif 3:2 sans avoir à être écrasée en largeur pour tenir la hauteur. */
.zone-cueillette .illustration-personnage {
    aspect-ratio: 3 / 2;
}

/* Les deux gestes de récolte sauvage sont exclusifs et à parité stricte --
   même colonne, même bouton .bouton-principal (retour bêta du 19/07 :
   Collecter avait hérité du bouton par défaut minuscule, à côté du bouton
   pleine largeur de Cueillir ou chasser). Empilés en dessous de 700px,
   côte à côte au-delà. */
/* Page dédiée du marché (Lot 2, 23/07) : offres disponibles à gauche, mes
   offres + formulaire de publication à droite sur grand écran. */
.marche-mise-en-page {
    display: grid;
    gap: 16px;
    grid-template-columns: 1fr;
    align-items: start;
    margin-top: 16px;
}

@media (min-width: 900px) {
    .marche-mise-en-page {
        grid-template-columns: 1fr 1fr;
    }
}

/* Colonne de droite du Marché (issue #19, correctif du 26/07) : « Mes offres »,
   la publication et le chapardage s'y empilent. La grille au-dessus n'attend
   que DEUX enfants ; un troisième posé directement dedans écrasait les colonnes
   et rejetait le bloc hors de vue -- constaté en jeu, pas en test. */
.marche-colonne {
    display: grid;
    gap: 16px;
    align-content: start;
}

/* Correctif du 26/07 (capture annotée de Gwendal) : `.fiche-perso` porte
   `margin: 16px auto`, hérité de son usage en pleine page. Dans une cellule de
   grille, une marge horizontale `auto` ABSORBE l'espace libre et rétrécit la
   carte à la largeur de son contenu au lieu de l'étirer -- la colonne des
   offres se réduisait à une bande, avec près de 200px de vide entre les deux
   colonnes. Les gouttières sont déjà tenues par `gap`. */
.marche-mise-en-page .fiche-perso {
    margin: 0;
}

.recolte-sauvage-choix {
    display: grid;
    gap: 16px;
    grid-template-columns: 1fr;
    align-items: stretch;
}

@media (min-width: 700px) {
    .recolte-sauvage-choix {
        grid-template-columns: 1fr 1fr;
    }
}

/* Les deux textes descriptifs n'ont pas la même longueur (Collecter passe
   sur deux lignes) : sans ceci, les deux boutons ne s'alignaient pas
   horizontalement (retour bêta du 19/07). Chaque colonne s'étire à la
   hauteur de la plus haute (stretch ci-dessus), et son formulaire pousse
   son bouton tout en bas. */
.recolte-sauvage-choix > div {
    display: flex;
}

.recolte-sauvage-choix form {
    display: flex;
    flex-direction: column;
    flex: 1;
}

.recolte-sauvage-choix form button {
    margin-top: auto;
}

/* Issue #17 (26/07), lot 3 : le résumé du Marché a quitté Cité — il doublait
   la page /marche, que la carte de destination annonce déjà avec son nombre
   d'offres. La colonne « échanges » a donc disparu de la grille, qui passe de
   trois colonnes à deux : les cases foncières, et le monument.

   Le monument RESTE ici, décision produit de Gwendal : c'est lui qui donne sa
   figure à la page, et ce n'est que le premier d'une série (obélisques,
   statues...) qu'un lot de GDD viendra étoffer. Cité montre ce qui fait une
   cité — où aller, ce qu'on y bâtit ensemble, et qui tient la terre. */
.tableau-zone {
    max-width: 1520px;
    display: grid;
    gap: 24px;
    grid-template-columns: 1fr;
    grid-template-areas:
        "terres"
        "monument";
}

@media (min-width: 1000px) {
    .tableau-zone {
        grid-template-columns: 1fr 1fr;
        grid-template-areas: "terres monument";
    }
}

.tableau-zone .colonne-terres { grid-area: terres; }
.tableau-zone .colonne-monument { grid-area: monument; display: flex; flex-direction: column; gap: 24px; }


/* Plateau des manoeuvres militaires (prototype). */
/* Mobile : le statut du tour prend toute la largeur (c'est l'info la plus
   utile en un coup d'œil), les deux camps se résument côte à côte en
   dessous -- jamais trois colonnes étroites illisibles sur 360px. */
.maneuver-entete {
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
        "statut statut"
        "nord sud";
    gap: 10px;
    align-items: stretch;
    margin: 8px auto 18px;
}

.maneuver-entete .maneuver-statut { grid-area: statut; }
.maneuver-entete .maneuver-camp--nord { grid-area: nord; }
.maneuver-entete .maneuver-camp--sud { grid-area: sud; }

@media (min-width: 700px) {
    .maneuver-entete {
        grid-template-columns: 1fr 1.4fr 1fr;
        grid-template-areas: "nord statut sud";
    }
}

.maneuver-camp {
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 10px;
    padding: 10px 14px;
    text-align: center;
    font-size: 14px;
}

.maneuver-camp strong {
    display: block;
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--antiqua-text-muted);
    margin-bottom: 2px;
}

.maneuver-camp--actif {
    border-color: var(--palette-bleu-nil);
    box-shadow: 0 0 0 2px rgba(36, 119, 154, 0.25);
}

.maneuver-statut {
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 10px;
    padding: 10px 14px;
    text-align: center;
    font-size: 14px;
}

.maneuver-statut p {
    margin: 2px auto;
}

.maneuver-actions {
    margin: 14px auto;
}

.legende-maneuver {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 18px;
    align-items: center;
    font-size: 12px;
    color: var(--antiqua-text-muted);
    margin: 0 auto 12px;
}

.legende-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.legende-item .case-maneuver {
    width: 24px;
    height: 24px;
    font-size: 10px;
}

/* Panneau d'actions (colonne gauche, quand une unité est sélectionnée) +
   plateau + fiche d'unité (colonne droite) en trois colonnes sur grand
   écran (le plateau ne bouge pas quand la fiche ou le panneau se mettent à
   jour) ; empilés dans l'ordre du DOM en dessous de 1100px -- le panneau
   d'actions en premier (retour du 20/07 : trop bas/hors champ tout en bas
   du plateau sur un écran de hauteur normale), le plateau ensuite, la fiche
   d'unité devenant un panneau bas fixe (voir .maneuver-unit-preview). */
.maneuver-plateau-layout {
    display: flex;
    flex-direction: column;
    gap: 16px;
    align-items: flex-start;
}

@media (min-width: 1100px) {
    .maneuver-plateau-layout {
        flex-direction: row;
    }

    .maneuver-plateau-layout .plateau-scroll-conteneur {
        flex: 1 1 auto;
        min-width: 0;
    }
}

/* Le plateau est volontairement large (12 cases d'au moins 40px, mission
   section 6 : zones tactiles >= 44px) : sur mobile, il défile horizontalement
   plutôt que de rapetisser les cases sous un seuil tactile fiable. Le
   conteneur enveloppant porte les dégradés de bord qui signalent que des
   colonnes restent hors champ (§ plateau et responsive de la passe graphique). */
.plateau-scroll-conteneur {
    position: relative;
    /* .maneuver-plateau-layout utilise align-items: flex-start (nécessaire
       pour que .maneuver-unit-preview ne s'étire pas en hauteur) : sans
       largeur explicite, un enfant flex se réduit à la largeur de son
       contenu au lieu de celle du conteneur -- la grille (fixe, ~550px)
       débordait alors de tout le body au lieu de rester dans son propre
       défilement horizontal. width: 100% + min-width: 0 (le minimum par
       défaut d'un enfant flex est son contenu, pas 0) referment ce débord. */
    width: 100%;
    min-width: 0;
}

.plateau-scroll-conteneur::before,
.plateau-scroll-conteneur::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 8px;
    width: 18px;
    pointer-events: none;
    z-index: 1;
}

.plateau-scroll-conteneur::before {
    left: 0;
    background: linear-gradient(to right, var(--antiqua-bg), transparent);
}

.plateau-scroll-conteneur::after {
    right: 0;
    background: linear-gradient(to left, var(--antiqua-bg), transparent);
}

.plateau-scroll {
    overflow-x: auto;
    padding-bottom: 8px;
    margin: 0 auto 16px;
}

.plateau-grille {
    display: grid;
    grid-template-columns: repeat(var(--taille-grille), 44px);
    grid-template-rows: repeat(var(--taille-grille), 44px);
    gap: 2px;
    width: max-content;
    /* Centré quand il tient dans .plateau-scroll (desktop) ; sur un écran plus
       étroit que le plateau, ce margin n'a aucun effet et .plateau-scroll
       prend le relais avec son défilement horizontal habituel. */
    margin: 0 auto;
    background-color: var(--antiqua-border);
    border: 1px solid var(--antiqua-border);
}

.case-forme {
    display: contents;
}

.case-maneuver {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    background-color: var(--antiqua-panel);
    font-size: 12px;
    font-family: Georgia, serif;
    color: var(--antiqua-text);
    border: none;
    padding: 0;
    /* Feuille UA de <button> : marge par défaut que <div>/<a> n'ont pas.
       Sans ce reset, une case rendue en <button> (unité non sélectionnable,
       case de destination) se retrouve visiblement décalée dans sa cellule
       de grille par rapport aux cases en <div>/<a> du même plateau -- décalage
       net, pas un simple sous-pixel de rendu de police/masque. */
    margin: 0;
    text-decoration: none;
    box-sizing: border-box;
}

a.case-maneuver,
button.case-maneuver {
    cursor: pointer;
}

/* Distinction Nord/Sud par forme autant que par couleur (mission section 6 :
   « états compréhensibles sans dépendre uniquement de la couleur ») -- carré
   tronqué et gamme Nil au Nord, cercle et gamme terre cuite au Sud. */
.case-maneuver--nord {
    background-color: #eef4f4;
    border: 2px solid #668c91;
    color: #4f5875;
    border-radius: 4px 4px 4px 12px;
    font-weight: 600;
}

.case-maneuver--sud {
    background-color: #faf1e6;
    border: 2px solid #a96f46;
    color: #a96f46;
    border-radius: 50%;
    font-weight: 600;
}

.case-maneuver--nord .unit-glyph,
.case-maneuver--sud .unit-glyph {
    color: #5f4932;
}

.case-maneuver--selectionnee {
    outline: 3px solid var(--palette-or-vieilli);
    outline-offset: -3px;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.22);
}

/* Déjà déplacée/inactive : lavis désaturé, camp encore reconnaissable (pas
   un simple opacity uniforme qui délaverait aussi le glyphe). */
.case-maneuver--jouee {
    filter: saturate(0.45);
    opacity: 0.65;
}

.case-maneuver--destination {
    background-color: rgba(79, 122, 76, 0.16);
    border: 2px dashed var(--palette-vert-roseau);
    color: var(--palette-vert-roseau);
    border-radius: 4px;
}

.case-maneuver--attaque {
    border: 2px dashed var(--palette-terre-cuite);
    box-shadow: inset 0 0 0 2px rgba(199, 99, 63, 0.3);
}

/* Case vide de la zone de déploiement, cible valide pour le glisser-déposer
   (mais pas pour un clic direct -- il faut d'abord sélectionner une unité de
   la réserve, ou glisser). .case-maneuver--depot-survolee est ajoutée par le
   contrôleur Stimulus maneuver-deploiement pendant un survol de glisser actif. */
.case-maneuver--depot {
    border: 2px dashed var(--antiqua-accent);
    background-color: rgba(201, 164, 104, 0.12);
}

.case-maneuver--depot-survolee {
    background-color: rgba(79, 122, 76, 0.22);
    border-color: var(--palette-vert-roseau);
}

.maneuver-reserve {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin: 0 auto 16px;
}

.maneuver-reserve-unite {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px 6px 6px;
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 8px;
    text-decoration: none;
    color: var(--antiqua-text);
    font-size: 13px;
    cursor: grab;
    min-height: 44px;
    box-sizing: border-box;
}

.maneuver-reserve-unite:active {
    cursor: grabbing;
}

.maneuver-reserve-unite--selectionnee {
    outline: 3px solid var(--palette-or-vieilli);
    outline-offset: -1px;
}

.maneuver-reserve-unite .case-maneuver {
    width: 32px;
    height: 32px;
    pointer-events: none;
}

/* Glyphe tactique : un seul fichier SVG par type, coloré par le camp parent
   via currentColor (mask-image), même technique que .event-icon. */
.unit-glyph {
    display: inline-block;
    width: 22px;
    height: 22px;
    background: currentColor;
    mask-position: center;
    mask-size: contain;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    -webkit-mask-size: contain;
    -webkit-mask-repeat: no-repeat;
}

/* SVG inline plutôt qu'un caractère "+" : les glyphes texte ("＋" pleine
   chasse, ou "+" ASCII) ont une boîte de police dont le centre optique ne
   correspond pas au centre géométrique, visible dès qu'on centre en flex. */
.case-maneuver-plus {
    display: block;
    width: 18px;
    height: 18px;
    color: var(--palette-vert-roseau);
}

.legende-item .unit-glyph {
    width: 14px;
    height: 14px;
}

/* ?v=2 : ces SVG (contrairement à app.css/app.js, gérés par AssetMapper avec
   une URL dérivée du contenu) vivent sous public/ sans nom versionné -- sans
   ce paramètre, un navigateur ayant déjà mis l'ancien fichier en cache ne le
   revalide pas forcément à un simple rechargement. Incrémenter à chaque
   nouvelle retouche du dessin. */
.unit-glyph--spearman {
    mask-image: url("/images/manoeuvre/units/unit_spearman.svg?v=2");
    -webkit-mask-image: url("/images/manoeuvre/units/unit_spearman.svg?v=2");
}

.unit-glyph--blades {
    mask-image: url("/images/manoeuvre/units/unit_blades.svg?v=2");
    -webkit-mask-image: url("/images/manoeuvre/units/unit_blades.svg?v=2");
}

.unit-glyph--skirmisher {
    mask-image: url("/images/manoeuvre/units/unit_skirmisher.svg?v=2");
    -webkit-mask-image: url("/images/manoeuvre/units/unit_skirmisher.svg?v=2");
}

.unit-glyph--light_chariot {
    mask-image: url("/images/manoeuvre/units/unit_light_chariot.svg?v=2");
    -webkit-mask-image: url("/images/manoeuvre/units/unit_light_chariot.svg?v=2");
}

/* Kit visuel V2 officiel (18/07/2026) : BW et Ps ont chacun leur propre
   glyphe dédié (bow/psiloi), le général se distingue du char ordinaire par
   son étendard. Remplace les glyphes de repli de la première passe V2. */
.unit-glyph--bow {
    mask-image: url("/images/manoeuvre/units/unit_bow.svg?v=1");
    -webkit-mask-image: url("/images/manoeuvre/units/unit_bow.svg?v=1");
}

.unit-glyph--psiloi {
    mask-image: url("/images/manoeuvre/units/unit_psiloi.svg?v=1");
    -webkit-mask-image: url("/images/manoeuvre/units/unit_psiloi.svg?v=1");
}

.unit-glyph--general_light_chariot {
    mask-image: url("/images/manoeuvre/units/unit_general_light_chariot.svg?v=2");
    -webkit-mask-image: url("/images/manoeuvre/units/unit_general_light_chariot.svg?v=2");
}

/* Zone de menace, groupe et tir (mission V2, section « UX ») : des liserés
   fins superposables au reste des états plutôt que des aplats de couleur,
   pour ne jamais surcharger le plateau (mission : « sans surcharger »). */
.case-maneuver--menacee {
    box-shadow: inset 0 0 0 2px rgba(199, 99, 63, 0.55);
}

.case-maneuver--groupe {
    outline: 2px solid var(--palette-bleu-nil, #668c91);
    outline-offset: -2px;
}

/* Sélection manuelle de groupe en cours de constitution (mission V2.1, Lot
   B) : distincte de .case-maneuver--groupe (groupe automatique V2 stricte,
   déjà formé) par un remplissage plein plutôt qu'un simple contour, pour ne
   jamais confondre "en train de choisir" et "groupe déjà valide". */
.case-maneuver--groupe-choisi {
    outline: 3px solid var(--palette-bleu-nil, #668c91);
    outline-offset: -3px;
    background-color: color-mix(in srgb, var(--palette-bleu-nil, #668c91) 25%, transparent);
}

/* Panneau de constitution de groupe (mission V2.1, Lot B) : caché par
   défaut via une règle CSS dédiée plutôt que l'attribut HTML hidden -- un
   hidden combiné à un style inline display:flex serait silencieusement
   ignoré (l'inline l'emporte sur la feuille de style du user-agent). */
.maneuver-groupe-panneau {
    display: none;
    align-items: center;
}

.maneuver-groupe-panneau--actif {
    display: flex;
}

.case-maneuver--tir {
    border: 2px dashed var(--palette-or-vieilli);
    box-shadow: inset 0 0 0 2px rgba(201, 164, 104, 0.35);
}

/* Marqueur d'orientation (mission V2 : « marqueur d'orientation très
   lisible ») : petit chevron superposé au jeton, tourné vers la case
   menacée -- lisible même sans distinguer les nuances de couleur. */
.unit-orientation-marqueur {
    position: absolute;
    width: 9px;
    height: 9px;
    color: inherit;
    opacity: 0.85;
    pointer-events: none;
}

.unit-orientation-marqueur--nord { top: 1px; left: 50%; transform: translateX(-50%) rotate(0deg); }
.unit-orientation-marqueur--est { top: 50%; right: 1px; transform: translateY(-50%) rotate(90deg); }
.unit-orientation-marqueur--sud { bottom: 1px; left: 50%; transform: translateX(-50%) rotate(180deg); }
.unit-orientation-marqueur--ouest { top: 50%; left: 1px; transform: translateY(-50%) rotate(270deg); }

.case-maneuver {
    position: relative;
}

/* Panneau d'actions unifié de l'unité sélectionnée (mission V2.1, Lot A) :
   cible d'ancre (#panneau-actions-unite) pour que les redirections
   post-action y ramènent directement, sans repartir du haut de page.
   Premier enfant de .maneuver-plateau-layout (retour du 20/07) : colonne
   fixe à gauche du plateau dès 1100px, pleine largeur empilée en dessous. */
.maneuver-panneau-actions {
    width: 100%;
    box-sizing: border-box;
    padding: 12px 16px;
    margin: 8px 0 16px;
    border: 1px solid var(--antiqua-border);
    border-radius: 8px;
    background-color: var(--antiqua-panel);
    scroll-margin-top: 16px;
}

@media (min-width: 1100px) {
    .maneuver-panneau-actions {
        flex: 0 0 300px;
        width: 300px;
        margin: 0;
    }
}

/* Chevron d'orientation dans le flux du texte (mission V2.1) : même dessin
   que .unit-orientation-marqueur mais sans le position:absolute pensé pour
   se superposer à un jeton du plateau. */
.maneuver-orientation-chevron-inline {
    display: inline-block;
    width: 10px;
    height: 10px;
    vertical-align: middle;
    color: inherit;
}

.maneuver-orientation-actuelle {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 14px;
    font-weight: normal;
    color: var(--antiqua-text-muted);
}

/* Compass de choix d'orientation (contrôleur Stimulus maneuver-orientation). */
.maneuver-orientation-choix {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    margin: 8px auto 12px;
    font-size: 13px;
    color: var(--antiqua-text-muted);
}

.maneuver-orientation-bouton {
    min-width: 44px;
    min-height: 32px;
    padding: 4px 10px;
    border: 1px solid var(--antiqua-border);
    border-radius: 6px;
    background-color: var(--antiqua-panel);
    color: var(--antiqua-text);
    cursor: pointer;
}

.maneuver-orientation-bouton--actif {
    border-color: var(--palette-or-vieilli);
    background-color: rgba(201, 164, 104, 0.18);
    font-weight: 600;
}

/* Aperçu du coût en commandement avant validation (mission V2, section « UX »). */
.maneuver-cout-previsionnel {
    font-size: 12px;
    color: var(--antiqua-text-muted);
    margin: 0 0 8px;
}

/* Fiche illustrée de l'unité : aside stable sur grand écran (voir
   .maneuver-plateau-layout), empilée sous le plateau en dessous de 1100px,
   panneau bas fixe sur mobile (voir la media query dédiée plus bas). */
.maneuver-unit-preview {
    width: 100%;
    max-width: 280px;
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 10px;
    padding: 14px;
    box-sizing: border-box;
}

.maneuver-unit-preview-vide {
    color: var(--antiqua-text-muted);
    font-size: 13px;
    margin: 0;
}

.maneuver-unit-preview-image {
    width: 100%;
    aspect-ratio: 2 / 3;
    object-fit: contain;
    background-color: var(--antiqua-bg);
    border-radius: 8px;
    opacity: 0;
    transform: translateY(4px);
    transition: opacity 160ms ease, transform 160ms ease;
}

.maneuver-unit-preview[data-maneuver-preview-remplie="true"] .maneuver-unit-preview-image {
    opacity: 1;
    transform: translateY(0);
}

/* Repli quand aucune illustration de fiche n'existe encore pour le type
   (TypeUniteManeuver::aFicheIllustree() faux -- mission V2, section
   « Assets » : « une solution de repli si un nouvel asset manque »). Le
   glyphe SVG existe toujours, agrandi ici plutôt que de laisser une image
   cassée ou d'emprunter l'illustration d'un autre type. */
.maneuver-unit-preview-glyphe-repli {
    display: none;
    width: 100%;
    aspect-ratio: 2 / 3;
    align-items: center;
    justify-content: center;
    background-color: var(--antiqua-bg);
    border-radius: 8px;
}

.maneuver-unit-preview-glyphe-repli .unit-glyph {
    width: 40%;
    height: 40%;
}

.maneuver-unit-preview[data-maneuver-preview-sans-fiche="true"] .maneuver-unit-preview-glyphe-repli {
    display: flex;
}

.maneuver-unit-preview[data-maneuver-preview-sans-fiche="true"] .maneuver-unit-preview-image {
    display: none;
}

.maneuver-unit-preview-capacites {
    font-size: 12px;
    color: var(--antiqua-text-muted);
    margin: 4px 0 0;
}

.maneuver-unit-preview-nom {
    margin: 10px 0 4px;
    font-size: 16px;
}

.maneuver-unit-preview-badge {
    display: inline-block;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 2px 8px;
    border-radius: 999px;
    margin-bottom: 6px;
}

.maneuver-unit-preview-badge--nord {
    background-color: #eef4f4;
    color: #4f5875;
    border: 1px solid #668c91;
}

.maneuver-unit-preview-badge--sud {
    background-color: #faf1e6;
    color: #a96f46;
    border: 1px solid #a96f46;
}

.maneuver-unit-preview-etat {
    font-size: 13px;
    color: var(--antiqua-text-muted);
    margin: 0;
}

.maneuver-unit-preview-fermer {
    display: none;
}

@media (prefers-reduced-motion: reduce) {
    .maneuver-unit-preview-image {
        transition: none;
    }
}

/* Panneau bas fixe sur mobile/tablette tactile : la fiche n'a pas de place
   fixe à côté du plateau en dessous de 1100px (voir .maneuver-plateau-layout). */
@media (max-width: 1099.98px) {
    .maneuver-unit-preview {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        max-width: none;
        max-height: 60dvh;
        overflow-y: auto;
        border-radius: 16px 16px 0 0;
        box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.18);
        transform: translateY(100%);
        transition: transform 180ms ease;
        z-index: 30;
    }

    .maneuver-unit-preview[data-maneuver-preview-ouverte="true"] {
        transform: translateY(0);
    }

    .maneuver-unit-preview-fermer {
        display: block;
        margin-left: auto;
        background: none;
        border: none;
        font-size: 20px;
        line-height: 1;
        color: var(--antiqua-text-muted);
        cursor: pointer;
        padding: 4px 8px;
    }

    @media (prefers-reduced-motion: reduce) {
        .maneuver-unit-preview {
            transition: none;
        }
    }
}

button.lien-discret {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    font: inherit;
}

/* Temple : révélation du senet sur place (le clic ne quitte pas la page, voir
   senet_embed_controller.js) plutôt qu'un lien vers /senet -- garde la navigation et le
   fond clairs d'Antiqua visibles pendant la partie, corrige au passage le portrait du
   prêtre (détouré pour un fond clair, illisible sur le thème sombre du jeu lui-même). */
/* Colonne par défaut, bascule en ligne à partir de 1500px de fenêtre --
   `.temple-jeu` ne fait plus que 2/3 de la page depuis la recomposition du
   Temple en 1/3-2/3 du 24/07 (au lieu de sa pleine largeur), donc le seuil
   ne peut plus être le même qu'avant : 720px de plateau + texte lisible
   n'entrent côte à côte que quand la fenêtre est assez large pour que ce
   tiers-restant dépasse ~900px. Un essai avec une container query sur
   `.temple-jeu` (plus précis en théorie) a été abandonné : combinée à la
   grille 1fr/2fr de `.temple-layout`, `container-type: inline-size`
   provoquait un effondrement du conteneur à quelques dizaines de pixels
   (bug de circularité taille-conteneur/piste de grille, reproduit et
   confirmé hors navigateur avant d'y renoncer) -- un media query sur la
   fenêtre est moins élégant mais fiable, comme partout ailleurs sur ce
   projet (aucune autre container query dans la base). */
.temple-senet {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 28px;
}

@media (min-width: 1500px) {
    .temple-senet {
        flex-direction: row;
    }
}

/* Le texte prend tout ce que le plateau (largeur fixe ci-dessous) ne prend pas --
   inversé par rapport à un premier essai qui fixait le texte à 360px et laissait le jeu
   s'étirer sur tout le reste : le plateau se retrouvait minuscule au milieu d'un immense
   rectangle sombre, et le texte coincé dans une colonne étroite. */
.temple-senet-texte {
    flex: 1 1 auto;
    min-width: 0;
}

.temple-senet-portrait {
    float: right;
    width: 100px;
    height: auto;
    margin: 4px 0 8px 16px;
    border-radius: 10px;
    border: 1px solid var(--antiqua-border);
}

@media (min-width: 1500px) {
    .temple-senet-portrait {
        width: 140px;
    }
}

.temple-senet-jeu {
    flex: 0 0 auto;
    width: 720px;
    max-width: 100%;
    /* Coins arrondis + recadrage : sans ça, le panneau du jeu (voir
       .senet-racine) heurte les coins carrés à l'intérieur de la carte .fiche-perso. */
    border-radius: 10px;
    overflow: hidden;
}

/* Bouton de repli du plateau (retour bêta : on pouvait s'asseoir mais pas se
   relever). Discret, aligné à droite au-dessus du jeu. */
.temple-senet-fermer {
    display: block;
    margin: 0 0 6px auto;
    background: none;
    border: none;
    cursor: pointer;
    font-size: 13px;
    font-family: inherit;
    color: var(--antiqua-text-muted);
    padding: 4px 8px;
}

/* button.xxx:hover : il faut au moins la spécificité du
   button:hover:not(:disabled) global pour que le fond reste transparent. */
@media (hover: hover) and (pointer: fine) {
    button.temple-senet-fermer:hover:not(:disabled) {
        background: none;
        color: var(--antiqua-accent-dark);
        text-decoration: underline;
    }
}

.temple-senet-jeu[hidden] {
    display: none;
}


/* Inventaire de Chez moi (issue #11, 25/07) : des cartes compactes en
   grille plutôt qu une liste pleine largeur. Classes NEUVES et non
   modification de .carte-ressource-possedee, qui reste utilisée telle
   quelle par la fiche Personnage. */
.inventaire-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 12px;
    margin: 8px 0 16px;
    padding: 0;
    list-style: none;
}

.carte-inventaire {
    display: block;
    background-color: var(--antiqua-bg);
    border: 1px solid var(--antiqua-border);
    border-radius: 6px;
    padding: 10px 12px;
}


/* Cité, hub spatial public (issue #7, 25/07).

   Deux familles neuves, aucune retouche des classes existantes : la grille
   de destinations (« où aller ? ») et la liste compacte des cases foncières
   (« qu est-ce qui existe autour de moi ? »). Le desktop est prioritaire --
   1440 et 1920 affichent respectivement 4 et 5 destinations par rangée sans
   étirer les cartes, la liste des cases reste une ligne par case. */
.zone-destinations {
    max-width: 1520px;
    margin: 16px auto 8px;
}

.destinations-grille {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 12px;
    margin-top: 12px;
}

/* Issue #31 (28/07) : « ici » et « ailleurs » sont deux questions, donc deux
   blocs. 3/5 - 2/5 à partir de 1100px (même seuil que les autres grilles à
   deux colonnes du site, pour que les pages basculent ensemble).
   `align-items: start` empêche la colonne de voyage, plus courte, de s'étirer
   à la hauteur des six tuiles. */
.zone-destinations-grille {
    display: grid;
    grid-template-columns: 1fr;
    gap: 28px;
    align-items: start;
}

@media (min-width: 1100px) {
    .zone-destinations-grille {
        grid-template-columns: 3fr 2fr;
    }

    /* Trois colonnes fixes pour les six destinations locales : c'est la
       composition demandée (3 x 2), et elle rend chaque tuile PLUS large
       qu'avant, où six se partageaient toute la ligne. En dessous de ce seuil,
       la grille reprend son `auto-fill` : elle passe d'elle-même à deux
       colonnes puis à une, sans qu'on ait à maintenir trois mises en page. */
    .destinations-ici .destinations-grille {
        grid-template-columns: repeat(3, 1fr);
    }

    /* Une seule colonne à droite quel que soit le nombre de cités : deux
       destinations s'empilent, elles ne se serrent pas côte à côte dans 2/5
       de la largeur. */
    .destinations-grille--voyages {
        grid-template-columns: 1fr;
    }
}

.carte-destination {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 6px;
    text-decoration: none;
    color: inherit;
    box-shadow: 0 1px 4px rgba(58, 47, 30, 0.06);
}

@media (hover: hover) and (pointer: fine) {
    .carte-destination:hover {
        border-color: var(--antiqua-accent-dark);
        box-shadow: 0 2px 8px rgba(58, 47, 30, 0.12);
    }
}

.carte-destination__icone {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
}

.carte-destination__icone svg {
    width: 32px;
    height: 32px;
}

.carte-destination__texte {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.carte-destination__description,
.carte-destination__statut {
    font-size: 12px;
    color: var(--antiqua-text-muted);
}

.carte-destination__statut {
    font-style: italic;
}

/* Une ligne par case foncière : type, propriétaire, un état court, un lien.
   Tout le reste (conditions, partage, prérequis, rendement) vit sur la page
   dédiée de la case -- c est précisément ce que cette liste ne répète plus. */
.cases-liste {
    list-style: none;
    padding: 0;
    margin: 0 0 8px;
}

.case-ligne {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid var(--antiqua-border);
}

.case-ligne:last-child {
    border-bottom: none;
}

.case-ligne__icone {
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    background-size: cover;
    background-position: center;
    border-radius: 4px;
}

.case-ligne__icone svg {
    width: 34px;
    height: 34px;
}

.case-ligne__texte {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    flex-grow: 1;
}

.case-ligne__statut {
    font-size: 12px;
    color: var(--antiqua-text-muted);
}

.case-ligne .bouton-contour {
    flex-shrink: 0;
    margin: 0;
}


/* Mon abri, lieu de vie actif (issue #10, 25/07) : le repos se lit d un seul
   tenant -- l état, puis le geste. La mise côte à côte avec l illustration,
   introduite avec ce lot, a été retirée par l issue #14 (voir plus haut). */
.bloc-abri-vie {
    display: flex;
    flex-direction: column;
    gap: 4px;
}


/* Place publique recentrée sur les paroles (issue #8, 25/07).

   Deux colonnes de poids égal donnaient au Journal automatique du monde
   autant d importance qu aux mots des personnages. La grille dit maintenant
   la hiérarchie : deux tiers pour les conversations, un tiers pour ce qui les
   entoure. En dessous de 1100px, tout s empile -- et les conversations
   passent AVANT la colonne d appui, dans l ordre du document. */
.place-publique-grille {
    display: grid;
    grid-template-columns: 1fr;
    gap: 28px;
    align-items: start;
}

@media (min-width: 1100px) {
    .place-publique-grille {
        grid-template-columns: 2fr 1fr;
    }
}

.pp-entete {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}

/* Le formulaire complet vit derrière un <details> : accessible au clavier
   sans JavaScript, et sans repousser les conversations sous le pli. Le
   <summary> emprunte l apparence du bouton principal, marqueur natif retiré. */
.pp-nouvelle-parole {
    flex-shrink: 0;
}

.pp-declencheur {
    display: inline-block;
    cursor: pointer;
    list-style: none;
    user-select: none;
}

.pp-declencheur::-webkit-details-marker {
    display: none;
}

.pp-nouvelle-parole[open] .pp-declencheur {
    margin-bottom: 12px;
}

.pp-nouvelle-parole-contenu {
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 6px;
    padding: 14px 16px;
    margin-top: 4px;
    max-width: 620px;
}

/* Colonne d appui : même contenu qu avant, poids visuel réduit -- fond de
   panneau, titres plus petits, texte resserré. */
.pp-secondaire {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.pp-carte {
    background-color: var(--antiqua-panel);
    border: 1px solid var(--antiqua-border);
    border-radius: 6px;
    padding: 12px 14px;
}

.pp-carte h2 {
    font-size: 18px;
    margin: 0 0 8px;
}

.pp-carte h3 {
    font-size: 15px;
}

.pp-carte ul {
    margin: 0;
    padding-left: 0;
    list-style: none;
}

.pp-carte li {
    font-size: 13px;
}

/* Le Journal reste entier, filtres compris, mais il ne monopolise plus la
   moitié de l écran : sa liste défile au-delà d une hauteur raisonnable. */
.pp-journal .liste-journal {
    max-height: 460px;
    overflow-y: auto;
}

/* Un bouton .lien-discret au fil d une phrase (Modifier / Supprimer d une
   prise de parole) héritait du margin-top des boutons et cassait la ligne de
   métadonnées en deux -- visible dès que la colonne se resserre. Il se
   comporte maintenant comme le lien voisin auquel il ressemble. */
button.lien-discret {
    margin-top: 0;
    padding: 0;
    vertical-align: baseline;
}

/* /admin/mesures recomposé par chantier (issue #22, 26/07) -- la page suivait
   une colonne unique qui dépassait 3000px, exactement le défaut déjà corrigé
   sur /admin/parametres le 22/07. Le sommaire latéral et sa colonne collante
   sont donc les mêmes : ces alias évitent d en écrire une seconde version qui
   divergerait à la première retouche. Le nom historique reste en place tant
   qu il est le seul appelant identifié ; à la prochaine page admin longue,
   c est lui qui devra converger vers le nom générique. */
.admin-sommaire {
    margin-bottom: 20px;
    padding: 14px 16px;
    border: 1px solid var(--antiqua-border);
    border-radius: 10px;
    background-color: var(--antiqua-panel);
}

.admin-sommaire nav ul {
    list-style: none;
    margin: 8px 0 0;
    padding: 0;
}

.admin-sommaire nav li {
    padding: 4px 0;
}

/* La question de bêta à laquelle la section répond : elle ouvre chaque bloc,
   parce qu un nombre sans question est exactement ce que cette refonte
   cherche à retirer de l écran. */
.mesure-question {
    margin: 0 0 10px;
    font-size: 13px;
    font-style: italic;
    color: var(--antiqua-text-muted);
    border-left: 2px solid var(--antiqua-border);
    padding-left: 10px;
}

.mesure-note {
    color: var(--antiqua-text-muted);
    font-size: 12px;
}

.mesure-section {
    width: 100%;
    scroll-margin-top: 80px;
}

.mesure-section h2 {
    margin-top: 0;
}

.grille-mesures {
    display: grid;
    gap: 16px;
}

@media (min-width: 1100px) {
    .admin-mise-en-page {
        display: flex;
        align-items: flex-start;
        gap: 24px;
    }

    .admin-sommaire {
        flex: 0 0 220px;
        position: sticky;
        /* 71px = hauteur réelle de .nav-admin, sticky juste au-dessus (même
           valeur que .admin-parametres-sommaire et .admin-joueurs-filtre). */
        top: 71px;
        margin-bottom: 0;
    }

    .admin-contenu {
        flex: 1;
        min-width: 0;
    }
}

/* Deux colonnes de sections au-delà de 1400px : à 1520px de large, une
   colonne unique de cartes laissait la moitié droite de l écran vide tout en
   allongeant le défilement. Les sections ne se lisent pas dans l ordre -- on
   vient y chercher un chantier précis -- donc rien ne se perd à les mettre
   côte à côte. */
@media (min-width: 1400px) {
    .grille-mesures {
        grid-template-columns: repeat(2, 1fr);
        align-items: start;
    }

    /* Une carte de section fait ici ~620px : .grille-parametres y garderait
       ses deux colonnes (héritées d une règle qui interroge la largeur de la
       FENÊTRE, pas celle du conteneur), ce qui casse « Naissances en attente
       (compte créé, personnage jamais né) » sur trois lignes pour afficher un
       nombre à deux chiffres. Une mesure par ligne dans une carte étroite ;
       les deux sections pleine largeur, elles, gardent leurs deux colonnes. */
    .mesure-section:not(.mesure-section--pleine-largeur) .grille-parametres {
        grid-template-columns: 1fr;
    }

    .mesure-section--pleine-largeur {
        grid-column: 1 / -1;
    }
}

/* Issue #30 (28/07) : signal de recrutement de la Caserne. Une manœuvre
   ouverte par quelqu'un d'autre n'était visible qu'en changeant d'onglet à la
   main -- elle attendait un adversaire pendant que les visiteurs repartaient
   sans l'avoir vue.

   Le bandeau s'insère dans le flux, entre l'entraînement et les onglets : il
   signale sans masquer les autres activités de la Caserne, comme le demande
   l'issue. Ton accentué mais pas alarmant -- c'est une invitation, pas une
   urgence personnelle ; celles-là gardent leur place dans « À toi de jouer ». */
.caserne-recrutement {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin: 16px 0 0;
    padding: 12px 16px;
    border: 1px solid var(--antiqua-accent);
    border-left-width: 3px;
    border-radius: 8px;
    background: var(--antiqua-panel);
    color: #2E6F8E;
}

.caserne-recrutement p {
    flex: 1 1 320px;
    margin: 0;
    font-size: 13px;
    color: var(--antiqua-text);
}

/* Le label pilote le radio de l'onglet « À rejoindre » : aucun JavaScript, même
   esprit que les onglets eux-mêmes. */
.caserne-recrutement__action {
    flex-shrink: 0;
    cursor: pointer;
}

/* ------------------------------------------------------------------
   Issue #29 (28/07) — un titre est une ancre, et le retour y ramène
   ------------------------------------------------------------------

   Le comportement existe déjà : le navigateur sait sauter à `#monument` et le
   bouton précédent sait y revenir. Deux choses seulement lempêchaient

/* ------------------------------------------------------------------
   Issue #29 (28/07) — un titre est une ancre, et le retour y ramène
   ------------------------------------------------------------------

   Le comportement existe déjà : le navigateur sait sauter à une section par
   son fragment, et le bouton précédent sait y revenir. Deux choses seulement
   l'empêchaient d'être utilisable, et aucune des deux n'est propre à une page.

   1. La nav est collante en haut de l'écran : une cible atteinte par un
      fragment se retrouvait CACHÉE dessous. Trois endroits du site avaient
      déjà posé leur propre décalage -- 16px, 16px et 80px, trois valeurs pour
      un seul problème, dont deux insuffisantes. Le décalage est désormais
      nommé une fois et s'applique à toute cible.

   2. Rien ne disait où l'on venait d'atterrir. Un rappel bref et discret
      suffit -- surtout pas une couleur qui reste, qui ferait croire à une
      sélection persistante.

   Écrit globalement plutôt que page par page : poser un identifiant sur un
   titre suffit désormais à le rendre atteignable ET lisible, sans que l'auteur
   du gabarit ait à connaître la hauteur de la nav ni à recopier quoi que ce
   soit. C'est la raison d'être de cette règle : les trois valeurs divergentes
   ci-dessus sont exactement ce qui arrive quand chacun résout le problème dans
   son coin. */
:root {
    /* Hauteur de la nav collante, plus une respiration. Une seule valeur à
       reprendre le jour où la nav change de gabarit. */
    --antiqua-decalage-ancre: 80px;
}

:target {
    scroll-margin-top: var(--antiqua-decalage-ancre);
    border-radius: 6px;
    /* `animation` et non `transition` : le rappel doit se déclencher à
       l'arrivée puis s'effacer tout seul, sans laisser d'état derrière lui. */
    animation: antiqua-retour-ancre 1.6s ease-out 1;
}

@keyframes antiqua-retour-ancre {
    from { background-color: rgba(138, 106, 63, 0.18); }
    to { background-color: transparent; }
}

/* Le mouvement lui-même est adouci pour qui le demande : le saut reste
   instantané, seul le fondu du rappel disparaît. */
@media (prefers-reduced-motion: reduce) {
    :target {
        animation: none;
    }
}
