/* ==========================================================================
   WORLDMAP — вертикальный разрез мира и Golden Elevator (§102-106, §282-288)

   Раньше карта была списком горизонтальных карточек: шесть картинок,
   замок «откроется на уровне 10» и ничего между ними. Теперь это один
   разрез: ярусы стоят вплотную друг к другу сверху вниз, шахта лифта
   нарисована ровно по центру каждой картинки и переходит из яруса в
   ярус, а спуск — это прокрутка страницы.

   Три правила файла, без которых он ломается.

   **Ярусы стыкуются без зазора.** Между двумя соседними бандами нет ни
   отступа, ни скругления: разрез земли не бывает с полями. Рамка и тень
   есть только у всего столба целиком.

   **Узлы позиционируются долями кадра.** Сервер присылает центр узла
   числами от нуля до единицы, вёрстка переводит их в проценты. Пиксельных
   координат внутри банда нет ни одной: на 360 px нора обязана остаться
   ровно на своей норе.

   **Закрытый ярус остаётся красивым.** Он притемнён и подписан тизером,
   но не вырезан и не заменён серым прямоугольником — §105 запрещает и
   выставлять счёт («нужен уровень 50»), и прятать мир от игрока.
   ========================================================================== */

.trumpamole__map {
    display: flex;
    flex-direction: column;
    gap: var(--ui-space-2);
    /* Место под нижнее меню отмеряет сама `.page`; второй такой отступ
       здесь оставлял бы под последним ярусом пустой экран. */
    padding: 0 var(--ui-space-2) var(--ui-space-3);
    box-sizing: border-box;
}

/* ----- Шапка -------------------------------------------------------------
   Одна строка: название раздела и две плитки — сколько ярусов открыто и
   сколько звёзд собрано. Больше в шапку не помещается ничего полезного,
   а карта важнее любой сводки. */
/* Материал шапки — карточка рамы (§6): своя заливка по `--brown-*` вела
   на фиолетовый корпус, но на пол-тона мимо соседних панелей игры. */
.trumpamole__map-head {
    display: flex;
    align-items: center;
    gap: var(--ui-space-2);
    padding: var(--ui-space-2) var(--ui-space-3);
}

/* Название раздела набрано как подпись секции (§3 рамы): плотный капслок
   с обводкой. Прежний Nunito золотом читался подписью карточки, а не
   заголовком экрана, и в узкой строке с двумя чипами обрезался раньше. */
.trumpamole__map-title {
    flex: 1 1 auto;
    min-width: 0;
    font-family: var(--ui-font-condensed);
    font-size: var(--ui-size-value);
    font-weight: 900;
    letter-spacing: 0.05em;
    line-height: 1.15;
    text-transform: uppercase;
    color: var(--ui-ivory-light);
    text-shadow:
        -1px -1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent), 1px -1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent),
        -1px  1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent), 1px  1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Заливку, кромку и радиус чипа задаёт §10 рамы; здесь остаётся строй и
   набор. Своя полупрозрачная чернота с золотой линией в 1px — ровно тот
   «обычный card», что запрещает §62 ТЗ. */
.trumpamole__map-chip {
    display: flex;
    align-items: center;
    gap: 5px;
    flex: 0 0 auto;
    padding: 5px 9px;
    font-family: var(--ui-font-condensed);
    font-size: var(--ui-size-small);
    font-weight: var(--ui-weight-value);
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.trumpamole__map-chip svg {
    color: var(--ui-gold-light);
    flex: 0 0 auto;
}

/* ----- Столб ярусов ------------------------------------------------------ */
.trumpamole__map-shaft {
    position: relative;
    border-radius: var(--ui-radius-lg);
    border: var(--ui-border-thick) solid var(--ui-panel-edge);
    overflow: hidden;
    /* Столб почти целиком закрыт артом ярусов, поэтому он остаётся
       тёмным корпусом, а не светлой доской: перепад «поле тёмное —
       панели светлые» держат шапка сверху и карточки узлов внутри. */
    background: var(--ui-panel-dark);
    box-shadow: 0 5px 0 var(--ui-panel-edge), var(--ui-shadow-soft);
}

/* Ярус. Высота задана пропорцией картинки, а не пикселями: банды обязаны
   стыковаться на любой ширине телефона. */
.trumpamole__map-region {
    position: relative;
    display: block;
    width: 100%;
    aspect-ratio: 16 / 9;
    /* Нижняя кромка земли: без неё стык двух картинок читается как шов
       вёрстки, а не как слой почвы. */
    box-shadow: inset 0 -2px 0 rgba(0, 0, 0, 0.55);
    overflow: hidden;
}

.trumpamole__map-region-art {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    user-select: none;
    -webkit-user-drag: none;
}

/* Ярус без картинки не показывает битую ссылку: под ней лежит слой
   земли того же тона, что и края разреза. */
.trumpamole__map-region-fill {
    position: absolute;
    inset: 0;
    background:
        var(--ui-dirt-wide),
        var(--ui-dirt),
        radial-gradient(120% 80% at 50% 0%,
            color-mix(in srgb, var(--ui-panel-light) 55%, transparent) 0%,
            transparent 70%),
        linear-gradient(180deg, var(--ui-wood) 0%, var(--ui-panel-dark) 100%);
}

/* Притемнение под подписи: текст на нарисованной земле иначе не читается
   ни на светлом газоне, ни на тёмном комплексе. */
/*
 * Середина вуали была почти прозрачной (10 %), а узлы стоят именно в
 * середине кадра: подписи ложились на светлый газон и золото хранилища
 * и переставали читаться. Плотность поднята до трети — арт по-прежнему
 * узнаётся, но работает как фактура под содержимым, а не как картинка
 * поверх него.
 */
.trumpamole__map-region-veil {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--ui-bg-deep) 66%, transparent) 0%,
        color-mix(in srgb, var(--ui-bg-deep) 34%, transparent) 30%,
        color-mix(in srgb, var(--ui-bg-deep) 32%, transparent) 64%,
        color-mix(in srgb, var(--ui-bg-deep) 62%, transparent) 100%);
    pointer-events: none;
}

