/* =====================================================================
   TABLEAU DE BORD DE JEU
   Trois bandes fixes : où je suis (haut) · ce qui se passe (centre) ·
   mon état et mes actions (bas). Rien ne change de place entre
   l'exploration et le combat — c'est tout l'intérêt.

   Les bandes sont du verre sombre posé sur le décor du monde ; le plateau,
   au centre, prend toute la largeur. Le journal flotte par-dessus, en bas à
   gauche, et s'efface vers le haut.
   ===================================================================== */

.game-layout {
    display: grid;
    grid-template-rows: auto 1fr auto;
    position: fixed;
    inset: 0;
    z-index: 10;
    /*
     * Le décor du monde, très assombri : le plateau et les bandeaux se lisent
     * par-dessus sans effort, mais on n'est plus suspendu dans le noir. La
     * même image sert à la descente et au combat — c'est le même endroit.
     */
    background:
        linear-gradient(180deg, rgba(10, 10, 7, 0.52), rgba(10, 10, 7, 0.76)),
        var(--world-bg, none) center / cover no-repeat,
        var(--ink);

    --world-accent: var(--verdant);
    --world-deep: #0a0f0c;
    --tile-face: #21211e;
    --tile-face-alt: #262623;
    --tile-wall: #090d0b;
    --tile-visited: #181815;
}

.game-layout[data-theme="earth"] {
    --world-bg: url('../assets/backdrops/bg_world_1.webp');
    --world-accent: #5fd68a;
    --world-deep: #080d0a;
    --tile-face: #22221f;
    --tile-face-alt: #282825;
    --tile-wall: #080c09;
    --tile-visited: #181815;
}

.game-layout[data-theme="fire"] {
    --world-bg: url('../assets/backdrops/bg_world_2.webp');
    --world-accent: #ff8a4c;
    --world-deep: #0f0705;
    --tile-face: #291a15;
    --tile-face-alt: #30201a;
    --tile-wall: #0d0605;
    --tile-visited: #1b100c;
}

.game-layout[data-theme="water"] {
    --world-bg: url('../assets/backdrops/bg_world_3.webp');
    --world-accent: #a8c900;
    --world-deep: #0d0d0a;
    --tile-face: #232320;
    --tile-face-alt: #2a2a27;
    --tile-wall: #0d0d0a;
    --tile-visited: #1b1b18;
    background-color: #151512;
}

.game-layout[data-theme="glace"] {
    --world-bg: url('../assets/backdrops/bg_world_5.webp');
    --world-accent: #9fd8ff;
    --world-deep: #070b0e;
    --tile-face: #1e252b;
    --tile-face-alt: #232b32;
    --tile-wall: #080c10;
    --tile-visited: #171d22;
}

.game-layout[data-theme="air"] {
    --world-bg: url('../assets/backdrops/bg_world_4.webp');
    --world-accent: #8fd3c7;
    --world-deep: #0d0b08;
    --tile-face: #26221b;
    --tile-face-alt: #2c2720;
    --tile-wall: #0c0a07;
    --tile-visited: #1c1914;
}

/* En combat, l'ambiance générale bascule : le joueur sait instantanément
   qu'il a changé de mode, sans qu'aucun élément ne se déplace. */
.game-layout.in-combat { --world-accent: var(--blood-lit); }

/* ---------- Bande haute ---------- */
.hud-top {
    position: relative;
    display: flex;
    align-items: center;
    gap: 18px;
    min-height: 64px;
    padding: 8px 18px 8px 14px;
    background: linear-gradient(180deg, rgba(11, 11, 8, 0.94), rgba(13, 13, 10, 0.84));
    border-bottom: 1px solid var(--line);
    box-shadow: 0 10px 26px rgba(0, 0, 0, 0.4);
    z-index: 2;
}

/* L'étage dans un médaillon cerclé de la couleur du monde. */
.hud-floor {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    line-height: 1;
    min-width: 66px;
    padding: 6px 8px 5px;
    border: 1px solid color-mix(in srgb, var(--world-accent) 40%, transparent);
    border-radius: var(--radius-lg);
    background: radial-gradient(ellipse at 50% 0%, color-mix(in srgb, var(--world-accent) 18%, transparent), rgba(0, 0, 0, 0.5));
}

/*
 * Point de reprise, sous le numéro d'étage. Discret tant qu'il ne bouge pas —
 * c'est un repère, pas une alarme — et franchement allumé le temps de quelques
 * pulsations quand il vient d'être débloqué.
 */
.hud-checkpoint {
    margin-top: 5px;
    font-size: 0.68rem;
    letter-spacing: 0.04em;
    color: var(--verdant);
    opacity: 0.75;
    white-space: nowrap;
}

.hud-checkpoint.gagne {
    animation: checkpointGagne 1.1s ease-in-out 3;
    will-change: opacity, transform;
}

@keyframes checkpointGagne {
    0%, 100% { opacity: 0.75; transform: scale(1); }
    50% { opacity: 1; transform: scale(1.18); }
}

@media (prefers-reduced-motion: reduce) {
    .hud-checkpoint.gagne { animation: none; opacity: 1; }
}

.hud-floor small {
    font-size: 0.6rem;
    text-transform: uppercase;
    letter-spacing: 0.2em;
    color: var(--text-dim);
}

