/* =====================================================================
   Arcana Lands — оформление сайта
   Автор: Xrustick83

   Собственный CSS без сборщика: сайт открывается в том числе как Telegram
   Mini App, и лишний build-шаг там ничего не даёт, а деплой усложняет.
   Вёрстка mobile-first — Mini App живёт в узком вертикальном вьюпорте.
   ===================================================================== */

:root {
    --bg:            #07120c;
    --surface:       #0e1f16;
    --surface-2:     #1e3a24;
    --border:        #1e3a2a;
    --brand:         #1b6b3a;
    --brand-bright:  #2e9455;
    --accent:        #3fd07e;
    /* Жёлтый и тёмно-зелёный — из логотипа. Один и тот же цвет на знаке
       и на ценниках держит страницу собранной. */
    --gold:          #f2b52c;
    /* Заливка под тёмный текст: на ней ценник читается в любой теме. */
    --gold-solid:    #f2b52c;
    --brand-deep:    #1e3a24;
    --danger:        #d0453f;
    --text:          #e9f2ec;
    --muted:         #9cb3a5;

    /* Цвета, которые на светлой теме обязаны стать другими: раньше они были
       вписаны прямо в правила, и на светлом фоне превращались в нечитаемые. */
    --header-bg:   rgba(7, 18, 12, .85);
    --glow:        rgba(46, 148, 85, .22);
    --ok-text:     #b9f3d3;
    --err-text:    #f3c3c1;
    --badge-err:   #f0817c;
    --shadow:      rgba(0, 0, 0, .45);
    --shadow-soft: rgba(0, 0, 0, .3);
    --backdrop:    rgba(3, 10, 6, .62);

    --radius: 14px;
    --gap: 18px;
    --maxw: 1440px;
}

/* Светлая тема. Включается кнопкой в шапке, выбор запоминается в браузере.
   Фирменный зелёный остаётся тем же, меняются только фоны и контраст:
   на белом акцентный #3fd07e не читается, поэтому он темнеет. */
:root[data-theme="light"] {
    --bg:            #f1f6f2;
    --surface:       #ffffff;
    --surface-2:     #e9f1ec;
    --border:        #d2e2d8;
    --brand:         #1b6b3a;
    --brand-bright:  #22824a;
    --accent:        #12703c;
    --gold:          #9a6f14;
    --gold-solid:    #f2b52c;
    --brand-deep:    #1e3a24;
    --danger:        #c0392b;
    --text:          #1e3a24;
    --muted:         #597265;

    --header-bg:   rgba(255, 255, 255, .88);
    --glow:        rgba(46, 148, 85, .16);
    --ok-text:     #10603a;
    --err-text:    #8f231d;
    --badge-err:   #a3322a;
    --shadow:      rgba(24, 51, 35, .16);
    --shadow-soft: rgba(24, 51, 35, .10);
    --backdrop:    rgba(16, 38, 26, .45);
}

/* Telegram навязывает свою тему. Берём от неё фон, но фирменный зелёный
   на кнопках и акцентах оставляем свой — иначе бренд растворяется. */