/* Закрытый ярус: приглушён и обесцвечен, но узнаваем. */
.trumpamole__map-region.is-locked .trumpamole__map-region-art {
    filter: grayscale(0.75) brightness(0.42) contrast(0.92);
}

/* Безымянный ярус (B-99 до главы 16) — почти силуэт: игрок видит, что
   там что-то есть, и не видит что. */
.trumpamole__map-region.is-unnamed .trumpamole__map-region-art {
    filter: grayscale(1) brightness(0.22) contrast(1.15);
}

/* Пройденный ярус меняется визуально (§106): тёплый свет и золотая
   кромка вместо серой земли. */
.trumpamole__map-region.is-cleared .trumpamole__map-region-art {
    filter: saturate(1.12) brightness(1.06);
}

.trumpamole__map-region.is-cleared::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--ui-gold-light) 14%, transparent) 0%,
        color-mix(in srgb, var(--ui-gold-dark) 8%, transparent) 100%);
    pointer-events: none;
}

/* ----- Табличка яруса ----------------------------------------------------
   Этаж, название и состояние. Стоит сверху слева, где на всех картинках
   разреза земля, а не содержимое. */
.trumpamole__map-plate {
    position: absolute;
    top: 8px;
    left: 8px;
    right: 8px;
    display: flex;
    align-items: center;
    gap: 8px;
    pointer-events: none;
}

.trumpamole__map-floor {
    flex: 0 0 auto;
    padding: 3px 8px;
    border-radius: var(--ui-radius-sm);
    background:
        var(--ui-dirt-lite),
        linear-gradient(180deg, var(--ui-gold) 0%, var(--ui-gold-dark) 100%);
    border: var(--ui-border) solid var(--ui-gold-btn-edge);
    /* Кегль 11px: обводка съела бы просвет буквы (§21 рамы), поэтому на
       золоте здесь тёмная надпись, а не кремовая с контуром. */
    color: var(--ui-text-dark);
    font-family: var(--ui-font-condensed);
    font-size: var(--ui-size-small);
    font-weight: 900;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
}

.trumpamole__map-region.is-locked .trumpamole__map-floor {
    background:
        var(--ui-dirt-wide),
        var(--ui-dirt),
        linear-gradient(180deg, var(--ui-wood) 0%, var(--ui-panel-dark) 100%);
    border-color: var(--ui-panel-edge);
    color: var(--ui-locked-text);
}