.hud-floor b {
    font-family: var(--font-display);
    font-size: 1.65rem;
    color: var(--world-accent);
    text-shadow: 0 0 20px color-mix(in srgb, var(--world-accent) 55%, transparent);
    font-variant-numeric: tabular-nums;
}

/* Jalon court terme : le prochain gardien. Sans repère, une descente
   infinie n'a aucun relief. */
.hud-depth { flex: 1; max-width: 340px; min-width: 120px; }

.depth-bar {
    height: 6px;
    background: rgba(0, 0, 0, 0.6);
    border: 1px solid var(--line-soft);
    border-radius: 4px;
    overflow: hidden;
}

.depth-fill {
    height: 100%;
    width: 0;
    background: linear-gradient(90deg, var(--gold-deep), var(--gold));
    box-shadow: 0 0 8px rgba(217, 164, 65, 0.5);
    transition: width 0.4s ease;
}

.hud-depth small { display: block; margin-top: 5px; font-size: 0.74rem; color: var(--text-dim); letter-spacing: 0.04em; }

/* Faveurs de songe : une pastille par faveur, le cumul en exposant. */
.hud-boons { display: flex; align-items: center; flex-wrap: wrap; gap: 5px; max-width: 330px; }

/* Sceaux de l'expédition : carrés et braise, là où les faveurs sont rondes et bleutées. */
.hud-seals {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 3px 6px 3px 4px;
    border-radius: 6px;
    background: rgba(255, 122, 60, 0.1);
    border: 1px solid rgba(255, 122, 60, 0.45);
}
.hud-seals.hidden { display: none; }
.seal-chip {
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    border-radius: 4px;
    background: rgba(0, 0, 0, 0.45);
    box-shadow: inset 0 0 0 1px rgba(255, 122, 60, 0.35);
}
.seal-chip .chip-art { width: 86%; height: 86%; object-fit: contain; }
.seal-chip.emblem { background: none; box-shadow: none; }
.seal-chip, .seal-chip-points { cursor: help; }

/* Élixirs actifs : pastilles rondes au liseré vert, comme leur infobulle. */
.hud-elixirs { display: flex; align-items: center; gap: 4px; }
.hud-elixirs.hidden { display: none; }
.elixir-chip {
    display: grid;
    place-items: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.45);
    border: 1px solid rgba(79, 212, 138, 0.55);
    cursor: help;
}
.elixir-chip .chip-art { width: 80%; height: 80%; object-fit: contain; }
.log-line.log-loot { cursor: help; }

.seal-chip-points {
    margin-left: 2px;
    font-family: var(--font-display);
    font-size: 0.8rem;
    color: #ffa472;
    font-variant-numeric: tabular-nums;
}

.boon-chip {
    --tier: var(--stone-500);
    position: relative;
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border: 1px solid color-mix(in srgb, var(--tier) 75%, transparent);
    border-radius: 50%;
    background: radial-gradient(circle at 50% 35%, color-mix(in srgb, var(--tier) 24%, transparent), rgba(0, 0, 0, 0.65));
    box-shadow: 0 0 10px color-mix(in srgb, var(--tier) 30%, transparent);
    font-size: 0.92rem;
    line-height: 1;
    cursor: help;
}

.boon-chip small {
    position: absolute;
    right: -5px;
    bottom: -4px;
    padding: 0 3px;
    border: 1px solid color-mix(in srgb, var(--tier) 75%, transparent);
    border-radius: 6px;
    background: var(--ink);
    color: #fff;
    font-size: 0.5rem;
    font-weight: 700;
    line-height: 1.4;
}

.boon-chip.more { font-size: 0.62rem; font-weight: 700; color: var(--text-soft); }
.boon-chip.spotted { --tier: var(--arcane-lit); color: var(--arcane-lit); animation: blink 1.4s ease-in-out infinite; }
.boon-chip.fresh { animation: boonPop 0.6s cubic-bezier(0.3, 1.6, 0.5, 1); }

@keyframes boonPop {
    0% { transform: scale(0.3); }
    60% { transform: scale(1.25); }
    100% { transform: scale(1); }
}

.hud-chips { display: flex; gap: 8px; margin-left: auto; }

.hud-chip {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 5px 13px 5px 7px;
    background: rgba(0, 0, 0, 0.45);
    border: 1px solid var(--line-soft);
    border-radius: 999px;
    font-size: 0.86rem;
}