body.tg {
    --bg: var(--tg-theme-bg-color, #07120c);
    --surface: var(--tg-theme-secondary-bg-color, #0e1f16);
    --text: var(--tg-theme-text-color, #e9f2ec);
    --muted: var(--tg-theme-hint-color, #9cb3a5);
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--text);
    font-family: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
    font-size: 16px;
    line-height: 1.55;
    -webkit-text-size-adjust: 100%;
}

body {
    /* Мягкое зелёное свечение сверху: страница не выглядит плоской заливкой */
    background-image:
        radial-gradient(900px 380px at 50% -180px, var(--glow), transparent 70%);
    background-repeat: no-repeat;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { line-height: 1.25; margin: 0 0 .6em; font-weight: 650; }
h1 { font-size: 1.65rem; letter-spacing: -.02em; }
h2 { font-size: 1.25rem; }
h3 { font-size: 1.05rem; }
p { margin: 0 0 1em; }

.wrap {
    width: 100%;
    max-width: var(--maxw);
    margin: 0 auto;
    /* 28 по краям: на широком мониторе прежние 16 читались как «текст
       прилип к рамке». На телефоне ужимаем обратно — там каждый пиксель
       ширины на счету. */
    padding: 0 28px;
}
@media (max-width: 700px) {
    .wrap { padding: 0 14px; }
}

/* ---------- шапка ----------
   Одна строка: логотип слева, меню справа. Онлайн и адрес сервера здесь
   намеренно отсутствуют — они переехали на главную, в карточку сервера:
   в шапке они ломали строку на две и висели приклеенным вторым рядом. */

.site-header {
    border-bottom: 1px solid var(--border);
    background: var(--header-bg);
    backdrop-filter: blur(10px);
    position: sticky;
    top: 0;
    z-index: 20;
}

.site-header .wrap {
    display: flex;
    align-items: center;
    gap: 18px;
    min-height: 72px;
}

.logo {
    font-weight: 800;
    font-size: 1.22rem;
    letter-spacing: .01em;
    color: var(--text);
    display: inline-flex;
    align-items: center;
    gap: 10px;
    white-space: nowrap;
}
.logo:hover { text-decoration: none; }
/* Логотип картинкой. Высота задана, ширина считается по пропорциям файла —
   в шапке он не должен ни растягиваться, ни прыгать при загрузке. */
.logo-word {
    display: block;
    height: 38px;
    width: auto;
}
@media (max-width: 700px) {
    .logo-word { height: 30px; }
}

nav.main {
    display: flex;
    gap: 6px;
    margin-left: auto;
    align-items: center;
}

/* Крупные кнопки: по мелким промахиваются мышкой, и на широком мониторе
   они выглядят потерянными. */
nav.main a, nav.main button {
    color: var(--muted);
    padding: 11px 16px;
    border-radius: 12px;
    font-size: 1.02rem;
    font-weight: 600;
    line-height: 1;
    border: 0;
    background: transparent;
    cursor: pointer;
    font-family: inherit;
    white-space: nowrap;
    transition: background .12s ease, color .12s ease;
}
nav.main a:hover, nav.main button:hover {
    background: var(--surface-2);
    color: var(--text);
    text-decoration: none;
}
nav.main a.active {
    color: #fff;
    background: linear-gradient(135deg, var(--brand), var(--brand-bright));
}
/* Кнопка «Регистрация» уже оформлена как .btn — второй фон ей не нужен.
   Только не призрачная: у неё фона нет вовсе, и белый текст на светлой теме
   делал шапку поддоменов пустой — кнопки были, но их не было видно. */
/* Фон нужен явно: правило nav.main a выше сбрасывает его в transparent и по
   специфичности сильнее самого .btn — заполненная кнопка теряла фон, и в
   светлой теме «Личный кабинет» был белым текстом на белом. */
nav.main a.btn:not(.ghost) {
    color: #fff;
    background: linear-gradient(135deg, var(--brand), var(--brand-bright));
    box-shadow: var(--lift);
}
nav.main a.btn:not(.ghost):hover { filter: brightness(1.06); color: #fff; }
nav.main a.btn.ghost { color: var(--text); border: 1px solid var(--border); }
nav.main a.btn.ghost:hover { background: var(--surface-2); border-color: var(--brand-bright); }

/* Голова игрока в шапке: рядом с ником, не растягивая кнопку по высоте. */
nav.main .menu-btn .head,
nav.main .menu-btn .mc-head,
nav.main .btn .head,
nav.main .btn .mc-head { border-radius: 5px; margin: -2px 0; flex: 0 0 auto; }
nav.main .menu-btn { display: inline-flex; align-items: center; gap: 8px; }

/* Переключатель темы: квадратная кнопка с иконкой, а не текст. */
/* Селектор с элементом и двумя классами намеренно: правило nav.main button
   выше делает кнопки flex-контейнерами с выравниванием по левому краю, и с
   более слабым селектором иконка съезжала влево от центра. */
nav.main button.theme-toggle {
    display: inline-grid;
    place-items: center;
    width: 44px;
    height: 44px;
    padding: 0;
    gap: 0;
    /* Строка текста внутри кнопки поднимала иконку выше центра. */
    line-height: 0;
    border-radius: 12px;
    box-shadow: inset 0 0 0 1px var(--border);
}
nav.main button.theme-toggle .i {
    width: 22px;
    height: 22px;
    color: var(--icon);
    /* Сдвиг под базовую линию текста нужен иконкам в строке, а в кнопке
       он смещает её вверх от центра. */
    vertical-align: 0;
    /* display здесь не задаём: им управляют правила видимости ниже, и общее
       display: block перебивало их по специфичности — в тёмной теме
       показывались сразу обе иконки. */
}
nav.main button.theme-toggle:hover .i { color: var(--brand-bright); }

/* Какая иконка видна — решает тема, а не скрипт: в светлой теме солнце,
   в тёмной луна. Кнопка показывает текущее состояние, а не то, на что
   переключит: так это и выглядело раньше, и менять привычное поведение
   вместе с починкой бага незачем.
   Селекторы того же веса, что и у самой кнопки, иначе её общее правило
   перебивает скрытие, и видны сразу обе иконки. */
nav.main button.theme-toggle .i-sun,
nav.main button.theme-toggle .i-moon { display: none; }
/* :not вместо [data-theme="dark"] — атрибута может не быть вовсе, если скрипт
   не сработал, и тогда кнопка осталась бы совсем без иконки. */
:root:not([data-theme="light"]) nav.main button.theme-toggle .i-moon { display: block; }
:root[data-theme="light"] nav.main button.theme-toggle .i-sun { display: block; }

/* Узкий экран: меню переносится под логотип. Нормальная боковая панель по
   кнопке — отдельная задача, здесь только чтобы ничего не вылезало. */
@media (max-width: 1100px) {
    .site-header .wrap { flex-wrap: wrap; gap: 10px; padding-top: 10px; padding-bottom: 10px; }
    nav.main { margin-left: 0; width: 100%; flex-wrap: wrap; }
    nav.main a, nav.main button { padding: 9px 12px; font-size: .95rem; }
}

/* ---------- карточки и сетки ---------- */

/* Воздух над первым блоком и под последним: без него баннер срастается
   с шапкой, а подвал — с последней карточкой. */
main { flex: 1; padding: 28px 0 64px; }
main > .wrap > :last-child { margin-bottom: 0; }

.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 22px;
    margin-bottom: var(--gap);
}
.card.tight { padding: 14px; }

.grid { display: grid; gap: var(--gap); }
/* Внутри сетки расстояние задаёт только gap. Со своим margin-bottom карточки
   получали двойной отступ снизу, и ряды выглядели съехавшими. */
.grid > .card,
.grid > .panel { margin-bottom: 0; }
/* Зато самой сетке отступ снизу нужен: карточки его лишились, и следующий за
   сеткой блок вставал к ней вплотную. Только сетки страницы — у сеток внутри
   карточек расстояние снизу уже даёт padding карточки. */
main > .wrap > .grid { margin-bottom: var(--gap); }
.grid.cols-2 { grid-template-columns: 1fr; }
.grid.cols-3 { grid-template-columns: 1fr; }
.grid.cols-4 { grid-template-columns: repeat(2, 1fr); }

@media (min-width: 720px) {
    .grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
    .grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
    .grid.cols-4 { grid-template-columns: repeat(4, 1fr); }
    h1 { font-size: 2rem; }
}
@media (min-width: 1200px) {
    .grid { gap: 22px; }
}

/* ---------- цифры ---------- */

.stat {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 14px;
    text-align: center;
}
.stat .value { font-size: 1.5rem; font-weight: 700; color: var(--text); }
.stat .value.gold { color: var(--gold); }
.stat .value.accent { color: var(--accent); }
.stat .label { color: var(--muted); font-size: .85rem; }

/* ---------- кнопки ---------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 11px 18px;
    border-radius: 11px;
    border: 1px solid transparent;
    background: var(--brand);
    color: #fff;
    font-weight: 600;
    font-size: .95rem;
    font-family: inherit;
    cursor: pointer;
    transition: background .15s ease, transform .05s ease;
}
.btn:hover { background: var(--brand-bright); text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn:disabled, .btn.disabled {
    background: var(--surface-2);
    color: var(--muted);
    cursor: not-allowed;
}
.btn.ghost { background: transparent; border-color: var(--border); color: var(--text); }
.btn.ghost:hover { background: var(--surface-2); }
.btn.gold { background: var(--gold-solid); color: #2a1e04; }
.btn.gold:hover { background: #e3b747; }
.btn.block { width: 100%; }
.btn.sm { padding: 7px 12px; font-size: .87rem; }

/* ---------- формы ---------- */

label { display: block; margin-bottom: 6px; font-size: .9rem; color: var(--muted); }

input[type="text"], input[type="password"], input[type="number"], select, textarea {
    width: 100%;
    padding: 11px 13px;
    border-radius: 11px;
    border: 1px solid var(--border);
    background: var(--bg);
    color: var(--text);
    font-size: 1rem;      /* меньше 16px — iOS зумит страницу при фокусе */
    font-family: inherit;
}
input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--brand-bright);
    box-shadow: 0 0 0 3px rgba(46, 148, 85, .18);
}
.field { margin-bottom: 14px; }
.hint { color: var(--muted); font-size: .82rem; margin-top: 5px; }

.checkbox {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    font-size: .9rem;
    color: var(--muted);
}
.checkbox input { width: auto; margin-top: 3px; }

/* ---------- сообщения ---------- */

.flash {
    border-radius: 12px;
    padding: 12px 15px;
    margin-bottom: var(--gap);
    border: 1px solid;
    font-size: .93rem;
}
.flash.ok  { background: rgba(63, 208, 126, .10); border-color: rgba(63, 208, 126, .35); color: var(--ok-text); }
.flash.err { background: rgba(208, 69, 63, .10); border-color: rgba(208, 69, 63, .38); color: var(--err-text); }

.errors { list-style: none; padding: 0; margin: 0; }
.errors li { color: var(--err-text); font-size: .88rem; }

/* ---------- бейджи ---------- */

.badge {
    display: inline-block;
    padding: 3px 9px;
    border-radius: 999px;
    font-size: .78rem;
    font-weight: 600;
    border: 1px solid;
}
.badge.ok   { color: var(--accent); border-color: rgba(63, 208, 126, .4); background: rgba(63, 208, 126, .1); }
.badge.wait { color: var(--gold);   border-color: rgba(212, 165, 55, .4); background: rgba(212, 165, 55, .1); }
.badge.err  { color: var(--badge-err);       border-color: rgba(208, 69, 63, .4);  background: rgba(208, 69, 63, .1); }
.badge.off  { color: var(--muted);  border-color: var(--border); }

.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.dot.on { background: var(--accent); box-shadow: 0 0 8px rgba(63, 208, 126, .8); }
.dot.off { background: #45564c; }

/* ---------- товар ---------- */

.item {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.item .icon { font-size: 1.9rem; line-height: 1; }
.item .name { font-weight: 650; }
.item .desc { color: var(--muted); font-size: .88rem; flex: 1; }
.item .price { font-size: 1.2rem; font-weight: 700; color: var(--gold); }
.item .old { color: var(--muted); text-decoration: line-through; font-size: .9rem; margin-left: 6px; font-weight: 400; }
.item .sale {
    background: var(--danger); color: #fff;
    border-radius: 7px; padding: 2px 7px; font-size: .75rem; font-weight: 700;
}

/* ---------- таблицы ---------- */

.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: .92rem; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border); white-space: nowrap; }
th { color: var(--muted); font-weight: 600; font-size: .82rem; text-transform: uppercase; letter-spacing: .04em; }
tr:last-child td { border-bottom: 0; }
td.num, th.num { text-align: right; }

/* ---------- лестница ежедневных наград ---------- */

.ladder { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
@media (min-width: 560px) { .ladder { grid-template-columns: repeat(7, 1fr); } }

.ladder .day {
    border: 1px solid var(--border);
    border-radius: 11px;
    padding: 10px 4px;
    text-align: center;
    background: var(--bg);
}
.ladder .day.done { border-color: var(--brand-bright); background: rgba(46, 148, 85, .14); }
.ladder .day.next { border-color: var(--gold); background: rgba(212, 165, 55, .12); }
.ladder .day .n { font-size: .74rem; color: var(--muted); }
.ladder .day .v { font-weight: 700; color: var(--gold); }

/* ---------- подвал ---------- */

.site-footer {
    border-top: 1px solid var(--border);
    padding: 22px 0 32px;
    color: var(--muted);
    font-size: .87rem;
    /* Подвал по центру: ссылок мало, и прижатые влево они выглядели обрубком. */
    text-align: center;
}
.site-footer .links {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    justify-content: center;
    margin-bottom: 10px;
}
.site-footer a { color: var(--muted); }
.site-footer a:hover { color: var(--text); }

/* ---------- мелочи ---------- */

.muted { color: var(--muted); }
.gold { color: var(--gold); }
.accent { color: var(--accent); }
.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.between { display: flex; gap: 12px; align-items: center; justify-content: space-between; flex-wrap: wrap; }
.mt { margin-top: var(--gap); }
.mb0 { margin-bottom: 0; }
.mono { font-family: ui-monospace, Consolas, monospace; font-size: .85rem; }
.empty { text-align: center; color: var(--muted); padding: 26px 12px; }

.legal h2:not(summary h2) { margin-top: 1.4em; }
.legal li { margin-bottom: .4em; }

/* ---------- карточка товара: картинка ---------- */

/* Жёсткий размер обязателен: без него браузер рисует картинку в натуральную
   величину, и один товар занимает пол-экрана. */
.item-image {
    width: 56px;
    height: 56px;
    min-width: 56px;
    object-fit: cover;
    border-radius: 12px;
    border: 1px solid var(--border);
    background: var(--bg);
    display: block;
}
.item-image.lg { width: 84px; height: 84px; min-width: 84px; }

/* ---------- окно покупки ---------- */

.buy-dialog {
    width: min(560px, calc(100vw - 24px));
    max-height: calc(100vh - 48px);
    border: 1px solid var(--border);
    border-radius: 18px;
    /* Свой фон и цвет текста обязательны: иначе диалог рисуется системным белым. */
    background: var(--surface);
    color: var(--text);
    padding: 20px;
    box-shadow: 0 24px 70px var(--shadow);
    overflow-y: auto;
}

/* Размытие фона под открытым окном. */
.buy-dialog::backdrop {
    background: var(--backdrop);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}

.buy-dialog h2 { color: var(--text); }
.buy-dialog .close-row { display: flex; justify-content: flex-end; margin-bottom: 2px; }
.buy-dialog label { color: var(--muted); }

/* Описание приходит с переносами строк — сохраняем их,
   но шрифт берём обычный, а не моноширинный. */
.item-desc {
    white-space: pre-wrap;
    font-family: inherit;
    font-size: .9rem;
    color: var(--muted);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px 14px;
    margin: 14px 0;
    max-height: 300px;
    overflow-y: auto;
}

/* ---------- доплата за апгрейд привилегии ---------- */

.upgrade {
    border: 1px solid rgba(63, 208, 126, .35);
    background: rgba(63, 208, 126, .10);
    border-radius: 12px;
    padding: 12px 14px;
    margin-bottom: 14px;
    font-size: .92rem;
}
.upgrade .old { text-decoration: line-through; color: var(--muted); }
/* ---------- шапка страницы ----------
   Заголовок и кнопки в одной строке. Отдельный класс нужен, потому что
   inline-стилем margin-bottom:0 у заголовка убирался отступ, и следующий
   блок прилипал к шапке вплотную. */

.page-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin: 0 0 20px;
}
.page-head h1, .page-head h2 { margin: 0; }
.page-head + .page-sub { margin-top: -12px; }

/* Вкладки админки: переносятся на узком экране, а не сжимаются в кашу. */
.tabs { display: flex; flex-wrap: wrap; gap: 8px; }

/* Подзаголовок под шапкой: не должен упираться в следующий блок. */
.page-sub { color: var(--muted); margin: 0 0 20px; }

/* Заголовок раздела внутри страницы. */
h2.section { margin: 28px 0 14px; }

/* ---------- шапка внутри карточки ---------- */

.card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}
.card-head h2, .card-head h3 { margin: 0; }

/* Края карточки: первый элемент не должен добавлять отступ сверху,
   последний — снизу. Иначе внутренний padding удваивается и всё
   выглядит съехавшим. */
.card > :first-child { margin-top: 0; }
.card > :last-child { margin-bottom: 0; }

/* Формы в карточках: последнее поле не прижимается к кнопке. */
.card form > .field:last-of-type { margin-bottom: 16px; }

/* Пагинация Laravel идёт своим блоком — ей нужен воздух сверху. */
.card + nav[role="navigation"], nav[role="navigation"] { margin: 4px 0 20px; }

/* ---------- строка списка ----------
   Раньше повторялась inline-стилями в шести местах, и у последней строки
   оставалась лишняя разделительная линия. */

.list-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
}
.list-row:last-child { border-bottom: 0; padding-bottom: 0; }
.list-row:first-of-type { padding-top: 0; }