.trumpamole__map-name {
    min-width: 0;
    flex: 1 1 auto;
    font-family: var(--ui-font-title);
    font-size: var(--ui-size-body);
    font-weight: var(--ui-weight-value);
    line-height: 1.2;
    color: var(--ui-text-main);
    text-shadow: var(--ui-text-shadow-sm);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.trumpamole__map-region.is-cleared .trumpamole__map-name {
    color: var(--ui-gold-light);
}

/* Счётчик узлов яруса. У закрытого его нет: сколько там боёв — часть
   того, что ещё предстоит узнать. */
.trumpamole__map-count {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 3px 7px;
    /* Материал — утопленная поверхность рамы (§8): счётчик показывает
       значение, а не зовёт нажать. */
    font-family: var(--ui-font-condensed);
    font-size: var(--ui-size-small);
    font-weight: var(--ui-weight-value);
    white-space: nowrap;
}

.trumpamole__map-count svg { color: var(--ui-gold-light); }

/* Собственный display перебивает браузерное правило для [hidden]. Без
   этих строк тизер горел и на открытых ярусах, поверх узлов. */
.trumpamole__map-count[hidden],
.trumpamole__map-teaser[hidden] { display: none; }

/* ----- Тизер закрытого яруса ---------------------------------------------
   Единственный текст, который видит игрок вместо условия открытия. Он
   дразнит и ничего не считает: точное условие остаётся на сервере. */
.trumpamole__map-teaser {
    position: absolute;
    left: 50%;
    bottom: 12px;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 8px;
    max-width: min(86%, 320px);
    padding: 7px 12px;
    /* Материал — утопленная поверхность рамы (§8). Свой прямоугольник с
       золотой линией в 1px стоял на пёстром арте наклейкой. */
    font-family: var(--ui-font-main);
    font-size: var(--ui-size-small);
    font-weight: var(--ui-weight-body);
    line-height: 1.3;
    text-align: left;
    pointer-events: none;
}

.trumpamole__map-teaser svg {
    flex: 0 0 auto;
    color: var(--ui-gold-light);
}

/* ----- Узел --------------------------------------------------------------
   Центр узла приходит долями кадра и ставится в атрибут style. Здесь
   только оформление. */
.trumpamole__map-node {
    position: absolute;
    transform: translate(-50%, -50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    width: 56px;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    transition: transform var(--tam-t-state) ease;
}

.trumpamole__map-node:active {
    transform: translate(-50%, -50%) scale(0.94);
}

/*
 * Щит уровня — главный предмет карты.
 *
 * Замер по кадру «КАРТА УРОВНЕЙ» (as/5.png): пятиугольник со скруглённым
 * верхом и острым низом, ширина 52px при телефоне в 390 CSS-px, толстая
 * почти чёрная кромка, внутри тёплое дерево на ступень темнее панели, и
 * крупный кремовый номер плотным шрифтом с обводкой.
 *
 * Форма собрана двумя слоями, а не рамкой: `border` не умеет идти по
 * `clip-path`, и кромка обрезалась бы по прямоугольнику. Внешний слой —
 * это и есть кромка, внутренний (::before, инсет 3px) — заливка.
 */
.trumpamole__map-node-shield {
    position: relative;
    display: grid;
    place-items: center;
    /*
     * Форма снята с кадра пипеткой (as/5.png, щит уровня 50): это
     * ГЕРАЛЬДИЧЕСКИЙ щит, а не пятиугольник. Три признака, без которых
     * фигура читается булавкой карты:
     *   - он ШИРЕ, чем выше: 58x48 при кадре в 330px, то есть 1.2:1;
     *   - верхняя кромка с выемкой посередине;
     *   - низ сходится плавно на последней трети, а не углом от середины.
     * Прежний вариант (54x54, обрезка от 68 % к острию) давал каплю.
     */
    width: 56px;
    height: 47px;
    background: var(--ui-panel-edge);
    clip-path: polygon(
        0% 10%, 12% 0%, 41% 0%, 50% 8%, 59% 0%, 88% 0%,
        100% 10%, 100% 58%, 80% 84%, 50% 100%, 20% 84%, 0% 58%);
    filter: drop-shadow(var(--ui-art-shadow-pin));
    pointer-events: none;
}

.trumpamole__map-node-shield::before {
    content: "";
    position: absolute;
    inset: 3px;
    background:
        var(--ui-dirt-wide),
        var(--ui-dirt),
        linear-gradient(180deg,
            var(--ui-wood-light) 0%, var(--ui-wood) 54%, var(--ui-panel-dark) 100%);
    clip-path: polygon(
        0% 10%, 12% 0%, 41% 0%, 50% 8%, 59% 0%, 88% 0%,
        100% 10%, 100% 58%, 80% 84%, 50% 100%, 20% 84%, 0% 58%);
    box-shadow: inset 0 2px 0 color-mix(in srgb, var(--ui-purple-glow) 22%, transparent);
}

/* Узел босса — тот же щит, но красный: место читается как опасное. */
.trumpamole__map-node-shield.is-boss::before {
    background:
        var(--ui-dirt-wide),
        var(--ui-dirt),
        linear-gradient(180deg,
            var(--ui-red) 0%, var(--ui-wood-light) 54%, var(--ui-panel-main) 100%);
}

.trumpamole__map-node-num {
    position: relative;
    z-index: 1;
    /* Номер стоит в верхней, широкой части щита, а не по центру фигуры:
       низ пятиугольника острый, и цифра в геометрическом центре выглядит
       съехавшей вниз. */
    margin-top: -5px;
    display: flex;
    align-items: center;
    color: var(--ui-ivory-light);
    font-family: var(--ui-font-condensed);
    font-weight: 900;
    font-size: var(--ui-size-title);
    line-height: 1;
    font-variant-numeric: tabular-nums;
    text-shadow:
        -1px -1px 0 color-mix(in srgb, var(--ui-text-outline) 92%, transparent), 1px -1px 0 color-mix(in srgb, var(--ui-text-outline) 92%, transparent),
        -1px  1px 0 color-mix(in srgb, var(--ui-text-outline) 92%, transparent), 1px  1px 0 color-mix(in srgb, var(--ui-text-outline) 92%, transparent),
         0 3px 0 rgba(0, 0, 0, 0.45);
}

/* Запасной вид узла: пока картинка стиля не нарисована, на её месте
   стоит золотая марка с номером, а не пустое место. */
.trumpamole__map-node-disc {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background:
        var(--ui-dirt-lite),
        linear-gradient(180deg, var(--ui-gold-light) 0%, var(--ui-gold-dark) 100%);
    border: var(--ui-border) solid var(--ui-gold-btn-edge);
    box-shadow: var(--ui-edge-gold), var(--ui-shadow-soft);
    color: var(--ui-text-dark);
    font-family: var(--ui-font-condensed);
    font-size: var(--ui-size-value);
    font-weight: 900;
    pointer-events: none;
}

.trumpamole__map-node-disc[hidden],
.trumpamole__map-node-stars[hidden] { display: none; }

/*
 * ПОДПИСИ НА КАРТЕ НЕТ.
 *
 * Два захода подряд пытались уместить название уровня под щитом:
 * сначала одна строка, потом три, потом ширина 76px вместо 68. Ни один
 * не помог, и причина не в вёрстке: на ярусе стоят до шести узлов,
 * координаты им задаёт каталог, и расстояние между соседями бывает
 * меньше ширины подписи. Живой пример из кадра — «ЗОЛОТЫЕ СЛИТКИ»
 * поверх щита «5» и «БУХГАЛТЕР» поверх щита «9».
 *
 * На обоих референсах у узла карты подписи нет вовсе: только щит,
 * номер, звёзды и замок; название игрок читает в карточке уровня,
 * когда по нему нажал. Подпись остаётся в разметке и уходит в
 * `aria-label` кнопки — программе чтения с экрана она нужна.
 */
.trumpamole__map-node-label {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
    pointer-events: none;
}

/*
 * ТРОПА МЕЖДУ УЗЛАМИ.
 *
 * Пунктирная дорожка от уровня к уровню — то, по чему кадр «КАРТА
 * УРОВНЕЙ» узнаётся с первого взгляда. Тянется под узлами и не
 * перехватывает нажатия: щиты остаются единственной целью пальца.
 */
.trumpamole__map-trail {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    z-index: 1;
    pointer-events: none;
    overflow: visible;
}

.trumpamole__map-trail-back,
.trumpamole__map-trail-line {
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
    /* Толщина не тянется вместе с полем: без этого при
       `preserveAspectRatio="none"` линия становится жирной по горизонтали
       и волосяной по вертикали. */
    vector-effect: non-scaling-stroke;
}

.trumpamole__map-trail-back {
    stroke: color-mix(in srgb, var(--ui-bg-deep) 72%, transparent);
    stroke-width: 9;
}

.trumpamole__map-trail-line {
    stroke: color-mix(in srgb, var(--ui-gold-hi) 62%, transparent);
    stroke-width: 5;
    stroke-dasharray: 1 13;
}

/* Узлы стоят поверх тропы. */
.trumpamole__map-node { z-index: 2; }

/* Звёзды узла — служебный значок, поэтому вектор, а не картинка. */
/*
 * Звёзды стоят ПОД щитом и заходят на его остриё.
 *
 * На кадре три звезды лежат ровно на нижнем крае щита и частично
 * перекрывают его: щит и звёзды читаются одним предметом. Отдельная
 * строка звёзд под узлом (как было) отрывала их от щита и добавляла
 * узлу восемь лишних пикселей высоты — на ярусе они складывались в
 * наложение подписей соседних узлов.
 */
.trumpamole__map-node-stars {
    display: flex;
    gap: 2px;
    margin-top: -11px;
    color: color-mix(in srgb, var(--ui-ivory) 24%, transparent);
    filter: drop-shadow(var(--ui-art-shadow-pin));
    pointer-events: none;
}

.trumpamole__map-node-stars svg {
    width: 13px;
    height: 13px;
}

.trumpamole__map-node-stars .is-on { color: var(--ui-gold-light); }

/* Закрытый уровень — тот же щит, только погашенный: на кадре у уровня 51
   щит темнее соседей и поверх него висит замок. */
.trumpamole__map-node.is-locked .trumpamole__map-node-shield::before {
    background: linear-gradient(180deg, var(--ui-panel-main) 0%, var(--ui-bg-dark) 100%);
}

.trumpamole__map-node.is-locked .trumpamole__map-node-num {
    color: var(--ui-locked-text);
}

.trumpamole__map-node.is-locked .trumpamole__map-node-disc {
    filter: grayscale(0.9) brightness(0.55);
}

.trumpamole__map-node.is-locked .trumpamole__map-node-label {
    color: var(--ui-locked-text);
}

.trumpamole__map-node-lock {
    position: absolute;
    top: 26px;
    left: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    color: var(--ui-ivory);
    filter: drop-shadow(var(--ui-art-shadow-pin));
    pointer-events: none;
}

.trumpamole__map-node-lock[hidden] { display: none; }

/* Следующий шаг игрока подсвечен: без этого на девяти ярусах непонятно,
   куда идти дальше. Пульсация медленная — карта не витрина.

   На кадре текущий уровень обведён золотым кольцом, поэтому у щита
   меняется не только свечение, но и кромка. */
.trumpamole__map-node.is-next .trumpamole__map-node-shield {
    background: var(--ui-gold);
    animation: tamMapPulse 2.6s ease-in-out infinite;
}

.trumpamole__map-node.is-next .trumpamole__map-node-shield::before {
    inset: 4px;
}

.trumpamole__map-node.is-next .trumpamole__map-node-disc {
    animation: tamMapPulse 2.6s ease-in-out infinite;
}

@keyframes tamMapPulse {
    0%, 100% { filter: drop-shadow(0 0 var(--ui-glow-sm) color-mix(in srgb, var(--ui-gold-light) 50%, transparent)); }
    50%      { filter: drop-shadow(0 0 var(--ui-glow-md) color-mix(in srgb, var(--ui-gold-light) 95%, transparent)); }
}

/* ----- Панель лифта ------------------------------------------------------
   Кнопка висит над картой, панель выезжает справа. Постоянная колонка
   этажей съедала бы шестую часть ширины телефона, а разрез мира важнее
   списка, в который смотрят раз в сессию. */
/*
 * Кнопка лифта — золотая клавиша игры, а не жёлтый кружок.
 *
 * Круг с плоской заливкой и «парящей» тенью в 42px не встречается на
 * референсах ни разу: там любая кнопка — скруглённый прямоугольник с
 * толстой тёмной кромкой и направленной нижней гранью. Форма меняется
 * на квадрат со скруглением `--ui-radius-md`, у значка появляется
 * тёмная обводка, а тень становится гранью — кнопку стало видно на
 * пёстром арте яруса, где раньше жёлтое пятно сливалось с газоном.
 */
.trumpamole__map-lift-open {
    position: fixed;
    right: 12px;
    bottom: calc(var(--tam-nav-h, 68px) + 16px + var(--safe-bottom, 0px));
    z-index: 30;
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--ui-tap);
    height: var(--ui-tap);
    border-radius: var(--ui-radius-md);
    background:
        var(--ui-dirt-lite),
        linear-gradient(180deg,
        var(--ui-gold-btn-hi) 0%, var(--ui-gold-btn-top) 6%,
        var(--ui-gold-btn) 46%, var(--ui-gold-btn-low) 100%);
    border: var(--ui-border) solid var(--ui-gold-btn-edge);
    box-shadow: var(--ui-edge-gold), var(--ui-shadow-soft),
                inset 0 1px 0 color-mix(in srgb, var(--ui-gold-hi) 55%, transparent);
    color: var(--ui-ivory-light);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: transform var(--ui-ease), box-shadow var(--ui-ease);
}

.trumpamole__map-lift-open svg {
    filter: drop-shadow(0 1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent))
            drop-shadow(0 -1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent))
            drop-shadow(1px 0 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent))
            drop-shadow(-1px 0 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent));
}

