/* ============================================
   БОКОВОЕ МЕНЮ (дощечки на полке)
   ============================================ */

/* Когда сцена не достаёт до края экрана, полка висит в воздухе,
   и обрубленный правый край читается как обрезанная картинка.
   Достраиваем скругление и рамку по всему периметру */
body.has-side-bars .side-menu,
body.has-side-bars .info-panel {
    border-radius: 12px;
    border-right: 4px solid #3d2a1c;
    margin-right: 14px;
}

.side-menu {
    position: fixed;
    right: 0;
    top: 20px;
    padding: 20px 12px 20px 18px;

    display: flex;
    gap: 20px;
    flex-direction: column;
    justify-content: space-evenly;
    align-items: flex-end;

    /* Полка-подложка */
    background-color: #5a3d2b;
    background-image:
        linear-gradient(to left, rgba(0,0,0,0.15) 0%, rgba(255,255,255,0.05) 50%, rgba(0,0,0,0.2) 100%),
        url('resources/images/wood_pattern.webp');
    background-size: auto;

    border-radius: 12px 0 0 12px;
    border-left: 4px solid #3d2a1c;
    border-top: 3px solid #7a5a45;
    border-bottom: 4px solid #2a1a10;

    box-shadow:
        -6px 0 20px rgba(0, 0, 0, 0.4),
        inset 2px 0 8px rgba(0, 0, 0, 0.3);

    z-index: 10;
}

/* Кнопка-дощечка */
.menu-plank {
    width: 100%;
    min-width: 120px;
    max-width: 120px;
    padding: 16px 8px;
    text-orientation: mixed;

    /* Надпись не переносится НИКОГДА: «Доска почёта» в две строки
       ломает полку, и у одного из тестеров это уже случилось. Запас
       по ширине копеечный, а шрифт грузится не мгновенно — с запасным
       надпись шире и не влезает. Поэтому не полагаемся на неё вовсе:
       перенос запрещён, а кегль подгоняется под планку (js/text_fit.js) */
    white-space: nowrap;

    /* Стиль дерева */
    background-color: #a0522d;
    background-image:
        linear-gradient(to bottom, rgba(255, 255, 255, 0.12) 0%, rgba(0, 0, 0, 0.1) 100%),
        url('resources/images/wood_pattern.webp');
    background-size: cover;

    border-radius: 5px;
    border-top: 2px solid #c9956c;
    border-left: 2px solid #c9956c;
    border-right: 2px solid #6b3a1f;
    border-bottom: 3px solid #4a2815;

    box-shadow:
        inset 0 0 6px rgba(0, 0, 0, 0.2),
        2px 2px 4px rgba(0, 0, 0, 0.3);

    font-family: 'CommonFont', serif;
    font-size: 1rem;
    font-weight: bold;
    letter-spacing: 1px;
    color: #ffe8d0;
    text-shadow:
        1px 1px 1px rgba(0, 0, 0, 0.8),
        -1px -1px 1px rgba(0, 0, 0, 0.4),
        0 0 8px rgba(0, 0, 0, 0.5);

    cursor: pointer;
    transition: transform 0.25s ease, box-shadow 0.25s ease, color 0.2s ease, text-shadow 0.2s ease;
    transform-origin: right center;
}

/* Надпись занимает всю планку: подгонка кегля меряет её ширину, а inline
   всегда по содержимому — переполнения не случилось бы даже когда текст
   не влезает, и мерить было бы нечего */
.menu-plank > span {
    display: block;
    width: 100%;
    overflow: hidden;
}

.menu-plank:hover {
    transform: translateX(-4px) rotate(-1deg);
    color: #fff;
    text-shadow:
        1px 1px 1px rgba(0, 0, 0, 0.9),
        -1px -1px 1px rgba(0, 0, 0, 0.5),
        0 0 12px rgba(255, 220, 180, 0.6),
        0 0 20px rgba(255, 200, 150, 0.3);
    box-shadow:
        inset 0 0 6px rgba(0, 0, 0, 0.2),
        3px 3px 8px rgba(0, 0, 0, 0.35);
}

.menu-plank:active {
    transform: translateX(-2px);
    color: #ffd9b3;
    box-shadow:
        inset 0 0 10px rgba(0, 0, 0, 0.35),
        1px 1px 4px rgba(0, 0, 0, 0.25);
}

/* ============================================
   ИНФО-ПАНЕЛЬ (конфеты + режим)
   ============================================ */

.info-panel {
    position: fixed;
    right: 0;

    /* Прижата к низу, а не отсчитана от верха.
       Было top: calc(25% + 280px) — расчёт под высокий экран: при высоте
       окна 747px панель уезжала на 67px за нижний край, дейлик обрезался,
       а строка режима не была видна вовсе. В оболочке Яндекса высота
       ещё меньше — там свой хедер поверх игры */
    bottom: 12px;

    /* Если и этого мало (совсем низкое окно) — панель прокручивается
       внутри себя, но не вылезает за экран и не наезжает на меню */
    max-height: calc(var(--stage-h) - 240px);
    overflow-y: auto;
    padding: 20px 12px 20px 18px;
    width: 120px;

    display: flex;
    flex-direction: column;
    gap: 10px;
    align-items: center;

    /* Деревянная подложка */
    background-color: #4a3525;
    background-image:
        linear-gradient(to left, rgba(0,0,0,0.2) 0%, rgba(255,255,255,0.05) 50%, rgba(0,0,0,0.25) 100%),
        url('resources/images/wood_pattern.webp');
    background-size: auto;

    border-radius: 10px 0 0 10px;
    border-left: 3px solid #3d2a1c;
    border-top: 2px solid #6a5040;
    border-bottom: 3px solid #2a1a10;

    box-shadow:
        -4px 0 15px rgba(0, 0, 0, 0.35),
        inset 2px 0 6px rgba(0, 0, 0, 0.25);

    z-index: 9;
}

/* ============================================
   ДОЩЕЧКА В ИГРЕ ПО ССЫЛКЕ

   Конфет за такую партию не начисляем и задание не двигаем. Просто
   спрятать счётчики нельзя — они бы моргнули и пропали, и это читается
   как поломка. Поэтому дощечку сначала поворачиваем изнанкой,
   заколоченной накрест, — это объясняет, что случилось, — а потом
   уводим за правый край: в таком виде она места не стоит. Что показать
   на освободившемся месте в сетевой партии, решим отдельно.

   Поворот делаем одной панелью, без preserve-3d: у неё overflow-y: auto,
   а непрозрачное переполнение принудительно возвращает плоскую укладку,
   и настоящая объёмная карточка тут просто не собралась бы. Лицо гасим
   прозрачностью в середине поворота — на глаз выходит то же самое.
   ============================================ */
@keyframes info-panel-away {
    0%   { transform: none; }

    /* Поворот, потом заметная стоянка: изнанку надо успеть разглядеть,
       иначе дощечка просто мигнёт и уедет */
    45%  { transform: perspective(900px) rotateY(180deg); }
    62%  { transform: perspective(900px) rotateY(180deg); }

    /* Сдвиг стоит ПЕРЕД поворотом в записи, значит применяется после
       него — и едет по неперевёрнутой оси, вправо, как и надо */
    100% { transform: perspective(900px) translateX(130%) rotateY(180deg); }
}

/* ОТКЛЮЧЕНО: класс больше никто не вешает.
   Делалось, когда в партии по ссылке не начислялись конфеты и не
   двигалось задание, — тогда дощечке и правда было нечего показывать.
   Теперь начисляются и двигается, и панель видна всегда.
   Правила оставлены: вещь сделана и может пригодиться */
.info-panel.is-net-off {
    animation: info-panel-away 1.3s ease forwards;
}

.info-panel > .info-row,
.info-panel > .info-daily-quest {
    transition: opacity 0.15s ease 0.25s;
}

.info-panel.is-net-off > .info-row,
.info-panel.is-net-off > .info-daily-quest {
    opacity: 0;
    pointer-events: none;
}

.info-panel-back {
    position: absolute;
    inset: 0;
    border-radius: 10px 0 0 10px;

    /* Изнанка: то же дерево, но без бликов лицевой стороны */
    background-color: #43301f;
    background-image:
        linear-gradient(to right, rgba(0,0,0,0.28) 0%, rgba(255,255,255,0.04) 55%, rgba(0,0,0,0.3) 100%),
        url('resources/images/wood_pattern.webp');

    /* Зеркалим: панель повёрнута, и без этого доски легли бы наоборот */
    transform: scaleX(-1);

    /* Своё обрезание, а не панельное: доски нарочно шире дощечки,
       и без него у панели включился бы горизонтальный скрол —
       overflow-y: auto тянет за собой overflow-x */
    overflow: hidden;

    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease 0.25s;
}

.info-panel.is-net-off .info-panel-back {
    opacity: 1;
}

/* Две доски накрест */
.info-panel-back::before,
.info-panel-back::after {
    content: "";
    position: absolute;
    left: -30%;
    top: 50%;
    width: 160%;
    height: 22px;
    margin-top: -11px;

    background-color: #5c452f;
    background-image: url('resources/images/wood_pattern.webp');
    border-top: 2px solid #7d6349;
    border-bottom: 2px solid #2f2013;
    box-shadow: 0 5px 12px rgba(0, 0, 0, 0.45);
}

.info-panel-back::before { transform: rotate(24deg); }
.info-panel-back::after  { transform: rotate(-24deg); }

.info-row {
    display: flex;
    align-items: center;
    gap: 8px;

    font-family: 'CommonFont', serif;
    font-size: 1rem;
    color: #ffe8d0;
    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.6);
}

.info-candies {
    font-size: 1.4rem;
    font-weight: bold;
}

.info-icon {
    width: 64px;
    height: 64px;
    object-fit: contain;
    filter: drop-shadow(1px 1px 2px rgba(0,0,0,0.4));
}

.info-mode {
    font-size: 0.85rem;
    color: rgba(255, 232, 208, 0.7);
    padding-right: 2px;
}

/* Дейлик (ежедневное задание) */
.info-daily-quest {
    padding: 10px 8px;
    margin: 5px 0;
    background: rgba(0, 0, 0, 0.2);
    border-radius: 8px;
    text-align: center;
}

.quest-desc {
    font-family: 'CommonFont', serif;
    font-size: 0.75rem;
    color: rgba(255, 232, 208, 0.9);
    line-height: 1.3;
    margin-bottom: 6px;
}

.quest-progress {
    font-family: 'NoteLocal', serif;
    font-size: 1rem;
    color: #fff;
    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
}

.quest-reward {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    margin-top: 6px;
    font-family: 'CommonFont', serif;
    font-size: 0.85rem;
    color: #7cb342;
}

.quest-reward-icon {
    width: 18px;
    height: 18px;
}

/* Выполненный дейлик.

   Зелёная заливка говорила «готово» тем же цветом, каким полоска
   говорит «идёт», — состояния различались только насыщенностью.
   Теперь выполненное задание становится бумажкой: тот же paper.webp,
   что у записок и заголовков модалок, и на неё ляжет печать.

   Бумага светлая, а панель вокруг тёмная, поэтому все надписи внутри
   приходится перекрашивать в чернила — иначе светлый текст исчезает */
.info-daily-quest.completed {
    background: url("resources/images/paper.webp") 0 0 / 100% 100% no-repeat;

    /* Печать кладётся absolute по этому углу */
    position: relative;
}

.info-daily-quest.completed .quest-desc,
.info-daily-quest.completed .quest-progress {
    color: var(--modal-title-color);
    text-shadow: none;
}

.info-daily-quest.completed .quest-reward {
    color: var(--modal-title-color);
}

/* Жёлоб полоски на бумаге: тёмный по светлому, а не наоборот */
.info-daily-quest.completed .quest-progress-bar {
    background: rgba(93, 78, 55, 0.18);
}

/* Печать по бумаге. Лежит в разметке всегда, но существует только
   у выполненного — держать её в JS незачем, класс на блоке уже есть */
.quest-seal {
    display: none;
}

.info-daily-quest.completed .quest-seal {
    display: block;
    position: absolute;

    /* Печать свисает за нижний край, по середине ширины. По углам она
       накрывала награду «+5», а приложенная целиком внутрь читалась бы
       как нарисованная на листке, а не оттиснутая поверх. Снизу по центру
       она попадает в промежуток между «2/2» слева и наградой справа.
       Обрезать некому — до body с его overflow: hidden отсюда далеко.

       Центр держим на right: calc(50% − половина ширины), а не на
       translateX: постоянный transform внутри масштабированной сцены
       поднимает слой композиции, и соседи по панели мылятся */
    right: calc(50% - 20px);
    bottom: -12px;
    width: 40px;

    /* Печать декоративная: курсор и наведение сквозь неё проходят
       к самому блоку, у него свой обработчик */
    pointer-events: none;
}

/* Удар печати. Ставится один раз, классом из stampQuestSeal(), и класс
   снимается по animationend — постоянного слоя композиции внутри
   масштабированной сцены после себя не оставляем */
.quest-seal.is-stamping {
    /* 1140 мс, а не 380: на глаз выбрано после прогона в замедлении.
       На коротком удар читался как мигание — фазы «занесли», «приложили»,
       «отпустили» сливались в одну */
    animation: quest-seal-stamp 1140ms cubic-bezier(0.25, 0.9, 0.3, 1) both;
}

@keyframes quest-seal-stamp {
    /* Заходит сверху крупной и прозрачной — будто печать ещё в руке */
    0%   { transform: scale(2.3) translateY(-10px); opacity: 0; }
    45%  { opacity: 1; }
    /* Приложили с нажимом: чуть меньше своего размера */
    65%  { transform: scale(0.9) translateY(0); opacity: 1; }
    /* И отпустили */
    100% { transform: scale(1) translateY(0); opacity: 1; }
}

/* Кому анимации мешают — печать просто появляется */
@media (prefers-reduced-motion: reduce) {
    .quest-seal.is-stamping { animation: none; }
}

/* ============================================
   МОДАЛЬНЫЕ ОКНА
   ============================================ */

/* Затемняющий оверлей для fullscreen модалок */
.modal-overlay {
    position: fixed;
    /* Не до края сцены, а до края ЭКРАНА. Сцена уже окна, когда
       пропорции не совпали, и затемнение по её границе оставляло
       по бокам полосы неприкрытой доски. Лишнее срезает
       overflow: hidden у body */
    inset: calc(var(--stage-bleed-y, 0px) * -1) calc(var(--stage-bleed-x, 0px) * -1);
    background: rgba(0, 0, 0, 0.75);
    z-index: 100;
    opacity: 1;
    transition: opacity 0.3s ease;
}

.modal-overlay.hidden {
    display: none;
    opacity: 0;
}

/* Затемняющий оверлей для диалогов (поверх fullscreen) */
.dialog-overlay {
    position: fixed;
    /* Не до края сцены, а до края ЭКРАНА. Сцена уже окна, когда
       пропорции не совпали, и затемнение по её границе оставляло
       по бокам полосы неприкрытой доски. Лишнее срезает
       overflow: hidden у body */
    inset: calc(var(--stage-bleed-y, 0px) * -1) calc(var(--stage-bleed-x, 0px) * -1);
    background: rgba(0, 0, 0, 0.6);
    z-index: 200;
    opacity: 1;
    transition: opacity 0.3s ease;
}

.dialog-overlay.hidden {
    display: none;
    opacity: 0;
}

/* Строгое окно — комната сетевой партии. Затемняем стол заметно
   сильнее: игра ждёт именно этого окна, а не прикрыта им мимоходом,
   и закрыть его щелчком мимо нельзя */
.dialog-overlay.is-strict {
    background: rgba(0, 0, 0, 0.82);
}

/* Строгое окно закрывают только своей кнопкой — крестика у него нет */
.modal[data-strict] .modal-close {
    display: none;
}

/* Комната открыта посреди партии: позвать ушедшего друга обратно.
   Здесь незачем ни Сундук (набор давно зафиксирован), ни «Готов»
   (партия идёт) — зато нужен путь назад, к столу */
#net-room-back {
    display: none;
}

/* Соперник подобран — приглашать некого: прячем код, ссылку и QR.
   Сундук и «Готов» остаются: набор собирают уже здесь */
#modal-net-room.is-matched .net-room-invite {
    display: none;
}

#modal-net-room.is-calling #net-room-back {
    display: inline-block;
}

#modal-net-room.is-calling #net-room-chest {
    display: none;
}

/* Базовый класс модалки */
.modal {
    position: fixed;
    z-index: 101;
    font-family: 'CommonFont', serif;
}

.modal.hidden {
    display: none;
}

/* Диалоги (маленькие модалки) поверх fullscreen */
.modal-small,
.modal-medium {
    z-index: 201;
}

/* ============================================
   МАЛЕНЬКАЯ МОДАЛКА (подтверждение)
   ============================================ */

.modal-small {
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);

    width: 40%;
    max-width: calc(var(--stage-w) * 0.9);
    min-width: 500px;

    background: #faf7ee;
    background-image: url('resources/images/bg_note_big.webp');
    background-size: cover;
    background-position: center;

    border-radius: 12px;
    padding: 35px 30px;
    text-align: center;

    box-shadow:
        0 0 0 4px rgba(128, 128, 128, 0.4),
        0 15px 40px rgba(0, 0, 0, 0.5);
}

.modal-small .modal-content p {
    margin: 0 0 15px 0;
    font-size: 1.4rem;
    color: #4d5675;
}

.modal-small .modal-subtitle {
    font-size: 1rem !important;
    color: #777 !important;
    line-height: 1.4;
}

.modal-buttons {
    display: flex;
    gap: 15px;
    justify-content: center;
    margin-top: 25px;
}

.modal-buttons button {
    padding: 12px 24px;
    border-radius: 8px;
    font-family: 'CommonFont', serif;
    font-size: 1.1rem;
    cursor: pointer;
    transition: all 0.2s ease;
}

/* Общий hover для всех кнопок */
.btn-cancel:hover,
.btn-confirm:hover,
.btn-watch-ad:hover:not(:disabled),
.btn-buy-candies:hover {
    filter: brightness(1.08);
}

.btn-cancel {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 20px;
    border-radius: 10px;
    cursor: pointer;
    transition: all 0.2s ease;

    background: linear-gradient(135deg, #9e9e9e 0%, #757575 100%);
    border: none;
    border-bottom: 3px solid #616161;

    font-family: 'CommonFont', serif;
    font-size: 1rem;
    color: #fff;
    text-shadow: 1px 1px 2px rgba(0,0,0,0.3);

    box-shadow: 0 3px 10px rgba(117, 117, 117, 0.4);
}

.btn-confirm {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 20px;
    border-radius: 10px;
    cursor: pointer;
    transition: all 0.2s ease;

    background: linear-gradient(135deg, #7cb342 0%, #558b2f 100%);
    border: none;
    border-bottom: 3px solid #33691e;

    font-family: 'CommonFont', serif;
    font-size: 1rem;
    color: #fff;
    text-shadow: 1px 1px 2px rgba(0,0,0,0.3);

    box-shadow: 0 3px 10px rgba(85, 139, 47, 0.4);
}

#btn-confirm-relic {
    min-width: 240px;
}

/* ============================================
   ФУЛЛСКРИН МОДАЛКА
   ============================================ */

.modal-fullscreen {
    position: fixed;

    /* Не до края СЦЕНЫ, а до края окна. Сцена — это 1236×659 в своих
       единицах, и при высоком окне она не занимает его целиком: сверху
       и снизу остаются поля, куда модалка не дотягивалась. Читать
       правила в узкой полосе посреди пустоты неудобно.

       Тот же приём, что у затемнения обучения: выходим за сцену
       на её же поля (их считает js/stage.js), лишнее срезает
       overflow: hidden у body */
    inset: calc(10px - var(--stage-bleed-y, 0px)) calc(10px - var(--stage-bleed-x, 0px));
    margin: 0 auto;

    border-radius: 16px;
    display: flex;
    flex-direction: column;

    /* Рамка + тень */
    border: 4px solid #8b5a2b;
    box-shadow: 0 15px 50px rgba(0, 0, 0, 0.4);

    background-image: url("resources/images/test_5.webp");
    background-repeat: repeat;
    background-size: 50%;
}

.modal-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    padding: 20px 30px 0;
    position: relative;
}

.modal-header h2 {
    margin: 0;
    font-family: 'NoteLocal', 'CommonFont', serif;
    font-size: 1.8rem;
    color: #ffe8d0;
    text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8),
    -1px -1px 1px rgba(0, 0, 0, 0.4),
    0 0 8px rgba(0, 0, 0, 0.5);

    background-image: url("resources/images/desk.webp");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    height: 100px;
    padding: 0 10px 10px;
    word-wrap: break-word;
    flex: 0 0 300px;
    text-align: center;

    display: flex;
    align-items: center;
    justify-content: center;
}

.modal-header-center {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin: 0 20px;
}

/* Подсказка в шапке окна.

   Высота ФИКСИРОВАННАЯ, в rem: описания диковин разной длины, а расти
   блоку нельзя — поедет витрина под ним. Раньше тут стоял
   -webkit-line-clamp: 2, и длинные описания обрывались многоточием
   на полуслове. Описание диковины стоит конфет, читать его надо
   целиком, поэтому вместо обрезки уменьшаем кегль (js/text_fit.js).

   Именно rem, а не em: em считается от собственного кегля, и коробка
   ужималась бы вместе с текстом — подгонка никогда бы не сошлась */
.modal-hint {
    margin: 0;
    font-family: 'NoteLocal', 'CommonFont', serif;
    font-size: 1.2rem;
    color: #5d4e37;
    line-height: 1.4;
    background-color: rgba(255, 255, 255, 0.6);
    border-radius: 10px;
    padding: 10px;
    height: 3.36rem;
    display: block;
    overflow: hidden;
}

.modal-close {
    width: 46px;
    height: 46px;
    flex-shrink: 0;
    font-size: 2rem;
    line-height: 1;
    background: rgba(0,0,0,0.05);
    border: none;
    border-radius: 8px;
    color: #666;
    cursor: pointer;
    transition: all 0.2s ease;
}

/* Крестик в малых окнах. Раньше выходило наоборот: у полноэкранных
   окон был крестик, а у малых — целая кнопка «Закрыть», крупнее его.
   Теперь крестик везде, а мимо малого окна можно ещё и просто кликнуть.

   Обёртке нужен position: relative — крестик садится в её угол */
.modal-small .modal-body,
.modal-small .modal-content {
    position: relative;
}

.modal-close-small {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 38px;
    height: 38px;
    font-size: 1.6rem;
    z-index: 2;
}

.modal-close:hover {
    background: rgba(0,0,0,0.1);
    color: #333;
}

.modal-body {
    flex: 1;
    padding: 10px 30px;
    overflow-y: auto;
    color: #4d5675;
    border-radius: 16px;


}

.modal-body.help-rules {
    /* Фон скроллится вместе с содержимым */
    background-image: url("resources/images/test_5.webp");
    background-repeat: repeat;
    background-size: 50%;
    background-attachment: local;
}

/* Стилизованный скроллбар */
.modal-body::-webkit-scrollbar {
    width: 10px;
}

.modal-body::-webkit-scrollbar-track {
    background: #8b6b3a;
    border-radius: 5px;
    margin: 4px 0;
}

.modal-body::-webkit-scrollbar-thumb {
    background: linear-gradient(180deg, #c49a5c, #8b6b3a);
    border-radius: 5px;
    border: 2px solid rgba(93, 78, 55, 0.2);
}

.modal-body::-webkit-scrollbar-thumb:hover {
    background: linear-gradient(180deg, #d4a86a, #9b7b4a);
}

.modal-body h3 {
    font-family: 'NoteLocal', serif;
    margin-top: 0;
}

/* ============================================
   СРЕДНЯЯ МОДАЛКА (результаты)
   ============================================ */

.modal-medium {
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 500px;
    max-width: calc(var(--stage-w) * 0.95);

    background: #faf7ee;
    background-image: url('resources/images/bg_note_big.webp');
    background-size: cover;
    background-position: center;

    border-radius: 16px;
    padding: 40px 35px;
    text-align: center;

    box-shadow:
        0 0 0 5px rgba(128, 128, 128, 0.45),
        0 20px 50px rgba(0, 0, 0, 0.55);
}

/* ============================================
   МОДАЛКА ВЫБОРА РЕЖИМА
   ============================================ */

.modal-title {
    font-family: 'NoteLocal', 'CommonFont', serif;
    font-size: 1.6rem;
    color: #4d5675;
    margin: 0 0 10px 0;
}

/* ============================================
   МОДАЛКА "НОВАЯ ИГРА"
   ============================================ */

#modal-new-game {
}

/* «Новая игра» шире остальных маленьких окон.
   Правило именно на неё, а не на .modal-small: тот же класс носят
   подтверждения и приветствие, а им лишняя ширина ни к чему.
   Здесь же два ряда кнопок с подписями и поле ввода кода — в общие
   40% они влезали, только вытягиваясь в высоту, а высота у нас
   дороже: игру держат в альбомной ориентации */
#modal-new-game {
    width: 60%;
    min-width: 620px;
}

.new-game-body {
    text-align: center;
    padding: 20px !important;
}

.new-game-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-bottom: 16px;
}

.mode-buttons {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    margin: 20px 0 0 0;
}

/* Вопрос над кнопками — без подложки. Плашка стоила 70 пикселей
   высоты ради одной строки, а окно с четырьмя режимами и без того
   упиралось в край сцены */
/* Отсчёт до подмены — прямо в табличке соперника. Приглушённый:
   это не главное, что там написано, а объяснение красной точки */
.name-plate-timer {
    font-family: 'NoteLocal', serif;
    font-size: 1.05rem;
    color: #a3421f;
    margin-left: 6px;
    white-space: nowrap;
}

.name-plate-timer:empty {
    display: none;
}

.mode-intro {
    text-align: center;
    margin-bottom: 4px;
}

/* Тихая подпись над строкой: делит четыре режима на две пары —
   кого приводит игра и кого приводит игрок. Негромкая нарочно,
   это указатель, а не кнопка */