/* Чекбокс в одну строку с полем — без inline-стилей по месту. */
.checkbox.inline { margin: 0; align-items: center; white-space: nowrap; }
.inline-label { margin: 0; }

/* ---------- переписка в поддержке ---------- */

.msg {
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 12px 14px;
    margin-bottom: 12px;
    background: var(--bg);
}
/* Ответ администрации выделен рамкой, чтобы не искать глазами, кто написал. */
.msg.staff {
    border-color: rgba(46, 148, 85, .55);
    background: rgba(46, 148, 85, .08);
}
.msg-head {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    font-size: .84rem;
    margin-bottom: 6px;
}
/* Переносы строк из сообщения сохраняются, длинные слова не рвут вёрстку. */
.msg-body { white-space: pre-wrap; overflow-wrap: anywhere; }

/* ---------- страница ошибки ---------- */

.error-page {
    text-align: center;
    padding: 60px 18px;
    max-width: 560px;
    margin: 0 auto;
}
.error-code {
    font-size: clamp(3.4rem, 14vw, 6rem);
    font-weight: 800;
    line-height: 1;
    color: var(--brand-bright);
    letter-spacing: -.03em;
}

/* ---------- статус сервера и адрес ---------- */

.ip-box { cursor: pointer; user-select: none; }
.ip-box .copy-hint {
    font-size: .72rem;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: .06em;
}
.ip-box.copied .copy-hint { color: var(--accent); }
.ip-box.copied .copy-hint::after { content: ' ✓'; }
.server-status { font-size: .88rem; margin-top: 8px; }

/* ---------- лента последних покупок ---------- */

.purchase-feed {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 10px;
}
.feed-item {
    display: block;
    text-align: center;
    padding: 12px 8px;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--surface-2);
    color: var(--text);
}
.feed-item:hover { border-color: var(--brand-bright); text-decoration: none; }
/* Скины пиксельные: сглаживание при масштабировании превращает их в кашу. */
.head { image-rendering: pixelated; border-radius: 8px; }
.feed-nick { display: block; font-weight: 600; margin-top: 6px; }
.feed-item-name,
.feed-time { display: block; font-size: .78rem; color: var(--muted); }
.feed-item-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- вопрос-ответ ---------- */

.faq-item {
    border-bottom: 1px solid var(--border);
    padding: 10px 0;
}
.faq-item:last-child { border-bottom: 0; }
.faq-item summary {
    cursor: pointer;
    font-weight: 600;
    list-style: none;
    display: flex;
    gap: 8px;
    align-items: baseline;
}
.faq-item summary::before { content: '›'; color: var(--accent); transition: transform .15s ease; }
.faq-item[open] summary::before { transform: rotate(90deg); }
.faq-answer { color: var(--muted); padding: 8px 0 4px 16px; overflow-wrap: anywhere; }

/* ---------- мониторинги ---------- */

.vote-card { text-align: center; display: block; color: var(--text); }
.vote-card:hover { border-color: var(--brand-bright); text-decoration: none; }
.vote-card img { max-width: 100%; height: auto; border-radius: 10px; }
.vote-name { font-weight: 700; font-size: 1.05rem; margin-bottom: 6px; }

/* ---------- форум ---------- */

.crumbs { font-size: .88rem; margin-bottom: 10px; }
.crumbs a { color: var(--muted); }

.forum-row,
.thread-row {
    display: grid;
    grid-template-columns: 1fr;
    gap: 4px;
    padding: 12px 0;
    border-bottom: 1px solid var(--border);
}
.forum-row:last-child,
.thread-row:last-child { border-bottom: 0; }

.forum-row { grid-template-columns: 34px 1fr; }
/* Тема: голова автора слева, всё остальное одной колонкой. Прежние три
   колонки со счётчиками читались как таблица из базы, а не как обсуждение. */
.thread-row { grid-template-columns: 40px 1fr; gap: 12px; align-items: start; padding: 14px 0; }
/* Первая тема начинается сразу под отступом карточки: своё padding-top давало
   двойной отступ, и список выглядел провисшим. Последняя — без нижнего. */
.forum-row:first-child,
.thread-row:first-child { padding-top: 0; }
.forum-row:last-child,
.thread-row:last-child { padding-bottom: 0; }
/* line-height как у текста рядом: иначе строка метки съезжает вниз от головы. */
.thread-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; line-height: 1.25; }
.thread-flag { color: var(--muted); line-height: 0; }
.thread-flag .i { width: 15px; height: 15px; }
.thread-by { font-size: .82rem; margin-top: 2px; }
.thread-excerpt {
    margin: 6px 0 0;
    color: var(--muted);
    font-size: .9rem;
    overflow-wrap: anywhere;
}
.thread-foot { display: flex; gap: 14px; flex-wrap: wrap; font-size: .82rem; margin-top: 8px; }
.forum-icon { font-size: 1.3rem; line-height: 1.4; }
.forum-title,
.thread-title { font-weight: 650; font-size: 1.02rem; color: var(--text); }
.forum-title:hover,
.thread-title:hover { color: var(--accent); text-decoration: none; }
.forum-desc { font-size: .86rem; }
.forum-counts,
.thread-counts {
    display: flex;
    gap: 12px;
    font-size: .82rem;
    color: var(--muted);
}
.forum-last,
.thread-last { font-size: .82rem; }

/* На широком экране раскладываем в колонки, как на обычном форуме. */
@media (min-width: 860px) {
    .forum-row { grid-template-columns: 34px 1fr 150px 200px; align-items: center; }
    .forum-counts { flex-direction: column; gap: 0; }
}

/* Шапка темы: название крупно, счётчики сбоку и не спорят с ним за внимание. */
.thread-top { display: grid; grid-template-columns: 1fr; gap: 10px; }
@media (min-width: 720px) {
    .thread-top { grid-template-columns: 1fr auto; align-items: start; }
}
.thread-top h1 { margin: 6px 0 0; font-size: 1.5rem; line-height: 1.25; }
.thread-top-side { display: flex; gap: 14px; font-size: .84rem; }
@media (min-width: 720px) {
    .thread-top-side { flex-direction: column; gap: 2px; text-align: right; }
}

.rename-box summary { cursor: pointer; font-size: .88rem; color: var(--muted); }
.rename-form { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.rename-form input { flex: 1 1 260px; }

.mod-bar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* Выбор статуса: раскрывающийся список, где каждая метка показана своим
   цветом. Обычному select цвет пунктов задать нельзя, поэтому details с
   кнопками формы внутри — и работает без JavaScript. */
.status-form { position: relative; }
.status-picker summary {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    list-style: none;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 6px 10px;
    min-width: 170px;
}
.status-picker summary::-webkit-details-marker { display: none; }
.status-picker summary:hover { border-color: var(--brand-bright); }
.status-picker summary .i { margin-left: auto; width: 16px; height: 16px; color: var(--muted); }
.status-picker[open] summary .i { transform: rotate(180deg); }

.status-menu {
    position: absolute;
    z-index: 30;
    top: calc(100% + 6px);
    left: 0;
    min-width: 210px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 6px;
    box-shadow: 0 14px 32px rgba(0, 0, 0, .35);
}
.status-option {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    background: none;
    border: 0;
    border-radius: 8px;
    cursor: pointer;
    font: inherit;
    padding: 6px 8px;
    text-align: left;
}
.status-option:hover { background: var(--surface-2); }
/* Текущий статус помечаем галочкой: по одному цвету не понять, что уже стоит. */
.status-option.is-current::after {
    content: '✓';
    margin-left: auto;
    color: var(--accent);
}
.mod-bar form { display: inline; }

.post { display: grid; grid-template-columns: 1fr; gap: 12px; }
@media (min-width: 720px) {
    .post { grid-template-columns: 140px 1fr; }
}
.post-side {
    text-align: center;
    border-bottom: 1px solid var(--border);
    padding-bottom: 10px;
}
@media (min-width: 720px) {
    .post-side { border-bottom: 0; border-right: 1px solid var(--border); padding: 0 12px 0 0; }
}
.post-author { display: block; font-weight: 650; margin-top: 6px; }
.post-meta { font-size: .8rem; margin-bottom: 8px; }
/* Текст сообщения — разметка SimpleText: абзацы и списки уже теги, поэтому
   pre-wrap здесь не нужен, он только добавлял бы пустые строки между ними.
   Длинная ссылка вёрстку не разрывает. */
.post-text { overflow-wrap: anywhere; }
.post-text > :first-child { margin-top: 0; }
.post-text > :last-child { margin-bottom: 0; }
.post-text p { margin: 0 0 10px; }
.post-text h3 { margin: 16px 0 8px; font-size: 1.08rem; }
.post-text ul, .post-text ol { margin: 0 0 10px; padding-left: 22px; }
.post-text li { margin-bottom: 4px; }
.post-num { color: var(--muted); margin-right: 6px; }
.post-actions {
    display: flex;
    gap: 12px;
    margin-top: 10px;
    font-size: .84rem;
}
.post-actions form { display: inline; }

/* Кнопка, которая выглядит ссылкой: «удалить» обязана быть формой с CSRF,
   но в ряду текстовых действий кнопка смотрелась бы чужеродно. */
.link-btn {
    background: none;
    border: 0;
    padding: 0;
    color: var(--muted);
    cursor: pointer;
    font: inherit;
    font-size: .84rem;
    text-decoration: underline;
}
.link-btn:hover { color: var(--danger); }

label.narrow { max-width: 150px; }

/* Блок личной поддержки на форуме: текст слева, кнопка справа. */
.support-box {
    display: flex;
    gap: 14px;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    border-color: var(--brand-bright);
}
.support-box h2.section { margin-bottom: 4px; }
.site-footer .links a.strong { color: var(--accent); font-weight: 650; }

/* ---------- привилегии из игры ---------- */

/* Префикс приходит из LuckPerms со своими цветами, поэтому свой цвет фона
   бейдж не задаёт — только рамку и подложку. */
.badge.rank {
    border-color: var(--brand-bright);
    background: var(--surface-2);
    font-weight: 650;
}
.rank-inline {
    font-size: .85rem;
    font-weight: 650;
    white-space: nowrap;
}
.page-head h1 .head { vertical-align: -6px; margin-right: 6px; }

/* Голова игрока в строке списка.
   Вариантов разметки два: вырезанная из текстуры скина (.mc-head) и запасной
   рендер по нику (.head). Правила были заданы только второму, поэтому в топе
   ники стояли на разном расстоянии от номера — у кого свой скин, у кого нет.
   Отступ слева не нужен: его уже даёт значок места. */
.list-row .head,
.list-row .mc-head {
    vertical-align: -4px;
    margin: 0 6px 0 0;
    border-radius: 6px;
}

/* ---------- графики и чат в админке ---------- */

.spark {
    width: 100%;
    height: 120px;
    display: block;
}
.spark-axis {
    display: flex;
    justify-content: space-between;
    font-size: .76rem;
    margin-top: 4px;
}
.stat .value.bad { color: var(--danger); }

.chat-line {
    display: grid;
    grid-template-columns: 1fr;
    gap: 2px;
    padding: 6px 0;
    border-bottom: 1px solid var(--border);
    font-size: .9rem;
}
.chat-line:last-child { border-bottom: 0; }
@media (min-width: 720px) {
    /* Время и ник фиксированной ширины: так текст сообщений выстраивается
       в одну колонку и читается как настоящий чат. */
    .chat-line { grid-template-columns: 140px 150px 1fr; align-items: baseline; gap: 10px; }
}
.chat-time { font-size: .78rem; font-family: ui-monospace, Consolas, monospace; }
.chat-nick { font-weight: 650; }
.chat-text { overflow-wrap: anywhere; }

/* ---------- скин в кабинете ---------- */

.skin-card { display: grid; grid-template-columns: 1fr; gap: 18px; }
@media (min-width: 720px) {
    .skin-card { grid-template-columns: 160px 1fr; }
}
.skin-preview {
    display: grid;
    place-items: center;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 12px;
}
/* Скин пиксельный: сглаживание при масштабировании превращает его в кашу. */
.skin-preview img { image-rendering: pixelated; height: auto; max-width: 100%; }

.wardrobe { display: flex; flex-wrap: wrap; gap: 8px; }
.wardrobe form { display: inline; }
.wardrobe-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px 6px 6px;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: var(--surface-2);
    color: var(--text);
    font: inherit;
    font-size: .85rem;
    cursor: pointer;
}
.wardrobe-item:hover { border-color: var(--brand-bright); }
.wardrobe-item.active { border-color: var(--accent); }