.trumpamole__map-lift-open:active {
    transform: translateY(var(--ui-press));
    box-shadow: 0 2px 0 var(--ui-gold-deep), var(--ui-shadow-soft);
}

/* Панель выезжает под шапкой игры, а не поверх неё: шапка нарисована
   выше по слою, и её половина всё равно осталась бы видна — но первый
   этаж списка при этом уезжал бы под неё. */
.trumpamole__map-lift {
    position: fixed;
    top: var(--tam-page-top, 144px);
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 40;
    display: flex;
    justify-content: flex-end;
    background: color-mix(in srgb, var(--ui-bg-deep) 60%, transparent);
    opacity: 0;
    transition: opacity var(--tam-t-panel) ease;
}

.trumpamole__map-lift[hidden] { display: none; }
.trumpamole__map-lift.is-on { opacity: 1; }

/* Панель лифта — деревянная доска с фактурой, как любая поверхность
   игры. Прежняя заливка шла по серо-бурым `--brown-*` из старой гаммы
   и на тёплой карте читалась как чужая накладка. */
.trumpamole__map-lift-panel {
    display: flex;
    flex-direction: column;
    width: min(84%, 300px);
    max-height: 100%;
    padding: var(--ui-space-4) var(--ui-space-3)
             calc(var(--tam-nav-h, 68px) + 16px + var(--safe-bottom, 0px));
    background:
        var(--ui-dirt-wide),
        var(--ui-dirt),
        linear-gradient(180deg,
        var(--ui-panel-light) 0%, var(--ui-panel-main) 46%, var(--ui-panel-dark) 100%);
    border-left: var(--ui-border-thick) solid var(--ui-panel-edge);
    box-shadow: -18px 0 42px rgba(0, 0, 0, 0.5),
                inset 2px 0 0 color-mix(in srgb, var(--ui-purple-glow) 18%, transparent);
    transform: translateX(100%);
    transition: transform var(--tam-t-panel) ease;
    overflow-y: auto;
}