.mode-group-label {
    align-self: flex-start;
    margin: 2px 0 -4px 2px;
    font-family: 'NoteLocal', serif;
    font-size: 0.95rem;
    font-style: italic;
    color: #8a7859;
}

/* Две игры на одном устройстве — в строку. Игру держат в альбомной
   ориентации, и высота окна дороже ширины: в столбик три кнопки
   с подписями вытягивали «Новую игру» так, что на низком экране
   поле ввода кода уезжало под край */
.mode-row {
    display: flex;
    align-items: stretch;
    gap: 10px;
    width: 100%;
}

/* В строке кнопки делят место поровну независимо от длины подписи */
.mode-row .btn-mode-start {
    flex: 1 1 0;
    min-width: 0;
}

/* Иконка слева, подписи справа. Строкой, а не столбиком: иконка
   над текстом добавила бы кнопке высоты, а высота в этом окне —
   самое дорогое, что есть */
.mode-row .btn-mode-start {
    flex-direction: row;
    gap: 8px;
    justify-content: flex-start;
}

.btn-mode-icon-wrapper {
    /* Ширина жёсткая и ужиматься не должна: на неё опирается
       выравнивание всех четырёх кнопок — иконки стоят по одной линии
       независимо от того, широкий предмет или узкий */
    flex: none;
    width: 64px;
    text-align: center;
    display: flex;
    justify-content: center;
    align-items: center;
}

.btn-mode-icon {
    flex: none;
    /* Картинка не ловит клики: нажимают кнопку, а не рисунок */
    pointer-events: none;
}

/* Коробка у каждой иконки СВОЯ, и это не прихоть.
   Предметы нарисованы очень по-разному: банки на верёвке — 255x134,
   ходики — 164x256. В общей квадратной коробке банки заняли бы 40x21,
   а часы 26x40, и рядом банки читались бы вдвое мельче при одинаковой
   стороне. Поэтому сторона у всех разная, а ПЛОЩАДЬ одна — так плоский
   широкий предмет и узкий высокий весят на глаз поровну.

   Файлы обрезаны вплотную по содержимому, пустых полей внутри нет,
   и размеры ниже — это ровно размеры самих предметов */
.btn-mode-start[data-mode="hotseat"] .btn-mode-icon { max-height: 36px; }
.btn-mode-start[data-mode="bot"]     .btn-mode-icon { max-height: 44px; }
.btn-mode-start[data-mode="net"]     .btn-mode-icon { max-height: 32px; }
.btn-mode-start[data-mode="match"]   .btn-mode-icon { max-height: 36px; }

/* Подписи остаются столбиком внутри строки. min-width: 0 обязателен:
   без него длинная подпись не даёт flex-элементу ужаться и выдавливает
   иконку за край кнопки */
.btn-mode-text {
    /* Забирает всю ширину, что осталась от иконки, и центрует текст
       внутри себя. Основа 0, а не auto: иначе блок занял бы место
       по длине самой длинной подписи, и текст в четырёх кнопках стоял
       бы на четырёх разных отступах */
    flex: 1 1 0;

    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    /* Без этого длинная подпись не даёт блоку ужаться и выдавливает
       иконку за край кнопки */
    min-width: 0;
}

.btn-mode-start {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    width: 100%;
    padding: 14px 24px;
    border-radius: 10px;
    cursor: pointer;
    transition: all 0.2s ease;

    background: linear-gradient(135deg, #7cb342 0%, #558b2f 100%);
    border: none;
    border-bottom: 3px solid #33691e;

    font-family: 'CommonFont', serif;
    color: #fff;
    text-shadow: 1px 1px 2px rgba(0,0,0,0.3);
    box-shadow: 0 3px 10px rgba(85, 139, 47, 0.4);
}

.btn-mode-start:hover {
    filter: brightness(1.08);
}

.btn-mode-title {
    font-size: 1.4rem;
    letter-spacing: 0.4px;
}

.btn-mode-desc {
    font-size: 1rem;
    opacity: 0.9;
}

/* Кнопка занята делом: заводится комната. Гасим её, но не до вида
   «сломалась» — человек только что по ней попал, и она должна
   выглядеть работающей, просто занятой */
.btn-mode-start:disabled {
    cursor: default;
    filter: saturate(0.65) brightness(0.95);
}

.btn-mode-start.is-busy:disabled {
    filter: none;
}

/* Три точки, бегущие по кругу: 1 — 2 — 3, и снова.
   Прозрачностью, а не подстановкой content: content оживляют
   не все браузеры, прозрачность — все */
.btn-mode-dots {
    display: inline-block;
    margin-left: 2px;
    white-space: nowrap;
}

.btn-mode-dots i {
    display: inline-block;
    width: 0.32em;
    font-style: normal;
    opacity: 0.2;
    animation: mode-dots 1.2s infinite steps(1, end);
}

.btn-mode-dots i::before { content: '.'; }
.btn-mode-dots i:nth-child(2) { animation-delay: 0.4s; }
.btn-mode-dots i:nth-child(3) { animation-delay: 0.8s; }

@keyframes mode-dots {
    0%   { opacity: 1; }
    75%  { opacity: 1; }
    100% { opacity: 0.2; }
}

.btn-mode-cancel {
    margin-top: 40px;
}

.mode-interrupt-warning {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin-top: 10px;
    font-family: 'NoteLocal', serif;
    font-size: 1rem;
    color: #8B5A3C;
    font-style: italic;
}

.mode-interrupt-warning.hidden {
    display: none;
}

/* ============================================
   МОДАЛКА СМЕНЫ ХОДА (хотсит)
   ============================================ */

.modal-turn-content {
    padding: 20px 0;
}

.turn-character {
    width: 120px;
    height: 120px;
    margin: 0 auto 20px;
    border-radius: 50%;
    overflow: hidden;
    background: rgba(0,0,0,0.05);
    box-shadow: 0 4px 15px rgba(0,0,0,0.2);
}

.turn-character img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top;
}

.turn-text {
    font-family: 'NoteLocal', 'CommonFont', serif;
    font-size: 1.5rem;
    color: #4d5675;
    margin: 0 0 8px 0;
}

.turn-subtext {
    font-family: 'CommonFont', serif;
    font-size: 1.1rem;
    color: #777;
    margin: 0 0 25px 0;
}

.btn-ready {
    padding: 14px 40px;
    font-size: 1.2rem;
}

/* ============================================
   МОДАЛКА РЕЗУЛЬТАТОВ
   ============================================ */

.results-title {
    font-family: 'NoteLocal', 'CommonFont', serif;
    font-size: 2rem;
    color: #4d5675;
    margin: 0;
}

.results-scores {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 20px;
}

.player-result {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 15px 20px;
    border-radius: 12px;
    background: rgba(255,255,255,0.5);
    min-width: 120px;
}

.player-result.winner {
    background: rgba(255, 215, 0, 0.2);
    box-shadow: 0 0 20px rgba(255, 215, 0, 0.3);
}

.player-result img {
    width: 60px;
    height: 60px;
    border-radius: 50%;
    object-fit: cover;
    object-position: top;
    margin-bottom: 8px;
}

.player-result .player-name {
    font-family: 'CommonFont', serif;
    font-size: 1rem;
    color: #666;
}

.player-result .player-score {
    font-family: 'NoteLocal', serif;
    font-size: 2rem;
    color: #4d5675;
}

.results-vs {
    font-family: 'CommonFont', serif;
    font-size: 1.2rem;
    color: #999;
    font-weight: bold;
}

/* Расклад конфет */
.candy-breakdown {
    margin: 6px 0;
    padding: 10px 20px;
    background: rgba(139, 69, 19, 0.08);
    border-radius: 12px;
    border: 1px solid rgba(139, 69, 19, 0.15);
}

.candy-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    padding: 1px 0;
    font-family: 'CommonFont', serif;
    font-size: 1rem;
    color: #4d5675;
}

.candy-row.candy-cost {
    color: #b55;
}

.candy-row.candy-cost .candy-value {
    color: #c44;
}

.candy-row.candy-bonus {
    color: #5a8a5a;
}

.candy-row.candy-bonus .candy-value {
    color: #4a7a4a;
}

.candy-row.candy-total {
    margin-top: 8px;
    padding-top: 6px;
    border-top: 2px dashed rgba(77, 86, 117, 0.2);
    font-weight: bold;
    font-size: 1.15rem;
}

.candy-value {
    font-weight: bold;
    min-width: 40px;
    text-align: right;
}

.candy-total .candy-value {
    color: #d4a017;
    font-size: 1.2rem;
}

/* Название задания бывает длинным («Ежедневное задание: Собери
   „Пять подряд“»). В две строки оно выносило окно за край сцены,
   поэтому обрезаем многоточием: сумма справа важнее полного названия */
.candy-row > span:first-child {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.candy-row .candy-value {
    flex: none;
}

/* Кнопки итогов — в ряд: места хватает, а столбиком главная кнопка
   уезжала вниз и терялась. На узком экране переносим обратно */
/* Три кнопки итогов держим в ОДНОЙ строке.

   Считалось впритык: при имени соперника в подписи ряду нужно было 411
   единиц, а доступно 410 — и «Сундук» уезжал на вторую строку. С другими
   именами и в английском запас ещё меньше, поэтому дело не в одном
   пикселе: убираем перенос совсем и даём кнопкам ужиматься.
   Если подпись перестанет помещаться, она перенесётся ВНУТРИ кнопки,
   а ряд останется рядом */
.results-buttons {
    flex-direction: row;
    flex-wrap: nowrap;
    justify-content: center;
    gap: 8px;
}

.btn-replay {
    padding: 14px 30px;
    font-size: 1.1rem;
}

/* Кнопок в итогах стало три: «ещё раз», «другой режим» и «Сундук».
   На прежних размерах третья не влезала в строку и переносилась
   на вторую — главная кнопка оставалась одна наверху, а две мелкие
   висели под ней ступенькой. Ужимаем поля и кегль: строка из трёх
   должна помещаться и с длинным именем соперника
   («Давай по новой, Бабушка!»), а не только с коротким */
.results-buttons > button {
    padding: 12px 12px;
    font-size: 1rem;
    /* Общее правило кнопок держит min-width: 150px — вместе с полями
       это под 180 px на каждую, и «Сундук» из шести букв занимал
       столько же, сколько «Давай по новой, Бабушка!». Трёх таких
       в строку не помещается. Здесь ширина по содержимому */
    min-width: 0;
}

.results-buttons > .btn-replay {
    padding: 12px 18px;
}

/* ОТКЛЮЧЕНО вместе с переходом на сцену (js/stage.js).
   Игра теперь всегда свёрстана в 1236×659, и это условие на базе
   не срабатывало — значит его правила в макет никогда и не входили.
   Но медиазапрос смотрит на ОКНО, а не на сцену, и в маленьком окне
   он выстрелил бы поверх готовой раскладки. Оставлено на случай,
   если вернёмся к отдельной вёрстке под телефон.
@media (max-width: 560px) {
    .results-buttons {
        flex-direction: column;
    }
} */

/* ============================================
   АДАПТИВНОСТЬ
   ============================================ */

/* ОТКЛЮЧЕНО вместе с переходом на сцену (js/stage.js).
   Игра теперь всегда свёрстана в 1236×659, и это условие на базе
   не срабатывало — значит его правила в макет никогда и не входили.
   Но медиазапрос смотрит на ОКНО, а не на сцену, и в маленьком окне
   он выстрелил бы поверх готовой раскладки. Оставлено на случай,
   если вернёмся к отдельной вёрстке под телефон.
@media (max-width: 900px) {
    .side-menu {
        height: calc(var(--stage-h) * 0.7);
        padding: 15px 10px 15px 14px;
    }

    .menu-plank {
        width: 42px;
        padding: 14px 6px;
        font-size: 0.9rem;
    }

    .info-panel {
        padding: 10px 12px;
        max-height: calc(var(--stage-h) - 180px);
    }

    .info-icon {
        width: 22px;
        height: 22px;
    }

    .info-candies {
        font-size: 1rem;
    }

    .info-mode {
        font-size: 0.75rem;
    }

    .modal-fullscreen {
        inset: 15px;
    }
} */

/* ОТКЛЮЧЕНО вместе с переходом на сцену (js/stage.js).
   Игра теперь всегда свёрстана в 1236×659, и это условие на базе
   не срабатывало — значит его правила в макет никогда и не входили.
   Но медиазапрос смотрит на ОКНО, а не на сцену, и в маленьком окне
   он выстрелил бы поверх готовой раскладки. Оставлено на случай,
   если вернёмся к отдельной вёрстке под телефон.
@media (max-width: 600px) {
    .modal-small {
        width: calc(var(--stage-w) * 0.9);
        padding: 25px 20px;
    }

    .modal-buttons {
        flex-direction: column;
    }

    .modal-fullscreen {
        inset: 10px;
        border-radius: 12px;
    }

    .modal-header {
        padding: 15px 20px;
    }

    .modal-body {
        padding: 20px;
    }
} */

/* ============================================
   МАГАЗИН СКАТЕРТЕЙ
   ============================================ */

/* ============================================
   СЕКЦИЯ КОНФЕТ В МАГАЗИНЕ
   ============================================ */

.shop-candies-section {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    padding: 16px 20px;
    margin-bottom: 25px;
    background: linear-gradient(135deg, rgba(139, 69, 19, 0.1) 0%, rgba(160, 82, 45, 0.15) 100%);
    border-radius: 12px;
    border: 2px solid rgba(139, 69, 19, 0.2);
}

.shop-balance {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: 'CommonFont', serif;
    font-size: 1.5rem;
    color: #4d5675;
}

.shop-balance .candy-icon {
    width: 32px;
    height: 32px;
}

.btn-watch-ad {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 20px;
    border-radius: 10px;
    cursor: pointer;
    transition: all 0.2s ease;

    background: linear-gradient(135deg, #7cb342 0%, #558b2f 100%);
    border: none;
    border-bottom: 3px solid #33691e;

    font-family: 'CommonFont', serif;
    font-size: 1rem;
    color: #fff;
    text-shadow: 1px 1px 2px rgba(0,0,0,0.3);

    box-shadow: 0 3px 10px rgba(85, 139, 47, 0.4);
}



/* Кулдаун рекламы.
   Раньше стоял атрибут disabled, но такая кнопка в Chrome не получает
   событий мыши — подсказка «когда будет следующая награда» на ней
   не срабатывала бы вовсе. Поэтому блокируем классом, а нажатие
   отсекаем в обработчике */
/* Рекламы у площадки нет: вид как у кулдауна, но кнопка нажимается —
   нажатие пробует показать ролик ещё раз (см. updateRewardedAdButtonChest) */
.btn-watch-ad.is-no-ad {
    background: linear-gradient(135deg, #9e9e9e 0%, #757575 100%);
    border-bottom-color: #616161;
    opacity: 0.8;
    box-shadow: none;
}

.btn-watch-ad:disabled,
.btn-watch-ad.is-cooldown {
    background: linear-gradient(135deg, #9e9e9e 0%, #757575 100%);
    border-bottom-color: #616161;
    cursor: not-allowed;
    opacity: 0.7;
    box-shadow: none;
}

.btn-watch-ad-reward {
    font-weight: bold;
    font-size: 1.1rem;
}

.btn-watch-ad .candy-icon-small {
    width: 20px;
    height: 20px;
}

.ad-cooldown {
    font-family: 'CommonFont', serif;
    font-size: 0.95rem;
    color: #888;
    text-align: center;
}

.ad-cooldown.hidden {
    display: none;
}

#ad-cooldown-time {
    font-weight: bold;
    color: #e65100;
}

.shop-candies-buttons {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
}

/* Оранжевая кнопка. Не действие и не отказ, а «пойти в другое место» —
   в Сундук, в лавку. Цвет уже занят кнопкой покупки конфет, но там он
   вшит в её собственное правило; здесь тот же цвет отдельной накладкой,
   чтобы вешать на любую кнопку модалки */
/* Общего .hidden в проекте нет — он объявлен покомпонентно (см. заметку
   у завесы обучения). Кнопка «Готов» в окне комнаты из-за этого
   не пряталась вовсе: до прихода друга она горела и звала нажать себя,
   хотя начинать было не с кем */
.modal-buttons button.hidden {
    display: none;
}

.btn-orange {
    background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
    border-bottom: 3px solid #e65100;
    box-shadow: 0 3px 10px rgba(245, 124, 0, 0.4);
}

.btn-buy-candies {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 20px;
    border-radius: 10px;
    cursor: pointer;
    transition: all 0.2s ease;

    background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
    border: none;
    border-bottom: 3px solid #e65100;

    font-family: 'CommonFont', serif;
    font-size: 1rem;
    color: #fff;
    text-shadow: 1px 1px 2px rgba(0,0,0,0.3);

    box-shadow: 0 3px 10px rgba(245, 124, 0, 0.4);
}



/* ============================================
   МОДАЛКА ВЫБОРА ПАКЕТА КОНФЕТ
   ============================================ */

.modal-candy-shop-body {
    padding: 25px 30px;
    text-align: center;
}

.candy-packages {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px;
    margin: 20px 0;
}

/* Прежняя жёлтая карточка-кнопка убрана: теперь пакет — это ячейка
   с блюдцем, а покупает готовая оранжевая .btn-buy-candies */

.candy-package-badge {
    position: absolute;
    top: -10px;
    right: -10px;
    padding: 4px 10px;
    background: #7cb342;
    border-radius: 6px;
    font-family: 'CommonFont', serif;
    font-size: 0.75rem;
    color: #fff;
    text-shadow: 1px 1px 1px rgba(0,0,0,0.3);
}

.candy-package-amount {
    display: flex;
    align-items: center;
    gap: 6px;
    font-family: 'CommonFont', serif;
    font-size: 1.4rem;
    font-weight: bold;
    color: #4d5675;
}

.candy-package-amount img {
    width: 28px;
    height: 28px;
}

/* Прежнее правило цены убрано: серый мелкий текст остался от старой
   вёрстки, где цена стояла под карточкой. Теперь она внутри кнопки
   и наследует её шрифт — тот же, что у «Купить конфеты» */

/* ============================================
   МОДАЛКА "НЕ ХВАТАЕТ КОНФЕТ"
   ============================================ */

#modal-not-enough {
}

.not-enough-body {
}

.not-enough-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-bottom: 16px;
}

.not-enough-napkin {
    width: 180px;
    height: 180px;
    background-image: url("resources/images/dish.webp");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    display: flex;
    align-items: center;
    justify-content: center;
}

.not-enough-img {
    width: 64px;
    height: 64px;
    object-fit: contain;
    filter: drop-shadow(0 4px 8px rgba(0,0,0,0.2)) grayscale(50%);
}

.not-enough-title-wrapper {
    position: relative;
    display: inline-block;
}

.not-enough-title {
    background-image: url(resources/images/paper.webp);
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    padding: 15px 40px;
    font-size: 1.4rem;
    color: #5d4e37;
    margin: 0;
    min-height: 80px;
    min-width: 160px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.not-enough-info {
    background-color: rgba(255, 255, 255, 0.75);
    border-radius: 10px;
    padding: 15px 20px;
    margin-bottom: 16px;
}

.not-enough-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-family: 'NoteLocal', serif;
    font-size: 1.2rem;
    color: #5d4e37;
    padding: 5px 0;
}

.not-enough-value {
    display: flex;
    align-items: center;
    gap: 6px;
    font-weight: bold;
}

.not-enough-value .candy-icon-small {
    width: 24px;
    height: 24px;
}

.not-enough-need-value {
    color: #c62828;
}

.not-enough-have-value {
    color: #5d4e37;
}

.not-enough-buttons {
    flex-direction: row;
    gap: 10px;
}

.shop-section-title {
    font-family: 'NoteLocal', serif;
    font-size: 1.4rem;
    color: #4d5675;
    margin: 0 0 15px 0;
}

/* ============================================
   НАСТРОЙКИ ЗВУКА (слайдеры)
   ============================================ */

.sound-settings {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-bottom: 25px;
    padding: 15px;
    background: rgba(139, 69, 19, 0.08);
    border-radius: 12px;
}

/* Сетка на весь блок, а не на каждую строку отдельно: колонка
   подписи получается общей, и ползунки выходят одной длины.
   При строчной раскладке подпись занимала по своему тексту, ползунок
   забирал остаток — и строки не совпадали. По-английски разница
   заметнее: Sound volume против Music volume */
.settings-sound {
    display: grid;
    grid-template-columns: max-content 1fr max-content;
    align-items: center;
    gap: 12px;
}

/* Строки растворяются, их содержимое становится ячейками общей сетки */
.settings-sound .sound-slider-row {
    display: contents;
}

.sound-slider-row {
    display: flex;
    align-items: center;
    gap: 12px;
}

.sound-slider-row label {
    font-family: 'NoteLocal', serif;
    font-size: 1.1rem;
    color: #5d4e37;
}

.volume-slider {
    flex: 1;
    height: 8px;
    -webkit-appearance: none;
    appearance: none;
    background: rgba(139, 69, 19, 0.2);
    border-radius: 4px;
    outline: none;
    cursor: pointer;
}

.volume-slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 20px;
    height: 20px;
    background: linear-gradient(145deg, #8b5a2b, #6d4423);
    border-radius: 50%;
    cursor: pointer;
    box-shadow: 0 2px 4px rgba(0,0,0,0.3);
    transition: transform 0.15s ease;
}

.volume-slider::-webkit-slider-thumb:hover {
    transform: scale(1.1);
}

.volume-slider::-moz-range-thumb {
    width: 20px;
    height: 20px;
    background: linear-gradient(145deg, #8b5a2b, #6d4423);
    border-radius: 50%;
    cursor: pointer;
    border: none;
    box-shadow: 0 2px 4px rgba(0,0,0,0.3);
}

.volume-value {
    font-family: 'NoteLocal', serif;
    font-size: 1rem;
    color: #6d5d4d;
    min-width: 45px;
    text-align: right;
}





/* ============================================
   МОДАЛКА ПОКУПКИ СКАТЕРТИ
   ============================================ */

#modal-tablecloth-purchase {
    background-size: cover;
    background-position: center;
}

.tablecloth-purchase-body {
    text-align: center;
    padding: 20px !important;
}

.tablecloth-purchase-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-bottom: 16px;
}

.tablecloth-purchase-name-wrapper {
    position: relative;
    display: inline-block;
}

.tablecloth-purchase-name {
    background-image: url("resources/images/paper.webp");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    padding: 15px 40px;
    font-family: 'NoteLocal', serif;
    font-size: 1.4rem;
    color: #5d4e37;
    margin: 0;
    min-height: 60px;
    min-width: 140px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.tablecloth-purchase-price {
    position: absolute;
    bottom: -10px;
    right: -60px;
    transform: rotate(12deg);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px 25px;
    font-family: 'NoteLocal', serif;
    font-size: 1.3rem;
    color: #5d4e37;
    background-image: url("resources/images/price_2.webp");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    min-width: 60px;
    min-height: 30px;
}

.tablecloth-purchase-info {
    background-color: rgba(255, 255, 255, 0.75);
    border-radius: 10px;
    padding: 12px 16px;
    margin-bottom: 16px;
}

.tablecloth-purchase-desc {
    font-family: 'NoteLocal', serif;
    font-size: 1.1rem;
    color: #5d4e37;
    margin: 0;
    font-style: italic;
}

/* ============================================
   МОДАЛКА ПОКУПКИ КУБИКОВ
   ============================================ */

#modal-dice-purchase {
}

.dice-purchase-body {
    text-align: center;
    padding: 20px !important;
}

.dice-purchase-header {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-bottom: 16px;
    gap: 10px;
}

.dice-purchase-tray {
    width: 160px;
    height: 160px;
    background-image: url("resources/images/dice-tray.webp");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 10px;
}

.dice-purchase-tray .dice_wrapper {
    width: 70px;
    height: 70px;
}

.dice-purchase-tray .dice_img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    filter: drop-shadow(0 4px 8px rgba(0,0,0,0.3));
    margin: 0;
}

.dice-purchase-name-wrapper {
    position: relative;
    display: inline-block;
}

.dice-purchase-name {
    background-image: url("resources/images/paper.webp");

    /* Тянем бумажку по коробке, а не вписываем её.
       С contain ширина бумажки считалась от ВЫСОТЫ: 73 × 2,33 = 170,
       и сколько ни добавляй боковых полей, шире она не становилась —
       заголовок в 159 единиц ложился с пятью единицами запаса по краям
       и упирался в край таблички. Так же сделана бумажка выполненного
       задания (см. выше) */
    background-size: 100% 100%;
    background-repeat: no-repeat;
    background-position: center;
    padding: 15px 44px;
    font-family: 'NoteLocal', serif;
    font-size: 1.4rem;
    color: #5d4e37;
    margin: 0!important;
    min-height: 60px;
    min-width: 140px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.dice-purchase-price {
    position: absolute;
    bottom: -10px;
    right: -60px;
    transform: rotate(12deg);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px 25px;
    font-family: 'NoteLocal', serif;
    font-size: 1.3rem;
    color: #5d4e37;
    background-image: url("resources/images/price_2.webp");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    min-width: 60px;
    min-height: 30px;
}

.dice-purchase-info {
    background-color: rgba(255, 255, 255, 0.75);
    border-radius: 10px;
    padding: 12px 16px;
    margin-bottom: 16px;
}

.dice-purchase-desc {
    font-family: 'NoteLocal', serif;
    font-size: 1.2rem;
    color: #5d4e37;
    margin: 0;
}

.candy-icon-small {
    width: 32px;
    height: 32px;
}


/* ============================================
   УБРАНСТВО (MODAL-COZY)
   ============================================ */

#modal-cozy .modal-body {
    display: flex;
    flex-direction: column;
    overflow: hidden;

    padding-top: 20px;
}

.cozy-top-bar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
    background: rgba(255, 255, 255, 0.6);
    border-radius: 10px;
}

.cozy-balance {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: 'NoteLocal', serif;
    font-size: 1.4rem;
    color: #5d4e37;
    font-weight: bold;
}

.cozy-balance .candy-icon {
    width: 32px;
    height: 32px;
}

.cozy-products {
    flex: 1;
    display: flex;
    overflow: hidden;
}