/* Голова, вырезанная из текстуры скина. Размер задаёт --px, поэтому один
   класс годится и для 24px в топах, и для 56px на форуме. */
.mc-head {
    position: relative;
    display: inline-block;
    width: calc(var(--px) * 8);
    height: calc(var(--px) * 8);
    vertical-align: -.2em;
    border-radius: 4px;
    overflow: hidden;
}
.mc-head > span {
    position: absolute;
    inset: 0;
    background-repeat: no-repeat;
    background-size: var(--sheet) var(--sheet);
    image-rendering: pixelated;
}

/* Своя кнопка выбора файла: родной input оформлению не поддаётся. */
.file-pick { cursor: pointer; }
.file-name { font-size: .85rem; overflow-wrap: anywhere; }

/* ---------- просмотр скина из текстуры ---------- */

.skin-view {
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Куски текстуры стыкуются пиксель в пиксель — любой отступ разорвёт фигуру. */
    line-height: 0;
}
.skin-view .sv-row { display: flex; position: relative; }
.skin-view .sv {
    background-repeat: no-repeat;
    background-size: var(--sheet) var(--sheet);
    image-rendering: pixelated;
}
.sv-head { width: calc(var(--px) * 8); height: calc(var(--px) * 8); }
/* Шляпный слой лежит ровно поверх головы. */
.sv-hat { position: absolute; left: 0; top: 0; }
.sv-body { width: calc(var(--px) * 8); height: calc(var(--px) * 12); }
.sv-arm,
.sv-leg { width: calc(var(--px) * 4); height: calc(var(--px) * 12); }
/* Левая рука и нога — зеркало правых: так превью одинаково корректно и для
   64×64, и для старого 64×32, где отдельных левых частей просто нет. */
.sv-mirror { transform: scaleX(-1); }

/* =====================================================================
   ВИЗУАЛ: шапка с онлайном, баннеры, витрина магазина
   Автор: Xrustick83

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

   Всё на своих переменных: светлая тема и тема Telegram переопределяют
   их выше и здесь ничего не ломают.
   ===================================================================== */

:root {
    /* Тени мягче и глубже старых: постеры крупные, и резкая тень под ними
       выглядит грязно. */
    /* Цвет иконок: в тёмной теме светло-зелёный, в светлой — фирменный. */
    --icon: #6fd39a;

    --lift:      0 18px 40px -18px rgba(0, 0, 0, .55);
    --lift-hard: 0 26px 60px -22px rgba(0, 0, 0, .7);
    --ring:      0 0 0 1px var(--border);
    --radius-lg: 22px;
    --radius-xl: 28px;
}

/* ---------- шапка: онлайн и адрес сервера ---------- */

/* Обе плашки — одного вида, чтобы читались как один блок «состояние сети». */
.hdr-live {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-left: auto;
}

.hdr-online {
    display: flex;
    flex-direction: column;
    gap: 5px;
    min-width: 132px;
    padding: 7px 12px;
    border-radius: 14px;
    background: var(--surface-2);
    box-shadow: var(--ring);
}
.hdr-online .row-top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    font-size: .78rem;
    color: var(--muted);
    line-height: 1;
}
.hdr-online b { color: var(--text); font-size: .95rem; }
.hdr-online .bar {
    height: 4px;
    border-radius: 99px;
    background: var(--border);
    overflow: hidden;
}
.hdr-online .bar i {
    display: block;
    height: 100%;
    border-radius: 99px;
    background: linear-gradient(90deg, var(--brand), var(--accent));
}

/* Адрес сервера. Курсор-указатель и подпись «копировать» — иначе игрок
   не догадывается, что плашка кликабельна. */
.hdr-ip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 14px;
    border: 0;
    border-radius: 14px;
    background: linear-gradient(135deg, var(--brand), var(--brand-bright));
    color: #fff;
    font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
    font-size: .92rem;
    font-weight: 700;
    cursor: pointer;
    white-space: nowrap;
    box-shadow: var(--lift);
    transition: transform .12s ease, filter .12s ease;
}
.hdr-ip:hover { transform: translateY(-1px); filter: brightness(1.08); }
.hdr-ip::after { content: "⧉"; opacity: .75; font-family: inherit; }
.hdr-ip.copied { background: linear-gradient(135deg, var(--accent), var(--brand-bright)); }
.hdr-ip.copied::after { content: "✓"; opacity: 1; }

/* На узком экране онлайн уходит: адрес важнее, а строка не должна ломаться. */
@media (max-width: 720px) {
    .hdr-online { display: none; }
    .hdr-live { margin-left: 0; width: 100%; }
    .hdr-ip { width: 100%; justify-content: center; }
}

/* ---------- баннер ---------- */

/* Тёмная подложка с диагональным свечением и мягкой сеткой: узнаваемо
   «игровой» фон, который не требует ни одной картинки. */
.banner {
    position: relative;
    overflow: hidden;
    border-radius: var(--radius-xl);
    padding: clamp(26px, 5vw, 54px);
    color: #fff;
    background:
        radial-gradient(900px 380px at 12% -10%, rgba(63, 208, 126, .30), transparent 65%),
        radial-gradient(700px 420px at 92% 120%, rgba(27, 107, 58, .55), transparent 60%),
        linear-gradient(140deg, #06170e 0%, #0c2a19 48%, #071a10 100%);
    box-shadow: var(--lift-hard);
    margin-bottom: 22px;
}

/* Сетка кубов — намёк на Minecraft без единого ассета. */
.banner::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image:
        linear-gradient(rgba(255, 255, 255, .045) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, .045) 1px, transparent 1px);
    background-size: 34px 34px;
    mask-image: radial-gradient(120% 100% at 80% 0, #000 20%, transparent 75%);
    pointer-events: none;
}

.banner > * { position: relative; z-index: 1; }

.banner-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(260px, .65fr);
    gap: 28px;
    align-items: center;
}
/* Вторая колонка есть не на каждой странице: на привилегиях карточки справа
   нет, и делить баннер надвое незачем — текст занимает всю ширину. */
.banner-grid:not(:has(> :nth-child(2))) { grid-template-columns: 1fr; }
@media (max-width: 900px) {
    .banner-grid { grid-template-columns: 1fr; gap: 22px; }
}

.banner .eyebrow {
    display: inline-block;
    margin-bottom: 14px;
    padding: 5px 12px;
    border-radius: 99px;
    background: rgba(255, 255, 255, .1);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .16);
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}
.banner h1 {
    font-size: clamp(1.9rem, 5.4vw, 3.2rem);
    line-height: 1.04;
    margin: 0 0 .45em;
    letter-spacing: -.02em;
}
.banner h1 em {
    font-style: normal;
    background: linear-gradient(90deg, var(--accent), var(--gold));
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
}
.banner p.lead {
    max-width: 46ch;
    margin: 0 0 1.4em;
    font-size: 1.03rem;
    color: rgba(255, 255, 255, .82);
}
.banner .cta { display: flex; flex-wrap: wrap; gap: 10px; }