.trumpamole__map-lift.is-on .trumpamole__map-lift-panel { transform: translateX(0); }

/* Заголовок панели набран так же, как подпись секции (§3 рамы). */
.trumpamole__map-lift-title {
    padding: 0 var(--ui-space-1) var(--ui-space-3);
    font-family: var(--ui-font-condensed);
    font-size: var(--ui-size-value);
    font-weight: 900;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-align: center;
    color: var(--ui-ivory-light);
    text-shadow:
        -1px -1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent), 1px -1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent),
        -1px  1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent), 1px  1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent);
}

/* ----- Шахта -------------------------------------------------------------
 * По ТЗ (§19) лифт — сцена, а не выбор уровня списком: шахта, лампы,
 * механика, кабина с кротом. Сама шахта собрана стилями: два вертикальных
 * рельса по краям и утопленный тёмный канал между ними. Строки этажей
 * лежат внутри неё и читаются как двери, а не как пункты меню.
 */
.trumpamole__map-lift-shaft {
    position: relative;
    padding: var(--ui-space-2) 22px var(--ui-space-2) 26px;
    border-radius: var(--ui-radius-lg);
    background:
        var(--ui-dirt-wide),
        linear-gradient(180deg,
            color-mix(in srgb, var(--ui-bg-deep) 62%, transparent),
            color-mix(in srgb, var(--ui-bg-dark) 42%, transparent));
    box-shadow: var(--ui-inner-well);
}