.cozy-section {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.cozy-section-title {
    font-family: 'NoteLocal', serif;
    font-size: 1.3rem;
    color: #5d4e37;
    margin: 0 0 10px 0;
    text-align: center;
    padding: 15px 30px;

    background-image: url("resources/images/paper.webp");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    min-height: 64px;

    display: flex;
    align-items: center;
    justify-content: center;
}

.cozy-grid-container {
    flex: 1;
    overflow-x: hidden;
    overflow-y: auto;
}

/* Скроллбар под дерево */
.cozy-grid-container::-webkit-scrollbar {
    width: 6px;
}

.cozy-grid-container::-webkit-scrollbar-track {
    background: rgba(93, 78, 55, 0.1);
    border-radius: 3px;
}

.cozy-grid-container::-webkit-scrollbar-thumb {
    background: rgba(93, 78, 55, 0.3);
    border-radius: 3px;
}

.cozy-grid-container::-webkit-scrollbar-thumb:hover {
    background: rgba(93, 78, 55, 0.5);
}

.cozy-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 15px;
    padding: 10px 20px 0 0;
    justify-items: center;
    align-content: flex-start;
}

.cozy-footer {
    margin-top: 0;
    padding: 15px 30px;
    gap: 15px;
}

/* Скатерти */
.tablecloth-item {
    position: relative;
    width: 160px;
    height: 160px;
    cursor: pointer;
    transition: all 0.2s ease;
    background-color: #FFFFFF;
    border-radius: 8px;
}

.tablecloth-item:hover {
    transform: translateY(-3px);
}

.tablecloth-item.active {
    filter: drop-shadow(0 0 8px rgba(76, 175, 80, 0.6));
}

.tablecloth-preview {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 8px;
    box-shadow: 0 2px 6px rgba(0,0,0,0.2);
    transition: filter 0.2s ease;
}

.tablecloth-item:hover .tablecloth-preview {
    box-shadow: 0 4px 12px rgba(0,0,0,0.3);
}

.tablecloth-item.locked .tablecloth-preview {
    filter: grayscale(70%) brightness(0.8);
}

.tablecloth-item.locked:hover .tablecloth-preview {
    filter: none;
}

/* Галочка выбора для скатертей */
.tablecloth-check {
    position: absolute;
    top: -6px;
    right: -6px;
    width: 24px;
    height: 24px;
    background: #4caf50;
    border-radius: 50%;
    display: none;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 4px rgba(0,0,0,0.3);
    z-index: 3;
}

.tablecloth-item.active .tablecloth-check {
    display: flex;
    animation: checkPop 0.3s ease;
}

.tablecloth-check svg {
    width: 14px;
    height: 14px;
    fill: #fff;
}

/* Ценник для скатертей */
.tablecloth-price-tag {
    position: absolute;
    bottom: -10px;
    right: -30px;
    transform: rotate(12deg);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4px 0 4px 10px;

    background-image: url("resources/images/price_2.webp");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    min-width: 70px;
    min-height: 30px;

    font-family: 'NoteLocal', serif;
    font-size: 1.4rem;
    color: #5d4e37;
    font-weight: bold;
}

/* Замочек для скатертей */
.tablecloth-lock-icon {
    position: absolute;
    bottom: -15px;
    right: 14px;
    transform: translate(-50%, -50%);
    width: 32px;
    height: 32px;
    background: #5d4037;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
    z-index: 2;
    transition: opacity 0.3s ease;
}

.tablecloth-item:hover .tablecloth-lock-icon {
    /*opacity: 0;*/
}

.tablecloth-lock-icon svg {
    width: 16px;
    height: 16px;
    fill: #ffd54f;
}

/* Кубики на dice-tray */
.dice-skin-item {
    position: relative;
    width: 160px;
    height: 160px;
    flex-shrink: 0;
    cursor: pointer;
    transition: all 0.2s ease;

    background-image: url('resources/images/dice-tray.webp');
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;

    display: flex;
    justify-content: center;
    align-items: center;
}

.dice-skin-item:hover {
    transform: scale(1.05);
}

.dice-skin-item.active {
    filter: drop-shadow(0 0 8px rgba(74, 89, 61, 0.6));
}

.dice-skin-item.locked .dice_wrapper {
    filter: grayscale(70%) brightness(0.8);
}

.dice-skin-item.locked:hover .dice_wrapper {
    filter: none;
}

/* Галочка выбора для кубиков */
.dice-skin-check {
    position: absolute;
    top: -5px;
    right: -5px;
    width: 24px;
    height: 24px;
    background: #4caf50;
    border-radius: 50%;
    display: none;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 4px rgba(0,0,0,0.3);
    z-index: 3;
}

.dice-skin-item.active .dice-skin-check {
    display: flex;
    animation: checkPop 0.3s ease;
}

.dice-skin-check svg {
    width: 14px;
    height: 14px;
    fill: #fff;
}

/* Ценник для кубиков */
.dice-skin-price-tag {
    position: absolute;
    bottom: 0;
    right: -48px;
    transform: rotate(12deg);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4px 0 4px 10px;


    background-image: url("resources/images/price_2.webp");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    min-width: 70px;
    min-height: 30px;

    font-family: 'NoteLocal', serif;
    font-size: 1.4rem;
    color: #5d4e37;
    font-weight: bold;
}

/* Замочек для кубиков */
.dice-skin-lock-icon {
    position: absolute;
    bottom: -5px;
    right: -4px;
    transform: translate(-50%, -50%);
    width: 32px;
    height: 32px;
    background: #5d4037;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
    transition: opacity 0.3s ease;
    z-index: 2;
}

.dice-skin-item:hover .dice-skin-lock-icon {
    /*opacity: 0;*/
}

.dice-skin-lock-icon svg {
    width: 14px;
    height: 14px;
    fill: #ffd54f;
}

/* ============================================
   ЗАКРОМА (СУНДУК С ДИКОВИНАМИ)
   ============================================ */

.chest-top-bar {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 10px;
    background: rgba(255, 255, 255, 0.6);
    border-radius: 10px;
}

.chest-balance {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: 'NoteLocal', serif;
    font-size: 1.4rem;
    color: #5d4e37;
    font-weight: bold;
}

.chest-balance .candy-icon {
    width: 32px;
    height: 32px;
}

.chest-selected-info {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: 'NoteLocal', serif;
    font-size: 1.1rem;
    color: #6d5d4d;
}

.selected-count {
    font-weight: bold;
    color: #8b5a2b;
    background: rgba(139, 90, 43, 0.2);
    padding: 4px 10px;
    border-radius: 8px;
}

/* Футер с кнопкой */
.modal-fullscreen .modal-buttons {
    margin-top: 0;
    padding: 15px 30px;
}


/* Сетка диковин */
#modal-chest .modal-body {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Сундук держим в рабочей области ПО ШИРИНЕ.

   .modal-fullscreen тянется до края экрана через отрицательный
   --stage-bleed-x, и на широком окне сундук расползался на 1766 единиц
   при сцене в 1236 — витрина висела далеко за пределами стола.
   Правилам полный размах нужен, там много текста, а сундуку нет:
   пять диковин в ряд и так помещаются.

   По вертикали вылет оставляем: на низком экране он и даёт место
   под третий ряд */
/* Сундук держим в рабочей области ЦЕЛИКОМ, правила — только по ширине.

   .modal-fullscreen тянется до края экрана отрицательными отступами
   на величину вылета сцены. Сундуку это вредит с обеих сторон:
   на широком окне он расползался на 1766 единиц при сцене в 1236,
   а на высоком вырастал до 1239 при сцене в 659 — плитки раздувались
   до 344, и витрина переставала быть похожей на витрину.

   Проверять ориентацию окна не нужно: если окно вообще не покидает
   рабочую область, ломаться нечему ни в одном положении.

   Правилам вертикальный размах оставляем — там много текста */
#modal-chest {
    inset: 10px;
}

#modal-help {
    left: 10px;
    right: 10px;
}

/* Та же ловушка авто-минимума, что и у сетки, но уровнем выше: без
   min-height: 0 тело окна держит высоту содержимого и не ужимается,
   а значит и сетке внутри ужиматься не от чего */
#modal-chest .modal-body {
    min-height: 0;
}

/* Витрина диковин.

   min-height: 0 обязателен. У флекс-элемента по умолчанию min-height:
   auto, поэтому сетка держала высоту своего содержимого (три ряда
   по 135) и не ужималась до тела окна. На низком экране тело
   с overflow: hidden просто срезало третий ряд, и добраться до него
   было нечем. Теперь сетка сжимается и прокручивается */
.relics-grid {
    flex: 1;
    display: grid;
    grid-template-columns: repeat(5, 1fr);

    /* minmax(0, 1fr), а не просто 1fr: 1fr означает minmax(auto, 1fr),
       и авто-минимум не даёт ряду стать ниже содержимого. Ряды держали
       высоту картинок, сетка не влезала в тело окна, и на низком экране
       третий ряд срезало */
    grid-template-rows: repeat(3, minmax(0, 1fr));
    gap: 8px;
    min-height: 0;

    /* Поля под украшения плиток: зелёная галочка выбранной вещи и ценник
       вынесены за её край на 6 px. Без полей верхний ряд и правый столбец
       срезало телом окна */
    padding: 8px 8px 0;
}

/* Карточка диковины */
.relic-item {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.2s ease;

    background-image: url("resources/images/napkin_3_768.webp");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
}

.relic-item:hover {
    transform: translateY(-3px);
}

.relic-item.owned {
}

.relic-item.selected {
    /* Выделение через тень, чтобы не перекрыть фон */
    filter: drop-shadow(0 0 8px rgba(76, 175, 80, 0.6));
}

/* Тёмная салфетка под неактивным предметом. Светлая (napkin_3) —
   основная, тёмная (napkin_2) отмечает то, чем сейчас нельзя
   воспользоваться: некупленную диковину в Закромах и отработавшую
   на столе */
.relic-item.locked {
    background-image: url("resources/images/napkin_2_768.webp");
}

/* Наведение и превью-перебор оживляют диковину целиком, вместе
   с салфеткой. Раньше подсвечивалась только картинка, и предмет
   выглядел наполовину ожившим: сам яркий, а лежит на тусклом */
.relic-item.locked:hover,
.relic-item.locked.is-previewing {
    background-image: url("resources/images/napkin_3_768.webp");
}

/* Превью — то же самое, что наведение: снимаем приглушение с картинки */
.relic-item.locked.is-previewing .relic-image {
    filter: none;
}

.relic-item.locked:hover {
}

/* Контейнер изображения — квадрат от ширины плитки.

   Я было перевёл его на высоту ряда, чтобы витрина ужималась на низком
   экране. Оказалось лишним и вредным: height вместе с max-width спорят
   с aspect-ratio, и квадрат превращался в стоячий прямоугольник —
   110x144 на низком окне и 172x344 на высоком.

   Держать витрину в рабочей области достаточно: ширина плитки тогда
   известна заранее, и высота ряда под неё всегда находится */
.relic-image-container {
    position: relative;
    width: 50%;
    aspect-ratio: 1;
    display: flex;
    margin: 0 auto;
}

.relic-image {
    width: 75%;
    height: 100%;
    object-fit: contain;
    filter: drop-shadow(0 2px 4px rgba(0,0,0,0.2));
    transition: transform 0.2s ease;
    margin: 0 auto;
}

.relic-item:hover .relic-image {
    transform: scale(1.05);
}

.relic-item.locked .relic-image {
    filter: grayscale(70%) brightness(0.8) drop-shadow(0 2px 4px rgba(0,0,0,0.2));
}

.relic-item.locked:hover .relic-image {
    filter: none;
}

.relic-item:hover .relic-lock {
    /*opacity: 0;*/
}

/* Замочек */
.relic-lock {
    position: absolute;
    bottom: 56px;
    right: 44px;
    width: 32px;
    height: 32px;
    background: #5d4037;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
    z-index: 2;
    opacity: 1;
    transition: opacity 0.5s ease;
}

.relic-lock svg {
    width: 16px;
    height: 16px;
    fill: #ffd54f;
}

/* Галочка выбора */
.relic-check {
    position: absolute;
    top: -6px;
    right: -6px;
    width: 28px;
    height: 28px;
    background: #4caf50;
    border-radius: 50%;
    display: none;
    align-items: center;
    justify-content: center;
    box-shadow: 0 2px 4px rgba(0,0,0,0.3);
}

.relic-item.selected .relic-check {
    display: flex;
    animation: checkPop 0.3s ease;
}

@keyframes checkPop {
    0% { transform: scale(0); }
    50% { transform: scale(1.2); }
    100% { transform: scale(1); }
}

.relic-check svg {
    width: 18px;
    height: 18px;
    fill: #fff;
}

/* Название диковины */
.relic-name {
    position: absolute;
    bottom: -5px;
    left: 50%;
    transform: translateX(-50%);
    font-family: 'NoteLocal', serif;
    font-size: 1.2rem;
    color: rgba(255, 232, 208, 0.9);
    text-align: center;
    line-height: 1.2;
    white-space: nowrap;
}

/* Ценник справа */
.relic-price-tag {
    position: absolute;
    bottom: 45px;
    right: -20px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 4px 0 4px 10px;
    transform: rotate(12deg);
    background-image: url(resources/images/price_2.webp);
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    min-width: 70px;
    min-height: 30px;
}

.relic-price {
    font-family: 'NoteLocal', serif;
    font-size: 1.4rem;
    color: #5d4e37;
    font-weight: bold;
}

.candy-icon-tiny {
    width: 14px;
    height: 14px;
}

.relic-owned-badge {
    color: #8b5a2b;
    font-size: 0.8rem;
    padding: 2px 8px;
    background: rgba(139, 90, 43, 0.15);
    border-radius: 6px;
}

.relic-selected-badge {
    color: #2e7d32;
    font-size: 0.8rem;
    padding: 2px 8px;
    background: rgba(76, 175, 80, 0.2);
    border-radius: 6px;
}

/* ============================================
   МОДАЛКА ПОКУПКИ ДИКОВИНЫ
   ============================================ */

#modal-relic-purchase {
    background-size: cover;
    background-position: center;
}

.relic-purchase-body {
}

/* Ширину задаём самому окну, как у лавки: у .modal-small своя, и тело
   растекалось бы за пергамент */
#modal-relic-purchase {
    width: min(760px, calc(var(--stage-w) * 0.9));
    max-width: min(760px, calc(var(--stage-w) * 0.9));
}

/* Картинка и название — в ряд, а не колонкой.
   Колонкой шапка занимала 426 px из 659 доступных, и окно вылезало
   за нижний край кадра на 57 px. Ориентация у нас альбомная: по ширине
   место есть, по высоте его нет */
.relic-purchase-header {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 18px;
    margin-bottom: 14px;
}

/* Названию отдаём остаток строки, но не даём ужать салфетку */
.relic-purchase-header .relic-purchase-name-wrapper {
    flex: 0 1 auto;
    /* Ценник висит на -72px справа от бумажки — оставляем ему место,
       иначе он уедет за край окна */
    margin-right: 76px;
}

.relic-purchase-napkin {
    /* В ряду именно салфетка задаёт высоту шапки, поэтому 300 → 240:
       так окно укладывается в кадр с запасом */
    width: 240px;
    height: 240px;
    flex: none;
    background-image: url("resources/images/napkin_3_768.webp");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    display: flex;
    align-items: center;
    justify-content: center;
}

.relic-purchase-img {
    width: 160px;
    height: 160px;
    object-fit: contain;
    filter: drop-shadow(0 4px 8px rgba(0,0,0,0.2));
}

.relic-purchase-name-wrapper {
    position: relative;
    display: inline-block;
}

.relic-purchase-name {
    background-image: url("resources/images/paper.webp");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    padding: 15px 30px;

    font-family: 'NoteLocal', serif;
    font-size: 1.4rem;
    color: #5d4e37;
    margin: 0;
    min-height: 80px;
    min-width: 160px;

    display: flex;
    align-items: center;
    justify-content: center;
}

.relic-purchase-info {
    background-color: rgba(255, 255, 255, 0.75);
    border-radius: 10px;
    padding: 10px;
}

.relic-purchase-effect {
    font-family: 'NoteLocal', serif;
    font-size: 1.2rem;
    color: #5d4e37;
}

.relic-purchase-legend {
    font-family: 'NoteLocal', serif;
    font-size: 1rem;
    color: #8d6e63;
    font-style: italic;
}

.relic-purchase-price {
    position: absolute;
    bottom: 4px;
    right: -72px;
    transform: rotate(12deg);

    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px 25px;

    font-family: 'NoteLocal', serif;
    font-size: 1.3rem;
    color: #5d4e37;

    background-image: url("resources/images/price_2.webp");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    min-width: 60px;
    min-height: 30px;
}

/* ============================================
   ПРЕМУДРОСТИ (правила игры)
   ============================================ */

.help-rules {
    padding: 10px 30px 30px;
    position: relative;
}

/* Кнопка закрытия поверх скролла */
.help-close-btn {
    position: absolute;
    top: 14px;
    right: 14px;
    z-index: 10;
}

/* Заголовок внутри скролла */
.help-header-inline {
    padding: 10px 0 0;
    display: flex;
    justify-content: flex-start;
    margin-bottom: 16px;
}

.help-header-inline h2 {
    width: 300px;
}

/* Вступление */
.help-intro {
    background: rgba(255, 249, 235, 0.9);
    border-radius: 14px;
    padding: 18px 22px;
    margin-bottom: 24px;
    border: 2px solid rgba(139, 90, 43, 0.2);
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.help-lead {
    font-family: 'CommonFont', serif;
    font-size: 1.25rem;
    color: #4a3f2f;
    line-height: 1.6;
    margin: 0;
    text-align: center;
}

/* Шаги */
.help-step {
    display: flex;
    gap: 16px;
    margin-bottom: 20px;
    align-items: flex-start;
}

.help-step-number {
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: linear-gradient(145deg, #d4a05a, #b07a3a);
    border: 3px solid #8b5a2b;
    color: #fff;
    font-family: 'NoteLocal', serif;
    font-size: 1.5rem;
    font-weight: bold;
    display: flex;
    align-items: center;
    justify-content: center;
    text-shadow: 1px 1px 2px rgba(0,0,0,0.4);
    box-shadow: 0 3px 8px rgba(0,0,0,0.2);
}

.help-step-content {
    flex: 1;
    background: rgba(255, 249, 235, 0.9);
    border-radius: 14px;
    padding: 16px 20px;
    border: 2px solid rgba(139, 90, 43, 0.2);
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.help-step-content h3 {
    font-family: 'NoteLocal', serif;
    font-size: 1.3rem;
    color: #5d4037;
    margin: 0 0 8px;
}

.help-step-content p {
    font-family: 'CommonFont', serif;
    font-size: 1.1rem;
    color: #4a3f2f;
    line-height: 1.5;
    margin: 0 0 8px;
}

.help-step-content p:last-child {
    margin-bottom: 0;
}

.help-hint {
    background: rgba(212, 160, 90, 0.15);
    border-radius: 8px;
    padding: 8px 12px !important;
    border-left: 4px solid #d4a05a;
    font-style: italic;
}

/* Место под скриншот.

   Пунктирная рамка с надписью «screenshot» убрана: все шесть мест
   заполнены, и правила были мёртвыми. Если понадобится добавить
   седьмое место, пустое, — вернуть можно из истории. */
.help-screenshot-placeholder {
    margin-top: 12px;
    display: flex;
    justify-content: center;
}

.help-screenshot-placeholder img {
    /* Показываем вдвое мельче, чем снято: снимки сделаны с двойной
       плотностью, и на своей полной ширине они выглядели огромными —
       «Премудрости» раздувало до восьми экранов прокрутки, абзац
       с картинкой не помещался в экран.

       Плотность при этом не теряется: файл остаётся 1040 px, браузер
       ужимает его до 520. На большом мониторе сцена растёт до полутора
       крат, то есть до 780 настоящих пикселей, — запас ещё есть */
    width: 100%;
    max-width: 520px;
    margin: 0 auto;

    border-radius: 8px;
    display: block;
    box-shadow: 0 2px 8px rgba(60, 40, 20, 0.18);
}


/* Разделитель */
.help-divider {
    height: 2px;
    background: linear-gradient(to right, transparent, rgba(139, 90, 43, 0.3), transparent);
    margin: 28px 0;
}

/* Заголовок секции */
.help-section-title {
    font-family: 'NoteLocal', serif;
    font-size: 1.5rem;
    color: #ffe8d0;
    text-align: center;
    margin: 0 0 20px;
    padding: 10px 24px;
    border-radius: 12px;
    display: inline-block;
    width: 100%;
    box-sizing: border-box;
    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.4);
}

/* Пример хода */
.help-example {
    display: flex;
    flex-direction: column;
    gap: 16px;
}

.help-example-step {
    background: rgba(255, 249, 235, 0.9);
    border-radius: 14px;
    padding: 16px 20px;
    border: 2px solid rgba(139, 90, 43, 0.2);
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.help-example-label {
    display: inline-block;
    font-family: 'NoteLocal', serif;
    font-size: 1rem;
    color: #fff;
    background: linear-gradient(145deg, #d4a05a, #b07a3a);
    border-radius: 20px;
    padding: 3px 14px;
    margin-bottom: 10px;
    text-shadow: 1px 1px 1px rgba(0,0,0,0.3);
}

.help-example-step p {
    font-family: 'CommonFont', serif;
    font-size: 1.1rem;
    color: #4a3f2f;
    line-height: 1.5;
    margin: 0;
}

/* Советы */
.help-tips {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.help-tip {
    display: flex;
    align-items: flex-start;
    gap: 12px;
    background: rgba(255, 249, 235, 0.9);
    border-radius: 12px;
    padding: 14px 18px;
    border: 2px solid rgba(139, 90, 43, 0.15);
    box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}

.help-tip-icon {
    font-size: 1.4rem;
    flex-shrink: 0;
    margin-top: 2px;
}

.help-tip p {
    font-family: 'CommonFont', serif;
    font-size: 1.3rem;
    color: #4a3f2f;
    line-height: 1.5;
    margin: 0;
}

/* Инлайн-кубик в тексте */
.help-dice {
    display: inline-block;
    width: 32px;
    height: 32px;
    vertical-align: middle;
    margin: 0 2px;
    border-radius: 6px;
    background: #fff;
    border: 2px solid #fff;
    box-shadow: 1px 2px 4px rgba(0,0,0,0.2);
}

.help-dice.locked {
    outline: 3px solid #4caf50;
    outline-offset: 1px;
    border-radius: 6px;
}

/* Адаптив для мобильных */
/* ОТКЛЮЧЕНО вместе с переходом на сцену (js/stage.js).
   Игра теперь всегда свёрстана в 1236×659, и это условие на базе
   не срабатывало — значит его правила в макет никогда и не входили.
   Но медиазапрос смотрит на ОКНО, а не на сцену, и в маленьком окне
   он выстрелил бы поверх готовой раскладки. Оставлено на случай,
   если вернёмся к отдельной вёрстке под телефон.
@media (max-width: 600px) {
    .help-rules {
        padding: 8px 14px 20px;
    }
    .help-step-number {
        width: 36px;
        height: 36px;
        font-size: 1.1rem;
    }
    .help-step-content h3 {
        font-size: 1.1rem;
    }
    .help-step-content p,
    .help-example-step p,
    .help-tip p,
    .help-lead {
        font-size: 1rem;
    }
} */

/* Блок, отбитый от предыдущего: подсказки заканчиваются, начинается
   новая тема, и без отступа они слипались в одну простыню */
.help-step-apart {
    margin-top: 26px;
}

/* Тот же кружок, что у шагов, только внутри не цифра, а наш кубик.
   Сам кружок остаётся как есть — он держит ряд значков в одну линейку */
.help-step-number.help-step-die {
    display: flex;
    align-items: center;
    justify-content: center;
}

.help-step-number.help-step-die img {
    width: 62%;
    height: 62%;
    object-fit: contain;
}

/* Список быстрых клавиш в «Премудростях» */
.help-keys {
    margin: 6px 0 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.help-keys li {
    display: flex;
    align-items: baseline;
    gap: 8px;
    flex-wrap: wrap;
}

/* Клавиша нарисована клавишей, а не написана словом: так строка
   читается взглядом, без чтения */
.help-keys kbd {
    display: inline-block;
    min-width: 1.6em;
    padding: 3px 8px;
    text-align: center;

    background: linear-gradient(to bottom, #fffaf0, #efe2c9);
    border: 1px solid rgba(120, 92, 58, 0.45);
    border-bottom-width: 3px;
    border-radius: 6px;
    box-shadow: 0 1px 2px rgba(70, 55, 35, 0.25);

    font-family: 'CommonFont', serif;
    font-size: 0.95rem;
    color: #5d4e37;
}

/* ============================================
   НАЛАДКА (настройки)
   ============================================ */

.modal-settings-content {
    display: flex;
    flex-direction: column;
    gap: 18px;
}

.settings-block {
    padding: 15px;
    background: rgba(139, 69, 19, 0.08);
    border-radius: 12px;
}

/* Блок кнопок платформы — в строку.

   Раньше кнопки стояли столбиком в такой же карточке-подложке, как
   «За кого играем» и громкость. Когда Яндекс разрешал обе — «Оценить
   игру» и «Добавить на рабочий стол», — окно вырастало до 716 px при
   высоте сцены 659 и вылезало за экран. Замерено, не на глаз.

   Подложку с её отступами убрали: внутри только две кнопки, обводить
   их рамкой незачем, а строка вместо столбика снимает ещё одну высоту
   кнопки. Вдвоём это 88 px — окно снова помещается. */
#settings-platform-block {
    display: flex;
    gap: 12px;
}

/* Пополам, каждой сколько есть. min-width из общего правила кнопок
   (150 px) здесь мешает: «Добавить на рабочий стол» длиннее половины
   окна и распирало бы строку */
#settings-platform-block .btn-settings {
    flex: 1 1 0;
    min-width: 0;
    padding: 10px 12px;
    font-size: 0.95rem;
    line-height: 1.2;
    text-align: center;
}


.btn-settings:disabled {
    opacity: 0.55;
    cursor: default;
}

/* ОТКЛЮЧЕНО: строка ответа под кнопками платформы убрана совсем.
   «Спасибо за оценку!» и «Ярлык добавлен» теперь говорятся обычной
   запиской сверху — той же, что в обучении. Отдельное место под них
   держало 20 px пустоты всегда, а показывало текст пару раз за всю
   жизнь игрока.
.settings-note {
    margin: 0;
    min-height: 1.2em;
    text-align: center;

    font-family: 'NoteLocal', serif;
    font-size: 1.05rem !important;
    color: #558b2f !important;

    opacity: 0;
    transition: opacity 0.3s ease;
}

.settings-note.visible {
    opacity: 1;
}
*/

.btn-settings-close {
    align-self: center;
    min-width: 160px;
    justify-content: center;
}

/* «Готово» и без того отделено от кнопок платформы пустой строкой
   уведомления и общим зазором колонки. Штатные 22 px сверху добавляли
   к ним третий отступ, и низ окна отваливался от содержимого */
.modal-settings-content .modal-buttons {
    margin-top: 0;
}

/* ============================================================
   ЕДИНОЕ ОФОРМЛЕНИЕ МОДАЛОК
   ------------------------------------------------------------
   Модалки исторически разошлись: 6 классов заголовка, 7 классов
   подзаголовка, две разные обёртки. Здесь всё сводится к общим
   токенам. Блок идёт последним в файле, поэтому перекрывает
   старые правила — при откате достаточно удалить эту секцию.

   Три типа модалок:
     fullscreen — Сундук, Убранство, Премудрости (крестик в углу)
     диалог     — покупки, магазин, Наладка (кнопка закрытия)
     выбор      — смена хода, результаты, «не хватает» (без закрытия)
   ============================================================ */

:root {
    /* Заголовок */
    --modal-title-font: 'NoteLocal', 'CommonFont', serif;
    --modal-title-size: 1.5rem;
    --modal-title-color: #5d4e37;   /* чернила по пергаментной табличке */

    /* Подзаголовок и описания */
    --modal-sub-font: 'NoteLocal', 'CommonFont', serif;
    --modal-sub-size: 1.1rem;
    --modal-sub-color: #6b6250;

    /* Ритм */
    --modal-gap: 16px;
}

/* --- Заголовок: один вид вместо шести --- */
.modal-card-title,
.modal-title,
.results-title,
.not-enough-title,
.relic-purchase-name,
.tablecloth-purchase-name,
.dice-purchase-name {
    font-family: var(--modal-title-font);
    font-size: var(--modal-title-size);
    color: var(--modal-title-color);
    text-align: center;
    font-weight: normal;
    margin: 0 0 var(--modal-gap) 0;
    /* padding НЕ трогаем: у заголовков на paper.webp он задаёт размер таблички */
}

/* Результаты — главный экран партии, заголовку положено быть крупнее */
.results-title {
    font-size: 1.9rem;
    margin-bottom: 10px;
}

/* --- Подзаголовок: один вид вместо семи --- */
.modal-card-subtitle,
.modal-subtitle,
.turn-subtext,
.tablecloth-purchase-desc,
.relic-purchase-effect {
    font-family: var(--modal-sub-font);
    font-size: var(--modal-sub-size) !important;
    color: var(--modal-sub-color) !important;
    text-align: center;
    line-height: 1.4;
    margin: 0 0 var(--modal-gap) 0;
}

/* Подсказка в шапке фуллскрина лежит на светлой бумажной плашке,
   поэтому остаётся тёмной — светлой она сливается с фоном */
.modal-header .modal-hint {
    color: #5d4e37 !important;
}

/* ОКНО ИТОГОВ НЕ ДОЛЖНО ВЫЛЕЗАТЬ ЗА ЭКРАН

   При широком и низком окне сцена упирается в высоту, --stage-bleed-y
   обнуляется, и всё видимое пространство — ровно --stage-h. Окно итогов
   с полным расчётом конфет (списание, результат, ЯХХУУ, бонус за верх,
   задание, итого) вырастает под 700 единиц и обрезается сверху и снизу
   вместе с крестиком.

   Ограничиваем высоту доступным местом, а переполнение отдаём ОДНОМУ
   блоку — расчёту конфет. Он и есть переменная часть: строк в нём
   от двух до шести. Заголовок, счёт, кнопки и крестик остаются
   на виду всегда, а прокрутка появляется только когда без неё никак.

   vh здесь нельзя: внутри масштабированной сцены он меряет не то,
   поэтому считаем от --stage-h и вылета сцены за экран */
#modal-results {
    /* border-box обязателен: у .modal свои паддинги, и при content-box
       они прибавлялись бы к max-height — окно выходило за экран ровно
       на их величину, хотя ограничение «работало» */
    box-sizing: border-box;
    max-height: calc(var(--stage-h) + var(--stage-bleed-y, 0px) * 2 - 24px);
    overflow: hidden;
}

#modal-results .modal-content {
    display: flex;
    flex-direction: column;
    max-height: 100%;
    box-sizing: border-box;
}

/* Сжиматься позволено только расчёту. Без этого флекс ужимал и портрет
   с очками, и кнопки — аватарки сплющивались, а нужен был всего лишь
   свиток на пару строк короче */
#modal-results .modal-content > * {
    flex-shrink: 0;
}

#modal-results #candy-breakdown {
    flex: 0 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* ОКНО КОМНАТЫ (игра по ссылке) */

/* Код набирают голосом или переписывают с чужого экрана, поэтому крупно
   и вразрядку: так «GHJK23» не превратится в «GHJK73» */
/* ============================================
   ВХОД ПО КОДУ (в окне выбора режима)

   Ссылку не всегда есть куда переслать: друг рядом, а мессенджера
   общего нет. Код он просто продиктует — ради этого код и короткий.
   ============================================ */
/* Подпись, поле и кнопка в ОДНУ строку. Колонкой окно выбора режима
   вырастало до 693 единиц при высоте сцены 659 и вылезало за край:
   на этой строке экономия и берётся */
.join-by-code {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 10px;

    margin-top: 4px;
    padding-top: 12px;
    border-top: 1px dashed rgba(93, 78, 55, 0.35);
}

.join-by-code-label {
    font-family: 'CommonFont', serif;
    font-size: 0.9rem;
    color: #6b5a42;
    white-space: nowrap;
}

/* Код набирают с чужих слов, поэтому вразрядку — как он и показан
   в окне комнаты */
.join-code-input {
    width: 128px;
    padding: 8px 10px;

    background: #fffdf5;
    border: 2px solid #a3906f;
    border-radius: 10px;

    font-family: 'NoteLocal', serif;
    font-size: 1.3rem;
    letter-spacing: 0.18em;
    text-align: center;
    text-transform: uppercase;
    color: #5d4e37;
}

.join-code-input:focus {
    outline: none;
    border-color: #7cb342;
}

/* Ширину задаём самому окну, как у лавки и покупки диковины: у
   .modal-small своя, а здесь и полоса диковин, и три кнопки в ряд —
   в 40% ширины сцены кнопки переносились на вторую строку */
#modal-net-room {
    width: min(640px, calc(var(--stage-w) * 0.9));
    max-width: min(640px, calc(var(--stage-w) * 0.9));

    /* Поля уже общих: в окне пять ярусов — заголовок, подпись,
       приглашение, набор диковин и кнопки, — и с общими 26 по вертикали
       оно вырастало до 660 при высоте сцены 659 */
    padding: 18px 24px;
}

/* ============================================
   ЧТО БЕРЁМ НА ПАРТИЮ

   Набор виден прямо в окне комнаты: устраивает — остался и нажал
   «Готов», не устраивает — Сундук рядом. Открывать Сундук только
   затем, чтобы вспомнить свой же набор, — лишний шаг.
   ============================================ */
.net-room-relics {
    margin: 8px 0 2px;
}

.net-room-relics-title {
    margin-bottom: 8px;
    font-family: 'CommonFont', serif;
    font-size: 0.9rem;
    color: #6b5a42;
}

.net-room-relics-row {
    display: flex;
    justify-content: center;
    gap: 14px;
}

.net-room-relic {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    width: 126px;
}

/* Салфетка под вещью — та же, что на полке у стола. Без неё диковины
   висят в пустоте, а на полке они лежат на белом кружеве, и человек
   узнаёт набор по одному виду, не читая подписей */
.net-room-relic img {
    width: 96px;
    height: 96px;
    padding: 14px;
    box-sizing: border-box;
    object-fit: contain;
    filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.3));

    background: url("resources/images/napkin_3_768.webp") center / contain no-repeat;
}