/* Карточка «наш сервер» в баннере: адрес, живой онлайн, кнопка. */
.server-card {
    padding: 20px;
    border-radius: var(--radius-lg);
    background: rgba(6, 20, 12, .55);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .12), var(--lift);
    backdrop-filter: blur(6px);
}
.server-card .title {
    display: flex;
    align-items: center;
    gap: 10px;
    font-weight: 800;
    font-size: 1.05rem;
    margin-bottom: 14px;
}
.server-card .addr {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    padding: 12px 14px;
    border: 0;
    border-radius: 14px;
    background: rgba(255, 255, 255, .08);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14);
    color: #fff;
    font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
    font-size: 1.02rem;
    font-weight: 700;
    cursor: pointer;
    transition: background .12s ease;
}
.server-card .addr:hover { background: rgba(255, 255, 255, .14); }
.server-card .addr .tag { font-size: .74rem; opacity: .7; font-family: inherit; }
.server-card .addr.copied { background: rgba(63, 208, 126, .22); }
.server-card .meta {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    margin-top: 14px;
    font-size: .84rem;
    color: rgba(255, 255, 255, .7);
}
.server-card .meta b { color: #fff; font-size: 1.15rem; }
.server-card .bar {
    height: 6px;
    margin-top: 8px;
    border-radius: 99px;
    background: rgba(255, 255, 255, .14);
    overflow: hidden;
}
.server-card .bar i {
    display: block;
    height: 100%;
    border-radius: 99px;
    background: linear-gradient(90deg, var(--accent), var(--gold));
}

/* ---------- витрина магазина ---------- */

.shop-layout {
    display: grid;
    grid-template-columns: 236px minmax(0, 1fr);
    gap: 22px;
    align-items: start;
}
@media (max-width: 900px) {
    .shop-layout { grid-template-columns: 1fr; }
}

/* Боковое меню категорий. Прилипает: витрина длинная, и без этого до
   переключения категории приходится скроллить обратно наверх. */
.shop-side { position: sticky; top: 78px; display: grid; gap: 8px; }
@media (max-width: 900px) {
    .shop-side {
        position: static;
        display: flex;
        gap: 8px;
        overflow-x: auto;
        padding-bottom: 4px;
        /* Полоса категорий на телефоне скроллится горизонтально; обрезать
           её нельзя — часть категорий стала бы недоступна. */
        scrollbar-width: none;
    }
    .shop-side::-webkit-scrollbar { display: none; }
    .shop-side .side-title { display: none; }
}

.shop-side .side-title {
    font-size: .76rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--muted);
    padding: 0 4px 2px;
}

.side-link {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 14px;
    border-radius: 16px;
    background: var(--surface);
    box-shadow: var(--ring);
    color: var(--text);
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    transition: background .12s ease, transform .12s ease;
}
.side-link:hover { background: var(--surface-2); text-decoration: none; transform: translateX(2px); }
.side-link .ico { font-size: 1.15rem; line-height: 1; }
.side-link .count { margin-left: auto; font-size: .8rem; color: var(--muted); }
.side-link.active {
    background: linear-gradient(135deg, var(--brand), var(--brand-bright));
    color: #fff;
    box-shadow: var(--lift);
}
.side-link.active .count { color: rgba(255, 255, 255, .8); }
@media (max-width: 900px) {
    .side-link { transform: none; }
    .side-link:hover { transform: none; }
}

/* Заголовок раздела витрины. */
.shop-block { margin-bottom: 30px; }
.shop-block > header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 14px;
}
.shop-block > header h2 { margin: 0; font-size: 1.25rem; }
.shop-block > header .hint-line { color: var(--muted); font-size: .88rem; }

/* Сетка карточек. Четыре в ряд на широком, дальше по убыванию — размер
   карточки при этом не пляшет, потому что она квадратная. */
.pgrid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
    gap: 16px;
}

/* ---------- карточка товара ---------- */

.pcard {
    position: relative;
    display: flex;
    flex-direction: column;
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow: var(--ring);
    overflow: hidden;
    cursor: pointer;
    transition: transform .14s ease, box-shadow .14s ease;
}
.pcard:hover { transform: translateY(-4px); box-shadow: var(--lift-hard); }
.pcard:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Постер. Картинка товара, если она есть; если нет — свой градиент из
   App\Support\Poster, поверх крупный значок. */
.pcard .art {
    position: relative;
    aspect-ratio: 1 / 1;
    background-color: var(--surface-2);
    overflow: hidden;
}
/* Картинка тегом, а не фоном: браузер умеет откладывать её загрузку только
   для img, и витрина из десяти артов перестаёт грузиться пачкой. */
.pcard .art img,
.rank-art img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.pcard .art.gen {
    background-image:
        radial-gradient(80% 60% at 50% 8%, color-mix(in srgb, var(--p-glow) 45%, transparent), transparent 70%),
        linear-gradient(160deg, var(--p-from), var(--p-to));
}
/* Диагональные полосы поверх градиента: дают постеру «печатную» текстуру,
   без них заливка выглядит как пустой блок. */
.pcard .art.gen::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image: repeating-linear-gradient(
        115deg,
        rgba(255, 255, 255, .07) 0 2px,
        transparent 2px 16px
    );
}
.pcard .art .glyph {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    font-size: clamp(2.6rem, 7vw, 3.8rem);
    filter: drop-shadow(0 8px 18px rgba(0, 0, 0, .45));
}


/* Название — плашкой в углу постера, на месте прежнего ценника. Цена в
   карточке пишется один раз, внизу у кнопки: два числа в разных углах
   заставляли сравнивать их между собой вместо покупки. */
.pcard .name-tag {
    position: absolute;
    top: 10px;
    left: 10px;
    /* Без right плашка сжимается по тексту: короткое название — короткая
       подложка, а не полоса во всю карточку. Ограничение по ширине оставляет
       место значку скидки справа. */
    max-width: calc(100% - 76px);
    z-index: 2;
    padding: 7px 12px;
    border-radius: 12px;
    background: rgba(6, 20, 12, .72);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14);
    backdrop-filter: blur(4px);
    color: #fff;
    font-weight: 800;
    font-size: .95rem;
    line-height: 1.22;
    /* Длинное название сжимаем до двух строк: третья уже лезет на арт. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-shadow: 0 2px 8px rgba(0, 0, 0, .5);
}
/* Справа оставлено место под плашку скидки; без неё название шире. */
.pcard .art:not(:has(.sale-tag)) .name-tag { max-width: calc(100% - 20px); }

.pcard .sale-tag {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 2;
    padding: 5px 10px;
    border-radius: 12px;
    background: var(--danger);
    color: #fff;
    font-weight: 800;
    font-size: .78rem;
    box-shadow: var(--lift);
}

/* Низ карточки: цена словами и кнопка. Кнопка широкая и подписанная —
   иконка корзины не говорит игроку, что будет по нажатию. */
.pcard .foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 14px 14px;
}
.pcard .foot .from { display: block; font-size: .74rem; color: var(--muted); line-height: 1.2; }
/* Цена в Arcanas: тем же кеглем, что и подпись, но золотом — видно, что это
   вторая цена, а не пояснение к первой. */
.pcard .foot .from.arc { color: var(--gold); font-weight: 700; }
.pcard .foot .sum { font-weight: 800; font-size: 1.22rem; }
.pcard .foot .sum s { color: var(--muted); font-weight: 600; font-size: .82rem; margin-left: 4px; }
.pcard .foot .go {
    flex: 0 0 auto;
    padding: 9px 16px;
    border: 0;
    border-radius: 13px;
    background: linear-gradient(135deg, var(--brand), var(--brand-bright));
    color: #fff;
    font-weight: 700;
    font-size: .92rem;
    cursor: pointer;
    transition: filter .12s ease, transform .1s ease;
}
.pcard .foot .go:hover { filter: brightness(1.1); }
.pcard .foot .go:active { transform: scale(.97); }

/* ---------- фото на баннере ----------
   Своя картинка ставится через arcana.banner_image. Поверх обязательны два
   слоя затемнения: на светлом скриншоте белый заголовок иначе не читается. */
.banner.has-photo {
    background-image:
        linear-gradient(120deg, var(--photo-veil-1) 0%, var(--photo-veil-2) 45%, var(--photo-veil-3) 100%),
        radial-gradient(700px 420px at 92% 120%, var(--photo-tint), transparent 60%),
        var(--photo);
    background-size: cover, cover, cover;
    background-position: center, center, center;
    color: var(--banner-text);
}
/* Слои поверх фотографии задаются переменными, потому что в тёмной теме фото
   нужно притемнить, а в светлой — наоборот высветлить: там текст на баннере
   тёмный, и затемнение сделало бы его нечитаемым. */
:root {
    --photo-veil-1: rgba(4, 14, 9, .92);
    --photo-veil-2: rgba(6, 22, 13, .72);
    --photo-veil-3: rgba(6, 22, 13, .35);
    --photo-tint:   rgba(27, 107, 58, .45);
    --banner-text:  #fff;
}
:root[data-theme="light"] {
    /* Прозрачное белое: фотография просвечивает и выглядит засвеченной, а не
       закрашенной. Слева пелена плотнее — там лежит тёмный текст, и без этого
       он теряется на снимке; справа почти чистое фото. */
    --photo-veil-1: rgba(255, 255, 255, .88);
    --photo-veil-2: rgba(252, 255, 253, .52);
    --photo-veil-3: rgba(248, 255, 251, .14);
    --photo-tint:   rgba(63, 208, 126, .14);
    --banner-text:  #10261a;
    --icon: #1b6b3a;
}