.hud-chip b { font-family: var(--font-display); font-variant-numeric: tabular-nums; color: #fff; }

.hud-chip.chain { position: relative; gap: 8px; padding: 4px 14px 7px; min-width: 96px; }
.chain-ico { width: 30px; height: 30px; flex-shrink: 0; font-size: 1.15rem; line-height: 1; }
.chain-body { display: flex; flex-direction: column; align-items: center; min-width: 0; }

/* La mèche : elle se vide à chaque pas sans victoire, se remplit à chaque maillon. */
.chain-fuse {
    position: absolute;
    left: 12px;
    right: 12px;
    bottom: 3px;
    height: 3px;
    background: rgba(255, 255, 255, 0.08);
    border-radius: 2px;
    overflow: hidden;
}

.chain-fuse i {
    display: block;
    height: 100%;
    width: 0;
    background: linear-gradient(90deg, var(--ember), var(--gold-lit));
    transition: width 0.25s linear;
}

.hud-chip.chain.burning .chain-fuse i { background: var(--blood-lit); animation: blink 0.6s infinite; }
.hud-chip.chain small { font-size: 0.58rem; text-transform: uppercase; letter-spacing: 0.16em; color: var(--text-dim); }
.hud-chip.chain b { font-size: 1rem; color: var(--text-soft); transition: color 0.2s, text-shadow 0.2s; }
.hud-chip.chain .chain-bonus { color: var(--verdant); letter-spacing: 0.04em; }

.hud-chip.chain.warm { border-color: rgba(240, 180, 41, 0.5); }
.hud-chip.chain.warm b { color: var(--gold-lit); text-shadow: 0 0 16px rgba(240, 180, 41, 0.6); }

.hud-chip.chain.hot { border-color: rgba(255, 122, 60, 0.6); background: rgba(255, 122, 60, 0.1); }
.hud-chip.chain.hot b {
    color: var(--ember);
    text-shadow: 0 0 22px rgba(255, 122, 60, 0.85);
    animation: chainPulse 0.9s ease-in-out infinite;
}

.hud-exit {
    padding: 9px 16px;
    background: linear-gradient(180deg, rgba(90, 26, 38, 0.9), rgba(40, 12, 18, 0.95));
    border: 1px solid #7a2a36;
    border-radius: var(--radius);
    color: #f1a7b0;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 0.72rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    cursor: pointer;
    transition: border-color var(--speed), color var(--speed);
}

.hud-exit:hover { border-color: var(--blood); color: #fff; }

/* ---------- Bande centrale ---------- */
.hud-stage {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    min-height: 0;
    overflow: hidden;
    /* Cette bande couvrait tout l'écran d'un aplat opaque : le décor du monde
       ne se voyait nulle part. Elle laisse maintenant passer, en gardant son
       halo d'ambiance et un voile assez dense pour le plateau. */
    background:
        radial-gradient(ellipse 80% 60% at 60% 45%,
            color-mix(in srgb, var(--world-accent) 9%, transparent), transparent 70%),
        linear-gradient(180deg,
            color-mix(in srgb, var(--world-deep) 52%, transparent),
            color-mix(in srgb, var(--world-deep) 72%, transparent));
}

/*
 * Le journal flotte en bas à gauche, par-dessus la scène : il ne prend plus
 * une colonne entière qu'il laissait vide aux trois quarts. Les lignes
 * anciennes s'effacent vers le haut ; la plus récente est en bas, sous l'œil.
 */
.stage-log {
    position: absolute;
    left: 16px;
    bottom: 14px;
    z-index: 5;
    width: min(320px, 28%);
    max-height: 46%;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px 12px 8px;
    background: linear-gradient(180deg, rgba(12, 12, 9, 0.5), rgba(12, 12, 9, 0.82));
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-lg);
    backdrop-filter: blur(4px);
    min-height: 0;
}

/* En combat, la frise et le bandeau du plateau racontent déjà tout. */
.game-layout.in-combat .stage-log { display: none; }

.stage-log h3 {
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: 0.64rem;
    text-transform: uppercase;
    letter-spacing: 0.2em;
    color: var(--text-dim);
}

.stage-log h3::after {
    content: '';
    flex: 1;
    height: 1px;
    background: linear-gradient(90deg, color-mix(in srgb, var(--world-accent) 50%, transparent), transparent);
}

.log-box {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    font-size: 0.8rem;
    line-height: 1.5;
    display: flex;
    flex-direction: column;
    -webkit-mask-image: linear-gradient(180deg, transparent, #000 28%);
    mask-image: linear-gradient(180deg, transparent, #000 28%);
}

.log-line {
    color: var(--text-soft);
    padding: 3px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.035);
    animation: slideIn 0.22s ease;
}

.log-good { color: var(--verdant); }

/*
 * Objet ramassé : une ligne en surbrillance, dans la couleur de sa rareté.
 * Plus la pièce est rare, plus la ligne s'allume — un commun reste discret,
 * un mythique ne peut pas passer inaperçu.
 */
.log-line.log-loot {
    --rar: var(--stone-500);
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 2px 0;
    padding: 4px 6px;
    border-left: 3px solid var(--rar);
    border-radius: 3px;
    background: linear-gradient(90deg, color-mix(in srgb, var(--rar) 22%, transparent), transparent 90%);
    color: color-mix(in srgb, var(--rar) 60%, #f4ecdc);
    font-weight: 600;
}
.log-line.log-loot.rarity-common { background: linear-gradient(90deg, rgba(255, 255, 255, 0.05), transparent 90%); font-weight: 500; }
.log-line.log-loot.rarity-legendary,
.log-line.log-loot.rarity-mythic {
    background: linear-gradient(90deg, color-mix(in srgb, var(--rar) 36%, transparent), transparent 95%);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--rar) 45%, transparent);
}
/* L'œuf ramassé : sa coquille, en petit. */
.log-loot-art .fam-egg { width: 15px; height: 20px; }
.log-loot-art { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 4px; background: color-mix(in srgb, var(--set, #000) 30%, rgba(0, 0, 0, 0.4)); }
.log-loot-img { width: 100%; height: 100%; object-fit: contain; }
.log-loot-text { min-width: 0; }
.log-bad { color: var(--blood-lit); }
.log-warn { color: #e0a458; }

.stage-view { min-width: 0; min-height: 0; display: flex; flex-direction: column; }

#grid-wrapper {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 12px;
    min-height: 0;
    overflow: hidden;
}

/* ---------- Plateau ---------- */
#game-board {
    --tile-size: 44px;
    --tile-gap: 2px;
    --grid-size: 7;
    position: relative;
    display: grid;
    grid-template-columns: repeat(var(--grid-size), var(--tile-size));
    grid-auto-rows: var(--tile-size);
    gap: var(--tile-gap);
    padding: 12px;
    background: linear-gradient(180deg, rgba(22, 22, 19, 0.95), rgba(12, 12, 9, 0.97));
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow:
        inset 0 0 60px rgba(0, 0, 0, 0.95),
        0 0 70px color-mix(in srgb, var(--world-accent) 14%, transparent),
        0 24px 60px rgba(0, 0, 0, 0.75);
}

#game-board::before {
    content: '';
    position: absolute;
    inset: 5px;
    pointer-events: none;
    border-radius: 4px;
    background:
        linear-gradient(var(--gold), var(--gold)) left top / 14px 1px no-repeat,
        linear-gradient(var(--gold), var(--gold)) left top / 1px 14px no-repeat,
        linear-gradient(var(--gold), var(--gold)) right top / 14px 1px no-repeat,
        linear-gradient(var(--gold), var(--gold)) right top / 1px 14px no-repeat,
        linear-gradient(var(--gold), var(--gold)) left bottom / 14px 1px no-repeat,
        linear-gradient(var(--gold), var(--gold)) left bottom / 1px 14px no-repeat,
        linear-gradient(var(--gold), var(--gold)) right bottom / 14px 1px no-repeat,
        linear-gradient(var(--gold), var(--gold)) right bottom / 1px 14px no-repeat;
    opacity: 0.7;
    z-index: 4;
}

.tile {
    position: relative;
    /* Une dalle, pas un aplat : lumière rasante en haut à gauche, ombre en bas
       à droite. Le grain vient par-dessus, dans ::before. */
    background:
        radial-gradient(circle at 28% 22%, rgba(255, 255, 255, 0.07), transparent 62%),
        linear-gradient(150deg, rgba(255, 255, 255, 0.04), rgba(0, 0, 0, 0.22) 78%),
        var(--tile-face);
    border-radius: 2px;
    display: grid;
    place-items: center;
    font-size: calc(var(--tile-size) * 0.54);
    line-height: 1;
    cursor: pointer;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.045), inset 0 -1px 0 rgba(0, 0, 0, 0.5);
    transition: background 0.18s, box-shadow 0.18s, opacity 0.3s;
}

/*
 * Grain de pierre sur chaque dalle. Le plateau était un aplat uni à côté des
 * illustrations peintes du reste du jeu ; une texture très légère suffit à lui
 * donner de la matière sans brouiller la lecture des icônes.
 */
.tile::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background-image: var(--noise);
    background-size: 58px 58px;
    /*
     * Pas de `mix-blend-mode` ici. Un mode de fusion force le navigateur à
     * traiter la dalle comme un calque à composer avec ce qu'il y a dessous —
     * multiplié par les deux cents dalles du plateau, c'était la moitié du coût
     * de peinture de l'écran. Une simple opacité sur fond sombre donne le même
     * grain pour rien.
     */
    opacity: 0.22;
    pointer-events: none;
}