.net-room-relic span {
    font-family: 'CommonFont', serif;
    font-size: 0.78rem;
    line-height: 1.15;
    color: #5d4e37;
}

.net-room-relics-empty {
    font-family: 'CommonFont', serif;
    font-size: 0.9rem;
    color: #8a7a62;
}

/* Код слева, кнопки справа. Три способа позвать друга, и какой из них
   подойдёт — заранее не угадать: телефон под рукой, мессенджер общий
   или просто голос через стол */
.net-room-invite {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 22px;
    margin: 6px 0 2px;
}

.net-room-invite-side {
    display: flex;
    gap: 10px;
}

/* Кнопки узкие: втроём в строку рядом с кодом они помещаются только
   без общего min-width в 150 единиц */
.net-room-invite-side button {
    justify-content: center;
    min-width: 0;
    padding: 9px 14px;
    font-size: 0.85rem;
    white-space: nowrap;
}

/* ============================================
   КРУПНЫЙ QR ПОВЕРХ ВСЕГО

   Код снимают чужой камерой, под углом и при каком попало свете.
   Поэтому во весь экран, чёрным по белому и с полем вокруг: на этом
   экономить нечем — не прочтётся, и всё приглашение впустую.
   ============================================ */
.qr-overlay {
    position: fixed;

    /* Не до края сцены, а до края ЭКРАНА — тем же приёмом, что
       и затемнение диалогов: слой лежит внутри #stage, а сцена уже окна,
       когда пропорции не совпали, и по краям оставались светлые полосы
       доски. Контраст тут не украшение: код снимают камерой */
    inset: calc(var(--stage-bleed-y, 0px) * -1) calc(var(--stage-bleed-x, 0px) * -1);
    z-index: 300;

    display: flex;
    align-items: center;
    justify-content: center;

    background: rgba(0, 0, 0, 0.88);
    cursor: pointer;
}

.qr-overlay.hidden {
    display: none;
}

.qr-overlay-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;

    padding: 18px;
    background: #fff;
    border-radius: 14px;
    box-shadow: 0 10px 40px rgba(0, 0, 0, 0.6);
}

/* Сторону берём от высоты сцены: окно бывает низким и широким,
   и по ширине код влез бы, а по высоте вылез */
.qr-overlay-image {
    width: min(420px, calc(var(--stage-h) * 0.62));
    height: min(420px, calc(var(--stage-h) * 0.62));
}

.qr-overlay-image svg {
    display: block;
    width: 100%;
    height: 100%;
}

/* Код цифрами тут же: телефон не всегда берёт с экрана, и тогда
   человек просто прочтёт четыре знака вслух */
.qr-overlay-code {
    font-family: 'NoteLocal', serif;
    font-size: 1.6rem;
    letter-spacing: 0.2em;
    color: #111;
}

.net-room-code {
    margin: 6px 0 10px;
    font-family: 'CommonFont', serif;
    font-size: 2rem;
    font-weight: bold;
    letter-spacing: 6px;
    text-align: center;
    color: var(--modal-title-color);
}

/* Поле со ссылкой на глаза не лезет: копировать её есть кому — кнопка
   рядом. Показываем только тогда, когда буфер обмена запрещён и текст
   приходится выделять руками (copyToClipboard в js/net_game.js).
   Общего .hidden в проекте нет, он объявлен покомпонентно, — без этой
   строки поле висело бы всегда */
.net-room-link.hidden {
    display: none;
}

.net-room-link {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-bottom: 10px;
}

/* Ссылка показана целиком и доступна для выделения: буфер обмена
   разрешён не везде, и тогда копировать придётся руками */
.net-room-link-input {
    flex: 1 1 auto;
    min-width: 0;
    padding: 8px 10px;

    background: rgba(255, 255, 255, 0.65);
    border: 1px solid rgba(93, 78, 55, 0.35);
    border-radius: 8px;

    font-family: var(--modal-sub-font);
    font-size: 0.9rem;
    color: var(--modal-title-color);
    text-overflow: ellipsis;
}

/* --- Ряд кнопок --- */
.modal-card-actions,
.modal-buttons {
    display: flex;
    gap: 12px;
    justify-content: center;
    flex-wrap: wrap;
    margin-top: 22px;
}

/* --- Кнопки: три роли вместо шести стилей --- */
/* основное действие — зелёная | вторичное — серая | оплата — оранжевая */
.btn-confirm,
.btn-cancel,
.btn-settings,
.btn-watch-ad,
.btn-buy-candies {
    padding: 12px 22px;
    font-size: 1rem;
    border-radius: 10px;
    min-width: 150px;
    justify-content: center;
}

/* Коричневая кнопка настроек была седьмым стилем. Сначала её свели
   к серой вторичной роли, но в «Наладке» серый читался как «выключено»:
   рядом стоит зелёное «Готово», и на его фоне живые кнопки платформы
   выглядели недоступными. Берём обычную нашу оранжевую — ту же, что
   у «Купить конфеты», включая светлую верхнюю грань */
.btn-settings {
    /* Основы у кнопки не было вовсе: ни шрифта, ни цвета текста, ни
       рамки. Браузер рисовал её сам — Arial, чёрным, с системной
       обводкой, — оттого она и выбивалась из остальных. Замерено
       через computed style, а не по картинке */
    display: flex;
    align-items: center;
    cursor: pointer;
    transition: all 0.2s ease;

    font-family: 'CommonFont', serif;
    color: #fff;
    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);

    border: none;
    background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
    border-bottom: 3px solid #e65100;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.38),
        0 3px 10px rgba(245, 124, 0, 0.40);
}

.btn-settings:hover:not(:disabled) {
    background: linear-gradient(135deg, #ffb74d 0%, #fb8c00 100%);
}

/* ============================================================
   ФУЛЛСКРИН: крестик
   Был серым (#666) на почти прозрачном фоне поверх пёстрой
   текстуры дерева — практически не читался.
   ============================================================ */

.modal-close {
    background: rgba(60, 35, 18, 0.75);
    color: #ffe8d0;
    border: 2px solid rgba(255, 232, 208, 0.55);
    border-radius: 10px;
    font-size: 1.9rem;
    line-height: 1;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.35);
}

.modal-close:hover {
    background: #b23a2e;
    color: #fff;
    border-color: #ffd9c9;
    /* Без увеличения: смены цвета достаточно, а прыжок размера
       на крестике читается как лишняя суета */
}

/* ============================================================
   МАЛЫЕ ОКНА: крестик потише
   Правило выше рисовалось под фуллскрин, где крестик лежит
   на пёстром дереве и обязан быть заметным. На светлом
   пергаменте малых окон тот же тёмно-коричневый бьёт по глазам
   и спорит с содержимым. Здесь он приглушён: тон родствен
   подложке, тень мягкая. Всё нужное — размер, попадание
   пальцем, — остаётся, а внимания на себя не тянет.
   ============================================================ */

.modal-small .modal-close-small {
    background: rgba(120, 92, 58, 0.09);
    color: rgba(96, 74, 48, 0.6);
    border: 2px solid rgba(120, 92, 58, 0.18);
    text-shadow: none;
    box-shadow: 0 2px 6px rgba(96, 74, 48, 0.14);
}

.modal-small .modal-close-small:hover {
    background: rgba(120, 92, 58, 0.18);
    color: rgba(96, 74, 48, 0.9);
    border-color: rgba(120, 92, 58, 0.32);
}

/* ============================================================
   ФУЛЛСКРИН: подложка под кнопки
   Кнопки лежали прямо на текстуре дерева и терялись.
   ============================================================ */

.chest-footer,
.cozy-footer,
.help-tutorial-cta {
    /* Подложка обнимает кнопки, а не растягивается на всю модалку */
    width: fit-content;
    max-width: calc(100% - 40px);
    margin: 0 auto 10px;
    padding: 16px 24px;

    /* Градиент сверху вниз: у верхнего края почти прозрачно, поэтому
       дерево не обрывается резко, а постепенно уходит в подложку */
    background: linear-gradient(to bottom,
        rgba(38, 22, 10, 0.30) 0%,
        rgba(38, 22, 10, 0.62) 100%);

    /* Размываем текстуру под плашкой — она перестаёт конкурировать
       с кнопками, переход от дерева к «пластику» становится мягким */
    backdrop-filter: blur(4px) saturate(0.85);
    -webkit-backdrop-filter: blur(4px) saturate(0.85);

    border: 1px solid rgba(255, 232, 208, 0.16);
    border-top-color: rgba(255, 232, 208, 0.10);
    border-radius: 16px;
    box-shadow: inset 0 1px 0 rgba(255, 232, 208, 0.10),
                0 6px 18px rgba(0, 0, 0, 0.28);
}

/* ============================================================
   ПРОБЕГАЮЩИЙ БЛИК на кнопках оплаты и рекламы
   Узкая светлая полоса проходит слева направо, между пробегами
   пауза — привлекает внимание, но не мельтешит.
   ============================================================ */

.btn-watch-ad,
.btn-buy-candies {
    position: relative;
    overflow: hidden;
    isolation: isolate;
}

.btn-watch-ad::after,
.btn-buy-candies::after {
    content: "";
    position: absolute;
    top: -60%;
    bottom: -60%;
    width: 15%;
    left: -30%;

    background: linear-gradient(90deg,
        rgba(255, 255, 255, 0) 0%,
        rgba(255, 255, 255, 0.55) 50%,
        rgba(255, 255, 255, 0) 100%);
    transform: skewX(-18deg);
    pointer-events: none;

    animation: btn-shine 3.4s ease-in-out infinite;
}

/* Купить конфеты — блик чуть ярче и со смещённой фазой,
   чтобы две кнопки не мигали синхронно */
.btn-buy-candies::after {
    background: linear-gradient(90deg,
        rgba(255, 255, 255, 0) 0%,
        rgba(255, 255, 255, 0.7) 50%,
        rgba(255, 255, 255, 0) 100%);
    animation-delay: 1.2s;
}

/* Пока кнопка недоступна (кулдаун рекламы) — блик не нужен */
.btn-watch-ad:disabled::after,
.btn-watch-ad.is-cooldown::after,
.btn-watch-ad.is-no-ad::after {
    animation: none;
    opacity: 0;
}

@keyframes btn-shine {
    0%, 62%  { left: -30%; }
    100%     { left: 115%; }
}

@media (prefers-reduced-motion: reduce) {
    .btn-watch-ad::after,
    .btn-buy-candies::after { animation: none; opacity: 0; }
}

/* ============================================================
   МАЛЫЕ МОДАЛКИ: скатерть как поле + локальные подложки
   ------------------------------------------------------------
   Приём тот же, что сработал в фуллскрине: поверхность видна,
   а содержимое сидит на локальных подложках, которые её обнимают.
   Разница только в тоне — под дерево тёмная, под скатерть светлая.

   Никакого сплошного листа поверх модалки: скатерть должна дышать
   между элементами, иначе она бессмысленна.

   Поверхностей в игре всего четыре, и все уже были:
     скатерть / дерево  — поле
     paper.webp          — табличка заголовка
     подложка           — группа элементов
     пластик            — действие
   ============================================================ */

.modal-small,
.modal-medium {
    background: url("resources/images/parchment_bg_6.webp") center / cover no-repeat, #f7efdd;
    border: 3px solid rgba(120, 92, 58, 0.35);
    padding: 26px 24px;
}

/* --- Табличка заголовка: была у 4 модалок из 8, теперь у всех --- */
.modal-title,
.results-title {
    background-image: url("resources/images/paper.webp");
    background-size: 100% 100%;
    background-repeat: no-repeat;
    background-position: center;

    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* в колоночном флексе (Наладка) дети тянутся на всю ширину —
       прижимаем табличку к центру, чтобы она обнимала текст */
    align-self: center;
    width: fit-content;
    min-height: 64px;
    min-width: 200px;
    padding: 14px 44px;
}

/* --- Локальная подложка под группу --- */
.modal-small .modal-buttons,
.modal-small .mode-buttons,
.modal-medium .modal-buttons,
.modal-small .settings-block,
.modal-small .dice-purchase-info,
.modal-small .tablecloth-purchase-info,
.modal-small .relic-purchase-info,
.modal-medium .results-scores,
.modal-medium .candy-breakdown,
.modal-small .not-enough-info,
.modal-small .candy-packages,
.modal-small .relic-purchase-info {
    background: rgba(122, 94, 58, 0.15);
    border: 1px solid rgba(105, 80, 48, 0.20);
    border-radius: 12px;
    padding: 14px 18px;
    /* внутренняя тень — блок выглядит утопленным в бумагу,
       а не наклеенным поверх */
    box-shadow: inset 0 2px 5px rgba(90, 68, 40, 0.16),
                0 1px 0 rgba(255, 252, 240, 0.55);
}

/* Ряд кнопок — подложка по ширине кнопок, по центру */
.modal-small .modal-buttons,
.modal-medium .modal-buttons {
    width: fit-content;
    max-width: 100%;
    margin-left: auto;
    margin-right: auto;
}

/* Столбик режимов — кнопки во всю ширину, подложка тоже */
.modal-small .mode-buttons {
    width: auto;
    margin: 18px 0 0 0;
}

/* У трёх модалок фон задан по id (#modal-new-game, #modal-not-enough,
   #modal-dice-purchase) — ID перебивает класс, поэтому перекрываем явно */

/* ============================================================
   СКИДКИ НА ПАКЕТЫ КОНФЕТ
   Проценты круглые (5/10/15/20) — их видно в интерфейсе и они
   читаются как предложение, а не как оправдание дробью.
   ============================================================ */

.candy-discount {
    /* красный ценник заметнее зелёного «выгодно» и однозначно
       читается как скидка */
    background: linear-gradient(135deg, #e53935 0%, #b71c1c 100%);
    box-shadow: 0 2px 6px rgba(183, 28, 28, 0.35);
    font-weight: bold;
    letter-spacing: 0.02em;
}

/* Самая большая скидка — крупнее и с лёгким покачиванием,
   чтобы взгляд цеплялся именно за неё */
.candy-discount-best {
    font-size: 0.95rem;
    padding: 5px 12px;
    animation: candy-discount-pulse 2.6s ease-in-out infinite;
}

@keyframes candy-discount-pulse {
    0%, 70%, 100% { transform: scale(1); }
    80%           { transform: scale(1.12); }
}

@media (prefers-reduced-motion: reduce) {
    .candy-discount-best { animation: none; }
}

/* ============================================================
   МЕСТА НА СТОЛЕ ПОД ДИКОВИНЫ
   ------------------------------------------------------------
   Столбиком у правого края: под кубиками нет места — там руки
   персонажей. Названий не пишем, предмет узнаётся по картинке,
   подробности — в подсказке при наведении.
   ============================================================ */

.relic-slots {
    position: fixed;
    right: 176px;
    top: 50%;
    transform: translateY(-50%);
    z-index: 5;

    display: flex;
    flex-direction: column;
    gap: 6px;

    width: fit-content;
    padding: 10px;

    /*background: rgba(255, 252, 245, 0.78);*/
    /*backdrop-filter: blur(4px);*/
    /*-webkit-backdrop-filter: blur(4px);*/
    /*border: 1px solid rgba(255, 255, 255, 0.6);*/
    /*border-radius: 18px;*/
    /*box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7),*/
    /*            0 4px 14px rgba(70, 55, 35, 0.2);*/
}

.relic-slots.hidden { display: none; }

/* ДВЕ ПОЛКИ РАЗОМ — сетевая партия.

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

   Шесть салфеток прежнего размера не влезают. Ужимаем на пятую часть,
   118 → 94, и подбираем промежутки: шесть мест с ними занимают около
   600 единиц при высоте сцены 659. Сильнее уменьшать не стали — вещь
   должна читаться без подписи, ради этого салфетку и делали крупной. */
.relic-slots.has-two .relic-slot-napkin {
    width: 94px;
    height: 94px;
}

.relic-slots.has-two .relic-slot-img {
    width: 58px;
    height: 58px;
}

/* Поля вокруг места лишние, когда мест шесть: они и съедали высоту */
.relic-slots.has-two .relic-slot {
    padding: 0;
}

/* Группы разъезжаются к краям полки, а не жмутся к середине.

   Промежутком между ними это не решалось: когда у одного вещь всего
   одна, а у другого ни одной, единственная салфетка вставала ровно
   посередине — и по ней не понять, чья она. Теперь высота полки задана,
   чужая группа прижата к верху, своя к низу, и место говорит само.

   620 — та высота, при которой шесть салфеток ещё помещаются в сцену:
   6×94 + внутренние промежутки + поля = 620 из 659 */
.relic-slots.has-two {
    gap: 0;
    padding: 4px 10px;
    height: 620px;
    justify-content: space-between;
}

/* Группа — три места одного игрока */
.relic-group {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* Своя группа растёт снизу вверх: одинокая салфетка должна лежать
   у нижнего края, а не в начале своей половины */
.relic-slots.has-two .relic-group.is-mine {
    justify-content: flex-end;
}

/* Чужая вещь не нажимается: это витрина, а не пульт */
.relic-slot.is-peer {
    cursor: default;
    pointer-events: none;
}

.relic-slot {
    display: block;
    padding: 4px;
    background: none;
    border: none;
    border-radius: 14px;
    cursor: default;
    transition: transform 0.15s ease, background 0.2s ease;
}

/* Салфетка крупная — предмет должен читаться без подписи */
.relic-slot-napkin {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 118px;
    height: 118px;

    background: url("resources/images/napkin_3_768.webp") center / contain no-repeat;
}

.relic-slot-img {
    width: 74px;
    height: 74px;
    object-fit: contain;
    filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.3));
}