/* Рельсы: две направляющие с металлическим бликом по центру. */
.trumpamole__map-lift-shaft::before,
.trumpamole__map-lift-shaft::after {
    content: "";
    position: absolute;
    top: 6px;
    bottom: 6px;
    width: 10px;
    border-radius: var(--ui-radius-pill);
    /* Латунь: тёмная сторона рельса берётся из золотой ветви словаря, а
       не отдельным коричневым — иначе она попадает в выдачу поиска
       остатков старой темы как «тёплое тёмное». */
    background: linear-gradient(90deg,
        color-mix(in srgb, var(--ui-bg-deep) 95%, transparent) 0%,
        var(--ui-gold-deep) 40%,
        var(--ui-gold-hi) 52%,
        color-mix(in srgb, var(--ui-bg-deep) 95%, transparent) 100%);
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .6);
}

.trumpamole__map-lift-shaft::before { left: 7px; }
.trumpamole__map-lift-shaft::after  { right: 6px; }

/* Кабина: золотая рама, едущая к доступному этажу. Касания не ловит —
   нажимаются сами двери, кабина лишь показывает, где игрок сейчас. */
.trumpamole__map-lift-cabin {
    position: absolute;
    left: 18px;
    right: 14px;
    top: 0;
    pointer-events: none;
    /* Тот же шаг, что у строки этажа (§7 рамы): кольцо кабины обводит
       её ровно по кромке, а не срезает углы. */
    border-radius: var(--ui-radius-md);
    border: var(--ui-border-thick) solid var(--ui-gold-deep);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--ui-bg-deep) 70%, transparent),
                0 0 22px color-mix(in srgb, var(--ui-gold) 35%, transparent),
                inset 0 0 24px color-mix(in srgb, var(--ui-gold) 18%, transparent);
    transition: top var(--tam-t-sheet) cubic-bezier(.2, .85, .2, 1);
}

.trumpamole__map-lift-cabin[hidden] { display: none; }