/* Le grain se décale d'une dalle à l'autre : sans cela, la même tache se répète
   en damier et se voit plus que la texture elle-même. */
.tile.v1::before { background-position: 17px 29px; }
.tile.v2::before { background-position: 34px 11px; }
.tile.v3::before { background-position: 8px 43px; }

.tile.fog::before { opacity: 0.07; }
/*
 * Aucun grain sur les murs : ils doivent rester noirs. En fusion `soft-light`
 * le bruit ne mordait pas sur du très sombre ; en opacité simple il le grisait,
 * et le labyrinthe perdait son dessin. Un mur est un trou dans la carte, pas
 * une dalle.
 */
.tile.wall::before { display: none; }

.tile-icon {
    display: block;
    position: relative;
    z-index: 1;
    filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.9));
    transition: transform 0.18s ease;
}

/* Ombre au sol sous la figurine : elle se pose sur la dalle au lieu d'y flotter. */
.tile-icon::after {
    content: '';
    position: absolute;
    left: 50%;
    bottom: -2px;
    width: 64%;
    height: 16%;
    transform: translateX(-50%);
    border-radius: 50%;
    background: radial-gradient(ellipse, rgba(0, 0, 0, 0.7), transparent 72%);
    pointer-events: none;
}

.tile.fog .tile-icon::after, .tile.wall .tile-icon::after { display: none; }

/* La teinte se pose par-dessus la texture du sol : la nature d'une case se lit
   avant même son icône, sans masquer la pierre. */