/* Значок состояния в углу салфетки */
.relic-slot-mark {
    position: absolute;
    right: 2px;
    bottom: 2px;
    width: 26px;
    height: 26px;

    /* Форма берётся из файла-маски, цвет задаётся фоном ниже */
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: 18px 18px;
    mask-size: 18px 18px;
    border-radius: 50%;
}

/* Светлый кружок под значком — иначе он теряется на картинке */
.relic-slot-napkin::after {
    content: "";
    position: absolute;
    right: 2px;
    bottom: 2px;
    width: 26px;
    height: 26px;
    background: rgba(255, 252, 245, 0.95);
    border-radius: 50%;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
}

.relic-slot-mark { z-index: 1; }

/* Постоянный эффект — зелёная бесконечность */
.relic-slot.is-passive .relic-slot-mark {
    -webkit-mask-image: url("resources/images/controls/relic-passive.svg");
    mask-image: url("resources/images/controls/relic-passive.svg");
    background-color: #4a7c2a;
}

/* Ждёт применения — оранжевые часики */
.relic-slot.is-ready {
    cursor: pointer;
}
.relic-slot.is-ready:hover {
    /* Только подсветка. Сдвиг влево заставлял салфетку дёргаться
       под курсором и мешал целиться */
    background: rgba(74, 124, 42, 0.28);
}
.relic-slot.is-ready .relic-slot-mark {
    -webkit-mask-image: url("resources/images/controls/relic-ready.svg");
    mask-image: url("resources/images/controls/relic-ready.svg");
    background-color: #4a7c2a;
    animation: relic-mark-pulse 2.2s ease-in-out infinite;
}

/* Сработала — синяя галочка, картинка приглушена */
.relic-slot.is-used {
    filter: grayscale(0.8);
}

/* Своё правило, а не часть общего: у .relic-slot-napkin фон задан
   сокращённой записью, и одной картинкой его не перебить */
.relic-slot.is-used .relic-slot-napkin {
    background-image: url("resources/images/napkin_2_768.webp");
}
.relic-slot.is-used .relic-slot-mark {
    -webkit-mask-image: url("resources/images/controls/relic-used.svg");
    mask-image: url("resources/images/controls/relic-used.svg");
    background-color: #1e6fa8;
    filter: none;
}

/* Нажать сейчас нельзя: чужой ход или не тот миг своего.
   Вид при этом ОБЫЧНЫЙ, не приглушённый. Серый в игре означает
   «уже использована» — если гасить им же и временный запрет, игрок
   решит, что вещь потрачена, хотя она при нём. О том, что момент
   не тот, говорит подсказка при наведении: «Сейчас недоступна».
   Меняется только значок на салфетке */
.relic-slot.is-blocked .relic-slot-mark {
    -webkit-mask-image: url("resources/images/controls/relic-ready.svg");
    mask-image: url("resources/images/controls/relic-ready.svg");
    background-color: #8d8378;
}

@keyframes relic-mark-pulse {
    0%, 100% { transform: scale(1); }
    50%      { transform: scale(1.14); }
}

/* ============================================================
   ПОДСКАЗКА ПО ДИКОВИНЕ
   ============================================================ */

/* ==========================================================================
   ОБЩАЯ ПОДСКАЗКА (js/tooltip.js) — диковины и дейлик

   Была собрана из пяти размеров, трёх шрифтов и четырёх цветов, причём
   самым крупным шло название-присказка, а то, ради чего игрок навёл
   курсор, — мелким серым. Для человека, которому за шестьдесят, это
   просто нечитаемо, а порядок чтения ещё и обратный.

   Здесь один шрифт на всю карточку, три размера вместо пяти и один
   акцентный цвет. Крупным набрано главное, художественное — мелким
   и в конце.
   ========================================================================== */

.tooltip {
    position: fixed;
    z-index: 300;
    max-width: 360px;
    padding: 22px 26px;

    background: linear-gradient(to bottom, #fffdf7 0%, #f7efdd 100%);
    border: 1px solid rgba(120, 92, 58, 0.35);
    border-radius: 16px;
    box-shadow: 0 8px 26px rgba(45, 30, 15, 0.35);

    /* Один шрифт на всю подсказку. Разные начертания внутри одной
       карточки читались как несколько несвязанных блоков */
    font-family: 'CommonFont', serif;
    color: #4a4034;

    opacity: 0;
    pointer-events: none;
    transition: opacity 0.16s ease;
}

.tooltip.visible { opacity: 1; }

/* --- Что это: надзаголовок --- */
.tooltip-kind {
    font-size: 0.95rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #9a8a72;
    margin-bottom: 8px;
}

/* --- Главное: что нужно сделать --- */
.tooltip-main {
    font-size: 1.6rem;
    line-height: 1.2;
    font-weight: bold;
    color: #3f3629;
    margin-bottom: 14px;
}

/* --- Факты: прогресс и награда --- */
.tooltip-fact {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 1.15rem;
    line-height: 1.35;
    margin-bottom: 6px;
}

.tooltip-fact.is-reward {
    color: #4a7a22;
    font-weight: bold;
}

/* Название звания — золотом. Именно название, не вся строка:
   подсвеченное «Звание:» сливалось с ним в одно пятно */
.tooltip-rank {
    color: #c77800;
    font-weight: bold;
}

.tooltip-fact.is-done {
    color: #c77800;
    font-weight: bold;
}

.tooltip-candy {
    width: 24px;
    height: 24px;
    flex-shrink: 0;
}

/* --- Когда следующее --- */
.tooltip-note {
    margin-top: 14px;
    padding-top: 10px;
    border-top: 1px solid rgba(120, 92, 58, 0.18);
    font-size: 1.05rem;
    color: #7a7060;
}

/* --- Подсказка диковины --- */
.tooltip-title {
    font-size: 1.5rem;
    line-height: 1.2;
    font-weight: bold;
    color: #3f3629;
    margin-bottom: 10px;
}

.tooltip-title .tooltip-kind {
    display: block;
    margin-top: 4px;
    margin-bottom: 0;
    font-weight: normal;
}

.tooltip-text {
    font-size: 1.15rem;
    line-height: 1.4;
    margin-bottom: 8px;
}

.tooltip-state {
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid rgba(120, 92, 58, 0.18);
    font-size: 1.1rem;
    color: #7a7060;
}

.tooltip-state.is-ready { color: #c77800; font-weight: bold; }
.tooltip-state.is-used  { color: #1e6fa8; }

@media (prefers-reduced-motion: reduce) {
    .relic-slot.is-ready .relic-slot-mark { animation: none; }
}

/* Ячейка, где записан ноль, но Золотая подкова его выкупает.
   Золотой цвет — сразу видно, что строка не потеряна зря. */
.relic-zero-bonus {
    /* Тот же золотой, что и у остальных следов диковин — токен в new_style.css */
    color: var(--relic-gold) !important;
    font-weight: bold;
    cursor: help;
    text-shadow: 0 0 6px var(--relic-gold-glow);
}

/* Доплата Счётов за строку, взятую на максимум: «12 +3».
   Само число остаётся обычным — золотом горит только прибавка,
   ровно как выкупленный ноль у Стальной подковы выше */
.relic-max-plus {
    color: var(--relic-gold);
    font-weight: bold;
}

.relic-max-bonus { cursor: help; }

/* Мини-значок диковины в названии строки: видно всю партию,
   места на столе не занимает */
.relic-row-mark {
    display: inline-block;
    width: 1.05em;
    height: 1.05em;
    margin-right: 0.35em;
    vertical-align: -0.2em;
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    /*opacity: 0.85;*/
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.35));
}

/* ============================================================
   ПОДСКАЗКА ДИКОВИНЫ (когда ждёт выбора кубика)
   ============================================================ */

.relic-prompt {
    /* Вне потока совсем. Раньше блок стоял обычным элементом внутри
       контейнера костей: стоило ему появиться — поднос и кнопка броска
       съезжали вниз, и вся середина стола прыгала на пустом месте.
       Теперь он ни на что не влияет.

       Опора — сцена: у неё transform, и для fixed-потомков она
       и есть содержащий блок. Координаты поэтому в единицах сцены.

       Координаты ставит код — placeBeside() из tooltip.js, у того же
       места диковины, где только что висело описание. Это два состояния
       одного окна: навёл — что вещь делает, нажал — что выбрать.
       Появляться в разных точках они не должны, поэтому и расчёт общий,
       а не «похожий» */
    position: fixed;
    left: 0;
    top: 0;

    /* Ширину под подносом задаёт код, и считает он ширину подноса
       целиком. Без border-box к ней прибавились бы поля и рамка —
       окно оказалось шире подноса на 40 px */
    box-sizing: border-box;

    /* Руки персонажей лежат фиксированным слоем (z-index: 3). Дощечкам
       быть под ними правильно, а этой полосе — нет: она объясняет, чего
       игра сейчас ждёт, и половина фразы уходила под ладонь */
    z-index: 6;

    /* Три строки: что просят, из чего выбрать, отказаться. В строку
       это не влезало с тех пор, как выбор стал кубиками, а не цифрами */
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;

    width: max-content;
    /* Не шире свободного места между тетрадью и салфетками с диковинами.
       У места диковины окно встаёт слева от неё, правым краем на 912;
       тетрадь кончается на 450, значит на окно остаётся 430 с зазором.
       С прежними 50% ширины сцены длинная просьба «укажите строку»
       растягивала его до 589 и накрывала три строки тетради — ровно те,
       по которым и надо было выбирать */
    max-width: 430px;
    padding: 12px 18px;

    /* Когда ширину задаёт код (у подноса, у тетради), длинная просьба
       обязана переноситься, а не распирать окно. По умолчанию строка
       не переносится — иначе цена с валютой ломалась бы пополам */
    text-align: center;

    background: linear-gradient(to bottom,
        rgba(255, 250, 236, 0.94) 0%,
        rgba(252, 243, 224, 0.96) 100%);
    border: 2px solid rgba(240, 165, 0, 0.55);
    border-radius: 14px;
    box-shadow: 0 4px 16px rgba(70, 55, 35, 0.28);

    font-family: 'NoteLocal', serif;
    font-size: 1.05rem;
    color: #5d4e37;

    animation: relic-prompt-in 0.2s ease;
}

.relic-prompt.hidden { display: none; }

/* Просьба переносится по словам: у тетради и подноса ширина задана,
   и «Укажите строку в таблице — очки в ней вырастут в полтора раза»
   в одну строку туда не влезает */
#relic-prompt-text {
    line-height: 1.25;

    /* Перенос из самой строки. Нужен Зеркальцу: пары граней стоят
       отдельной строкой, иначе они рвутся посередине — «1⇄6 2⇄5»
       сверху, «3⇄4» снизу, — и читаются как обрывок */
    white-space: pre-line;
}

@keyframes relic-prompt-in {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: none; }
}

.relic-prompt-cancel {
    padding: 5px 14px;
    border: none;
    border-radius: 8px;
    cursor: pointer;

    background: linear-gradient(135deg, #9e9e9e 0%, #757575 100%);
    border-bottom: 2px solid #616161;

    font-family: 'CommonFont', serif;
    font-size: 0.85rem;
    color: #fff;
}

.relic-prompt-cancel:hover { filter: brightness(1.1); }

/* Кубики в режиме выбора — подсвечены и просятся, чтобы на них нажали */
.picking-dice .dice_wrapper,
.picking-dice .dice_empty {
    cursor: pointer;
    animation: dice-pick-glow 1.4s ease-in-out infinite;
}

/* Дыхание приглушено: было 12 px при почти полной непрозрачности,
   и в паре с подсказкой на наведении выходил ярмарочный блеск */
@keyframes dice-pick-glow {
    0%, 100% { filter: drop-shadow(0 0 0 rgba(240, 165, 0, 0)); }
    50%      { filter: drop-shadow(0 0 6px rgba(240, 165, 0, 0.45)); }
}

@media (prefers-reduced-motion: reduce) {
    .picking-dice .dice_wrapper,
    .picking-dice .dice_empty { animation: none; }
    .relic-prompt { animation: none; }
}

/* Кнопки выбора числа для Шепотка и Катушки */
.relic-prompt-values {
    display: flex;
    gap: 8px;
}

.relic-prompt-values.hidden { display: none; }

/* Грань выбирается самим кубиком, а не цифрой на плашке: игрок ищет
   на подносе картинку, а не число, и просить его перевести одно
   в другое незачем. Скин берётся текущий — тот же, что на столе */
.relic-value-btn {
    width: 46px;
    height: 46px;
    padding: 0;
    border: none;
    border-radius: 10px;
    background: none;
    cursor: pointer;
    line-height: 0;
    transition: transform 0.15s ease, filter 0.15s ease;
}

.relic-value-btn img {
    width: 100%;
    height: 100%;
    display: block;
    filter: drop-shadow(0 2px 3px rgba(70, 55, 35, 0.45));
}

/* Плоским скинам движок и на столе добавляет подложку с рамкой —
   без неё грань висит в воздухе. Здесь то же самое */
.relic-value-btn.is-flat img {
    background: #fff;
    border-radius: 9px;
    box-shadow: inset 0 0 0 1px rgba(90, 68, 40, 0.35);
}

.relic-value-btn:hover {
    filter: brightness(1.08);
    transform: translateY(-3px);
}

/* Призрак предсказанного броска (диковина «Бабкин сонник»).

   Геометрия ровно как у настоящей кости — 70 px, поля 8 px сверху.
   Было width/height: 100% по коробке кубика, и картинку плющило
   по чужим пропорциям.

   Полупрозрачным и синеватым остаётся нарочно, в отличие от подсказки
   при наведении: та отвечает «станет вот таким», а этот — «так ВЫПАДЕТ,
   если бросишь». Обещание будущего, и выглядеть оно должно иначе,
   чем свершившийся факт */
.dice_preview {
    position: absolute;
    top: 8px;
    left: 50%;
    margin-left: -35px;
    width: 70px;
    height: auto;
    pointer-events: none;

    opacity: 0.55;
    filter: grayscale(0.4) drop-shadow(0 0 6px rgba(90, 140, 220, 0.9));
    animation: dice-preview-in 0.2s ease;
}

@keyframes dice-preview-in {
    from { opacity: 0; }
    to   { opacity: 0.55; }
}

/* ОТКЛЮЧЕНО: подпись «так выпадет» мелким шрифтом под подносом.
   Про предсказание теперь говорит общая дощечка ограничений раунда —
   там же, где «только чётные» и «не выпадет». Две подписи об одном
   и том же, да ещё разного вида, только сбивали.
.has-preview .dice_row::after {
    content: attr(data-preview-label);
    position: absolute;
    left: 50%;
    bottom: -22px;
    transform: translateX(-50%);

    font-family: 'NoteLocal', serif;
    font-size: 0.85rem;
    color: #3f6fb5;
    text-shadow: 0 1px 2px rgba(255, 255, 255, 0.8);
}
*/

/* Таблица в режиме выбора строки (диковина «Чернильница») */
.picking-category tr[data-row]:hover {
    background: rgba(240, 165, 0, 0.25);
    cursor: pointer;
}

/* Строка, помеченная Чернильницей — очки в ней в полтора раза больше */
/* Метка Чернильницы — В КОЛОНКЕ ИГРОКА, а не на названии строки.

   На строке она была двусмысленной: набор диковин у игроков свой,
   и «×1,5» посреди листа не говорит, чей это множитель. В хотсите набор
   общий и это сходило с рук, но в игре по ссылке стало бы прямой
   неправдой. Заодно и в хотсите теперь видно, у кого какая строка. */
table.score td.inkwell-cell {
    position: relative;
    color: #6a4b8a;
}

table.score td.inkwell-cell::after {
    content: "×1,5";
    position: absolute;
    top: 1px;
    right: 2px;

    /* Плотная плашка, а не бледная подложка. Прежняя — сиреневые буквы
       в 0,62 от шрифта на прозрачном фоне — на телефоне не читалась
       вовсе: соперник видел очки в полтора раза больше и не видел,
       откуда они (22.09.2026) */
    padding: 0 4px;
    background: #7a57a0;
    border-radius: 5px;
    box-shadow: 0 1px 2px rgba(60, 35, 90, 0.35);

    font-family: 'CommonFont', serif;
    font-size: 0.78rem;
    font-style: normal;
    font-weight: normal;
    line-height: 1.35;
    color: #fff;

    /* Метка декоративная: клик по ячейке должен доходить до самой ячейки */
    pointer-events: none;
}

/* Таблица в режиме стирания записи (диковина «Чай с лимоном»).

   Колонку берём у ХОЗЯИНА диковины, а не первую попавшуюся: в партии
   по ссылке им может быть и второе место за столом, а в хотсите хозяин
   меняется с каждым ходом. Номер проставляет js/main.js в data-owner —
   стирать чужие записи нельзя, и подсвечивать их тем более */
.picking-written[data-owner="1"] tr[data-row] td.clicked[data-player="1"],
.picking-written[data-owner="2"] tr[data-row] td.clicked[data-player="2"] {
    background: rgba(200, 60, 60, 0.22);
    cursor: pointer;
}

.picking-written[data-owner="1"] tr[data-row]:hover td.clicked[data-player="1"],
.picking-written[data-owner="2"] tr[data-row]:hover td.clicked[data-player="2"] {
    background: rgba(200, 60, 60, 0.38);
}

/* Баланс в модалке покупки диковины */
.relic-purchase-balance {
    margin: 10px 0 0;
    text-align: center;

    font-family: 'CommonFont', serif;
    font-size: 0.95rem;
    color: #6d5d4d;
}

.relic-purchase-balance.not-enough {
    color: #b23a2e;
    font-weight: bold;
    letter-spacing: 0.5px;
}

.btn-confirm:disabled {
    background: linear-gradient(135deg, #b8b8b8 0%, #949494 100%);
    border-bottom-color: #7d7d7d;
    box-shadow: none;
    cursor: default;
    opacity: 0.85;
}

/* ============================================================
   РОЛЬ «ОПЛАТА» — оранжевая кнопка
   Третья и последняя роль: основное действие зелёное,
   второстепенное серое, оплата оранжевая. Цвет денег оставлен
   осознанно — платное действие должно отличаться от обычного.
   ============================================================ */

.btn-payment {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 12px 22px;
    min-width: 150px;
    border-radius: 10px;
    cursor: pointer;
    transition: all 0.2s ease;

    background: linear-gradient(135deg, #ff9800 0%, #f57c00 100%);
    border: none;
    border-bottom: 3px solid #e65100;

    font-family: 'CommonFont', serif;
    font-size: 1rem;
    color: #fff;
    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
    box-shadow: 0 3px 10px rgba(230, 81, 0, 0.35);
}

.btn-payment:hover { filter: brightness(1.08); }

/* ============================================================
   ПАУЗА ПЛАТФОРМЫ
   Яндекс показывает рекламу или игрок ушёл со вкладки. Стол
   блокируем, чтобы клик «сквозь рекламу» не сделал ход.
   ============================================================ */

.game-paused .dice_container,
.game-paused table.score,
.game-paused .side-menu,
.game-paused .relic-slots,
/* Панель с конфетами и заданием оставалась единственным ярким пятном
   на приглушённом столе — и читалась как живая, хотя нажать на ней
   ничего нельзя. Она такая же часть стола, как тетрадь */
.game-paused .info-panel,
/* Окошко диковины, если пауза застала игрока на выборе */
.game-paused .relic-prompt {
    pointer-events: none;
    filter: saturate(0.6) brightness(0.9);
}

/* ============================================================
   ДОСКА ПОЧЁТА (фуллскрин)
   Таблица на десять строк в малой модалке смотрелась тесно,
   поэтому живёт на дереве, как Закрома. Список кладём на светлую
   подложку — тот же приём, что и везде на деревянном фоне.
   ============================================================ */

.leaderboard-tabs {
    display: flex;
    gap: 10px;
    /* Печати лежат прямо на тетради, светлая подложка им не нужна:
       у сургуча свой плотный силуэт, он читается на любом фоне */
    padding: 0 0 2px 14px;
}

.leaderboard-tab {
    /* Вкладка — сургучная печать. Это не кнопка-действие, а переключатель
       состояния, поэтому свой вид не спорит с тремя ролями кнопок.

       Печать рисуется ОДНОЙ картинкой, растянутой на весь размер.
       Раньше здесь был 9-slice через border-image: он позволял тянуть
       середину под любую длину надписи, не трогая рант. Но браузер
       рисует девять кусков по отдельности, и на дробных координатах —
       а со сценой они дробные почти всегда — между кусками оставался
       волосяной просвет. По печати шла светлая сетка 3×3, хорошо
       заметная при увеличении.

       Один проход отрисовки — стыкам взяться неоткуда, и вести себя
       одинаково будет в любом браузере.

       Размер жёсткий и держит отношение сторон источника (382×140),
       поэтому печать не сплющена ни по одной оси. Под текст остаётся
       184 px внутри ранта; самая длинная подпись — «Больше всех
       ЯХХУУ», 163 px. Английские короче. Если подпись перестанет
       влезать, меняем подпись, а не размер печати. */
    width: 240px;
    height: 88px;
    flex: none;

    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 0 28px;
    box-sizing: border-box;

    border: none;
    cursor: pointer;

    background: url("resources/images/controls/tab-seal.webp") center / 100% 100% no-repeat;

    font-family: 'NoteLocal', serif;
    font-size: 1.05rem;
    line-height: 1.15;
    color: #ffe8d0;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);

    /* Неактивная — обесцвеченная: та же печать, только серым сургучом.
       Отдельная картинка не нужна, и геометрия совпадает точно */
    filter: grayscale(1) brightness(0.92);
    transition: filter 0.18s ease, transform 0.15s ease;
}

/* Наведение и выбор различаются только цветностью печати: серый сургуч
   оживает. Заливкой фона не подсвечиваем — она стёрла бы картинку */
.leaderboard-tab:hover {
    filter: grayscale(0.55) brightness(1);
}

.leaderboard-tab.is-active {
    filter: none;
    transform: translateY(-1px);
    color: #fff8ee;
    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.3);
}

.leaderboard-body {
    /* Внутри листа — только список, фон и тень уехали на общий лист */
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding-right: 6px;
}

.leaderboard-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.leaderboard-row {
    display: flex;
    align-items: center;
    gap: 14px;

    /* Снизу отступ меньше: у рукописного шрифта большой подстрочный
       запас, и при равных паддингах строка кажется съехавшей вверх */
    padding: 7px 6px 4px;
    line-height: 1.1;

    font-family: 'NoteLocal', sans-serif;
    font-size: 1.3rem;
    color: rgb(77, 86, 117);

    /* Строка — это запись, а не поле ввода: текстовая «палка» здесь
       ни к чему. И гасим общий стиль li из style.css */
    cursor: default;
    margin: 0;
    border-bottom: none;
    user-select: none;
}

/* Голубая линовка — как между строками в таблице счёта */
.leaderboard-row + .leaderboard-row {
    border-top: 1px solid #A8D4D7;
}

/* Своя строка — чтобы найти себя не глядя */
/* Своя строка оформлена как записанная ячейка в таблице счёта:
   тот же серый фон и скругление. Янтарная подсветка читалась
   как наведение мышью, а не как «это вы» */
.leaderboard-row.is-me {
    background-color: #ddd;
    border-radius: 6px;
    color: #4d5675;
    font-weight: bold;
}

.leaderboard-row.is-me .leaderboard-place,
.leaderboard-row.is-me .leaderboard-score {
    color: #4d5675;
    text-shadow: none;
}

.leaderboard-place {
    flex-shrink: 0;
    width: 42px;
    text-align: center;
    font-size: 1.3rem;
    color: #adadad;
}

.leaderboard-name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.leaderboard-score {
    flex-shrink: 0;
    min-width: 68px;
    text-align: right;
    font-size: 1.5rem;
    font-weight: bold;
    text-shadow: 0.6px 0.6px 0 rgba(0, 0, 0, 0.12),
                -0.5px -0.5px 0 rgba(255, 255, 255, 0.5);
}

.leaderboard-message {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 10px;
    min-height: 200px;
    text-align: center;
}

.leaderboard-message-title {
    font-family: 'NoteLocal', sans-serif;
    font-size: 1.4rem;
    color: rgb(77, 86, 117);
}

.leaderboard-message-text {
    font-family: 'CommonFont', serif;
    font-size: 0.95rem;
    line-height: 1.45;
    color: #7a7060;
    max-width: 340px;
}

/* Область доски: тетрадь прижата к левому краю, вкладки над ней */
/* Тетрадь целиком: и закладки-печати, и список записей на одном листе.
   Прижата к левому краю, как настоящая тетрадка на столе. */
.leaderboard-area {
    display: flex;
    flex-direction: column;
    align-items: stretch;

    width: 100%;
    max-width: 660px;
    margin: 0;
    padding: 16px 20px 18px;

    background-color: #F4F4F4;
    border-radius: 6px;
    box-shadow:
        0 1px 0 rgba(30, 20, 10, .25),
        0 8px 18px rgba(30, 20, 10, .25);
}

/* Печати лежат на бумаге сверху, список под ними */
.leaderboard-area .leaderboard-tabs {
    flex-shrink: 0;
    padding: 0 0 14px 4px;
    border-bottom: 1px solid #A8D4D7;
    margin-bottom: 6px;
}

/* ============================================================
   ПОЛОСА ПРОКРУТКИ ПОД ТЕТРАДЬ
   Системный скролл на бумажном листе выглядит инородно
   ============================================================ */

.leaderboard-body {
    scrollbar-width: thin;
    scrollbar-color: #A8D4D7 transparent;
}

.leaderboard-body::-webkit-scrollbar {
    width: 10px;
}

.leaderboard-body::-webkit-scrollbar-track {
    background: transparent;
    border-left: 1px solid #A8D4D7;
}

.leaderboard-body::-webkit-scrollbar-thumb {
    background: #A8D4D7;
    border-radius: 6px;
    border: 2px solid #F4F4F4;
}

.leaderboard-body::-webkit-scrollbar-thumb:hover {
    background: #8fc2c6;
}

/* Модалка доски не добавляет своих отступов — лист сам себе граница */
#modal-leaderboard .modal-body.leaderboard-area {
    /* Отступ снизу — чтобы тетрадь не упиралась в край модалки */
    margin: 0 0 24px 30px;
    align-self: flex-start;

    /* Лист по высоте — по содержимому, а не во всю модалку.
       В оболочке Яндекса окно всего 659px, и растянутая тетрадь
       с двумя строками списка превращалась в белое поле на пол-экрана.
       Длинный список упрётся в предел и начнёт прокручиваться внутри */
    flex: 0 0 auto;
    /* Предел считаем от окна, а не от родителя: у родителя высота
       не задана, и «100%» разрешался во что попало — длинный список
       вылезал за нижний край экрана.
       176px — шапка модалки плюс нижний отступ */
    max-height: calc(var(--stage-h) - 176px);
}

/* ==========================================================================
   ЗАПИСКИ — короткие сообщения поверх игры (js/notice.js)

   Заменили нативные alert() и молчаливые console.error. Оформлены как
   бумажка на столе: тот же paper.webp, что у заголовков модалок, — чтобы
   сообщение читалось как часть игры, а не как ошибка браузера.
   ========================================================================== */

.notice-stack {
    position: fixed;
    top: 18px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 2000;              /* выше модалок: об ошибке надо сказать поверх всего */
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    pointer-events: none;       /* стол под записками остаётся кликабельным */
    max-width: min(560px, calc(var(--stage-w) * 0.9));
}

.notice {
    pointer-events: auto;       /* саму записку убрать кликом можно */
    cursor: pointer;

    padding: 14px 26px;
    border-radius: 4px;

    background-image: url("resources/images/paper.webp");
    background-size: 100% 100%;
    background-repeat: no-repeat;

    font-family: var(--modal-sub-font);
    font-size: 1.05rem;
    line-height: 1.35;
    color: var(--modal-title-color);
    text-align: center;
    text-wrap: balance;

    /* Появление: записка слегка падает сверху */
    opacity: 0;
    transform: translateY(-14px);
    transition: opacity 0.22s ease, transform 0.22s ease,
                max-height 0.26s ease, margin 0.26s ease,
                padding 0.26s ease;
    max-height: 320px;
}

.notice.is-shown {
    opacity: 1;
    transform: translateY(0);
}

/* Уходящая записка сжимается вместе с угасанием. Раньше она гасла,
   но продолжала держать место: новая появлялась ниже и в момент
   удаления старой прыгала на ступеньку вверх. Схлопывание высоты
   убирает рывок — стопка съезжает плавно */
.notice.is-leaving {
    opacity: 0;
    transform: translateY(-10px);
    max-height: 0;
    margin-top: 0;
    margin-bottom: 0;
    padding-top: 0;
    padding-bottom: 0;
    overflow: hidden;
}

/* Ошибка — та же бумажка, но написана красным.
   Рамку не рисуем: край у paper.webp рваный, и прямоугольная обводка
   вокруг него читается как нашлёпка. Цвета чернил достаточно */
.notice-error {
    color: #96341f;
    font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
    .notice { transition: opacity 0.15s linear; transform: none; }
    .notice.is-shown,
    .notice.is-leaving { transform: none; }
}

/* ==========================================================================
   КНОПКА «КУПИТЬ КОНФЕТЫ»

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

   Роль (оранжевая = оплата) не трогаем: она уже задана и работает.
   ========================================================================== */

.btn-buy-candies {
    display: inline-flex;
    align-items: center;
    gap: 8px;

    /* Ширина как у соседки: пара кнопок в подвале должна читаться
       как пара, а не как «главная и довесок» */
    min-width: 225px;

    /* Верхняя грань светлее — тот же «пластик», что у остальных кнопок.
       Плоская заливка рядом с деревом смотрелась как веб-кнопка */
    background-image: linear-gradient(135deg, #ffa726 0%, #f57c00 100%);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.38),
        0 3px 10px rgba(245, 124, 0, 0.40);
}

.btn-buy-candies:hover:not(:disabled) {
    background-image: linear-gradient(135deg, #ffb74d 0%, #fb8c00 100%);
}

/* Конфета в кнопке покупки чуть крупнее, чем в «+5 🍬»:
   там она поясняет число, здесь — сама по себе */
.btn-buy-candies .candy-icon-small {
    width: 22px;
    height: 22px;
}

/* ==========================================================================
   ОКНО РЕЗУЛЬТАТОВ

   Показывается после каждой партии, то есть чаще любого другого окна.
   Было три проблемы:

   1. Вместо портретов стояли grandpa.webp / grandma.webp — изображения
      персонажей за столом целиком. В кружке 60×60 от них оставались
      только кисти рук, и это читалось как ошибка загрузки.
   2. Игроки сидели на белых карточках поверх пергаментной подложки —
      тот самый «белый поверх бумаги», от которого отказались в остальных
      малых модалках.
   3. Победитель подсвечивался жёлтой заливкой: выглядело как «выделено
      мышью», а не как победа.
   ========================================================================== */

/* Карточки игроков растворяются в подложке: она уже есть у .results-scores */
/* Когда разбор конфет вырастает до пяти строк — выполнил дейлик и взял
   ЯХХУУ, — окно упиралось в края сцены. Резать пришлось по мелочи
   отовсюду, потому что одного жирного куска тут нет: портреты, поля
   карточек, отступ над кнопками и высота строк разбора. Замерено:
   642 px из 659 доступных, и любая подпись в две строки выносила окно
   за край */
#modal-results .player-result {
    background: none;
    box-shadow: none;
    padding: 4px 18px;
    gap: 2px;
}

/* Портрет в круглой рамке под цвет бумаги */
#modal-results .player-result img {
    /* Аватар — руки вместе с макушкой, ровно тот вид, что игрок видит
       за столом всю партию: у Дедушки клетчатые манжеты, у Бабушки
       оранжевые рукава и красный платок. Лиц в игре нет вовсе,
       поэтому опознавательный знак — именно этот набор */
    width: 84px;
    height: 84px;
    object-fit: cover;
    border: 3px solid rgba(120, 92, 56, 0.45);
    background: rgba(255, 250, 238, 0.65);
    box-shadow: 0 3px 8px rgba(60, 40, 20, 0.28);
    margin-bottom: 6px;
    transition: border-color 0.2s ease, filter 0.2s ease;
}

#modal-results .player-result .player-name {
    font-family: var(--modal-sub-font);
    font-size: 1.05rem;
    color: var(--modal-sub-color);
}