/* Крот едет в кабине: он привязан к её правому краю, чтобы не залезать
   на золотую табличку этажа и на название яруса. */
.trumpamole__map-lift-rider {
    position: absolute;
    right: -12px;
    bottom: -8px;
    width: 36px;
    height: 36px;
    object-fit: contain;
    filter: drop-shadow(var(--ui-art-shadow-pin));
}

/* Этаж — широкая плита с номером слева и названием справа: подпись вроде
   PENTHOUSE в узкую колонку не помещается ни на одном из пяти языков. */
/* Этаж — строка списка (§7 рамы): материал берётся оттуда, здесь только
   строй, рост и состояния. Своя копия того же градиента жила числами и
   расходилась с соседними списками игры на пол-тона. */
.trumpamole__map-lift-floor {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--ui-space-2);
    width: 100%;
    min-height: 48px;
    margin-bottom: 8px;
    padding: 6px 10px;
    text-align: left;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

.trumpamole__map-lift-floor:active {
    transform: translateY(var(--ui-press));
}

/* Закрытый этаж остаётся плотным: прозрачность на пёстром фоне читается
   как сбой отрисовки, а не как «пока рано». */
.trumpamole__map-lift-floor.is-locked {
    background:
        var(--ui-dirt-wide),
        var(--ui-dirt),
        linear-gradient(180deg, var(--ui-panel-main) 0%, var(--ui-bg-dark) 100%);
    box-shadow: var(--ui-inner-well);
}

.trumpamole__map-lift-num {
    flex: 0 0 auto;
    min-width: 58px;
    padding: 5px 6px;
    border-radius: var(--ui-radius-xs);
    background:
        var(--ui-dirt-lite),
        linear-gradient(180deg, var(--ui-gold-btn-hi) 0%, var(--ui-gold-btn-top) 8%,
        var(--ui-gold-btn) 50%, var(--ui-gold-btn-low) 100%);
    border: var(--ui-border) solid var(--ui-gold-btn-edge);
    box-shadow: 0 2px 0 var(--ui-gold-btn-deep);
    /* Кегль 11px — обводка съела бы просвет буквы (§21), поэтому здесь
       тёмная надпись на золоте, а не кремовая с контуром. */
    color: var(--ui-text-dark);
    font-family: var(--ui-font-condensed);
    font-size: var(--ui-size-small);
    font-weight: 900;
    letter-spacing: 0.05em;
    text-align: center;
    text-transform: uppercase;
}

.trumpamole__map-lift-floor.is-locked .trumpamole__map-lift-num {
    background:
        var(--ui-dirt-wide),
        var(--ui-dirt),
        linear-gradient(180deg, var(--ui-wood-dark) 0%, var(--ui-bg-dark) 100%);
    border-color: rgba(0, 0, 0, 0.5);
    box-shadow: var(--ui-inner-well);
    color: var(--ui-locked-text);
}

.trumpamole__map-lift-name {
    flex: 1 1 auto;
    min-width: 0;
    font-family: var(--ui-font-main);
    font-size: var(--ui-size-body);
    font-weight: var(--ui-weight-section);
    color: var(--ui-text-main);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.trumpamole__map-lift-floor.is-locked .trumpamole__map-lift-name {
    color: var(--ui-locked-text);
}

.trumpamole__map-lift-mark {
    flex: 0 0 auto;
    display: flex;
    color: var(--ui-gold-light);
}

.trumpamole__map-lift-mark[hidden] { display: none; }

/* ----- Лампа и замок этажа -----------------------------------------------
 * Состояние этажа видно значком, а не только словом: на кадре у каждого
 * этажа своя метка. Лампа горит у доступного, замок стоит у закрытого —
 * оба места заняты всегда, поэтому строка не дёргается при смене.
 */
.trumpamole__map-lift-lamp {
    flex: 0 0 auto;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: radial-gradient(circle at 35% 30%,
                var(--ui-gold-hi) 0%, var(--ui-gold) 45%, var(--ui-gold-dark) 100%);
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--ui-bg-deep) 80%, transparent),
                0 0 8px color-mix(in srgb, var(--ui-gold) 70%, transparent);
}

.trumpamole__map-lift-floor.is-locked .trumpamole__map-lift-lamp {
    background: radial-gradient(circle at 35% 30%,
                var(--ui-wood-light) 0%, var(--ui-panel-dark) 100%);
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--ui-bg-deep) 80%, transparent),
                inset 0 1px 2px rgba(0, 0, 0, .7);
}

.trumpamole__map-lift-lock {
    flex: 0 0 auto;
    display: none;
    color: var(--ui-locked-text);
}

.trumpamole__map-lift-floor.is-locked .trumpamole__map-lift-lock { display: flex; }