.tile::after { content: ''; position: absolute; inset: 0; border-radius: inherit; background: var(--tint, transparent); pointer-events: none; }
.tile:hover:not(.wall):not(.fog) .tile-icon { transform: scale(1.12); }
.tile-sprite {
    display: block;
    width: calc(var(--tile-size) * 0.92);
    height: calc(var(--tile-size) * 0.92);
    object-fit: contain;
    /* Les illustrations détourées n'ont pas d'ombre propre : on la leur donne. */
    filter: drop-shadow(0 3px 4px rgba(0, 0, 0, 0.85));
}
.tile.fog.hinted .tile-sprite { opacity: 0.45; }
.legend-sprite { display: block; width: 18px; height: 18px; object-fit: contain; }

/* Variation de teinte par case : évite l'effet damier trop régulier. */
.tile.v1 { --tint: rgba(255, 255, 255, 0.05); }
.tile.v2 { --tint: rgba(0, 0, 0, 0.14); }
.tile.v3 { --tint: rgba(255, 255, 255, 0.09); }

/* Teinte par type : la nature d'une case se lit à la couleur avant l'icône. */
.tile.t-monster { --tint: rgba(212, 58, 74, 0.3); box-shadow: inset 0 0 12px rgba(212, 58, 74, 0.28); }
.tile.t-elite { --tint: rgba(255, 59, 92, 0.34); box-shadow: inset 0 0 14px rgba(255, 59, 92, 0.4); }
.tile.t-chest { --tint: rgba(217, 164, 65, 0.3); box-shadow: inset 0 0 14px rgba(217, 164, 65, 0.4); }
.tile.t-shrine { --tint: rgba(88, 200, 255, 0.28); box-shadow: inset 0 0 14px rgba(88, 200, 255, 0.35); }
.tile.t-crystal { --tint: rgba(166, 139, 255, 0.3); box-shadow: inset 0 0 14px rgba(166, 139, 255, 0.4); }
.tile.t-start { --tint: rgba(120, 140, 190, 0.2); }

.tile:hover:not(.wall):not(.fog) {
    --tint: color-mix(in srgb, var(--world-accent) 26%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--world-accent) 55%, transparent);
}

.tile.wall {
    /* `--tint` doit être neutralisé ici : les variations v1/v2/v3 posent un voile
       clair par-dessus, prévu pour animer le sol — sur un mur, il le délave. */
    --tint: transparent;
    background: var(--tile-wall);
    cursor: default;
    box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.95), inset 0 -1px 0 rgba(255, 255, 255, 0.02);
    filter: none;
}

.tile.visited { --tint: rgba(0, 0, 0, 0.45); filter: none; }

.tile.fog {
    --tint: #090906;
    color: transparent;
    cursor: default;
    box-shadow: inset 0 0 14px rgba(0, 0, 0, 1);
    filter: none;
}

.tile.fog.hinted { color: color-mix(in srgb, var(--world-accent) 40%, transparent); filter: blur(0.7px); }

.tile.exit {
    --tint: color-mix(in srgb, var(--world-accent) 24%, transparent);
    box-shadow: inset 0 0 16px color-mix(in srgb, var(--world-accent) 40%, transparent);
}

.tile.boss {
    --tint: rgba(255, 59, 92, 0.32);
    box-shadow: inset 0 0 18px rgba(255, 59, 92, 0.4);
    animation: bossGlow 2.2s ease-in-out infinite;
}

.tile.under-player { --tint: color-mix(in srgb, var(--world-accent) 20%, transparent); }
.tile.pulse-hit { animation: pulseHit 0.42s ease; }
.tile.pulse-good { animation: pulseGood 0.5s ease; }

#player-token {
    position: absolute;
    width: var(--tile-size);
    height: var(--tile-size);
    display: grid;
    place-items: center;
    font-size: calc(var(--tile-size) * 0.58);
    border-radius: 50%;
    background: radial-gradient(circle, color-mix(in srgb, var(--world-accent) 45%, transparent), transparent 68%);
    box-shadow: 0 0 20px color-mix(in srgb, var(--world-accent) 65%, transparent);
    pointer-events: none;
    z-index: 3;
    transition: transform 0.14s cubic-bezier(0.3, 0.9, 0.4, 1);
}

#player-token.no-anim { transition: none; }

#player-token .token-art { display: grid; place-items: center; width: 92%; height: 92%; }
#player-token .token-img { width: 100%; height: 100%; object-fit: contain; filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.8)); }

/*
 * Lanterne : une lumière large qui déborde sur les dalles voisines et respire.
 * C'est elle qui dit où l'on est, avant même de chercher le jeton, et qui relie
 * ce plateau très géométrique à l'éclairage des autres écrans.
 */
#player-token::before {
    content: '';
    position: absolute;
    inset: -155%;
    border-radius: 50%;
    background: radial-gradient(circle,
        color-mix(in srgb, var(--world-accent) 30%, transparent) 0%,
        color-mix(in srgb, var(--world-accent) 12%, transparent) 36%,
        transparent 68%);
    pointer-events: none;
    z-index: -1;
    animation: lantern 3.4s ease-in-out infinite;
    /*
     * Ni `mix-blend-mode`, ni animation d'autre chose que l'opacité et la
     * transformation : ces deux-là seules se jouent sur la carte graphique.
     * Avec `screen`, le halo devait relire le plateau sous lui à CHAQUE image,
     * et le repeindre — une boucle à soixante images par seconde qui tournait
     * en continu, sans rapport avec la vitesse de descente. C'était le gel.
     */
    will-change: opacity, transform;
}