/* В светлой теме баннер целиком светлый, а не тёмно-зелёный. */
:root[data-theme="light"] .banner:not(.has-photo) {
    background:
        radial-gradient(900px 380px at 12% -10%, rgba(63, 208, 126, .22), transparent 65%),
        radial-gradient(700px 420px at 92% 120%, rgba(27, 107, 58, .18), transparent 60%),
        linear-gradient(140deg, #ffffff 0%, #eef7f1 48%, #e3f2e9 100%);
    color: #10261a;
}
:root[data-theme="light"] .banner .eyebrow {
    background: rgba(16, 38, 26, .07);
    box-shadow: inset 0 0 0 1px rgba(16, 38, 26, .12);
    color: #17402a;
}
:root[data-theme="light"] .banner p.lead { color: #3c5a49; }
:root[data-theme="light"] .banner::before {
    background-image:
        linear-gradient(rgba(16, 38, 26, .05) 1px, transparent 1px),
        linear-gradient(90deg, rgba(16, 38, 26, .05) 1px, transparent 1px);
}
/* Карточка сервера на светлом фоне: белая, а не полупрозрачно-тёмная. */
:root[data-theme="light"] .server-card {
    background: rgba(255, 255, 255, .82);
    box-shadow: inset 0 0 0 1px rgba(16, 38, 26, .12), var(--lift);
    color: #10261a;
}
:root[data-theme="light"] .server-card .addr {
    background: rgba(16, 38, 26, .06);
    box-shadow: inset 0 0 0 1px rgba(16, 38, 26, .14);
    color: #10261a;
}
:root[data-theme="light"] .server-card .addr:hover { background: rgba(16, 38, 26, .1); }
:root[data-theme="light"] .server-card .meta { color: #3c5a49; }
:root[data-theme="light"] .server-card .meta b { color: #10261a; }
:root[data-theme="light"] .server-card .bar { background: rgba(16, 38, 26, .12); }
/* Сетка кубов поверх фотографии лишняя — она и без неё насыщенная. */
.banner.has-photo::before { display: none; }

/* ---------- бегущая строка покупок ----------
   Ставится под баннером: чужие покупки — самое убедительное доказательство,
   что магазин работает и выдача доходит. */
.ticker {
    position: relative;
    overflow: hidden;
    border-radius: 16px;
    background: var(--surface);
    box-shadow: var(--ring);
    padding: 10px 0;
    /* Отступ с обеих сторон: строка стоит между двумя карточками, и своего
       верхнего отступа у неё не было — она липла к предыдущей. */
    margin: var(--gap) 0;
}
/* Края растворяются, иначе строка выглядит обрубленной. */
.ticker::before,
.ticker::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    width: 60px;
    z-index: 2;
    pointer-events: none;
}
.ticker::before { left: 0; background: linear-gradient(90deg, var(--surface), transparent); }
.ticker::after { right: 0; background: linear-gradient(270deg, var(--surface), transparent); }

.ticker-track {
    display: flex;
    align-items: center;
    gap: 26px;
    width: max-content;
    animation: ticker-run 42s linear infinite;
}
/* Наведение останавливает бег: иначе прочитать конкретную покупку невозможно. */
.ticker:hover .ticker-track { animation-play-state: paused; }

/* Содержимое продублировано в вёрстке, поэтому сдвиг ровно на половину даёт
   бесшовную петлю без прыжка. */
@keyframes ticker-run {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

/* Кому анимация мешает — строка просто стоит. */
@media (prefers-reduced-motion: reduce) {
    .ticker-track { animation: none; }
    .ticker { overflow-x: auto; }
}

.ticker-item {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    white-space: nowrap;
    color: var(--text);
    text-decoration: none;
    font-size: .92rem;
}
.ticker-item:hover { text-decoration: none; }
.ticker-item .head { flex: 0 0 auto; }
.ticker-item b { font-weight: 700; }
.ticker-item .what { color: var(--accent); }
.ticker-item .when { color: var(--muted); font-size: .82rem; }

/* ---------- описание привилегий ---------- */

.rank-row {
    display: grid;
    grid-template-columns: 220px minmax(0, 1fr);
    gap: 20px;
    align-items: stretch;
    margin-bottom: 18px;
    padding: 18px;
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow: var(--ring);
}
@media (max-width: 760px) {
    .rank-row { grid-template-columns: 1fr; }
}

.rank-art {
    position: relative;
    min-height: 190px;
    border-radius: 16px;
    overflow: hidden;
    background-color: var(--surface-2);
    background-size: cover;
    background-position: center;
}
.rank-art.gen {
    background-image:
        radial-gradient(80% 60% at 50% 10%, color-mix(in srgb, var(--p-glow) 45%, transparent), transparent 70%),
        linear-gradient(160deg, var(--p-from), var(--p-to));
}
.rank-art .glyph {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    font-size: 3.4rem;
    filter: drop-shadow(0 8px 18px rgba(0, 0, 0, .45));
}


.rank-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}
/* Название привилегии живёт только здесь, поэтому кегль крупнее обычного
   заголовка: это шапка всей строки, а не подпись к списку. */
.rank-head h2 { margin: 0; font-size: 1.5rem; letter-spacing: -.01em; }
.rank-price {
    padding: 6px 12px;
    border-radius: 12px;
    background: var(--gold-solid);
    color: #2a1e04;
    font-weight: 800;
    white-space: nowrap;
}

/* Возможности в две колонки: список длинный, в одну он выглядит бесконечным. */
.perks {
    list-style: none;
    margin: 0;
    padding: 0;
    columns: 2;
    column-gap: 22px;
}
@media (max-width: 620px) {
    .perks { columns: 1; }
}
.perks .perk {
    position: relative;
    padding-left: 22px;
    margin-bottom: 5px;
    break-inside: avoid;
    color: var(--text);
    font-size: .93rem;
}
.perks .perk::before {
    content: "✓";
    position: absolute;
    left: 0;
    color: var(--accent);
    font-weight: 800;
}
.perks .perk.cmd code {
    background: var(--surface-2);
    border-radius: 7px;
    padding: 1px 7px;
    font-size: .88rem;
}
.perks .perk-head {
    break-inside: avoid;
    margin: 8px 0 4px;
    font-size: .76rem;
    font-weight: 800;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--muted);
}
.perks .perk-head:first-child { margin-top: 0; }

/* ---------- пополнение баланса ---------- */

.topup-note {
    padding: 14px 16px;
    border-radius: 14px;
    background: var(--surface-2);
    box-shadow: inset 0 0 0 1px var(--border);
    color: var(--muted);
    font-size: .9rem;
}
.topup-sum {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    margin: 14px 0;
    padding: 14px 16px;
    border-radius: 14px;
    background: var(--surface-2);
}
.topup-sum b { font-size: 1.5rem; }

/* Быстрые суммы: игрок редко вводит число руками. */
.amount-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.amount-chips button {
    padding: 8px 14px;
    border: 0;
    border-radius: 12px;
    background: var(--surface-2);
    box-shadow: inset 0 0 0 1px var(--border);
    color: var(--text);
    font-weight: 700;
    cursor: pointer;
}
.amount-chips button:hover { background: var(--brand); color: #fff; }

/* Пометка тестового режима. Красная и заметная: с ней нельзя перепутать
   эмуляцию с настоящей оплатой. */
.test-mode {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px;
    border-radius: 99px;
    background: rgba(208, 69, 63, .16);
    box-shadow: inset 0 0 0 1px var(--danger);
    color: var(--badge-err);
    font-size: .82rem;
    font-weight: 700;
}

/* ---------- иконки ----------
   Размер в em, цвет — currentColor: иконка живёт по правилам текста рядом
   и не требует отдельной настройки под каждую тему. */
.i {
    width: 1.15em;
    height: 1.15em;
    flex: 0 0 auto;
    vertical-align: -.18em;
    /* Иконки набора — контурные. Без этих двух строк браузер применяет
       значения по умолчанию (fill: black, stroke: none) и рисует чёрные
       залитые силуэты вместо линий. */
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    /* Свой цвет, а не цвет текста: наследуя текст, иконки в светлой теме
       становились чёрными и выглядели грязно. */
    color: var(--icon);
}

/* Там, где иконка стоит на цветной подложке или на постере, цвет должен
   идти от родителя — иначе зелёная иконка на зелёной кнопке исчезает. */
.btn .i,
nav.main a.active .i,
.side-link.active .i,
.pcard .art .glyph .i,
.rank-art .glyph .i,
.hdr-ip .i,
.server-card .addr .i,
.test-mode .i,
.amount-chips button .i,
.rank-price .i { color: inherit; }

/* Кнопки: иконка и подпись в одну строку. Пунктов меню это правило больше
   не касается — иконок в меню нет, а для кнопки темы оно ломало центрирование. */
.btn { display: inline-flex; align-items: center; gap: 8px; justify-content: center; }


/* Заголовки разделов: иконка акцентным цветом, чтобы бросалась в глаза. */
h1 .i, h2 .i, .shop-block > header h2 .i { color: var(--accent); }

/* Крупные иконки на постерах — вместо эмодзи по центру карточки. */
.pcard .art .glyph .i { width: clamp(2.8rem, 7vw, 3.6rem); height: auto; opacity: .92; color: #fff; }
.rank-art .glyph .i { width: 3.2rem; height: 3.2rem; color: #fff; opacity: .95; }
.dialog-glyph .i { width: 2.6rem; height: 2.6rem; color: var(--accent); }
.side-link .ico .i { width: 1.25em; height: 1.25em; }
.server-card .title .i { width: 1.2rem; height: 1.2rem; color: var(--accent); }
.test-mode .i { width: 1rem; height: 1rem; }
.forum-icon .i { width: 1.5rem; height: 1.5rem; color: var(--accent); }
.admin-ico .i { width: 1.4rem; height: 1.4rem; color: var(--muted); }
.hdr-ip .i, .server-card .addr .i { width: 1rem; height: 1rem; }

/* ---------- страница со статистикой и списками ----------
   Общие блоки для топов, наград, покупок и поддержки: одинаковые заголовки
   и строки списка, чтобы страницы не выглядели собранными из разного. */

.page-lead {
    max-width: 70ch;
    margin: -6px 0 22px;
    color: var(--muted);
    font-size: 1rem;
}

/* Плитка раздела: заголовок с иконкой и содержимое. Заменяет разнобой из
   .card с ручными отступами. */
.panel {
    background: var(--surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--ring);
    padding: 22px;
    margin-bottom: var(--gap);
}
.panel > h2 {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 4px;
    font-size: 1.18rem;
}
.panel > .sub { color: var(--muted); font-size: .9rem; margin: 0 0 16px; }

/* Место в топе: номер кружком, первые три — золото, серебро, бронза. */
.rank-num {
    display: inline-grid;
    place-items: center;
    /* Отступ до ника: без него номер и голова игрока стояли вплотную,
       и строка читалась как одно слипшееся слово. */
    margin-right: 10px;
    width: 30px;
    height: 30px;
    border-radius: 10px;
    background: var(--surface-2);
    box-shadow: inset 0 0 0 1px var(--border);
    font-weight: 800;
    font-size: .88rem;
    color: var(--muted);
}
.rank-num.top-1 { background: linear-gradient(135deg, #f0c96b, #b57e1a); color: #2a1e04; box-shadow: none; }
.rank-num.top-2 { background: linear-gradient(135deg, #dfe6e9, #9aa5ab); color: #22292b; box-shadow: none; }
.rank-num.top-3 { background: linear-gradient(135deg, #e4a672, #a4602c); color: #2a1608; box-shadow: none; }

/* Мелочи вёрстки, которые раньше жили инлайн-стилями по месту. */
.server-card .meta.first { margin-top: 0; }
.card-note { margin: 12px 0 0; color: var(--muted); font-size: .86rem; }
.dialog-title { margin-bottom: .2em; }

/* ---------- подсказка на графиках админки ----------
   Линия SVG тонкая, попасть в неё мышкой невозможно, поэтому ближайшая точка
   считается по положению курсора, а вертикальная направляющая показывает, к
   какому именно моменту относятся цифры. */

.chart-box { position: relative; }

.chart-guide,
.chart-dot,
.chart-tip {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    transition: opacity .1s ease;
}
.chart-box.hover .chart-guide,
.chart-box.hover .chart-dot,
.chart-box.hover .chart-tip { opacity: 1; }

.chart-guide {
    top: 0;
    bottom: 0;
    width: 1px;
    background: var(--muted);
}

.chart-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: var(--surface);
    box-shadow: 0 0 0 2px var(--accent), 0 2px 8px var(--shadow);
    transform: translate(-50%, -50%);
}

.chart-tip {
    bottom: calc(100% + 8px);
    z-index: 6;
    display: grid;
    gap: 2px;
    padding: 9px 12px;
    border-radius: 12px;
    background: var(--surface-2);
    box-shadow: inset 0 0 0 1px var(--border), var(--lift);
    color: var(--text);
    font-size: .85rem;
    line-height: 1.35;
    white-space: nowrap;
    /* Подсказка следует за курсором, поэтому центрируется по своей середине;
       крайние положения ограничены скриптом, чтобы она не уезжала за карточку. */
    transform: translateX(-50%);
}
.chart-tip b { color: var(--text); }
.chart-tip > b:first-child {
    margin-bottom: 3px;
    color: var(--accent);
    font-family: ui-monospace, "Cascadia Code", Consolas, monospace;
}

/* ---------- выпадающие меню шапки ----------
   Разделов много, а шапка одна: справочное и личное собраны в два меню,
   иначе в строке стояло бы десять ссылок и она ломалась бы на две. */

.menu { position: relative; }

.menu-btn { display: inline-flex; align-items: center; gap: 6px; }
.menu-btn .caret {
    width: .95em;
    height: .95em;
    opacity: .7;
    transition: transform .12s ease;
}
.menu.open .menu-btn .caret { transform: rotate(180deg); }

.menu-drop {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 40;
    display: none;
    min-width: 232px;
    padding: 8px;
    border-radius: 16px;
    background: var(--surface);
    box-shadow: inset 0 0 0 1px var(--border), var(--lift-hard);
}
.menu.open .menu-drop { display: grid; }

/* На широком экране меню открывается и наведением: так быстрее, а клик
   остаётся для тех, у кого наведения нет вовсе. */
@media (hover: hover) and (min-width: 1101px) {
    .menu:hover .menu-drop { display: grid; }
    /* Полоса-мост под кнопкой: без неё меню закрывается в зазоре между
       кнопкой и списком, пока мышь до него доезжает. */
    .menu:hover::after {
        content: "";
        position: absolute;
        top: 100%;
        right: 0;
        width: 100%;
        height: 10px;
    }
}

/* Пункты внутри меню: ссылки и кнопка выхода выглядят одинаково. */
.menu-drop a,
.menu-drop button {
    display: block;
    width: 100%;
    padding: 9px 12px;
    border: 0;
    border-radius: 10px;
    background: transparent;
    color: var(--text);
    font: inherit;
    font-size: .96rem;
    font-weight: 500;
    text-align: left;
    white-space: nowrap;
    cursor: pointer;
}
.menu-drop a:hover,
.menu-drop button:hover {
    background: var(--surface-2);
    text-decoration: none;
}
.menu-drop form { margin: 0; }

/* Разделитель между смысловыми группами пунктов. */
.menu-sep {
    display: block;
    height: 1px;
    margin: 6px 4px;
    background: var(--border);
}

/* Узкий экран: меню разворачивается на месте, а не всплывает поверх —
   всплывающий список у края экрана уезжает за границу. */
@media (max-width: 1100px) {
    .menu { position: static; }
    .menu-drop {
        position: static;
        min-width: 0;
        margin: 4px 0 8px;
        box-shadow: inset 0 0 0 1px var(--border);
    }
}

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

/* Правила занимают всю ширину, как остальные страницы: узкая колонка
   посреди широкого монитора выглядела чужеродно. Чтобы строки не тянулись
   на весь экран, списки на широких экранах идут в две колонки — читать
   короткие строки легче, а место используется. */
.legal { max-width: none; }
.legal > h1 { font-size: clamp(1.7rem, 4vw, 2.2rem); margin-bottom: .2em; }

.legal-part {
    border-top: 1px solid var(--border);
    padding: 4px 0;
}
.legal-part:first-of-type { border-top: 0; }

.legal-part > summary {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 0;
    cursor: pointer;
    /* Родная стрелка списка мелкая и своя у каждого браузера — рисуем свою. */
    list-style: none;
}
.legal-part > summary::-webkit-details-marker { display: none; }

.legal-part > summary::after {
    content: "";
    width: 9px;
    height: 9px;
    margin-left: auto;
    border-right: 2px solid var(--muted);
    border-bottom: 2px solid var(--muted);
    transform: rotate(45deg);
    transition: transform .15s ease;
}
.legal-part[open] > summary::after { transform: rotate(-135deg); }
.legal-part > summary:hover h2 { color: var(--accent); }

/* Заголовки разделов крупнее обычных: по ним ищут нужный пункт правил. */
.legal-part > summary h2 {
    margin: 0;
    font-size: 1.35rem;
    line-height: 1.25;
}

.legal-body { padding: 0 0 14px; }
.legal-body > :last-child { margin-bottom: 0; }

/* Нумерованные пункты: номер держится в колонке, а не сползает под текст. */
.legal-body ol,
.legal-body ul { margin: 0 0 1em; padding-left: 1.6em; }
@media (min-width: 1100px) {
    .legal-body ol,
    .legal-body ul { columns: 2; column-gap: 42px; }
    .legal-body li { break-inside: avoid; }
}
.legal-body ol { list-style: decimal; }
.legal-body li { margin-bottom: .45em; }
.legal-body ol > li::marker { color: var(--accent); font-weight: 700; }

/* ---------- метки тем форума ----------
   Цвета взяты по смыслу, а не по вкусу: синий — внимание без тревоги,
   фиолетовый — служебное, голубой — процесс идёт, зелёный — закрыто. */

.badge.info { color: #93a7ff; border-color: rgba(74, 99, 216, .45); background: rgba(74, 99, 216, .14); }
.badge.rule { color: #c7a6ff; border-color: rgba(139, 92, 246, .45); background: rgba(139, 92, 246, .14); }
.badge.work { color: #7fd6ea; border-color: rgba(58, 168, 201, .45); background: rgba(58, 168, 201, .14); }
.badge.done { color: #7fd8a4; border-color: rgba(34, 139, 87, .5);  background: rgba(34, 139, 87, .16); }

/* В светлой теме те же цвета темнее: на белом фоне светлый текст не читается. */
:root[data-theme="light"] .badge.info { color: #2f42a8; }
:root[data-theme="light"] .badge.rule { color: #6b34d6; }
:root[data-theme="light"] .badge.work { color: #1a6d85; }
:root[data-theme="light"] .badge.done { color: #14663d; }

/* Кнопки решения в теме: цвет подсказывает, что произойдёт по нажатию. */
.mod-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.mod-row form { margin: 0; }
.btn.sm.mod-approve { background: rgba(63, 208, 126, .16); color: var(--accent); box-shadow: inset 0 0 0 1px rgba(63, 208, 126, .4); }
.btn.sm.mod-deny    { background: rgba(208, 69, 63, .16);  color: var(--badge-err); box-shadow: inset 0 0 0 1px rgba(208, 69, 63, .4); }
.btn.sm.mod-wait    { background: rgba(242, 181, 44, .16); color: var(--gold); box-shadow: inset 0 0 0 1px rgba(242, 181, 44, .4); }
.btn.sm.mod-info    { background: rgba(74, 99, 216, .16);  color: #93a7ff; box-shadow: inset 0 0 0 1px rgba(74, 99, 216, .45); }
.btn.sm.mod-rule    { background: rgba(139, 92, 246, .16); color: #c7a6ff; box-shadow: inset 0 0 0 1px rgba(139, 92, 246, .45); }
.btn.sm.mod-work    { background: rgba(58, 168, 201, .16); color: #7fd6ea; box-shadow: inset 0 0 0 1px rgba(58, 168, 201, .45); }
.btn.sm.mod-done    { background: rgba(34, 139, 87, .18);  color: #7fd8a4; box-shadow: inset 0 0 0 1px rgba(34, 139, 87, .5); }
.btn.sm[class*="mod-"]:hover { filter: brightness(1.25); }
:root[data-theme="light"] .btn.sm.mod-info { color: #2f42a8; }
:root[data-theme="light"] .btn.sm.mod-rule { color: #6b34d6; }
:root[data-theme="light"] .btn.sm.mod-work { color: #1a6d85; }
:root[data-theme="light"] .btn.sm.mod-done { color: #14663d; }

/* ---------- панель форматирования ---------- */

/* Кнопки над полем ввода: вставляют символы разметки. Выглядят кнопками, но
   поле остаётся обычным textarea — без JS всё ещё можно набрать руками. */
.format-bar {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-wrap: wrap;
    margin-bottom: 6px;
}
.format-bar button {
    background: var(--surface-2, rgba(0, 0, 0, .04));
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text);
    cursor: pointer;
    font: inherit;
    font-size: .82rem;
    padding: 5px 10px;
    line-height: 1.1;
}
.format-bar button:hover { border-color: var(--brand-bright); color: var(--accent); }
.format-hint { flex: 1 1 100%; font-size: .78rem; }
.format-hint code {
    background: var(--surface-2, rgba(0, 0, 0, .05));
    border-radius: 5px;
    padding: 1px 5px;
    font-size: .95em;
}

/* Карточка магазина на главной — целиком ссылка. Подпись «Купить» здесь текст,
   а не кнопка: сама покупка происходит в магазине. */
a.pcard { color: inherit; text-decoration: none; }
a.pcard:hover { text-decoration: none; }
a.pcard .go { pointer-events: none; }

/* ---------- вики ---------- */

/* Две колонки: меню разделов и статья. На узком экране меню уходит наверх —
   листать статью, обходя длинный список ссылок, невозможно. */
.wiki-layout { display: grid; grid-template-columns: 1fr; gap: var(--gap); }
@media (min-width: 1000px) {
    .wiki-layout { grid-template-columns: 280px 1fr; align-items: start; }
    .wiki-side { position: sticky; top: 84px; max-height: calc(100vh - 100px); overflow-y: auto; }
}

.wiki-side {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 16px;
}
/* Поиск: поле, иконка и кнопка — один элемент с общей рамкой. Рамка живёт на
   форме, а у поля своей нет: две рамки рядом читаются как два контрола. */
.wiki-search {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 18px;
    padding: 0 6px 0 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 12px;
    transition: border-color .15s ease, box-shadow .15s ease;
}
.wiki-search:focus-within {
    border-color: var(--brand-bright);
    box-shadow: 0 0 0 3px rgba(46, 158, 91, .18);
}
.wiki-search .search-glyph { width: 16px; height: 16px; color: var(--muted); flex: 0 0 auto; }
.wiki-search input {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    padding: 9px 0;
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    color: var(--text);
    font: inherit;
    font-size: .92rem;
}
.wiki-search input:focus { outline: none; box-shadow: none; }
/* Крестик очистки в Safari и Chrome красит поле своим цветом — убираем. */
.wiki-search input::-webkit-search-cancel-button { -webkit-appearance: none; }
.wiki-search button {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 0;
    border-radius: 9px;
    background: var(--surface-2);
    color: var(--muted);
    cursor: pointer;
}
.wiki-search button:hover { background: var(--brand); color: #fff; }
.wiki-search button .i { width: 16px; height: 16px; }

/* Название раздела и подраздела. Общий .side-title оформлен только внутри
   витрины магазина, здесь у меню свои отступы: подраздел должен читаться как
   часть раздела, а не как ещё один раздел. */
.wiki-side .side-title {
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--muted);
    margin: 0 0 8px;
    padding: 0 2px;
}
/* Складной подраздел. Стрелка поворачивается, счётчик статей справа —
   закрытый список должен говорить, сколько в нём спрятано. */
.wiki-fold { margin: 10px 0 4px; }
.wiki-fold summary {
    display: flex;
    align-items: center;
    gap: 7px;
    cursor: pointer;
    list-style: none;
    padding: 6px 8px;
    border-radius: 10px;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--muted);
}
.wiki-fold summary::-webkit-details-marker { display: none; }
.wiki-fold summary:hover { background: var(--surface-2); color: var(--text); }
.wiki-fold .fold-caret {
    width: 14px;
    height: 14px;
    flex: 0 0 auto;
    transition: transform .15s ease;
}
.wiki-fold[open] .fold-caret { transform: rotate(90deg); }
.wiki-fold .fold-count {
    margin-left: auto;
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
    opacity: .7;
}

/* Ссылки меню плоские: в списке из десятка статей карточка с тенью на каждой
   строке выглядит тяжелее самого текста. Заголовки переносятся — «Сортировочный
   центр» в 280 пикселей одной строкой не влезает, а общий .side-link запрещает
   перенос ради витрины магазина. */
.wiki-side .side-link {
    display: block;
    white-space: normal;
    background: none;
    box-shadow: none;
    border-radius: 10px;
    padding: 7px 10px;
    font-weight: 500;
    font-size: .94rem;
    line-height: 1.35;
    transform: none;
}
.wiki-side .side-link:hover { background: var(--surface-2); transform: none; }
.wiki-side .side-link.active {
    background: linear-gradient(135deg, var(--brand), var(--brand-bright));
    color: #fff;
}
/* Вложенная статья: сдвиг и черта слева — видно, что она внутри подраздела. */
.wiki-side .side-link.nested {
    margin-left: 8px;
    padding-left: 12px;
    border-left: 2px solid var(--border);
    border-top-left-radius: 4px;
    border-bottom-left-radius: 4px;
}
.wiki-side .side-link.nested:hover,
.wiki-side .side-link.nested.active { border-left-color: var(--brand-bright); }

.wiki-group + .wiki-group { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--border); }

/* Главная вики: подзаголовок группы и ряды плиток. */
.wiki-subhead { margin: 18px 0 10px; font-size: 1rem; color: var(--muted); }
.wiki-subhead:first-of-type { margin-top: 14px; }
.wiki-tiles + .wiki-subhead { margin-top: 22px; }
.wiki-tiles { margin-bottom: 0; }

.wiki-tile {
    display: block;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 14px 16px;
    color: var(--text);
}
.wiki-tile:hover { border-color: var(--brand-bright); text-decoration: none; }
.wiki-tile strong { display: block; margin-bottom: 4px; }
.wiki-tile span { font-size: .86rem; line-height: 1.4; }

/* Статья: заголовки и списки должны читаться как текст, а не как вёрстка. */
.wiki-article h1 { margin: 0 0 10px; }
.wiki-article > .lead { margin: 0 0 18px; }
.wiki-article h2, .wiki-article h3 { margin: 24px 0 10px; }
.wiki-article h3 { font-size: 1.12rem; }
.wiki-article p { margin: 0 0 12px; }
.wiki-article ul, .wiki-article ol { margin: 0 0 14px; padding-left: 22px; }
.wiki-article li { margin-bottom: 6px; }
.wiki-article li:last-child { margin-bottom: 0; }
.wiki-article > :first-child { margin-top: 0; }
.wiki-article > :last-child { margin-bottom: 0; }

/* Таблицы в статьях: описания лута длинные, и nowrap из общего правила
   превращал бы их в бесконечную горизонтальную прокрутку. */
.wiki-article .table-wrap { margin: 0 0 16px; }
.wiki-article td { white-space: normal; }
.wiki-article th { white-space: nowrap; }
.wiki-article table { font-size: .9rem; }

.wiki-foot { margin-top: 22px; padding-top: 14px; border-top: 1px solid var(--border); font-size: .84rem; }
.wiki-nav { display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap; }

/* Компактная шапка поддоменов: кнопки в ряд, иконка и подпись рядом. */
nav.main.compact { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
nav.main.compact .btn { display: inline-flex; align-items: center; gap: 7px; }
nav.main.compact .btn .i { width: 16px; height: 16px; }

/* ---------- панель кабинета ---------- */

/* Все разделы кабинета плитками над содержимым страницы: что в кабинете есть,
   должно быть видно без раскрытия меню в шапке. */
.cabinet-nav {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
    margin-bottom: var(--gap);
}
@media (min-width: 720px) { .cabinet-nav { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .cabinet-nav { grid-template-columns: repeat(7, minmax(0, 1fr)); } }

.cabinet-tile {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    color: var(--text);
    min-width: 0;
}
.cabinet-tile:hover { border-color: var(--brand-bright); text-decoration: none; }
.cabinet-tile.active {
    border-color: var(--brand-bright);
    background: linear-gradient(135deg, var(--brand), var(--brand-bright));
    color: #fff;
}
.cabinet-tile.active .muted { color: rgba(255, 255, 255, .8); }
.cabinet-tile .ico {
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    flex: 0 0 auto;
    border-radius: 10px;
    background: var(--surface-2);
}
.cabinet-tile.active .ico { background: rgba(255, 255, 255, .16); }
.cabinet-tile .ico .i { width: 18px; height: 18px; }
.cabinet-tile .text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.cabinet-tile strong { font-size: .92rem; line-height: 1.2; }
/* Подпись в одну строку: «надет ✿ Пижон» не должен ломать высоту плиток. */
.cabinet-tile .muted {
    font-size: .76rem;
    line-height: 1.25;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---------- титулы и подписка ---------- */

/* Выбор цвета ника: кнопка сразу показывает ник этим цветом — так понятнее,
   чем квадратик с названием оттенка. */
.nick-colors { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.nick-color {
    background: #0d1a12;
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 8px 12px;
    cursor: pointer;
    font: inherit;
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    font-size: .9rem;
    color: var(--c, #fff);
}
.nick-color:hover { border-color: var(--c, var(--brand-bright)); }
.nick-color.active { border-color: var(--c, var(--brand-bright)); box-shadow: 0 0 0 2px var(--c); }
.nick-color.reset { color: var(--muted); background: var(--surface-2); font-family: inherit; }

/* Карточка титула: сам титул крупно, подсказка мелко, цена и кнопка внизу.
   Цвет редкости приходит переменной --rarity — в разметке он один раз, а
   используется полосой, свечением и рамкой при наведении. */
.title-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
}
@media (min-width: 620px) { .title-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .title-grid { grid-template-columns: repeat(3, 1fr); } }

.title-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 16px 16px 14px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-left: 3px solid var(--rarity, var(--border));
    border-radius: 14px;
}
.title-card:hover { border-color: var(--rarity, var(--brand-bright)); }

/* Титул рисуется теми же цветами, что и в игре, поэтому фон под ним тёмный
   всегда: на светлой теме белые и жёлтые буквы иначе исчезают. */
.title-render {
    background: #0d1a12;
    border-radius: 10px;
    padding: 12px 14px;
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
    font-size: 1.02rem;
    line-height: 1.3;
    overflow-wrap: anywhere;
}
.title-hint { font-size: .84rem; margin: 0; }
.title-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    margin-top: auto;
}
.title-price { font-weight: 800; font-size: 1.05rem; }
.title-lock { position: absolute; top: 10px; right: 12px; font-size: .74rem; }
.title-lock .i { width: 12px; height: 12px; vertical-align: -2px; }

.rarity-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    margin-right: 8px;
    vertical-align: 1px;
}

/* Свои титулы: строка со всем сразу — вид, откуда взялся, что с ним делать. */
.owned-title {
    display: grid;
    gap: 8px;
    padding: 14px 0;
    border-bottom: 1px solid var(--border);
}
@media (min-width: 900px) {
    .owned-title { grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
    .owned-meta { grid-column: 1; }
    .owned-actions { grid-column: 2; grid-row: 1 / span 2; }
}
.owned-title:first-child { padding-top: 0; }
.owned-title:last-child { padding-bottom: 0; border-bottom: 0; }
.owned-title.is-on .owned-render { box-shadow: inset 0 0 0 1px var(--brand-bright); }
.owned-render {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    background: #0d1a12;
    border-radius: 10px;
    padding: 10px 14px;
    font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
}
.owned-meta { font-size: .84rem; }
.owned-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* Подарок спрятан за details: действие необратимое, и кнопка «отдать» не
   должна стоять вплотную к «надеть». */
.gift-box summary { list-style: none; cursor: pointer; }
.gift-box summary::-webkit-details-marker { display: none; }
.gift-form { display: flex; gap: 8px; margin-top: 8px; }
.gift-form input { margin: 0; min-width: 0; }

/* Титул на публичной странице: строка под ником, а не ещё одна карточка. */
.player-title {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin: 0 0 var(--gap);
    padding: 10px 14px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 3px solid var(--rarity, var(--border));
    border-radius: 12px;
    font-size: .88rem;
}
.player-title .title-render { padding: 8px 12px; font-size: .96rem; }

.perk-list { margin: 0; padding-left: 20px; }
.perk-list li { margin-bottom: 8px; }
.premium-note {
    margin-top: 16px;
    padding: 14px 16px;
    border-radius: 12px;
    background: var(--surface-2);
    border-left: 3px solid var(--gold);
    font-size: .9rem;
}