#modal-results .player-result .player-score {
    font-family: var(--modal-title-font);
    font-size: 2.1rem;
    line-height: 1.05;
    color: var(--modal-title-color);
}

/* --- Победитель --- */
/* Не заливка, а тёплая рамка и свечение: «отмечен», а не «выделен» */
#modal-results .player-result.winner img {
    border-color: #c9962f;
    box-shadow: 0 0 0 2px rgba(201, 150, 47, 0.35),
                0 4px 14px rgba(150, 105, 20, 0.40);
}

#modal-results .player-result.winner .player-score {
    color: #8a5a12;
    text-shadow: 0 1px 0 rgba(255, 250, 235, 0.8);
}

/* Проигравший чуть блёкнет — контраст делает победу заметной
   без единого нового изображения */
#modal-results .player-result:not(.winner) img {
    filter: saturate(0.6) brightness(0.97);
}

/* Ничья: победителя нет, никого не выделяем и не гасим */
#modal-results .results-scores.is-draw .player-result img {
    filter: none;
}

/* «против» вместо латинского VS — рукописно и негромко */
#modal-results .results-vs {
    font-family: var(--modal-sub-font);
    font-size: 1rem;
    font-weight: normal;
    color: rgba(107, 98, 80, 0.75);
    letter-spacing: 0.02em;
    align-self: center;
    padding-bottom: 18px;   /* визуально к линии имён, а не к центру блока */
}

/* ==========================================================================
   ИНФОПАНЕЛЬ: дейлик и лучший счёт

   У звания была полоса прогресса, у дейлика — только «1/3» текстом,
   хотя прогресс там ровно такой же по смыслу. А лучший счёт не был
   виден нигде: он определяет звание, но самого числа игрок не знал.
   ========================================================================== */

/* --- Полоса прогресса дейлика (та же, что у звания) --- */
.quest-progress-bar {
    width: 100%;
    height: 6px;
    margin: 2px 0 5px;
    background: rgba(0, 0, 0, 0.3);
    border-radius: 3px;
    overflow: hidden;
}

.quest-progress-fill {
    height: 100%;
    width: 0%;
    border-radius: 3px;
    /* Зелёная, а не золотая: золото у звания означает «расту вообще»,
       зелень у дейлика — «сегодняшнее задание». Разный смысл — разный цвет */
    background: linear-gradient(90deg, #9ccc65, #7cb342);
    transition: width 0.5s ease;
}

.info-daily-quest.completed .quest-progress-fill {
    background: linear-gradient(90deg, #ffd54f, #ffb300);
}

/* --- Лучший счёт --- */
.info-best {
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 6px;
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid rgba(255, 232, 208, 0.15);

    font-family: 'CommonFont', serif;
    font-size: 0.7rem;
    color: rgba(255, 232, 208, 0.6);
}

.info-best strong {
    font-family: 'NoteLocal', serif;
    font-size: 1.15rem;
    color: #ffe8d0;
    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
}

/* Пока партий не было, рекорда нет — не показываем ноль,
   он выглядит как поражение ещё до начала игры */
.info-best.is-empty {
    display: none;
}

/* ==========================================================================
   ИНФОПАНЕЛЬ И МЕНЮ: помещаемся по высоте

   Меню (406px) + панель (401px) + отступы = 839px при окне 747px.
   Панель прижата к низу, меню к верху, поэтому они наезжали друг на друга,
   и счётчик конфет уходил под меню — самый важный элемент становился
   невидимым. В оболочке Яндекса высота ещё меньше: там свой хедер.

   Уплотняем обе части, а не прячем содержимое под прокрутку:
   спрятанное в панели всё равно что отсутствующее.
   ========================================================================== */

.info-panel {
    padding: 12px 12px 12px 18px;
    gap: 8px;
    /* Прокрутку убираем: она прятала конфеты. Вместо неё — компактность */
    overflow: visible;
    max-height: none;
}

/* Конфета была 64px — крупнее, чем всё остальное в панели вместе взятое.
   Число рядом и так набрано жирным, иконке столько места не нужно */
.info-panel .info-icon {
    width: 38px;
    height: 38px;
}

.side-menu {
    gap: 12px;
}

/* --- Дейлик компактнее: счётчик уезжает в строку с наградой --- */
.info-daily-quest {
    padding: 8px 8px 7px;
    margin: 0;
}

.quest-desc  { margin-bottom: 4px; }

.quest-progress-bar { margin: 0 0 4px; }

/* Счётчик и награда в один ряд: «2/3» слева, «+5 🍬» справа.
   Двумя строками они занимали вдвое больше при том же смысле */
.info-daily-quest .quest-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.info-daily-quest .quest-progress,
.info-daily-quest .quest-reward {
    margin: 0;
    font-size: 0.85rem;
}

/* --- Звание компактнее --- */
.info-best {
    margin-top: 4px;
    padding-top: 4px;
}

/* ==========================================================================
   МЕНЮ: иконки вместо дощечек для редких разделов

   «Наладка» и «Премудрости» занимали столько же места, сколько игровые
   разделы, хотя открываются раз за сессию, а то и реже. Свели их в пару
   круглых кнопок под дощечками: и место освободилось, и порядок важности
   стал виден с первого взгляда.
   ========================================================================== */

.menu-icons {
    display: flex;
    justify-content: center;
    gap: 10px;
    width: 100%;
    max-width: 120px;
    margin-top: 2px;
}

.menu-icon {
    width: 46px;
    height: 46px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;

    /* То же дерево, что у дощечек: кнопки другие по форме, но из одного
       материала — иначе читались бы как чужеродные */
    background-color: #a0522d;
    background-image:
        linear-gradient(to bottom, rgba(255, 255, 255, 0.12) 0%, rgba(0, 0, 0, 0.12) 100%),
        url('resources/images/wood_pattern.webp');
    background-size: cover;

    border-radius: 50%;
    border-top: 2px solid #c9956c;
    border-left: 2px solid #c9956c;
    border-right: 2px solid #6b3a1f;
    border-bottom: 3px solid #4a2815;

    box-shadow:
        inset 0 0 6px rgba(0, 0, 0, 0.25),
        2px 2px 4px rgba(0, 0, 0, 0.3);

    transition: transform 0.15s ease, filter 0.15s ease;
}

.menu-icon:hover {
    /* Без подъёма: подсветки достаточно, а прыжок круглой кнопки
       на месте выглядит суетливо */
    filter: brightness(1.12);
}

.menu-icon:active {
    transform: translateY(1px);
    box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.4);
}

/* Символ «вырезан» в дереве: светлый с тёмной тенью снизу */
.menu-icon-glyph {
    display: block;
    color: #ffe8d0;
    filter: drop-shadow(1px 1px 1px rgba(0, 0, 0, 0.75));
}

/* Шестерня — SVG-маской, тем же приёмом, что иконки состояний диковин:
   так символ красится вместе с остальным интерфейсом */
.menu-icon-gear {
    width: 24px;
    height: 24px;
    background-color: #ffe8d0;
    -webkit-mask: url('resources/images/controls/gear.svg') center / contain no-repeat;
    mask: url('resources/images/controls/gear.svg') center / contain no-repeat;
}

/* Вопрос — обычным знаком в игровом шрифте: рисованная закорючка
   здесь уместнее геометрического SVG */
.menu-icon-help {
    font-family: 'NoteLocal', 'CommonFont', serif;
    font-size: 1.75rem;
    line-height: 1;
    font-weight: bold;
    text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8);
}

/* --- Строка рекорда в инфопанели --- */
.info-best {
    justify-content: center;
    gap: 6px;
    font-size: 0.75rem;
    color: rgba(255, 232, 208, 0.65);
}

.info-best strong {
    font-family: 'NoteLocal', serif;
    font-size: 1.2rem;
    color: #ffe8d0;
    text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
}

/* ==========================================================================
   ИНФОПАНЕЛЬ: читаемость

   Панель была 120px шириной, и всё в ней жалось: описание дейлика шло
   шрифтом 12px, счётчик прогресса — 13px. Разобрать это на деревянном
   фоне почти невозможно.

   После того как убрали звание и строку режима, вертикального места
   освободилось около 135px — тратим его на размер шрифта, а не
   на пустоту. Заодно панель чуть шире и с меньшими отступами по краям.
   ========================================================================== */

/* Ширина и горизонтальные отступы — ровно как у меню (120 + 18 + 12),
   иначе панель выпирает левее полки с дощечками и колонка справа
   перестаёт читаться как одна колонка */
.info-panel {
    width: 120px;
    padding: 14px 12px 14px 18px;
    gap: 10px;
}

/* --- Конфеты: главное число панели --- */
.info-panel .info-icon {
    width: 40px;
    height: 40px;
}

.info-candies {
    font-size: 1.5rem;
    gap: 6px;
}

/* --- Рекорд --- */
.info-best {
    gap: 6px;
    font-size: 0.8rem;
    color: rgba(255, 232, 208, 0.7);
}

.info-best strong {
    font-size: 1.3rem;
}

/* --- Дейлик: ему досталось освободившееся место --- */
/* Дейлик занимает всю ширину панели, но у него остаются свои поля:
   текст, упирающийся в край деревянной плашки, читается хуже */
.info-daily-quest {
    width: 100%;
    padding: 10px 8px 9px;
}

.quest-desc {
    font-size: 0.85rem;
    line-height: 1.3;
    margin-bottom: 7px;
    /* Описания вроде «Заработай 20 конфет» переносятся по словам,
       а не рвутся посреди слова */
    overflow-wrap: break-word;
}

.quest-progress-bar {
    height: 8px;
    margin: 0 0 7px;
}

.info-daily-quest .quest-progress,
.info-daily-quest .quest-reward {
    font-size: 0.95rem;
}

.quest-reward-icon {
    width: 17px;
    height: 17px;
}

/* ==========================================================================
   МЕТКА СЛОЖНОСТИ БОТА

   Точки в верхнем левом углу листка со счётом: одна — лёгкий соперник,
   две — средний. Нужна, чтобы во время тестов было видно, с кем идёт
   партия: снаружи уровни различаются только качеством игры, а это
   на одной партии не прочитывается.
   ========================================================================== */

/* Ячейка шапки выровнена по правому краю, как все остальные, —
   метку возвращаем в сам угол листка */
.thead_header th:first-child {
    text-align: left;
}

.bot-difficulty {
    display: inline-flex;
    gap: 4px;
    vertical-align: middle;
    padding-left: 4px;
}

.bot-difficulty::before,
.bot-difficulty::after {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #4d5675;
    opacity: 0.55;
}

/* Лёгкий — одна точка: вторую прячем */
.bot-difficulty.is-easy::after { display: none; }

/* Хотсит — соперника-бота нет, метка не нужна */
.bot-difficulty:not(.is-easy):not(.is-medium)::before,
.bot-difficulty:not(.is-easy):not(.is-medium)::after { display: none; }

/* ==========================================================================
   ИСТОРИЯ КОНФЕТ в подсказке на счётчике

   Игрок видел только итоговое число и не понимал, куда всё девается —
   особенно когда за партию приходит и уходит сразу несколько сумм.
   ========================================================================== */

.candy-log {
    margin: 10px 0 0;
    padding-top: 8px;
    border-top: 1px solid rgba(120, 92, 58, 0.18);
}

.candy-log-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    font-size: 1.05rem;
    line-height: 1.5;
}

.candy-log-reason {
    color: #4a4034;
}

.candy-log-delta {
    font-weight: bold;
    white-space: nowrap;
}

.candy-log-delta.is-plus  { color: #4a7a22; }
.candy-log-delta.is-minus { color: #96341f; }

/* Счётчик кликабельный на вид — по нему наводятся за подробностями */
.info-candies { cursor: help; }

/* --- Содержимое записки ---
   Иконка — настоящая игровая конфета, а не системный эмодзи: тот
   рисуется розовым в полоску и рядом с синей игровой выглядит чужим.
   Стоит после текста, рядом с числом. */

.notice-inner {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
}

.notice-icon {
    width: 38px;
    height: 38px;
    flex-shrink: 0;
}

/* Записка крупнее: её показывают в ответ на действие с деньгами
   или наградой, и мелкую наверху экрана просто не замечают */
.notice {
    font-size: 1.55rem;
    padding: 20px 38px;
    max-width: min(680px, calc(var(--stage-w) * 0.92));
}

/* Покачивание в первые полторы секунды — чтобы записку заметили.
   Играет на вложенном узле: на самой записке в это время идёт
   появление, и обе анимации трогали бы один transform */
@keyframes notice-wiggle {
    0%, 100%   { transform: rotate(0deg)    translateX(0); }
    20%        { transform: rotate(-1.6deg) translateX(-3px); }
    45%        { transform: rotate(1.4deg)  translateX(3px); }
    70%        { transform: rotate(-0.9deg) translateX(-2px); }
    88%        { transform: rotate(0.5deg)  translateX(1px); }
}

.notice.is-shown .notice-inner {
    animation: notice-wiggle 0.5s ease-in-out 3;
}

@media (prefers-reduced-motion: reduce) {
    .notice.is-shown .notice-inner { animation: none; }
}

/* Выбор персонажа в Наладке */
.settings-label {
    font-family: 'CommonFont', serif;
    font-size: 1.05rem;
    color: #5d4e37;
    margin-bottom: 8px;
    text-align: center;
}

/* Соперника нет за столом: он ещё не сел или отошёл — связь оборвалась.
   Фигура уезжает вверх за край, как будто человек встал и вышел.
   Сдвиг отдельной переменной, а не своим transform: у фигуры он уже
   занят — там и центровка, и сдвиг вслед за полем, и масштаб.
   Подменять соперника «не нами», пока он молчит, нельзя: при одинаковых
   выборах подмена показывала бы деда бабкой */
.character-top.is-away {
    --away-shift: -115%;
}

/* Своя фигура уходит и приходит в свою сторону — вниз */
.character-bottom.is-away {
    --away-shift: 115%;
}

.character-choice {
    display: flex;
    gap: 26px;
    justify-content: center;
}

.character-option {
    /* Оформлено так же, как аватары в окне результатов: кружок,
       подпись под ним. Рамки вокруг всей кнопки нет — выбранного
       отмечает обводка самого кружка */
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 4px;
    border: none;
    background: none;
    cursor: pointer;
    font-family: 'CommonFont', serif;
    font-size: 0.95rem;
    color: #5d4e37;
}

.character-option img {
    width: 60px;
    height: 60px;
    border-radius: 50%;
    object-fit: cover;
    object-position: top;
    background: rgba(255, 255, 255, 0.5);
    border: 3px solid transparent;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.character-option:hover img {
    border-color: rgba(184, 134, 11, 0.45);
}

.character-option.is-active img {
    border-color: var(--relic-gold);
    box-shadow: 0 0 14px var(--relic-gold-glow);
}

.character-option.is-active {
    font-weight: 700;
}

/* Во время партии сменить персонажа нельзя: колонки переставились бы,
   а записанные очки остались на местах */
.character-option.is-locked {
    opacity: 0.4;
    cursor: not-allowed;
}

.character-option.is-locked:hover img {
    border-color: transparent;
}

/* Карточка задания в конце партии: поднимаем над затемнением, чтобы
   было видно, к чему относится звук отметки */
.info-daily-quest.quest-spotlight {
    position: relative;
    z-index: 1200;
    animation: quest-spotlight-pulse 0.6s ease-out 2;
    box-shadow: 0 0 0 3px var(--relic-gold),
                0 0 24px 6px var(--relic-gold-glow);
    border-radius: 10px;
}

@keyframes quest-spotlight-pulse {
    0%   { transform: scale(1); }
    45%  { transform: scale(1.06); }
    100% { transform: scale(1); }
}

/* Названия комбинаций в тетради кликабельны — открывают разбор */
table.score tbody tr[data-row] th {
    cursor: pointer;
    transition: color 0.12s ease;
}

table.score tbody tr[data-row]:hover th {
    color: #2f3550;
}

/* Пример комбинации в модалке: поднос с костями, как на столе */
.combo-example {
    display: flex;
    justify-content: center;
    margin: 4px 0 14px;
}

.dice-example {
    display: flex;
    gap: 6px;
    padding: 26px 18px;
    background-image: url(resources/images/dices/dice_tray.webp);
    background-size: 100% 100%;
    background-repeat: no-repeat;
}

.dice-example .dice_img {
    width: 46px;
    margin: 0;
}

/* Кость, не попавшая в комбинацию */
.dice-example .dice_img.is-unused {
    opacity: 0.3;
    filter: grayscale(0.8);
}

/* Шрифт, кегль и цвет — те же, что у лида в «Премудростях»: объяснения
   должны читаться как одно целое, а не как два разных документа */
/* Через id: правило .modal-small .modal-content p весомее одного класса
   и перебивало цвет — текст выходил синеватым, как в тетради,
   а должен быть коричневым, как в «Премудростях» */
#modal-combo .combo-text {
    font-family: 'CommonFont', serif;
    font-size: 1.25rem;
    line-height: 1.6;
    color: #4a3f2f;
    text-align: center;
    margin: 0 0 12px;
}

#modal-combo .combo-score {
    font-family: 'CommonFont', serif;
    font-size: 1.25rem;
    line-height: 1.6;
    font-weight: 700;
    color: #4a3f2f;
    text-align: center;
    margin: 0 0 4px;
}

/* ============================================================
   ОНБОРДИНГ
   ============================================================ */

/* Приветствие. Кнопки столбиком: у них разный вес — «покажите
   на деле» главная, «я умею» самая тихая, и в ряд это не читается */
/* Заголовок и подпись приветствия берут общую разметку окон —
   пергамент и подпись под ним, как у «Новой игры». Свой заголовок
   у окна был один на всю игру: кубик и синяя надпись, — и приветствие
   выглядело чужим ровно там, где игрок видит игру впервые.

   Свои правила остались только у кнопок: их три, и они столбиком */

.welcome-buttons {
    flex-direction: column;
    gap: 10px;
}

/* Третий вариант — не кнопка, а отказ. Оформлен тише остальных,
   чтобы не соперничать с ними за внимание */
.btn-link {
    background: none;
    border: none;
    color: rgba(96, 74, 48, 0.65);
    font-size: 0.95rem;
    text-decoration: underline;
    cursor: pointer;
    padding: 6px;
}

.btn-link:hover {
    color: rgba(96, 74, 48, 0.95);
}

/* Класс .hidden в проекте объявлен только для модалок (.modal.hidden),
   на новых блоках он не действовал — завеса и полоса висели поверх
   стола до начала обучения. Объявляем для них явно */
.tutorial-veil.hidden,
.tutorial-hud.hidden,
.help-tutorial-cta.hidden,
.tutorial-next.hidden,
.combo-example.hidden,
.candy-legacy.hidden,
/* Кнопки в окне покупки диковины и в подвале Закромов: показывается
   та, что подходит под случай. Без этих строк класс висел, а кнопки
   оставались на экране все разом — и это НЕ ловится проверкой
   classList, только замером коробки на экране */
.relic-purchase-buttons > .hidden,
.chest-footer > .hidden,
.chest-footer.hidden,
.candy-packages.hidden,
.candy-legacy-warn.hidden,
.candy-cell-badge.hidden {
    display: none;
}

/* Бонус за первую покупку прячется ИНАЧЕ — местом, а не выключением.
   Он левая половина шапки, и правая (баланс) держит середину только
   пока обе одинаковой ширины. С display: none половина исчезала,
   и название окна уезжало влево у всех, кто уже что-нибудь покупал */
.candy-shop-firstbuy.hidden {
    visibility: hidden;
}

/* Затемнение на время обучения. Ниже модалок (у них 201), выше стола */
.tutorial-veil {
    position: fixed;
    /* Не до края сцены, а до края ЭКРАНА. Сцена уже окна, когда
       пропорции не совпали, и затемнение по её границе оставляло
       по бокам полосы неприкрытой доски. Лишнее срезает
       overflow: hidden у body */
    inset: calc(var(--stage-bleed-y, 0px) * -1) calc(var(--stage-bleed-x, 0px) * -1);
    z-index: 150;
    background: rgba(24, 16, 8, 0.62);
    animation: tutorial-veil-in 0.3s ease-out;
}

@keyframes tutorial-veil-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* Родитель подсвеченного элемента, если он создаёт свой контекст
   наложения. Без этого подсветка честно рисовалась ПОД завесой:
   у подноса костей z-index: 2, у таблицы — transform, и z-index цели
   считался внутри них. Поднимаем виновника чуть выше завесы */
/* Записка обучения не должна занимать пол-экрана. Лечится короткими
   текстами, а не мелким шрифтом: читать её будут новички, и жертвовать
   размером ради места — значит менять одну беду на другую */
body.tutorial-on .notice {
    max-width: min(640px, calc(var(--stage-w) * 0.9));
}

.tutorial-lift {
    z-index: 155 !important;
    position: relative;
}

/* Поднимая виновника контекста, мы вытаскиваем из-под завесы и всё
   его содержимое: вместе с двумя нужными строками всплывает вся
   тетрадь, вместе с одним кубиком — весь поднос. Возвращаем разницу
   приглушением: нужное горит, соседи меркнут */
/* Затемнять поднятую тетрадь оказалось ошибкой: слой поверх неё гасил
   ровно то, что игрок должен читать. Тетрадь остаётся светлой — она
   и так поднята над завесой, а внимание ведёт не темнота вокруг,
   а заливка нужных ячеек */

/* Ячейка, куда надо записать. Рамка на клетке таблицы не читается —
   границы схлопываются, и от неё остаются жёлтые уголки. Поэтому берём
   заливку и пускаем по ней полосу света */
/* Подсказка новичку берёт подсветку обучения ОДНИМ правилом, а не копией:
   разъехавшиеся копии — это две подсветки вместо одной, и правят их
   потом порознь. Условия показа — в js/suggest.js */
body.tutorial-on td.tutorial-target,
table.score td.suggested {
    position: relative;
    z-index: 2;
    background: rgba(255, 206, 84, 0.55) !important;
    box-shadow: inset 0 0 0 2px var(--relic-gold);
    border-radius: 4px;
    overflow: hidden;
    animation: none;
}

/* Подсказка новичку ещё и крупнее на пятую часть: три секунды подсветки
   он мог и не заметить, а пять секунд с увеличением уже не пропустишь.

   transform не влияет на раскладку — соседние строки остаются на местах,
   ячейка просто наезжает на них поверх. Именно поэтому не трогаем
   ни шрифт, ни поля: они бы двигали тетрадь */
table.score td.suggested {
    transform: scale(1.2);
}

body.tutorial-on td.tutorial-target::after,
table.score td.suggested::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg,
        transparent 20%,
        rgba(255, 255, 255, 0.75) 50%,
        transparent 80%);
    transform: translateX(-120%);
    animation: tutorial-cell-shine 2.2s ease-in-out infinite;
    pointer-events: none;
}