@keyframes lantern {
    0%, 100% { opacity: 0.72; transform: scale(1); }
    50% { opacity: 1; transform: scale(1.08); }
}

/* Légende : chaque pictogramme nommé une fois, plus jamais de devinette. */
.board-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px 12px;
    padding: 8px 14px 12px;
    flex-shrink: 0;
}

.legend-item {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 0.66rem;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-dim);
}

.legend-swatch {
    display: grid;
    place-items: center;
    width: 20px;
    height: 20px;
    border-radius: 3px;
    font-size: 0.72rem;
    background: var(--tile-face);
    border: 1px solid var(--stone-700);
}

.legend-item.t-monster .legend-swatch { background: #2b1a1c; border-color: rgba(212, 58, 74, 0.5); }
.legend-item.t-elite .legend-swatch { background: #33161f; border-color: rgba(255, 59, 92, 0.6); }
.legend-item.t-chest .legend-swatch { background: #2e2410; border-color: rgba(217, 164, 65, 0.6); }
.legend-item.t-shrine .legend-swatch { background: #252522; border-color: rgba(88, 200, 255, 0.5); }
.legend-item.t-crystal .legend-swatch { background: #272724; border-color: rgba(166, 139, 255, 0.6); }

/* ---------- Bande basse : globes, XP, actions ---------- */
.hud-bottom {
    position: relative;
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 20px;
    padding: 10px 22px 12px;
    background: linear-gradient(0deg, rgba(11, 11, 8, 0.96), rgba(13, 13, 10, 0.86));
    border-top: 1px solid var(--line);
    box-shadow: 0 -10px 26px rgba(0, 0, 0, 0.4);
    z-index: 2;
}

.orb-wrap { display: flex; flex-direction: column; align-items: center; gap: 4px; }

/*
 * Les globes sont la signature du tableau de bord : gros, ronds, remplis
 * d'un liquide qui descend. On lit son état de santé sans lire un chiffre —
 * et le globe de vie est un bouton, parce que « j'ai peu de PV » et
 * « je bois une potion » doivent être au même endroit.
 */
.orb {
    --orb: var(--blood);
    --fill: 1;
    position: relative;
    width: 92px;
    height: 92px;
    border-radius: 50%;
    border: 2px solid color-mix(in srgb, var(--orb) 45%, var(--stone-500));
    background: radial-gradient(circle at 50% 32%, #1f1f1c, #090906);
    box-shadow:
        inset 0 0 26px rgba(0, 0, 0, 0.95),
        0 0 26px color-mix(in srgb, var(--orb) 28%, transparent),
        var(--lift);
    overflow: hidden;
    cursor: pointer;
    padding: 0;
    transition: transform var(--speed), box-shadow var(--speed), border-color var(--speed);
}

.orb:hover:not(:disabled) {
    transform: translateY(-2px);
    box-shadow: inset 0 0 26px rgba(0, 0, 0, 0.9), 0 0 34px color-mix(in srgb, var(--orb) 50%, transparent), var(--lift);
}

.orb:disabled { cursor: default; }

.orb-liquid {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--orb) 70%, #fff),
        var(--orb) 45%,
        color-mix(in srgb, var(--orb) 70%, #000));
    /* Le niveau monte depuis le bas : la découpe se fait par le haut. */
    clip-path: inset(calc((1 - var(--fill)) * 100%) 0 0 0);
    transition: clip-path 0.4s cubic-bezier(0.3, 0.9, 0.4, 1);
}

.orb-gloss {
    position: absolute;
    inset: 0;
    pointer-events: none;
    background:
        radial-gradient(ellipse 60% 38% at 50% 14%, rgba(255, 255, 255, 0.28), transparent 70%),
        radial-gradient(ellipse 100% 70% at 50% 120%, rgba(0, 0, 0, 0.5), transparent 60%);
}

.orb-value {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    font-family: var(--font-display);
    font-size: 1.2rem;
    font-weight: 700;
    color: #fff;
    text-shadow: 0 2px 4px rgba(0, 0, 0, 0.95), 0 0 14px rgba(0, 0, 0, 0.8);
    font-variant-numeric: tabular-nums;
    pointer-events: none;
}

.orb-caption {
    font-size: 0.7rem;
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.05em;
}

.orb-hp { --orb: var(--blood); }
.orb-pa { --orb: #2f7fd8; }

/* Seuil critique : le globe pulse. Un seul seuil, pas trois — au-delà
   l'alerte devient du décor. */
.orb-hp.critical {
    animation: orbAlarm 1s ease-in-out infinite;
    border-color: var(--blood-lit);
}

.orb-pa.idle { filter: saturate(0.55) brightness(0.8); }

/* PM et PA côte à côte : c'est le budget du tour, comme dans Dofus. */
.orb-cluster { display: flex; align-items: flex-end; gap: 10px; }
.orb-small .orb { width: 66px; height: 66px; }
.orb-small .orb-value { font-size: 0.98rem; }
.orb-pm { --orb: #34a866; cursor: default; }
.orb-pm.idle { filter: saturate(0.55) brightness(0.8); }

/*
 * Anneau du globe : une ferronnerie posée par-dessus, un peu plus large que le
 * verre. Le globe garde son liquide et son chiffre ; l'anneau lui donne sa
 * monture et sa couleur sans rien masquer, puisque son centre est vide.
 */
.orb-holder { position: relative; display: block; }

.orb-ring {
    position: absolute;
    inset: -9%;
    display: block;
    pointer-events: none;
    filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.7));
}

/* Sous le globe : le symbole de la ressource, puis son compte. */
.orb-legend { display: flex; align-items: center; gap: 5px; }
.orb-mark { width: 17px; height: 17px; flex-shrink: 0; font-size: 0.8rem; line-height: 1; display: inline-flex; }
.orb-holder:has(.orb.idle) + .orb-legend .orb-mark { filter: saturate(0.5) brightness(0.75); }

/*
 * LE TABLEAU DE BORD DE DOFUS 3 : un cœur pour les PV, une étoile pour les PA,
 * un losange pour les PM (tools/dofus-habillage.py, pièces « frames/ »). Le
 * remplissage reste le même mécanisme : la version pleine est découpée par
 * le haut selon --fill, posée sur la version vide. Le reflet du cœur est
 * l'ancien anneau.
 */
.orb-hp, .orb-pa, .orb-pm {
    border: 0;
    border-radius: 0;
    box-shadow: none;
    overflow: visible;
    background: center / contain no-repeat;
    filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.6));
}

.orb-hp { background-image: url('../assets/frames/heart_back.webp'); }
.orb-pa { background-image: url('../assets/frames/pa_empty.webp'); }
.orb-pm { background-image: url('../assets/frames/pm_empty.webp'); }
.orb-hp .orb-liquid { background: url('../assets/frames/heart_fill.webp') center / contain no-repeat; }
.orb-pa .orb-liquid { background: url('../assets/frames/pa_full.webp') center / contain no-repeat; }
.orb-pm .orb-liquid { background: url('../assets/frames/pm_full.webp') center / contain no-repeat; }
.orb-hp .orb-gloss, .orb-pa .orb-gloss, .orb-pm .orb-gloss { display: none; }

.orb-hp:hover:not(:disabled), .orb-pa:hover:not(:disabled) {
    box-shadow: none;
    filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.6)) brightness(1.12);
}

.orb-holder:has(.orb-hp) .orb-ring { inset: 1.5%; filter: none; }
.orb-holder:has(.orb-pa) .orb-ring, .orb-holder:has(.orb-pm) .orb-ring { display: none; }

.hud-center { display: flex; flex-direction: column; gap: 7px; min-width: 0; }

.xp-strip { display: flex; align-items: center; gap: 11px; }
.xp-ico { width: 20px; height: 20px; flex-shrink: 0; font-size: 0.95rem; line-height: 1; }

.xp-level {
    font-family: var(--font-display);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--text-dim);
    white-space: nowrap;
}

.xp-level b { font-size: 0.92rem; color: var(--arcane-lit); }
.xp-strip .xp-track { flex: 1; height: 7px; }
.xp-num { font-size: 0.72rem; color: var(--text-dim); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---------- Barre d'action ---------- */
.action-bar { display: flex; align-items: stretch; gap: 8px; flex-wrap: wrap; justify-content: center; }

.act-btn {
    --rar: var(--stone-500);
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-width: 84px;
    min-height: 74px;
    padding: 8px 10px;
    background: linear-gradient(180deg, rgba(43, 43, 40, 0.95), rgba(17, 17, 14, 0.98));
    border: 1px solid color-mix(in srgb, var(--rar) 70%, transparent);
    border-radius: 7px;
    cursor: pointer;
    box-shadow: var(--bevel), inset 0 -10px 18px color-mix(in srgb, var(--rar) 12%, transparent);
    transition: transform 0.14s, box-shadow 0.14s, border-color 0.14s;
}

.act-btn:hover:not(:disabled) {
    transform: translateY(-4px);
    box-shadow: var(--bevel), 0 0 20px color-mix(in srgb, var(--rar) 55%, transparent);
}

.act-btn:disabled, .act-btn.empty { opacity: 0.34; cursor: not-allowed; filter: grayscale(0.85); }

.act-key {
    position: absolute;
    top: 3px;
    left: 4px;
    font-size: 0.58rem;
    color: var(--text-dim);
    border: 1px solid var(--stone-600);
    border-radius: 2px;
    padding: 0 3px;
}

/* Même pastille d'élément qu'au grimoire : un seul repère à apprendre. */
.act-elem { top: 3px; right: 3px; bottom: auto; left: auto; width: 20px; height: 20px; }
.act-elem .elem-art { width: 14px; height: 14px; }
.act-icon { font-size: 1.3rem; line-height: 1; }
.act-art { display: block; width: 2rem; height: 2rem; object-fit: contain; }
.boon-art { display: block; width: 3.1rem; height: 3.1rem; object-fit: contain; }
.chip-art { display: block; width: 1.25rem; height: 1.25rem; object-fit: contain; }
.mat-art { display: inline-block; width: 1.05rem; height: 1.05rem; vertical-align: -0.2em; object-fit: contain; }
.intent-art { display: block; width: 1.6rem; height: 1.6rem; object-fit: contain; }


.act-name {
    font-family: var(--font-display);
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-align: center;
    line-height: 1.2;
}

.act-power { font-family: var(--font-display); font-size: 0.78rem; font-weight: 700; color: var(--gold-lit); }
.act-cost { font-size: 0.68rem; color: #8dbaff; }

.act-btn.elem-terre { --rar: var(--elem-terre); }
.act-btn.elem-feu { --rar: var(--elem-feu); }
.act-btn.elem-eau { --rar: var(--elem-eau); }
.act-btn.elem-air { --rar: var(--elem-air); }

.act-btn.finisher { background: linear-gradient(180deg, #3a2a12, #16110a); }

.act-btn.finisher::after {
    content: '';
    position: absolute;
    inset: -1px;
    border-radius: var(--radius);
    border: 1px solid var(--gold);
    opacity: 0.55;
    pointer-events: none;
    animation: blink 1.8s infinite;
}

.act-btn.flee { --rar: #5f2029; min-width: 66px; }
.act-btn.flee .act-cost { color: #e8929c; }
.act-btn.potion { --rar: var(--verdant); }
.act-btn.potion .act-cost { color: var(--gold); }
.act-btn.wide-act { min-width: 108px; }
.act-btn.wide-act.paused { --rar: var(--gold); color: var(--gold-lit); }

/* Halte de sécurité : le bouton de reprise appelle le regard du joueur qui revient. */
.act-btn.wide-act.halted { --rar: var(--blood-lit); color: #ffd6dc; animation: haltGlow 1.6s ease-in-out infinite; }

@keyframes haltGlow {
    0%, 100% { box-shadow: var(--bevel); }
    50% { box-shadow: var(--bevel), 0 0 18px color-mix(in srgb, var(--blood-lit) 55%, transparent); }
}

/* Potion bue d'office sous le seuil : une pastille posée sur le bord du
   bouton, qui ne touche jamais l'icône. */
.act-auto {
    position: absolute;
    top: -6px;
    left: 50%;
    transform: translateX(-50%);
    padding: 0 5px;
    border: 1px solid var(--verdant);
    border-radius: 6px;
    background: var(--stone-900);
    font-size: 0.5rem;
    font-weight: 700;
    line-height: 1.5;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--verdant);
}

/* Groupe de doctrine : trois boutons collés, l'actif est évident. */
.act-group { display: flex; gap: 2px; }

.act-policy {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-width: 76px;
    min-height: 74px;
    padding: 8px 8px;
    background: rgba(0, 0, 0, 0.45);
    border: 1px solid var(--line-soft);
    color: var(--text-dim);
    cursor: pointer;
    transition: color var(--speed), border-color var(--speed), background var(--speed);
}

.act-policy:first-child { border-radius: var(--radius) 0 0 var(--radius); }
.act-policy:last-child { border-radius: 0 var(--radius) var(--radius) 0; }
.act-policy:hover { color: #fff; }

.act-policy.on {
    color: var(--gold-lit);
    border-color: var(--gold);
    background: linear-gradient(180deg, rgba(217, 164, 65, 0.18), rgba(0, 0, 0, 0.35));
    box-shadow: inset 0 0 14px rgba(217, 164, 65, 0.18);
}

.act-toggle {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    min-width: 84px;
    min-height: 74px;
    padding: 8px 10px;
    background: rgba(0, 0, 0, 0.45);
    border: 1px dashed var(--stone-500);
    border-radius: 7px;
    color: var(--text-dim);
    cursor: pointer;
    transition: color var(--speed), border-color var(--speed), background var(--speed);
}

.act-toggle:hover { color: #fff; }
.act-btn.wide-act.locked, .act-btn.wide-act.locked:hover { color: var(--text-dim); border-color: var(--stone-600); cursor: not-allowed; opacity: 0.75; }
.act-toggle.locked, .act-toggle.locked:hover { color: var(--text-dim); border-style: solid; border-color: var(--stone-600); cursor: not-allowed; opacity: 0.7; }

.act-toggle.on {
    color: var(--verdant);
    border-style: solid;
    border-color: var(--verdant);
    background: rgba(79, 212, 138, 0.12);
    box-shadow: inset 0 0 14px rgba(79, 212, 138, 0.15);
}

/* États allumés : un liseré intérieur de la couleur de l'état. */
.act-policy.on { box-shadow: inset 0 0 0 1px var(--gold), inset 0 0 16px rgba(201, 171, 69, 0.22); }
.act-toggle.on { box-shadow: inset 0 0 0 1px var(--verdant), inset 0 0 16px rgba(82, 209, 138, 0.2); }

.act-tools { display: flex; gap: 8px; margin-left: 8px; padding-left: 12px; border-left: 1px solid var(--line-soft); }

.action-hint {
    text-align: center;
    font-size: 0.74rem;
    color: var(--text-dim);
    letter-spacing: 0.05em;
    min-height: 1em;
}

/* Case Fragment de Songe. */
.tile.t-boon {
    background: #241a3c;
    box-shadow: inset 0 0 16px rgba(166, 139, 255, 0.5);
    animation: bossGlow 2.8s ease-in-out infinite;
}

.legend-item.t-boon .legend-swatch { background: #241a3c; border-color: rgba(166, 139, 255, 0.7); }