/* Этаж под кабиной подсвечен изнутри: игрок должен видеть, где стоит. */
/* Место под крота: только у текущего этажа, иначе название всех
   остальных строк сдвинулось бы ради картинки, которой там нет. */
.trumpamole__map-lift-floor.is-here .trumpamole__map-lift-name {
    padding-right: 20px;
}

.trumpamole__map-lift-floor.is-here {
    background:
        var(--ui-dirt-wide),
        var(--ui-dirt),
        linear-gradient(180deg,
        var(--ui-head-light) 0%, var(--ui-panel-light) 55%, var(--ui-wood) 100%);
}

/* ----- Карточка узла -----------------------------------------------------
   Содержимое окна фреймворка: цель боя, цена входа, состав врагов и
   прошлый результат — §287 требует показать это до нажатия «в бой». */
.trumpamole__map-card-hint {
    margin-bottom: var(--ui-space-2);
    color: var(--ui-text-muted);
    font-family: var(--ui-font-main);
    font-size: var(--ui-size-body);
    line-height: 1.35;
    text-align: center;
}

.trumpamole__map-card-facts {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
}

.trumpamole__map-fact {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 5px 9px;
    /* Материал — чип рамы (§10): цель боя, цена входа и состав врагов
       показывают значение, а нажимается кнопка под ними. */
    font-family: var(--ui-font-condensed);
    font-size: var(--ui-size-small);
    font-weight: var(--ui-weight-value);
    white-space: nowrap;
}

.trumpamole__map-fact svg { color: var(--ui-gold-light); flex: 0 0 auto; }

/* ----- Загрузка и отказ --------------------------------------------------- */
.trumpamole__map-skeleton {
    display: flex;
    flex-direction: column;
    gap: var(--ui-space-2);
    padding: 0 var(--ui-space-2);
}

.trumpamole__map-skeleton-bar,
.trumpamole__map-skeleton-shaft {
    border-radius: var(--ui-radius-lg);
    background: linear-gradient(100deg,
        color-mix(in srgb, var(--ui-wood) 45%, transparent) 0%,
        color-mix(in srgb, var(--ui-panel-light) 55%, transparent) 45%,
        color-mix(in srgb, var(--ui-wood) 45%, transparent) 90%);
    background-size: 240% 100%;
    animation: tamMapShimmer 1.5s ease-in-out infinite;
}

.trumpamole__map-skeleton-bar   { height: 52px; }
.trumpamole__map-skeleton-shaft { height: 60vh; }

@keyframes tamMapShimmer {
    0%   { background-position: 120% 0; }
    100% { background-position: -40% 0; }
}

.trumpamole__map-error {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--ui-space-3);
    min-height: 60vh;
    padding: var(--ui-space-5);
    text-align: center;
}

.trumpamole__map-error-icon { color: var(--ui-gold); }

/* Отказ — часть игры (§57 ТЗ), поэтому заголовок набран так же, как
   подпись секции, а не системным гротеском. */
.trumpamole__map-error-title {
    font-family: var(--ui-font-condensed);
    font-size: var(--ui-size-section);
    font-weight: 900;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--ui-ivory-light);
    text-shadow:
        -1px -1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent), 1px -1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent),
        -1px  1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent), 1px  1px 0 color-mix(in srgb, var(--ui-text-outline) 85%, transparent);
}

.trumpamole__map-error-text {
    max-width: 280px;
    font-family: var(--ui-font-main);
    font-size: var(--ui-size-body);
    font-weight: var(--ui-weight-body);
    line-height: 1.4;
    color: var(--ui-text-muted);
}

/* ----- Узкий экран --------------------------------------------------------
   На 360 px узлы соседних лунок начинают наезжать подписями, поэтому
   мельчают вместе с кадром. Переносить подпись в две строки нельзя: она
   тогда закрывает соседний узел. */
@media (max-width: 380px) {

    .trumpamole__map-node        { width: 54px; }
    .trumpamole__map-node-shield { width: 48px; height: 41px; }
    .trumpamole__map-node-num    { font-size: 18px; }
    .trumpamole__map-node-disc  { width: 38px; height: 38px; font-size: 13px; }
    .trumpamole__map-node-label { max-width: 64px; font-size: 9px; }
    .trumpamole__map-node-lock  { top: 24px; }

    .trumpamole__map-title { font-size: 13px; }
    .trumpamole__map-chip  { font-size: 11px; padding: 4px 7px; }
    .trumpamole__map-name  { font-size: var(--ui-size-small); }
    .trumpamole__map-floor { font-size: var(--ui-size-micro); }
    .trumpamole__map-teaser { font-size: 11px; padding: 6px 10px; }
}