@keyframes tutorial-cell-shine {
    0%        { transform: translateX(-120%); }
    55%, 100% { transform: translateX(120%); }
}

@media (prefers-reduced-motion: reduce) {
    body.tutorial-on td.tutorial-target::after,
    table.score td.suggested::after { animation: none; }
    table.score td.suggested { transform: none; }
}

/* Поднос костей: у #dice-row padding 60px сверху и снизу под тени,
   и рамка по его границам висела на полсотни пикселей ниже доски.
   Обводим саму доску отдельным слоем, а общую рамку с контейнера снимаем */
body.tutorial-on #dice-row.tutorial-target {
    box-shadow: none;
    animation: none;
}

body.tutorial-on #dice-row.tutorial-target::before {
    content: '';
    position: absolute;
    inset: 52px 22px;
    border-radius: 12px;
    box-shadow: 0 0 0 3px var(--relic-gold),
                0 0 26px 8px var(--relic-gold-glow);
    pointer-events: none;
    animation: tutorial-pulse 1.4s ease-in-out infinite;
}

/* Подсвеченный элемент. z-index работает, только если между ним
   и корнем нет контекста наложения — счётчик конфет лежит в панели
   с собственным контекстом, и его поднимает js/spotlight.js */
.tutorial-target {
    position: relative;
    z-index: 160;
    border-radius: 10px;
    box-shadow: 0 0 0 3px var(--relic-gold),
                0 0 26px 8px var(--relic-gold-glow);
    animation: tutorial-pulse 1.4s ease-in-out infinite;
}

@keyframes tutorial-pulse {
    0%, 100% { box-shadow: 0 0 0 3px var(--relic-gold),
                           0 0 20px 5px var(--relic-gold-glow); }
    50%      { box-shadow: 0 0 0 3px var(--relic-gold),
                           0 0 34px 12px var(--relic-gold-glow); }
}

@media (prefers-reduced-motion: reduce) {
    .tutorial-target { animation: none; }
    .tutorial-veil { animation: none; }
}

/* Полоса обучения */
.tutorial-hud {
    position: fixed;
    left: 50%;
    bottom: 18px;
    transform: translateX(-50%);
    z-index: 170;
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 10px 18px;
    border-radius: 12px;
    background: rgba(60, 35, 18, 0.92);
    border: 2px solid rgba(255, 232, 208, 0.45);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
    color: #ffe8d0;
    max-width: calc(var(--stage-w) - 24px);
}

.tutorial-progress {
    font-size: 1rem;
    white-space: nowrap;
}

/* Как «Прервать обучение»: обе кнопки служебные и живут в одной полосе,
   зелёная выбивалась и читалась как главное действие экрана */
.tutorial-next {
    background: rgba(255, 232, 208, 0.14);
    border: 1px solid rgba(255, 232, 208, 0.45);
    border-radius: 8px;
    color: #ffe8d0;
    padding: 6px 14px;
    font-size: 0.9rem;
    cursor: pointer;
    white-space: nowrap;
}

.tutorial-next:hover {
    background: rgba(255, 232, 208, 0.26);
}

.tutorial-next.hidden { display: none; }

.tutorial-abort {
    background: rgba(255, 232, 208, 0.14);
    border: 1px solid rgba(255, 232, 208, 0.45);
    border-radius: 8px;
    color: #ffe8d0;
    padding: 6px 14px;
    font-size: 0.9rem;
    cursor: pointer;
    white-space: nowrap;
}

.tutorial-abort:hover {
    background: rgba(255, 232, 208, 0.26);
}

/* Карточку задания на время обучения прячем: новичку хватает четырёх
   действий, а лишний интерфейс сбивает */
body.tutorial-on .info-daily-quest {
    visibility: hidden;
}

/* Призыв к обучению внизу «Премудростей». Подложка общая с кнопками
   Сундука — она размывает дерево под собой, и переход от доски
   к кнопке перестаёт быть резким */
.help-tutorial-cta {
    margin-top: 28px;
    text-align: center;
}



/* ОТКЛЮЧЕНО вместе с переходом на сцену (js/stage.js).
   Игра теперь всегда свёрстана в 1236×659, и это условие на базе
   не срабатывало — значит его правила в макет никогда и не входили.
   Но медиазапрос смотрит на ОКНО, а не на сцену, и в маленьком окне
   он выстрелил бы поверх готовой раскладки. Оставлено на случай,
   если вернёмся к отдельной вёрстке под телефон.
@media (max-width: 560px) {
    .tutorial-hud {
        flex-direction: column;
        gap: 8px;
        bottom: 10px;
    }
} */

/* ============================================================
   ЛАВКА КОНФЕТ

   Ячейка собрана снизу вверх: блюдце → сколько придёт на баланс →
   на что хватит → кнопка с ценой. Блюдце вынесено из кнопки: раньше
   вся карточка изображала «большую кнопку» жёлтой плашкой с рамкой,
   и получалась кнопка размером с открытку.

   Теней у текста здесь нет вовсе. Они мажут мелкий шрифт, а окно
   покупки должно читаться безупречно — тут человек расстаётся
   с деньгами.
   ============================================================ */

/* Ширину задаём САМОМУ окну, а не его телу: у .modal-small своя, и тело
   растекалось за пергамент — третья колонка висела в воздухе */
/* Название и баланс — в одну строку: отдельной строкой баланс съедал
   высоту, а сказать ему нужно три слова. Бумажку с названием не жмём,
   она остаётся прежнего размера */
.candy-shop-head {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 22px;
    margin-bottom: 16px;
}

.candy-shop-head .modal-title {
    margin: 0;
    /* Бумажка своей ширины, ужимать её нечем */
    flex: none;
}

/* Обе стороны получают поровну — только так название окажется ровно
   по центру окна. По содержимому они разной длины, и без этого
   середина строки уезжала к более короткой */
.candy-shop-head .candy-shop-firstbuy,
.candy-shop-head .candy-shop-balance {
    flex: 1 1 0;
    min-width: 0;
    margin: 0;
    /* Ограничение ширины снято: с ним половины снова стали бы разными */
    max-width: none;
}

/* Поля по краю вдвое от обычных: до содержимого было 54 px с каждой
   стороны — при шести ячейках это целая колонка, отданная пустоте */
#modal-candy-shop {
    padding: 13px 12px;
}

#modal-candy-shop .modal-body {
    padding: 8px 15px;
}

#modal-candy-shop {
    width: min(1160px, calc(var(--stage-w) * 0.94));
    max-width: min(1160px, calc(var(--stage-w) * 0.94));
}

.modal-candy-shop-body {
    max-width: none;
}

/* Баланс в самом окне: раньше он оставался позади, под затемнением,
   и решение «сколько брать» принималось вслепую.

   Одно правило на обе половины шапки. Раньше у них не совпадало ничего:
   слева сплошной зелёный жирный текст без иконки, справа — обычная
   подпись, конфета и жирное синее число. Две половины одной строки
   читались как из разных игр. Теперь общее у них строение, размеры
   и вес; расходятся только цветом — он и должен разводить «сколько
   есть» и «сколько дадут сверху» */
.candy-shop-balance,
.candy-shop-firstbuy {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin: 0;
    font-size: 1.15rem;
    line-height: 1.2;
}

.candy-shop-balance img,
.candy-shop-firstbuy img {
    width: 22px;
    height: 22px;
    /* Иконка не должна ужиматься, когда фраза слева длинная */
    flex: none;
}

.candy-shop-balance strong,
.candy-shop-firstbuy strong {
    font-size: 1.3rem;
}

.candy-shop-balance { color: #6b6455; }
.candy-shop-balance strong { color: #4d5675; }

.candy-packages {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 16px 28px;
    margin: 0 0 6px;
}

/* Подложка сетки приходит из общего правила .modal-small .candy-packages
   с отступом 14 px по кругу. По бокам он держит вид, сверху и снизу
   только съедает высоту, которой окну не хватало */
#modal-candy-shop .candy-packages {
    padding-top: 8px;
    padding-bottom: 8px;
    margin-bottom: 0;
}

.candy-cell {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}

/* Блюдце крупнее прежнего: конфеты налезали друг на друга и мазались.
   Сбавлено на 10% от 132 — окно не влезало в кадр по высоте, а на этом
   размере конфеты ещё не слипаются */
.candy-cell-dish {
    position: relative;
    width: 119px;
    height: 119px;
}

.candy-cell-dish .candy-dish {
    position: absolute;
    inset: 0;
    width: 119px;
    height: 119px;
}

.candy-cell-dish .candy-pack {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -46%);
    width: 86px;
    height: auto;
}

/* Сколько придёт на баланс. Зелёным и без тени — это прибыль,
   и цвет здесь тот же, что у выигранных очков */
/* ОТКЛЮЧЕНО: количество переехало на кнопку, см. .candy-package-gain.
   Отдельной строкой под блюдцем оно занимало высоту, а главное — не
   говорило, за что платишь: число конфет тут, цена там. На кнопке
   рядом стоит и то и другое.
.candy-cell-amount {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: 1.4rem;
    color: #5a7a3a;
    font-weight: bold;
}

.candy-cell-amount img {
    width: 20px;
    height: 20px;
}
*/

/* Кнопка целиком: «+250 🍬 за 500 Ян» одной строкой */
.candy-package {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    flex-wrap: nowrap;
    white-space: nowrap;
}

/* Сколько придёт на баланс. Выделено размером и весом: это то, что
   покупают, — цена лишь условие */
.candy-package-gain {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-weight: bold;
}

.candy-package-gain img {
    width: 18px;
    height: 18px;
}

/* «за» — служебное слово, ему громкости не нужно */
.candy-package-for {
    opacity: 0.75;
    font-weight: normal;
}

/* На что хватит. Считается из настоящих цен диковин — см. chest.js */
.candy-cell-worth {
    /* Высота жёсткая, а не минимальная: при min-height ряды сетки
       выходили разной высоты — где текст лёг в две строки, где в три, —
       и модалка вырастала на 29 px. С фиксированной высотой она
       одинакова и по-русски, и по-английски */
    height: 2.5em;
    overflow: hidden;
    font-size: 0.9rem;
    line-height: 1.25;
    text-align: center;
    color: #7a7060;
}

/* Кнопка берётся готовая — .btn-buy-candies, та же, что «Купить конфеты»
   внизу Сундука. Своего оформления ей не даём совсем: иначе выходят две
   оранжевые кнопки об одном и том же, оформленные по-разному */
.candy-package {
    justify-content: center;
    /* Размеры как у эталонной: .modal-buttons button задаёт их только
       кнопкам внутри своего ряда, а наша живёт в сетке пакетов */
    padding: 12px 24px;
    border-radius: 8px;
    font-size: 1.1rem;
}

.candy-package-price {
    white-space: nowrap;
}

/* Значок портальной валюты рядом с ценой. Приходит от SDK
   (getPriceCurrencyImage), поэтому размер задаём мы: что именно
   пришлёт платформа, заранее неизвестно */
.candy-package-price .currency-icon {
    height: 1em;
    width: auto;
    vertical-align: -0.12em;
}

/* Ярлычок скидки зелёный: красным в игре говорится об отказе
   («Не хватает 35 конфет»), и выгода тем же цветом сбивала */
.candy-cell-badge {
    position: absolute;
    top: 2px;
    right: 10px;
    z-index: 2;
    padding: 4px 9px;
    border-radius: 4px;
    background: #5a7a3a;
    color: #fff;
    font-size: 0.8rem;
}

/* Бонус за первую покупку. Строение и размеры пришли из общего правила
   выше, здесь остаётся только своё — зелёный цвет прибыли. Жирным
   светится ЧИСЛО, как и справа: раньше жирной была вся фраза, и она
   перекрикивала соседку */
.candy-shop-firstbuy {
    color: #5a7a3a;
}

.candy-shop-firstbuy strong {
    color: #5a7a3a;
}

/* Волна по кнопкам: блик идёт через все шесть по очереди, как одна
   полоса. Шаг задержки равен ДЛИНЕ ПРОБЕГА, иначе следующая кнопка
   вспыхивает, пока предыдущая ещё светится, и вместо волны выходит
   мельтешение.

   Цикл 7,2 с делится на восемь долей по 0,9 с: шесть уходят на пробег
   по кнопкам, две остаются паузой — без неё волна идёт без передышки
   и утомляет. Ярлычки скидок при этом не мигают: две анимации разом
   читаются как неисправность */
.candy-package::after {
    animation: candy-shine 7.2s linear infinite;
}

@keyframes candy-shine {
    0%, 87.5% { left: -30%; }
    100%      { left: 115%; }
}

.candy-packages .candy-cell:nth-child(1) .candy-package::after { animation-delay: 0s; }
.candy-packages .candy-cell:nth-child(2) .candy-package::after { animation-delay: 0.9s; }
.candy-packages .candy-cell:nth-child(3) .candy-package::after { animation-delay: 1.8s; }
/* Наследство идёт последним в волне — оно в своей строке */
.candy-legacy .candy-package::after { animation-delay: 2.7s; }

/* ============================================================
   БАБКИНО НАСЛЕДСТВО — отдельной строкой под пакетами

   Не пакет и меряется не в конфетах, поэтому и стоит не в сетке:
   четвёртой ячейкой оно читалось бы как «ещё один пакет, только
   странный». Строка во всю ширину разводит их по смыслу.

   Ложится вдоль, а не столбиком: у пакета над каждым словом есть
   картинка, а здесь картинка одна на всё, и в столбик строка
   вырастала бы на полторы сотни пикселей, которых окну взять неоткуда.
   ============================================================ */

.candy-legacy {
    margin-top: 14px;
}

/* Строка живёт по ТОЙ ЖЕ сетке, что и пакеты над ней: три колонки,
   тот же зазор, те же поля по краям. Картинка с текстом занимают
   первые две, кнопка — третью, и она встаёт ровно под кнопкой
   «Сладкого погреба».

   Не «подобрать отступ»: кнопки шириной по содержимому, а содержимое
   меняется — цена приезжает из каталога, значок валюты рисует
   платформа, по-английски надпись другой длины. Подогнанное число
   разъехалось бы на первой же правке цены в Консоли. По построению
   не разъедется никогда. */
.candy-cell-legacy {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    column-gap: 28px;
    align-items: center;
    padding: 10px 18px;

    /* Своя подложка потемнее — чтобы строка не сливалась с сеткой
       пакетов над ней и читалась как отдельное предложение */
    background: rgba(139, 69, 19, 0.10);
    border-radius: 14px;
}

/* Картинка с подписью — на две первые колонки, вдоль строки */
.candy-legacy-about {
    grid-column: 1 / 3;
    display: flex;
    align-items: center;
    gap: 18px;
    min-width: 0;
}

.candy-cell-legacy .candy-package {
    grid-column: 3;
    justify-self: center;
}

/* Блюдца под наследством нет: подложка нарисована на самой картинке */
.candy-legacy-img {
    width: 104px;
    height: 104px;
    flex: none;
}

.candy-legacy-text {
    /* Забирает всё, что осталось между картинкой и кнопкой, —
       так кнопка прижимается к правому краю без margin-left: auto */
    flex: 1 1 auto;
    min-width: 0;
    text-align: left;
}

.candy-legacy-title {
    font-size: 1.25rem;
    font-weight: bold;
    color: #5d4e37;
    line-height: 1.2;
}

.candy-legacy-sub {
    margin-top: 3px;
    font-size: 0.95rem;
    line-height: 1.25;
    color: #7a7060;
}

/* Предупреждение о неполной коллекции. Красным — тем же цветом, каким
   в игре говорится «не хватает»: это единственное место, где цена
   не соответствует ожиданию, и увидеть его нужно до оплаты, а не
   после. Отсюда и вес, и цвет, и место прямо под описанием */
.candy-legacy-warn {
    margin-top: 5px;
    font-size: 0.9rem;
    line-height: 1.25;
    font-weight: bold;
    color: #b23a2e;
}


/* Ярлычок выгоды у наследства прижат к верхнему правому углу СТРОКИ,
   а не ячейки: строка низкая и широкая, и на месте от пакетов
   (top: 2px; right: 10px) он повисал бы над пустотой */
.candy-cell-legacy .candy-cell-badge {
    top: 8px;
    right: 14px;
}

@media (prefers-reduced-motion: reduce) {
    .candy-package::after { animation: none; }
}

/* Итог обучения. Три предложения мелким шрифтом читались как сноска,
   да ещё одно из них жирным — глаз цеплялся не за то. Награда идёт
   первой строкой и крупно, остальное списком */
.tutorial-done-header {
    text-align: center;
    margin-bottom: 12px;
}

.tutorial-done-dish {
    position: relative;
    display: inline-block;
    width: 120px;
    height: 120px;
}

.tutorial-done-dish .candy-dish {
    position: absolute;
    left: 0;
    bottom: 0;
    width: 120px;
    height: auto;
}

.tutorial-done-dish .candy-pack {
    position: absolute;
    left: 50%;
    bottom: 20px;
    transform: translateX(-50%);
    width: 74px;
    height: auto;
    filter: drop-shadow(0 2px 5px rgba(0, 0, 0, 0.3));
}

.tutorial-done-title {
    margin: 8px 0 0;
    font-size: 1.5rem;
    color: #4d5675;
}

.tutorial-done-reward {
    text-align: center;
    margin: 0 0 14px;
    font-size: 1.2rem;
    color: #5a7a3a;
    font-weight: bold;
    letter-spacing: 0.5px;
}

.tutorial-done-list {
    /* Тело модалки раскладывает детей флексом, и три пункта встали
       в три колонки. Возвращаем обычный блок */
    display: block;
    /* border-box обязателен: без него ширина 100% складывалась
       с отступом слева и давала горизонтальный скролл в модалке */
    box-sizing: border-box;
    width: 100%;
    margin: 0;
    list-style: disc;
    color: #6b6455;
    line-height: 1.5;
    text-align: left;
}

.tutorial-done-list li {
    margin-bottom: 6px;
    font-size: 1.2rem;
}

/* ============================================================
   АНИМАЦИИ СОБЫТИЙ СТОЛА

   До этого оживали только персонажи — на ЯХХУУ, бонусе и итоге.
   А бросок, замок и запись, из которых партия и состоит, проходили
   без единого движения: звук был, картинка не менялась.

   Все четыре короткие. Длинная анимация в игре, где за ход делается
   до трёх бросков, превращается в ожидание.
   ============================================================ */

/* --- Приземление кости: УБРАНО ------------------------------------
   Приминание с растяжением делало кости желейными: у настоящей кости
   пропорции не меняются. Правило снято целиком, вернуть можно
   из истории. */

/* --- Щелчок замка -------------------------------------------------
   Только вспышка ободка, без движения самой кости.

   Просадка была и убрана: сжатие от центра сдвигает кость на семь-восемь
   пикселей внутрь, и на глаз это читается не как нажатие, а как рывок
   вбок и вниз. Возврат в исходную точку дела не спасал — мешало само
   движение, а не то, где кость окажется в конце. */
@keyframes dice-lock-glow {
    0%   { box-shadow: 0 0 0 0 rgba(255, 214, 140, 0.85); }
    100% { box-shadow: 0 0 0 14px rgba(255, 214, 140, 0); }
}

/* ::before, а НЕ ::after. У придержанной кости ::after занят самим
   замочком (new_style.css: full_lock.webp, top: 3px, left: -5px).
   Псевдоэлемент у элемента один, и мой inset: 6% перебивал положение
   замка: на время вспышки он съезжал вправо и вниз, а по её окончании
   возвращался. Это и был тот прыжок. */
.dice_wrapper.is-locking::before {
    content: "";
    position: absolute;

    /* Квадрат по грани кости, а не по её коробке.

       Было inset: 6% со всех сторон — но коробка кости не квадратная:
       сама грань 70×70, а сверху и снизу у неё поля по 8 px, итого
       70×86. Ореол повторял эту коробку и расходился прямоугольником.

       Теперь ширину берём от коробки (она равна ширине грани),
       высоту приравниваем к ней через aspect-ratio, а сверху отступаем
       на поле картинки с той же долей 6%. Работает и для ужатых костей
       при шести на подносе: там всё те же доли от меньшей ширины */
    left: 50%;
    top: 8px;              /* поле картинки сверху — с него начинается грань */
    width: 88%;            /* доля от ширины коробки, а она равна ширине грани */
    aspect-ratio: 1;       /* высота равна ширине — отсюда и квадрат */
    transform: translate(-50%, 6%);   /* по центру грани, с тем же полем */

    border-radius: 14%;
    pointer-events: none;
    z-index: 4;
    animation: dice-lock-glow 0.42s ease-out;
}

/* --- Прилёт числа в тетрадь: УБРАНО --------------------------------
   Число никуда не летело — его держит клетка таблицы, — а зелёная
   вспышка строки ложилась вторым слоем поверх уже существующей
   подсветки записи. Два разных свечения на одно событие.
   Вместо этого перекрашена сама подсветка, см. td.bot-choosing. */

/* --- 4. Сработала диковина ----------------------------------------
   Золотое число до этого просто меняло цвет — событие, ради которого
   диковину и покупали, проходило незаметно */
@keyframes relic-number-pop {
    0%   { transform: scale(1);    text-shadow: 0 0 0 var(--relic-gold-glow); }
    40%  { transform: scale(1.35); text-shadow: 0 0 14px var(--relic-gold-glow); }
    100% { transform: scale(1);    text-shadow: 0 0 0 var(--relic-gold-glow); }
}

table.score td.is-relic-firing {
    animation: relic-number-pop 0.55s ease-out;
}

/* Уважаем настройку системы: кому движение мешает, тому его не будет */
@media (prefers-reduced-motion: reduce) {
    .dice_wrapper.is-locking::before,
    table.score td.is-relic-firing {
        animation: none;
    }
}

/* ============================================================
   КУРСОР ДЛЯ ЗАПИСИ ВИДЕО (index.html?rec)

   Системная стрелка на съёмке либо не попадает в кадр, либо теряется
   на пёстром столе, и зрителю не видно, куда нажали. Вместо неё —
   светлый кружок с заметной вспышкой на нажатии.

   В обычной игре ничего из этого не включается.
   ============================================================ */

/* Прячем системную стрелку, включая заданные курсоры вроде карандаша
   над тетрадью — иначе она будет проступать поверх кружка */
body.rec-cursor-on,
body.rec-cursor-on * {
    cursor: none !important;
}

.rec-cursor {
    position: fixed;
    width: 44px;
    height: 44px;
    margin: -22px 0 0 -22px;
    border-radius: 50%;

    /* Матовое стекло: лёгкая заливка плюс размытие того, что под ней.
       Кружок читается на любом фоне, но не закрывает содержимое —
       сквозь него видно, куда наведено */
    background: rgba(255, 252, 245, 0.18);
    backdrop-filter: blur(2.5px) saturate(1.1);
    -webkit-backdrop-filter: blur(2.5px) saturate(1.1);

    border: 2px solid rgba(255, 252, 245, 0.75);
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.4),
                inset 0 0 12px rgba(255, 255, 255, 0.25);

    pointer-events: none;
    opacity: 0;
    z-index: 99999;
    transition: opacity 0.15s ease;
}

.rec-cursor.is-on { opacity: 1; }

/* Вспышка нажатия: кружок проваливается и расходится кольцом.
   Кольцо через box-shadow, а не через второй узел — так вспышка
   не сдвигает сам кружок */
@keyframes rec-cursor-tap {
    0% {
        transform: scale(1);
        background: rgba(255, 252, 245, 0.18);
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.4),
                    inset 0 0 12px rgba(255, 255, 255, 0.25),
                    0 0 0 0 rgba(255, 200, 110, 0.85);
    }
    35% {
        transform: scale(0.78);
        background: rgba(255, 200, 110, 0.55);
    }
    100% {
        transform: scale(1);
        background: rgba(255, 252, 245, 0.18);
        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.4),
                    inset 0 0 12px rgba(255, 255, 255, 0.25),
                    0 0 0 26px rgba(255, 200, 110, 0);
    }
}


.rec-cursor.is-tap { animation: rec-cursor-tap 0.45s ease-out; }

/* ОКНО ПОИСКА СЛУЧАЙНОГО СОПЕРНИКА

   Каркас целиком чужой: .new-game-body, .quest-progress-bar от карточки
   задания, .modal-buttons. Своего здесь — отступы и два вида окна:
   пока ищем и когда не нашли.

   Ни vw/vh, ни медиазапросов по ширине: окно внутри сцены, а она
   масштабируется целиком. Приём из прелоадера переиспользовать нельзя
   именно поэтому — он живёт снаружи сцены и меряет vw. */
/* Окно поиска соперника — шире обычной маленькой модалки.

   Художественные фразы («Спрашиваем на ярмарке — вдруг кто свободен…»)
   в 40% ширины ложились то в одну строку, то в две, и окно прыгало
   по высоте на каждой смене фразы — а меняются они каждые пять секунд.
   Ширины хватает почти всем фразам на одну строку, а место под вторую
   всё равно держим: оно ничего не стоит и убирает скачок насовсем */
#modal-net-search {
    width: 56%;
    min-width: 620px;
}

#net-search-phrase {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 2.9em;
    text-align: center;
    text-wrap: balance;
}

.net-search-bar {
    margin: 14px auto 8px;
    width: 70%;
}

/* Полоса УБЫВАЕТ, и плавность тут вредна: шаг таймера — секунда,
   а переход в полсекунды смазал бы каждый второй шаг. Оставляем
   короткий, чтобы движение читалось, но не отставало от числа */
.net-search-bar .quest-progress-fill {
    transition: width 0.25s linear;
}

.net-search-left {
    margin: 0;
    text-align: center;
    font-size: 1.05em;
    color: #4d5675;
}

.net-search-waiting {
    margin: 4px 0 0;
    text-align: center;
    font-size: 0.85em;
    color: #8b8b8b;
    min-height: 1.2em;   /* чтобы окно не прыгало, когда строка пуста */
}

/* Пока ищем — не показываем то, что относится к неудаче, и наоборот.
   Одно окно на два состояния: заводить второе значило бы дублировать
   и полку диковин, и кнопку выхода */
.net-search-failed-text,
#net-search-again,
#net-search-bot,
#net-search-invite,
.net-search-body.is-failed .net-search-bar,
.net-search-body.is-failed .net-search-left,
.net-search-body.is-failed .net-search-waiting,
.net-search-body.is-failed #net-search-phrase,
.net-search-body.is-failed #net-search-cancel {
    display: none;
}

.net-search-body.is-failed .net-search-failed-text {
    display: block;
}

.net-search-body.is-failed #net-search-again,
.net-search-body.is-failed #net-search-bot,
.net-search-body.is-failed #net-search-invite {
    display: block;
}

/* На последней попытке звать искать ещё незачем — прячем совсем,
   и тогда обычный hidden должен пересиливать правило выше */
.net-search-body.is-failed #net-search-again.hidden {
    display: none;
}

/* Пока ищем, выход один — отмена. Когда не нашли, выходов три,
   и они встают столбиком: в строку такие подписи не влезают */
.net-search-body.is-failed .net-search-buttons {
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
}

.net-search-body.is-failed .net-search-buttons button {
    width: 100%;
}

/* ============================================================
   ДОСКА ПОЧЁТА: звёзды званий
   ============================================================

   Звезда рисуется кодом (js/rank_star.js), а не картинкой: их девять
   штук в двух видах, и все нужны сразу в трёх местах — в тетради,
   на доске и на табличке соперника. Девятнадцать файлов ради одной
   формы это лишний вес и девятнадцать поводов разойтись.

   Невыбитая звезда — НЕ другая картинка, а та же самая, обесцвеченная
   и полупрозрачная. Так видно, что это одно и то же место, просто
   ещё не занятое. */

.rank-star {
    display: inline-block;
    position: relative;
    width: 1.5em;
    height: 1.5em;
    vertical-align: -0.35em;
    line-height: 0;
}

.rank-star svg {
    width: 100%;
    height: 100%;
    display: block;
    overflow: visible;
}

.rank-star-shape {
    fill: #f5c344;
    stroke: #8a5a12;
    stroke-width: 4;
    stroke-linejoin: round;
}

.rank-star-roman {
    fill: #6b4310;
    font-family: 'NoteLocal', serif;
    font-size: 30px;
    font-weight: 700;
    text-anchor: middle;
    dominant-baseline: middle;
    paint-order: stroke;
    stroke: rgba(255, 245, 210, 0.85);
    stroke-width: 5;
    stroke-linejoin: round;
}

/* Блик по выбитой звезде: светлое пятно расходится от середины
   к лучам и гаснет. Форма повторена клипом — точки те же, что
   у полигона, в процентах от квадрата 100×100.

   Раз в тридцать секунд, и это намеренно редко: доска открыта
   подолгу, а частая искра на девяти десятках звёзд превращается
   в мельтешение. Невыбитым блик не положен — им нечем блестеть */
.rank-star-glare {
    position: absolute;
    inset: 0;
    opacity: 0;
    pointer-events: none;
    background: radial-gradient(circle at 50% 50%,
        rgba(255, 255, 255, 0.95) 0%,
        rgba(255, 246, 206, 0.75) 35%,
        rgba(255, 240, 180, 0) 68%);
    clip-path: polygon(50% 2%, 61.5% 34.2%, 95.6% 35.2%, 68.6% 56%, 78.2% 88.8%,
        50% 69.5%, 21.8% 88.8%, 31.4% 56%, 4.4% 35.2%, 38.5% 34.2%);
}

.rank-star:not(.is-dim) .rank-star-glare {
    animation: rank-star-shine 30s linear infinite;
}

/* Медаль слева от названия звания не блестит. Она не клетка, которую
   выбивают, а подпись к ряду: мигающая подпись тянет взгляд туда,
   где ничего не происходит */
.rank-star.honour-medal:not(.is-dim) .rank-star-glare {
    animation: none;
}

@keyframes rank-star-shine {
    0% { opacity: 0; transform: scale(0.25); }
    1% { opacity: 0.95; transform: scale(0.4); }
    4% { opacity: 0.8; transform: scale(0.95); }
    7% { opacity: 0; transform: scale(1.35); }
    100% { opacity: 0; transform: scale(0.25); }
}

/* Ещё не выбита: та же звезда, обесцвеченная и приглушённая.

   Гасим ИМЕННО фигуру, а не всю обёртку: конфета лежит в том же узле,
   и обёртка утянула бы её за собой. А конфета — это обещание награды,
   серой и полупрозрачной она читается как «уже не дадут» */
.rank-star.is-dim svg {
    opacity: 0.38;
    filter: grayscale(1);
}

/* На этом месте лежит конфета — видно заранее, за чем идёшь.
   По центру звезды, в полном цвете: это главное на клетке,
   сама звезда тут только оправа */
.rank-star.has-candy::after {
    content: '';
    position: absolute;
    left: 50%;
    top: 50%;
    width: 1em;
    height: 1em;
    transform: translate(-50%, -50%);
    background: url('resources/images/blue_candy.webp') center/contain no-repeat;
    filter: drop-shadow(0 1px 2px rgba(60, 40, 20, 0.45));
}

.rank-star.has-candy {
    position: relative;
    overflow: visible;
}

/* --- Звезда рядом с итоговой суммой в тетради ---

   Меньше, чем на доске, и с заметным отступом от числа: это пометка
   рядом с суммой, а не вторая цифра. Вплотную к числу она читалась
   как часть счёта. */

.total_row td {
    white-space: nowrap;
}

.total-number {
    vertical-align: middle;
}

.total_row .rank-star {
    width: 1em;
    height: 1em;
    margin-left: 0.25em;
    margin-bottom: 0.1em;

    /* Строки итогов сделаны сквозными для мыши (pointer-events: none
       в new_style.css) — чтобы по ним нельзя было ткнуть, как по игровой
       клетке. Наследовалось это и на звезду: подсказка по наведению
       не открывалась вовсе, событие до неё просто не доходило.
       Возвращаем мышь ей одной — кликать в строке итогов по-прежнему
       нечего, звезда только показывает подсказку */
    pointer-events: auto;
    cursor: help;
}

/* ============================================================
   ДОСКА ПОЧЁТА: сетка девять на девять
   ============================================================ */

/* Лист под доской — тот же, что в «Премудростях»: на голых досках
   рукописный шрифт не читается вовсе, а лист даёт и фон, и поля */
.modal-body.honour-area {
    display: flex;
    flex-direction: column;
    gap: 5px;
    padding: 10px 26px 26px;
    overflow-y: auto;

    background-image: url("resources/images/test_5.webp");
    background-repeat: repeat;
    background-size: 50%;
    background-attachment: local;
}

/* Шапка и сама доска лежат на кремовых карточках — так же, как шаги
   в «Премудростях». На голых досках рукописный шрифт не читается
   вовсе: коричневым по коричневому. Карточка решает это разом */
.honour-head,
#honour-rows {
    background: rgba(255, 249, 235, 0.92);
    border-radius: 14px;
    box-shadow: 0 2px 8px rgba(60, 40, 20, 0.25);
}

.honour-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 18px;
}

#honour-rows {
    padding: 6px 14px;
}

/* Рекорды друзей: окно рисует площадка, у нас только кнопка.
   В шапке она третьим элементом и жмётся к правому краю, поэтому
   размер скромный — доска здесь главная, а не она */
.honour-records {
    flex: 0 0 auto;
    padding: 7px 14px;
    border-radius: 10px;
    font-size: 0.9rem;
    line-height: 1.2;
    white-space: nowrap;
}

.honour-summary {
    font-family: 'NoteLocal', serif;
    font-size: 1.15rem;
    color: #4a3f2f;
}

/* Полка трофеев. Рассчитана не на один предмет: ключ сейчас,
   что-нибудь ещё потом — встанет рядом без перестройки экрана */
.honour-shelf {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 44px;
}

.honour-trophy {
    width: 40px;
    height: 40px;
    object-fit: contain;
}

/* Ряд звания */
/* Ряды прижаты друг к другу и разделены линией, как строки в тетради:
   девять отдельных плашек с полями съедали бы всю высоту.

   Четыре столбца: звание — клетки — награда — кнопка. Награда своим
   столбцом, чтобы картинки призов встали в линию сверху вниз
   и их можно было сравнить глазом, не читая подписей */
.honour-row {
    display: grid;
    grid-template-columns: minmax(230px, 1fr) auto auto minmax(110px, auto);
    align-items: center;
    gap: 14px;
    padding: 4px 10px;
    border-radius: 8px;
}

.honour-row + .honour-row {
    border-top: 1px solid rgba(138, 120, 89, 0.35);
}

/* Ряд собран — приз ждёт. Подсвечиваем, но не мигаем:
   мигающее в списке из девяти строк читается как поломка */
.honour-row.is-ready {
    background: rgba(245, 195, 68, 0.35);
}

.honour-row-title {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

.honour-medal {
    width: 2.1em;
    height: 2.1em;
    flex: none;
}

.honour-row-name {
    font-family: 'NoteLocal', serif;
    font-size: 1.05rem;
    color: #4a3f2f;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.honour-row-at {
    font-family: 'NoteLocal', serif;
    font-size: 0.9rem;
    color: #8a7859;
    flex: none;
    white-space: nowrap;
}

.honour-cells {
    display: flex;
    gap: 4px;
}

.honour-cell {
    width: 1.8em;
    height: 1.8em;
}

.honour-row-tail {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}

.honour-done {
    font-family: 'NoteLocal', serif;
    font-size: 0.9rem;
    color: #8a7859;
    white-space: nowrap;
}

.honour-take {
    font-family: 'NoteLocal', serif;
    font-size: 1rem;
    padding: 4px 14px;
    border-radius: 8px;
    border: 1px solid #8a5a12;
    background: #f5c344;
    color: #5d3a08;
    cursor: pointer;
    white-space: nowrap;
}

.honour-take:hover {
    background: #ffd463;
}

/* Метка на дощечке меню: есть неотобранный приз */
.menu-plank .honour-mark {
    display: inline-block;
    width: 0.7em;
    height: 0.7em;
    margin-left: 0.4em;
    border-radius: 50%;
    background: #f5c344;
    box-shadow: 0 0 0 2px rgba(138, 90, 18, 0.5);
    vertical-align: 0.1em;
}

/* --- Награда ряда: конфеты и вещь --- */

/* Ширина постоянная: в одних рядах здесь вещь, в других «+9», и без
   распорки девять столбцов звёзд слева переставали стоять в линию */
.honour-reward {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 3px;
    width: 58px;
    white-space: nowrap;
}

.honour-reward-candy {
    width: 18px;
    height: 18px;
    object-fit: contain;
}

.honour-reward-count {
    font-family: 'NoteLocal', serif;
    font-size: 0.95rem;
    color: #5d4e37;
}

/* Предметы показываем как есть: ключ и печать нарисованы на прозрачном
   фоне, рамка с тенью превращает их в наклейку */
.honour-reward-prize {
    width: 26px;
    height: 26px;
    object-fit: contain;
}

/* Скатерть — куском ткани, а не целым полотном: узор виден,
   а места занимает как значок. Ей рамка нужна: без неё лоскут
   сливается с листом под доской */
.honour-reward-prize.is-cut {
    object-fit: cover;
    border-radius: 5px;
    border: 1px solid rgba(105, 80, 48, 0.45);
    box-shadow: 0 1px 3px rgba(60, 40, 20, 0.3);
}

/* ============================================================
   НАЛАДКА: выбор скатерти
   ============================================================

   Прилавок «Убранства» убран, а стелить стол по-прежнему надо.
   Здесь не магазин: показываем только то, что уже есть в сундуке.
   Скатерти приходят призами за ряды доски почёта. */

/* Строго одна строка. Скатертей не больше шести, и в перенос они
   уходить не должны: модалка «Наладки» тогда вырастает и вылезает
   за край сцены. Переполнение уводим в прокрутку, а не в высоту */
.cloth-row {
    display: flex;
    flex-wrap: nowrap;
    gap: 8px;
    justify-content: center;
    /* Поля со всех сторон, а не только снизу: полоска прокручиваемая,
       а значит обрезает всё, что вылезло за её границы, — и срезала
       верхнюю кромку выбранной скатерти вместе с её обводкой */
    overflow-x: auto;
    padding: 4px 2px;
}

.cloth-row .cloth-swatch {
    flex: none;
}

.cloth-swatch {
    width: 46px;
    height: 46px;
    padding: 0;
    border-radius: 8px;
    border: 2px solid rgba(105, 80, 48, 0.45);
    background: none;
    cursor: pointer;
    overflow: hidden;
    line-height: 0;
    transition: border-color 0.12s ease, box-shadow 0.12s ease;
}

.cloth-swatch img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* Подъём при наведении убран: полоска стоит в строку, и от толчка
   вверх соседи кажутся съехавшими вниз */

/* Постеленная сейчас. Толстой рамкой, а не галочкой поверх ткани:
   галочка на пёстром узоре теряется */
.cloth-swatch.is-active {
    border-color: #f5c344;
    box-shadow: 0 0 0 2px rgba(138, 90, 18, 0.55);
}

/* ============================================================
   ЗВАНИЕ НА ВИДУ: дощечка, табличка соперника, окно итогов
   ============================================================

   Одна и та же звезда во всех трёх местах — разного размера, но
   одной формы и с одной подписью. Разные значки для одного и того же
   заставляли бы игрока сверять их между собой. */

/* Рядом с рекордом. Рекорд — лучшая одна партия, звание — девять
   подряд: два разных достижения, и стоят они рядом */
/* .info-best — флексбокс с align-items: baseline, и vertical-align
   там не работает вовсе: у флекс-элемента его попросту нет. Поэтому
   align-self, а высоту строки звезда не раздвигает — отрицательные
   поля позволяют ей выйти за строку, а не растянуть её */
.info-best .rank-badge {
    width: 2.6em;
    height: 2.6em;
    cursor: help;
    align-self: center;
    margin-top: -0.6em;
    margin-bottom: -0.6em;
}

/* На табличке соперника. Между лицом и именем: звание — это часть
   того, кто он, а не приписка после имени */
.name-plate .rank-badge {
    width: 1.5em;
    height: 1.5em;
    flex: none;
    margin-right: 2px;
}

/* В окне итогов — справа от счёта, в одной с ним строке. Отдельной
   строкой она растила окно по высоте, а оно и так еле влезает в сцену */
.player-score-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
}

.player-result .rank-badge {
    width: 1.5em;
    height: 1.5em;
    flex: none;
}

/* У бота и у соседа по хотситу звания нет. Значок всё равно
   в разметке — распоркой: без него колонки итогов разной высоты */
#result-player2:not(.has-rank) .rank-badge {
    visibility: hidden;
}

/* Последняя поставленная звезда. Дышит размером — медленно и без
   мигания: найти её взглядом надо, а дёргать внимание нечем */
.rank-star.is-fresh {
    animation: rank-star-beat 2.4s ease-in-out infinite;
}

@keyframes rank-star-beat {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.28); }
}

/* Звезда, улетающая на дощечку «Доска почёта» в конце партии.

   Живёт в сцене и меряется её координатами: сцена масштабируется
   целиком, узел снаружи уехал бы и остался прежнего размера. */
/* Тень нужна затем, что звезда пролетает и над светлой тетрадью,
   и над тёмным деревом меню: без неё она теряется то там, то тут */
.rank-star.rank-fly {
    position: absolute;
    z-index: 1500;
    pointer-events: none;
    filter: drop-shadow(0 2px 5px rgba(50, 30, 10, 0.55));
    animation: rank-fly var(--fly-ms, 900ms) ease-out forwards;
}

/* Гаснет только под конец. Через transition это не выразить — там
   есть лишь начало и конец, и прозрачность таяла всю дорогу:
   звезда пропадала, пройдя треть пути */
@keyframes rank-fly {
    /* Короткий замах на месте: глаз успевает заметить, откуда она
       взялась, прежде чем она тронется.

       Дальше — подъём вдвое к середине пути и возврат к прилёту.
       Затеяно не для красоты: игрок жаловался, что не заметил,
       КУДА она улетела. Маленькая звезда пересекает экран незаметно,
       а раздувшаяся посреди сцены тянет взгляд за собой — и глаз
       доезжает вместе с ней до самой дощечки.

       Уменьшать её по дороге, наоборот, нельзя: так она выглядит
       улетающей вдаль, а не ложащейся на доску. */
    0% { transform: translate(0, 0) scale(0.7); opacity: 0; }
    10% { transform: translate(0, 0) scale(1.2); opacity: 1; }
    20% { transform: translate(0, 0) scale(1); opacity: 1; }
    60% {
        transform: translate(calc(var(--fly-dx, 0px) * 0.5),
                             calc(var(--fly-dy, 0px) * 0.5)) scale(2);
        opacity: 1;
    }
    88% { opacity: 1; }
    100% {
        transform: translate(var(--fly-dx, 0), var(--fly-dy, 0)) scale(1);
        opacity: 0;
    }
}

/* Дощечка принимает звезду: короткий толчок, без мигания */
.menu-plank.is-hit {
    animation: plank-hit 600ms ease-out;
}

@keyframes plank-hit {
    0% { transform: scale(1); }
    30% { transform: scale(1.06); }
    100% { transform: scale(1); }
}

/* ============================================================
   НАЛАДКА: персонаж и скатерть — в строку
   ============================================================

   Сцена альбомная (1236×659), а окно росло столбиком и вылезало
   за её низ. Два блока рядом снимают высоту разом, ширины хватает
   с запасом. Тот же приём, что у кнопок платформы ниже.

   Когда скатертей меньше двух, второй блок скрыт, и первый честно
   занимает всю строку: flex сам растянет единственного соседа. */

.settings-pair {
    display: flex;
    align-items: stretch;
    gap: 14px;
}

.settings-pair > .settings-block {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

/* Скрытый блок не должен занимать колонку: hidden у нас общий
   и ставит display:none, но flex-элемент с ним всё равно надо
   было бы гасить явно — оставляем как есть и не мешаем */
.settings-pair > .settings-block.hidden {
    display: none;
}

/* Окно шире обычной «маленькой» модалки: два блока в строку */
#modal-settings {
    width: min(760px, calc(var(--stage-w) * 0.9));
    max-width: min(760px, calc(var(--stage-w) * 0.9));
}

/* Отступы по образцу окна итогов: там их уже ужимали ровно по этой
   причине — окно не влезало в высоту сцены */
.modal-settings-content {
    gap: 12px;
}

.modal-small .settings-pair > .settings-block {
    padding: 10px 14px;
}

.settings-pair .character-choice {
    gap: 18px;
}

/* Идёт оплата (см. markPaying в js/purchases.js). Кнопка заперта,
   но не серая: она не «недоступна», она занята делом. Содержимое
   прячем, а не убираем, чтобы ширина осталась прежней, и пишем
   «Оплата…» поверх */
.btn-buy-candies.is-paying {
    cursor: wait;
    opacity: 1;
}

.btn-buy-candies.is-paying > :not(.pay-progress) {
    visibility: hidden;
}

.btn-buy-candies.is-paying::after {
    animation: none;
    opacity: 0;
}

/* Соседние кнопки покупки, пока идёт оплата, заперты — и должны
   выглядеть запертыми. Цвет тот же, что у кнопки рекламы в кулдауне.
   Сама кнопка с «Оплата…» остаётся оранжевой: она занята, а не выключена */
.btn-buy-candies:disabled:not(.is-paying) {
    background: linear-gradient(135deg, #9e9e9e 0%, #757575 100%);
    border-bottom-color: #616161;
    opacity: 0.8;
    box-shadow: none;
    cursor: default;
}

.btn-buy-candies:disabled:not(.is-paying)::after {
    animation: none;
    opacity: 0;
}

.pay-progress {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: bold;
    white-space: nowrap;
}

/* Звезда, на которой ждёт конфета. Она уже занята медалью, но конфету
   с неё ещё не забрали: нажатие отдаёт конфету (claimStarCandy
   в js/main.js). Показываем это курсором и лёгким покачиванием —
   значок конфеты на клетке рисует makeStar */
.honour-cell.is-claimable {
    cursor: pointer;
    animation: honour-candy-wait 2.4s ease-in-out infinite;
}

.honour-cell.is-claimable:hover {
    transform: scale(1.12);
}

.honour-cell.is-claimable:focus-visible {
    outline: 2px solid #ffb74d;
    outline-offset: 2px;
    border-radius: 4px;
}

@keyframes honour-candy-wait {
    0%, 70%, 100% { transform: none; }
    80% { transform: translateY(-2px) rotate(-4deg); }
    90% { transform: translateY(-2px) rotate(4deg); }
}

@media (prefers-reduced-motion: reduce) {
    .honour-cell.is-claimable { animation: none; }
}

/* ==========================================================
   Веб-демо (js/demo.js, класс .is-demo на <html>)
   ========================================================== */

/* Сетевые режимы видны, но закрыты: серые, и по нажатию — записка.
   Не прячем: человек должен видеть, что в полной версии это есть */
.is-demo .btn-mode-start[data-mode="net"],
.is-demo .btn-mode-start[data-mode="match"],
.is-demo .join-by-code {
    filter: grayscale(1);
    opacity: 0.55;
    cursor: not-allowed;
}

.is-demo .join-code-input:disabled {
    cursor: not-allowed;
}

/* Доска почёта в демо не открывается — и красная метка «приз ждёт»
   звала бы туда, куда нельзя */
.is-demo .honour-mark {
    display: none;
}

/* Приписка в окне «Понравилось?» — мельче основного текста */
.demo-end-note {
    font-size: 0.85em;
    opacity: 0.75;
}

/* Кнопки магазинов — ссылки, а не кнопки: убираем подчёркивание */
.demo-store {
    text-decoration: none;
    text-align: center;
}

/* Табличка «Демо-версия» на месте таблички соперника: тот же вид
   (.name-plate), но это не кнопка — нажимаются только значки */
.demo-plate {
    cursor: default;
    /* На треть меньше таблички соперника: это пометка, а не главное
       на экране (просьба владельца 23.09.2026) */
    font-size: 1.13rem;
    gap: 9px;
    padding: 4px 5px 4px 15px;
    border-width: 2px;
}

.demo-plate-stores {
    display: inline-flex;
    gap: 5px;
}

/* Значок магазина: круг цвета площадки с её буквами */
.demo-plate-store {
    width: 27px;
    height: 27px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;

    color: #fff;
    font-family: Arial, sans-serif;
    font-size: 0.7rem;
    font-weight: 700;
    text-decoration: none;

    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.8), 0 2px 4px rgba(0, 0, 0, 0.25);
    transition: filter 0.15s ease;
}

/* Под курсором значок чуть темнеет — как кнопка, на которую вот-вот
   нажмут. Без увеличения: прыгающий значок в табличке суетится */
.demo-plate-store:hover {
    filter: brightness(0.85);
}

/* Площадка ещё не открыла игру: значок есть, но приглушён */
.demo-plate-store.is-soon {
    filter: grayscale(0.7);
    opacity: 0.55;
}

.demo-plate-store.is-soon:hover {
    filter: grayscale(0.7) brightness(0.85);
}

/* Подарок-диковина в демо: картинку видно лучше, чем значок конфеты
   в обычной записке — на ней весь смысл сообщения */
.notice-relic-gift .notice-icon {
    width: 46px;
    height: 46px;
}
