/* ============================================================
   DantesW — стили внутренних страниц.
   Здесь только то, чего нет в style.css. Никаких дублей.
   ============================================================ */

/* ---------- Заголовок страницы ----------
   Вступительная плашка убрана со всех внутренних страниц: она занимала
   экран и повторяла то, что и так написано в меню. Сам заголовок остался
   в разметке как sr-only — его читают скринридеры и поисковики. */

/* ---------- Фильтры ---------- */
.filters {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 20px;
    margin-bottom: 36px;
}

.filters-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 16px;
    align-items: end;
}

.filter-group label {
    display: block;
    color: var(--text);
    font-weight: 600;
    font-size: 0.88rem;
    margin-bottom: 7px;
}

.categories-nav {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-bottom: 36px;
    justify-content: center;
}

.category-btn {
    padding: 9px 18px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-muted);
    font-family: var(--font-head);
    font-weight: 600;
    font-size: 0.88rem;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.category-btn:hover { border-color: var(--accent); color: var(--accent-2); }
.category-btn[aria-pressed="true"] {
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
    color: var(--on-accent);
    border-color: transparent;
}

/* ---------- Крупные карточки турниров ---------- */
.tournaments-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
    gap: 24px;
}

/* Вся карточка — ссылка на страницу турнира (pages/tournament.html), а не
   article с кнопками внутри: тег <a>, но выглядит и ведёт себя как раньше. */
.tournament-card-large {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    color: inherit;
    text-decoration: none;
    cursor: pointer;
    transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
}
.tournament-card-large:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: var(--accent); }

.tournament-status-note {
    display: inline-flex; align-items: center; gap: 8px;
    margin-top: 14px;
    padding: 8px 12px;
    border-radius: var(--radius-sm);
    background: var(--accent-soft);
    color: var(--accent-2);
    font-size: 0.88rem;
    font-weight: 600;
}
.tournament-status-note i { color: var(--accent-2); }
.tournament-status-note.is-invite { background: color-mix(in srgb, var(--warning) 14%, var(--surface-3)); color: var(--text); }
.tournament-status-note.is-invite i { color: var(--warning); }

.tournament-header-large {
    position: relative;
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 18px 22px;
    background: var(--surface-3);
    border-bottom: 1px solid var(--border);
}
.tournament-prize-large { margin-left: auto; color: var(--gold); font-weight: 700; font-size: 1.15rem; }

/* Своя фотография турнира (необязательное поле при создании) — просто
   баннер во всю ширину карточки, как у страницы турнира на большинстве
   киберспортивных площадок. Тут, в отличие от превью товара в магазине,
   обрезка по краям (cover) — ожидаемое поведение для широкого баннера,
   а не потеря содержимого: фото изначально выбирают под такую форму. */
.tournament-header-large.has-photo {
    /* Тот же размер, что у баннера на странице турнира
       (.tournament-detail-header.has-photo) */
    min-height: 150px;
    padding: 24px 26px;
    align-items: flex-end;
    background-image: linear-gradient(180deg, rgba(10, 10, 42, 0.15) 0%, rgba(10, 10, 42, 0.78) 100%), var(--bg-url);
    background-size: cover;
    background-position: center;
    border-bottom-color: transparent;
    border: 2px solid #fff;
}
.tournament-header-large.has-photo .tag-game,
.tournament-header-large.has-photo .tournament-prize-large {
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
}

.tournament-status {
    padding: 4px 12px;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 600;
    border: 1px solid currentColor;
    background: color-mix(in srgb, currentColor 14%, transparent);
}
.tournament-status.upcoming  { color: var(--warning); }
.tournament-status.active    { color: var(--success); }
.tournament-status.completed { color: var(--text-dim); }
.tournament-status.cancelled { color: var(--danger); }

/* Пометка «Приватный» на карточке турнира — сам турнир виден всем,
   поэтому это не статус, а отдельный, приглушённый значок рядом с ним. */
.tournament-private-tag {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 12px; border-radius: 999px;
    font-size: 0.78rem; font-weight: 600;
    color: var(--text-muted); border: 1px solid var(--border);
    background: color-mix(in srgb, var(--text-muted) 12%, transparent);
}

/* Плашка монетного буста турнира (эпик/мифич/лег, см. render.js:
   tournamentCardLarge) — тот же вид плашки, что private-tag выше, но
   в цветах монет, а не нейтральный. */
.tournament-coin-boost-tag {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 12px; border-radius: 999px;
    font-size: 0.78rem; font-weight: 600;
    color: var(--gold); border: 1px solid var(--gold);
    background: color-mix(in srgb, var(--gold) 14%, transparent);
}
.tournament-header-large.has-photo .tournament-coin-boost-tag {
    background: rgba(6, 6, 26, 0.82);
    border-color: currentColor;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
    backdrop-filter: blur(4px);
}

/* Полоса «турнир отменён» в шапке страницы турнира. Поверх фотографии
   обложки, поэтому фон непрозрачный: на светлом снимке красный текст
   без подложки читался бы плохо. */
.tournament-cancelled-note {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin: 10px 0 0;
    padding: 8px 14px;
    border-radius: 10px;
    font-weight: 600;
    color: var(--danger);
    border: 1px solid var(--danger);
    background: color-mix(in srgb, var(--surface-2) 88%, var(--danger));
}

/* Модалка «Управление турниром»: сверху обратимая отмена, снизу — то,
   что не отменить. Красная рамка и отступ между блоками нужны, чтобы
   удаление не читалось как продолжение соседней кнопки. */
.tournament-manage { display: flex; flex-direction: column; gap: 20px; }
.tournament-manage .manage-block {
    padding: 16px;
    border: 1px solid var(--border);
    border-radius: 14px;
    background: var(--surface-2);
}
.tournament-manage .manage-block h4 {
    margin: 0 0 6px;
    font-size: 1rem;
    display: flex;
    align-items: center;
    gap: 8px;
}
.tournament-manage .manage-block .form-hint { margin: 0 0 12px; }
.tournament-manage .manage-block.is-danger {
    border-color: color-mix(in srgb, var(--danger) 55%, transparent);
    background: color-mix(in srgb, var(--surface-2) 92%, var(--danger));
}
.tournament-manage .manage-block.is-danger h4 { color: var(--danger); }
.tournament-manage .manage-block .form-label { display: block; margin-bottom: 6px; font-size: 0.9rem; }
.tournament-manage .manage-block .form-input { margin-bottom: 12px; }
.tournament-manage .manage-block .btn { width: 100%; justify-content: center; }
.tournament-manage .btn[disabled] { opacity: 0.5; cursor: not-allowed; }

/* Четыре даты в две колонки: по одной в строке окно вытягивалось на
   два экрана, а поля тут короткие и просятся парами. */
.tournament-manage .manage-grid {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px;
}
.tournament-manage .manage-grid .form-group { margin-bottom: 0; }
.tournament-manage .manage-row { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 14px; }
.tournament-manage .manage-row .btn { flex: 1 1 200px; width: auto; }
@media (max-width: 560px) {
    .tournament-manage .manage-grid { grid-template-columns: 1fr; }
}

/* «Название уже меняли» на месте кнопки: не заглушённая кнопка, а
   пояснение — на неактивную кнопку жмут и не понимают, почему молчит. */
.team-edit-used {
    display: inline-flex; align-items: center;
    padding: 8px 12px;
    border-radius: var(--radius-md, 10px);
    background: var(--surface-3);
    border: 1px dashed var(--border);
    color: var(--text-muted);
    font-size: 0.84rem;
}

.tournament-body { padding: 22px; display: flex; flex-direction: column; flex: 1; }
.tournament-body h3 { font-size: 1.25rem; margin-bottom: 10px; color: var(--text); }
.tournament-description { color: var(--text-dim); margin-bottom: 18px; font-size: 0.95rem; font-weight: 600; }

.tournament-details {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 10px;
    margin-bottom: 20px;
    flex: 1;
}
.detail-item {
    display: flex; align-items: center; gap: 9px;
    color: var(--text-muted); font-size: 0.9rem;
}
.detail-item i { color: var(--accent-2); width: 16px; text-align: center; }

.tournament-actions { display: flex; gap: 10px; flex-wrap: wrap; }
.tournament-actions .btn { flex: 1; min-width: 140px; }
.tournament-invite-actions { display: flex; gap: 8px; flex-wrap: wrap; flex: 1; min-width: 220px; }
.tournament-invite-actions .btn { flex: 1; min-width: 120px; }

/* Приватный турнир без ссылки капитана в адресе — вместо кнопки поясняем,
   почему её нет, а не просто прячем действие молча. */
.tournament-private-notice {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 14px; border-radius: var(--radius-sm, 8px);
    background: var(--surface-3); border: 1px solid var(--border);
    color: var(--text-muted); font-size: 0.88rem; line-height: 1.4;
}
.tournament-private-notice i { color: var(--accent); flex-shrink: 0; }

/* ---------- Турниры: кнопка «Создать турнир» в ряду вкладок, приглашения в команду ----------
   Раньше это был отдельный .tournaments-toolbar над вкладками
   («Все турниры» / «Мои турниры»); теперь #tournamentsAdminSlot —
   последний ребёнок самого .tabs-nav (pages/tournaments.html).

   По просьбе все три пункта строки должны быть одинаковой ширины, а
   не «Создать турнир» мельче/крупнее двух настоящих вкладок — раньше
   здесь было flex: 0 0 auto + margin-left: auto (по размеру своего
   текста, прижатая вправо). flex-basis: auto (как у самого .tab-btn)
   тут не подошёл бы: он делит остаток поровну, но СТАРТУЕТ каждый
   пункт с его собственной длины текста — «Создать турнир» длиннее
   «Мои турниры», и после деления остатка поровну ширины всё равно
   не совпадали. flex-basis: 0 игнорирует длину текста и делит всю
   строку строго поровну — правило ниже, через aria-label самого
   .tabs-nav (это конкретно вкладки турниров, а не любой .tabs-nav
   сайта — в админке, например, вкладок 11 и подписи разной длины,
   там их насильно уравнивать не нужно).

   Важно: .tabs-nav-extra — обёртка-<div> вокруг кнопки «Создать
   турнир» (нужна, чтобы renderAdminSlot() мог её просто пустой
   очищать/заполнять). Раньше сама обёртка была flex-item'ом с
   display: flex внутри (кнопка растягивалась внутри неё). Это
   вложенный flex-контейнер внутри flex-контейнера — и браузер в
   такой схеме считает ширину вложенного flex-item'а иначе, чем у
   настоящих соседних кнопок, даже при абсолютно одинаковых
   flex-grow/shrink/basis/min-width/паддингах/рамках (проверено
   изолированным тестом рендеринга) — обёртка стабильно оказывается
   у́же двух других пунктов на глаз и по факту. Раз обёртка всегда
   содержит ровно одну кнопку и никакой своей разметки не несёт,
   решение — display: contents на самой обёртке: она полностью
   исчезает из дерева отрисовки (её box не участвует в layout), и
   кнопка внутри становится настоящим прямым flex-item'ом .tabs-nav,
   как и две другие вкладки — тогда все три получают идентичную
   ширину. */
.tabs-nav[aria-label="Разделы турниров"] > .tab-btn,
.tabs-nav[aria-label="Разделы турниров"] .tabs-nav-extra > .tab-btn {
    flex: 1 1 0%;
    min-width: 120px;
}
.tabs-nav-extra { display: contents; }
.tabs-nav-extra:empty { display: none; }

/* «Создать турнир» — обычная .tab-btn, без своего класса и без иконки:
   выглядит и подсвечивается при наведении абсолютно так же, как «Все
   турниры»/«Мои турниры» рядом, просто не переключает вкладку, а
   открывает модалку создания. Благодаря display: contents на
   .tabs-nav-extra кнопка — прямой flex-item .tabs-nav, поэтому
   растягивается по высоте (align-items: stretch у самого .tabs-nav)
   и по ширине наравне с соседними вкладками без каких-либо
   дополнительных переопределений. */

.team-invite-banner {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    flex-wrap: wrap;
    padding: 14px 18px;
    margin-bottom: 14px;
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--accent) 12%, var(--surface-2));
    border: 1px solid var(--accent);
}
.team-invite-banner i { color: var(--accent-2); margin-right: 6px; }
.team-invite-banner-actions { display: flex; gap: 8px; }

/* ---------- Состав команды ---------- */
.team-roster { list-style: none; margin: 0 0 16px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
/* Никакого space-between: в строке чаще всего только аватарка и имя, и
   он растаскивал их по краям, оставляя посередине пустую полосу.
   Прижимаем к левому краю, а трофеи сами уходят вправо (margin-left:auto
   ниже) — там, где их и ждут. */
.team-roster-item {
    display: flex; align-items: center; justify-content: flex-start; gap: 10px;
    width: 100%;
    padding: 9px 12px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm, 8px);
    background: var(--surface-3);
    color: inherit; font: inherit; text-align: left;
    cursor: pointer;
    transition: border-color .15s ease;
}
.team-roster-item:hover { border-color: var(--accent); }
.team-roster-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.team-roster.is-pending .team-roster-item { opacity: .65; }
.roster-subhead { margin: 14px 0 8px; font-size: 0.82rem; color: var(--text-muted); font-weight: 600; }

/* Лицо игрока: иконка из игры, аватарка сайта или буквы — что нашлось.
   Крупно: в составе именно по ней узнают человека, а не по строке текста. */
.roster-face {
    flex: 0 0 auto;
    width: 52px; height: 52px;
    border-radius: 50%;
    overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    background: var(--surface-2);
    border: 1px solid var(--border);
}
.roster-face img { width: 100%; height: 100%; object-fit: cover; }
/* Форма аватарки — та, что человек выбрал в настройках профиля
   (supabase/avatar_shape.sql). Это «как меня видят», а не настройка
   зрителя, поэтому едет вместе с аватаром и сюда, в состав. */
.roster-face.is-square { border-radius: 14px; }
.roster-player-face.is-square { border-radius: 18px; }
.roster-face-initials { font-size: 0.95rem; font-weight: 700; color: var(--text-muted); }
.team-roster-who { flex: 1 1 auto; }
/* Трофеи — второе, на что смотрят в составе после ника. Поэтому крупно и
   жирно, а кубок — игровой, нарисованный, а не шрифтовая чаша. */
.roster-trophies {
    display: inline-flex; align-items: center; gap: 6px;
    color: var(--gold); white-space: nowrap; flex: 0 0 auto; margin-left: auto;
}
.roster-trophies b { font-size: 1.02rem; font-weight: 800; letter-spacing: 0.01em; }
.trophy-icon { width: 1.15em; height: 1.15em; flex: 0 0 auto; }
.roster-player-trophies { display: flex; align-items: center; gap: 6px; }
.roster-player-trophies b { color: var(--gold); font-size: 1rem; font-weight: 800; }

/* Карточка игрока: кто это в игре и на сайте, и два пути дальше. */
.roster-player-card { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }
.roster-player-face {
    flex: 0 0 auto; width: 72px; height: 72px; border-radius: 50%;
    overflow: hidden; display: flex; align-items: center; justify-content: center;
    background: var(--surface-3); border: 1px solid var(--border);
}
.roster-player-face img { width: 100%; height: 100%; object-fit: cover; }
.roster-player-lines { min-width: 0; }
.roster-player-name { margin: 0 0 4px; font-size: 1.05rem; font-weight: 700; }
.roster-player-sub { margin: 0 0 2px; color: var(--text-muted); font-size: 0.84rem; }
.roster-player-captain {
    display: inline-block; margin-left: 8px; padding: 2px 10px;
    border-radius: 999px; background: var(--surface-3);
    color: var(--gold); font-size: 0.84rem; font-weight: 700; vertical-align: middle;
}

/* Логотип команды в форме */
.team-logo-preview img, .team-logo-current img {
    width: 72px; height: 72px; border-radius: 12px; object-fit: cover; border: 1px solid var(--border);
}
.team-logo-current { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; color: var(--text-muted); font-size: 0.84rem; }

/* ============================================================
   Публичная страница профиля (pages/user.html)
   ============================================================ */
.public-achievements { max-width: 420px; }
.public-achievements-count { font-size: 2.2rem; font-weight: 800; color: var(--gold); line-height: 1.1; }
.public-achievements-count span { font-size: 1rem; font-weight: 600; color: var(--text-muted); }
.public-achievements-bar {
    height: 10px; margin: 12px 0 10px;
    border-radius: 999px; background: var(--surface-3); overflow: hidden;
}
.public-achievements-bar span {
    display: block; height: 100%;
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
}

.public-tournaments { display: flex; flex-direction: column; gap: 10px; }
.public-tournament {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    padding: 12px 14px; border-radius: var(--radius-md);
    background: var(--surface-2); border: 1px solid var(--border);
    color: inherit; text-decoration: none;
    transition: border-color var(--transition);
}
.public-tournament:hover { border-color: var(--accent); }
.public-tournament-title { flex: 1 1 auto; font-weight: 600; min-width: 0; }
.public-tournament-team { color: var(--text-muted); font-size: 0.84rem; }
.public-tournament-prize { color: var(--gold); font-weight: 700; }

.public-friends {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 10px;
}
.public-friend {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 12px; border-radius: var(--radius-md);
    background: var(--surface-2); border: 1px solid var(--border);
    color: inherit; text-decoration: none; min-width: 0;
    transition: border-color var(--transition);
}
.public-friend:hover { border-color: var(--accent); }
.public-friend-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.public-friend-username { color: var(--text-muted); font-size: 0.78rem; }

/* Карточка игрового профиля на публичной странице */
.brawl-public-card { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }
.brawl-public-icon {
    width: 72px; height: 72px; border-radius: 16px;
    border: 2px solid var(--gold); background: var(--surface-3); object-fit: cover;
}
.brawl-public-name { margin: 0 0 2px; font-size: 1.1rem; font-weight: 700; }
.brawl-public-tag { margin: 0; color: var(--text-muted); font-size: 0.86rem; }
.brawl-public-stats { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.brawl-public-stats li {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 8px 12px; border-radius: var(--radius-sm, 8px); background: var(--surface-3);
}
.brawl-public-stats span { color: var(--text-muted); font-size: 0.86rem; }
.brawl-public-stats b { font-weight: 700; }

/* ---------- Отзывы ---------- */
.reviews-summary { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 18px; }
.reviews-average { font-size: 2rem; font-weight: 800; color: var(--gold); }
.reviews-stars { color: var(--gold); letter-spacing: 2px; }
.reviews-stars .is-empty { color: var(--surface-3); }
.reviews-count { color: var(--text-muted); font-size: 0.88rem; }

.review-form {
    padding: 14px; margin-bottom: 20px;
    border-radius: var(--radius-md); background: var(--surface-2); border: 1px solid var(--border);
}
.review-form h4 { margin: 0 0 10px; font-size: 0.95rem; }
.review-rating { display: flex; gap: 4px; margin-bottom: 10px; }
.review-star {
    padding: 4px; border: 0; background: none; cursor: pointer;
    color: var(--surface-3); font-size: 1.3rem; line-height: 1;
}
.review-star.is-on { color: var(--gold); }
.review-form .form-actions { margin-top: 12px; }

.reviews-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.review-item {
    display: flex; gap: 12px;
    padding: 12px 14px; border-radius: var(--radius-md);
    background: var(--surface-2); border: 1px solid var(--border);
}
.review-body { flex: 1 1 auto; min-width: 0; }
.review-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 6px; }
.review-author { font-weight: 600; color: inherit; text-decoration: none; }
.review-author:hover { color: var(--accent-2); }
.review-date { color: var(--text-dim); font-size: 0.78rem; }
.review-delete { margin-left: auto; color: var(--text-dim); }
.review-delete:hover { color: var(--danger); }
.review-text { margin: 0; white-space: pre-wrap; overflow-wrap: anywhere; }

/* Плитка-ссылка в шапке публичного профиля ведёт себя как карточка. */
a.stat-card { text-decoration: none; color: inherit; }

/* ---------- «Мои турниры»: роли, ссылка на турнир, итоги ---------- */
.role-switch { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 18px; }
.role-btn {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 10px 16px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-muted);
    font-family: var(--font-head); font-weight: 600; font-size: 0.9rem;
    cursor: pointer;
    transition: border-color var(--transition), color var(--transition), background var(--transition);
}
.role-btn:hover { border-color: var(--accent); color: var(--text); }
.role-btn.is-active {
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
    border-color: transparent; color: var(--on-accent);
}
.role-btn-count {
    min-width: 22px; padding: 1px 7px; border-radius: 999px;
    background: rgba(0, 0, 0, 0.22); font-size: 0.76rem; text-align: center;
}
.role-btn.is-active .role-btn-count { background: rgba(255, 255, 255, 0.24); }

.my-tournament-link { color: inherit; text-decoration: none; }
.my-tournament-link:hover { color: var(--accent-2); text-decoration: underline; }

/* Итоги турнира: место и команда крупно, дальше матчи. */
.my-tournament-summary {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 12px; margin-bottom: 18px;
}
.summary-place, .summary-side {
    display: flex; flex-direction: column; gap: 4px;
    padding: 12px 14px; border-radius: var(--radius-md);
    background: var(--surface-2); border: 1px solid var(--border);
}
.summary-place-label, .summary-side-label {
    font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim);
}
.summary-place-value { font-size: 1.4rem; font-weight: 800; color: var(--gold); }
.summary-side-value { font-size: 1.05rem; font-weight: 700; }

.my-matches { display: flex; flex-direction: column; gap: 16px; }
.my-match {
    padding: 14px; border-radius: var(--radius-md);
    background: var(--surface-2); border: 1px solid var(--border);
}
.my-match.is-won { border-color: color-mix(in srgb, var(--success) 55%, var(--border)); }
.my-match.is-lost { border-color: color-mix(in srgb, var(--danger) 45%, var(--border)); }
.my-match-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.my-match-stage { font-size: 0.76rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); }
.my-match-vs { flex: 1 1 auto; color: var(--text-muted); font-size: 0.9rem; }
.my-match-vs b { color: var(--text); }
.my-match-score { font-size: 1.2rem; font-weight: 800; color: var(--accent-2); }
.my-match.is-won .my-match-score { color: var(--success); }
.my-match.is-lost .my-match-score { color: var(--danger); }

/* ---------- Администраторы турнира ---------- */
.tournament-admins-list { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.tournament-admins-list li {
    display: flex; align-items: center; gap: 10px;
    padding: 9px 12px; border-radius: var(--radius-sm, 8px); background: var(--surface-3);
}
.tournament-admin-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.tournament-admin-name { font-weight: 600; }
.tournament-admin-sub { color: var(--text-muted); font-size: 0.78rem; }
.tournament-admin-kind {
    padding: 2px 8px; border-radius: 999px; background: var(--surface-2);
    color: var(--text-muted); font-size: 0.72rem; font-weight: 600; white-space: nowrap;
}
.tournament-admin-kind.is-owner { color: var(--gold); }

/* ---------- Выбор карт (маппул) ---------- */
.map-pool-picker { border: 1px solid var(--border); border-radius: var(--radius-md); padding: 10px; }
.map-pool-tools { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.map-pool-search { flex: 1 1 160px; min-width: 0; }
.map-pool-toggle { display: flex; align-items: center; gap: 6px; font-size: 0.82rem; color: var(--text-muted); white-space: nowrap; }
.map-pool-count { font-size: 0.82rem; color: var(--text-muted); white-space: nowrap; }
/* Ровно две карточки в высоту: список карт длинный, и без ограничения
   окно выбора уезжало на два экрана. Прокрутка колесом и пальцем работает.

   Высота считается от самой карточки: картинка 84px шириной с
   соотношением 3:4 плюс две строки подписи и отступы. */
.map-pool-groups {
    max-height: calc(2 * var(--map-pick-height, 189px) + 8px + 37px);
    overflow-y: auto;


}
.map-pool-group h5 { margin: 10px 0 6px; font-size: 0.82rem; color: var(--text-muted); }
.map-pool-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 8px; }
.map-pick {
    display: flex; flex-direction: column; align-items: center; gap: 4px;
    padding: 8px 6px;
    border: 1px solid var(--border); border-radius: var(--radius-sm, 8px);
    background: var(--surface-3); cursor: pointer; text-align: center;
    transition: border-color .15s ease;
}
.map-pick:hover { border-color: var(--accent); }
.map-pick img, .map-pick-noimg {
    width: 100%; max-width: 84px; aspect-ratio: 3 / 4; object-fit: cover;
    border-radius: 6px; background: var(--surface-2);
    display: flex; align-items: center; justify-content: center; color: var(--text-dim);
}
.map-pick-name { font-size: 0.78rem; font-weight: 600; line-height: 1.2; }
.map-pick-mode { font-size: 0.7rem; color: var(--text-muted); line-height: 1.2; }
.map-pick.is-rotated-out { opacity: .7; }
.map-pick:has(input:checked) { border-color: var(--accent); background: var(--surface-2); }
.map-pick input { accent-color: var(--accent); }

/* Формат по стадиям: в форме создания и на странице турнира */
.stage-formats { display: flex; flex-direction: column; gap: 8px; }
.stage-format-row {
    display: flex; align-items: center; gap: 10px;
    padding: 6px 10px; background: var(--surface-3);
    border-radius: var(--radius-sm, 8px);
}
.stage-format-name { flex: 1 1 auto; font-size: 0.88rem; }
/* Сколько команд играет на стадии — мелким рядом с её названием.
   Названия считаются по парам («1/64» — это 64 пары, то есть 128 команд),
   и без этой подписи вопрос «а где 1/128?» возникает у всех. */
.stage-format-teams { color: var(--text-dim); font-size: 0.76rem; margin-left: 8px; }
.stage-format-row .form-select { flex: 0 0 auto; width: 96px; }

.tournament-stage-formats { margin-top: 18px; }
.tournament-stage-formats h4 { margin: 0 0 10px; font-size: 0.95rem; }
.tournament-stage-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.tournament-stage-list li {
    display: flex; align-items: center; gap: 8px;
    padding: 6px 12px; background: var(--surface-2);
    border: 1px solid var(--border); border-radius: 999px; font-size: 0.84rem;
}
.tournament-stage-bo { color: var(--accent-2); font-weight: 700; }

/* Маппул кнопкой, а не простынёй в форме */
.map-pool-summary { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.map-pool-chosen { color: var(--text-muted); font-size: 0.86rem; }

/* Маппул турнира отдельным окном: две карточки в высоту, дальше скролл. */
.map-pool-view {
    max-height: calc(2 * var(--map-pool-card, 182px) + 10px);
    overflow-y: auto;


}
.map-pool-list-noimg {
    width: 100%; max-width: 88px; aspect-ratio: 3 / 4;
    display: flex; align-items: center; justify-content: center;
    border-radius: 6px; background: var(--surface-3); color: var(--text-dim);
}

/* Маппул на странице турнира */
.tournament-map-pool { margin-top: 18px; }
.tournament-map-pool h4 { margin: 0 0 10px; font-size: 0.95rem; }
.map-pool-list {
    list-style: none; margin: 0; padding: 0;
    display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: 10px;
}
.map-pool-list li {
    display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center;
    padding: 8px; background: var(--surface-2); border: 1px solid var(--border);
    border-radius: var(--radius-sm, 8px);
}
/* Высота карточки фиксирована, иначе ряд «схлопывался», когда картинка
   не загрузилась, — и окно переставало быть высотой ровно в две карты.
   Битую картинку прячем, но её место остаётся за ней. */
.map-pool-list li { min-height: var(--map-pool-card, 182px); justify-content: flex-start; }
.map-pool-list img {
    width: 100%; max-width: 88px; aspect-ratio: 3 / 4; object-fit: cover;
    border-radius: 6px; background: var(--surface-3);
}
.map-pool-list img.is-broken { visibility: hidden; }
.map-pool-list-name { font-size: 0.8rem; font-weight: 600; }
.map-pool-list-mode { font-size: 0.72rem; color: var(--text-muted); }

.team-roster-item i { color: var(--gold); }
.team-roster-status { color: var(--text-dim); font-size: 0.82rem; }
.team-roster-status.is-captain { color: var(--gold); font-weight: 600; }
.team-roster-you { color: var(--text-muted); font-size: 0.78rem; }

.tournaments-tabs { margin-bottom: 24px; }

/* ---------- Вкладка «Мои турниры» ---------- */
.my-tournaments-list { display: flex; flex-direction: column; gap: 18px; }

.my-tournament-card {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 20px 22px;
}
.my-tournament-head {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin-bottom: 6px;
}
.my-tournament-head h3 { margin: 0; font-size: 1.15rem; color: var(--text); }
.my-tournament-meta { color: var(--text-dim); font-size: 0.88rem; margin-bottom: 14px; }

.checkin-banner {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    flex-wrap: wrap;
    padding: 10px 14px;
    border-radius: var(--radius-md, 10px);
    background: var(--surface-3);
    border: 1px solid var(--border);
    color: var(--text-dim);
    font-size: 0.88rem;
    margin-bottom: 14px;
}
.checkin-banner i { margin-right: 4px; }
.checkin-banner.is-open {
    background: color-mix(in srgb, var(--warning) 14%, var(--surface-3));
    border-color: var(--warning);
    color: var(--text);
}
.checkin-banner.is-open i { color: var(--warning); }
/* Подтверждённое участие — короткая строка, и в баннере с
   justify-content: space-between она уезжала в середину. Здесь
   выравниваем по левому краю и делаем заметнее: это статус, ради
   которого баннер и остаётся на экране. */
.checkin-banner.is-done {
    justify-content: flex-start;
    background: color-mix(in srgb, var(--success) 14%, var(--surface-3));
    border-color: var(--success);
    color: var(--text);
    font-weight: 700;
    font-size: 0.92rem;
}
.checkin-banner.is-done i { color: var(--success); }

/* Почему кнопки нет: «ждём капитана» или «состав неполный». */
.checkin-reason { color: var(--text-dim); font-size: 0.84rem; text-align: right; }
.checkin-banner.is-missed {
    background: color-mix(in srgb, var(--danger) 14%, var(--surface-3));
    border-color: var(--danger);
    color: var(--text);
}
.checkin-banner.is-missed i { color: var(--danger); }

.my-tournament-participants { margin-bottom: 16px; }
.my-tournament-participants h4 {
    font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--text-dim); margin: 0 0 8px;
}
.participants-empty { color: var(--text-dim); font-size: 0.9rem; }

.participant-team { margin-bottom: 10px; }
.participant-team-name { font-weight: 600; color: var(--text); font-size: 0.92rem; margin-bottom: 4px; }
.participant-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.participant-chip {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 4px 10px; border-radius: 999px;
    background: var(--surface-3); color: var(--text-muted); font-size: 0.85rem;
}
.participant-chip i { color: var(--gold); font-size: 0.75rem; }
button.participant-chip { border: 0; font-family: inherit; cursor: pointer; transition: background .15s, color .15s; }
button.participant-chip:hover, button.participant-chip:focus-visible { background: var(--accent); color: #fff; }

/* ============================================================
   Полноценная страница турнира (pages/tournament.html) — открывается
   вместо инлайн-действий в сетке карточек (как на Матчерино): слева
   список остальных турниров, дальше баннер турнира, колонка разделов
   («левая колонка с кнопками» — обзор/участники/сетка/техподдержка) и
   контент, справа — призовой фонд, чек-ин и сама регистрация/команда.
   ============================================================ */
/* «Другие турниры» — колонкой слева во всю высоту страницы, баннер
   турнира правее неё. Так было изначально, так и вернулось: когда баннер
   растянули на всю ширину, а список опустили строкой ниже, слева под
   шапкой оставалась дыра, а сама левая колонка разрывалась надвое. */
.tournament-page-layout {
    display: grid;
    grid-template-columns: 220px 210px minmax(0, 1fr) 300px;
    grid-template-areas:
        "rail header header header"
        "rail nav    content sidebar";
    gap: 20px 24px;
    align-items: start;
}

.tournament-rail {
    grid-area: rail;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 16px;
    max-height: 640px;
    overflow-y: auto;
}
.tournament-rail h2 { font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); margin: 0 0 12px; }
/* Список — отдельная обёртка внутри .tournament-rail (не сам .tournament-rail),
   иначе flex применялся бы всего к двум прямым детям (заголовку и списку),
   а не к самим карточкам турниров внутри. */
.tournament-rail-list { display: flex; flex-direction: column; gap: 10px; }
.tournament-rail-item {
    display: flex; flex-direction: column; gap: 6px;
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--surface-3);
    color: inherit; text-decoration: none;
    transition: border-color var(--transition), background var(--transition);
}
.tournament-rail-item:hover { border-color: var(--accent); }
.tournament-rail-item.is-active { border-color: var(--accent); background: var(--accent-soft); }
.tournament-rail-title {
    font-weight: 600; font-size: 0.9rem; color: var(--text);
    overflow: hidden; text-overflow: ellipsis; display: -webkit-box;
    -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}

.tournament-detail-header {
    grid-area: header;
    position: relative;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 24px 26px;
}
.tournament-detail-header.has-photo {
    background-image: linear-gradient(180deg, rgba(10, 10, 42, 0.2) 0%, rgba(10, 10, 42, 0.82) 100%), var(--bg-url);
    background-size: cover;
    background-position: center;
    min-height: 150px;
    display: flex; flex-direction: column; justify-content: flex-end;
    border: 2px solid #fff;
}
/* Дисциплина и статус — без подложки: это самостоятельные пилюли со
   своим фоном и рамкой, и серая плашка вокруг них только загораживала
   баннер. Призовой отсюда убран совсем — он и так крупно стоит в правой
   колонке, а на светлом углу картинки жёлтая сумма не читалась. */
.tournament-detail-header-top {
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
    flex-wrap: wrap;
    width: 100%;
    margin-bottom: 14px;
}
/* Пилюли уезжают вправо и держатся вместе — margin-left:auto, а не
   justify-content на каждом: при переносе на узком экране они должны
   оставаться одной группой под названием, а не разъезжаться по краям. */
.tournament-detail-header-tags {
    display: inline-flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin-left: auto;
}
/* Пилюли поверх картинки турнира. Их заливка сделана из собственного
   цвета и почти прозрачна — на тёмной карточке это читается, а на ярком
   баннере жёлтый текст ложился на жёлтую картинку и пропадал. Здесь и
   только здесь даём им плотную тёмную подложку. */
.tournament-detail-header.has-photo .tag-game,
.tournament-detail-header.has-photo .tournament-status,
.tournament-detail-header.has-photo .tournament-private-tag,
.tournament-header-large.has-photo .tag-game,
.tournament-header-large.has-photo .tournament-status,
.tournament-header-large.has-photo .tournament-private-tag {
    background: rgba(6, 6, 26, 0.82);
    border-color: currentColor;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.5);
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85);
    backdrop-filter: blur(4px);
}
.tournament-detail-header.has-photo h1 { text-shadow: 0 2px 10px rgba(0, 0, 0, 0.85); }

/* margin: 0 — название теперь живёт в одной строке с пилюлями, и свой
   нижний отступ ему больше не нужен: его задаёт сама строка. */
.tournament-detail-header h1 { font-size: 1.6rem; margin: 0; color: var(--text); min-width: 0; }
.tournament-detail-header.has-photo h1 { color: #fff; text-shadow: 0 1px 6px rgba(0, 0, 0, 0.6); }
.tournament-detail-header.has-photo .tournament-detail-header-meta { color: rgba(255, 255, 255, 0.9); text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6); }
/* Даты и место — своей плашкой поверх баннера. На картинке турнира этот
   текст терялся: тень помогала не всегда, а светлый баннер делал его
   нечитаемым совсем. Полупрозрачная подложка решает это при любой
   картинке, не пряча её. */
.tournament-detail-header-meta {
    display: inline-flex; gap: 18px; flex-wrap: wrap;
    align-self: flex-start;
    /* Прижата к левому нижнему углу баннера. Отрицательные отступы
       съедают внутреннее поле шапки (24px сверху и снизу, 26px по
       бокам) и оставляют по 8px до края — плашка сидит в углу, но за
       скруглённый край не вылезает.

       Раньше было -10px слева и ничего снизу: плашка висела почти
       посреди картинки и читалась как продолжение названия. */
    margin: 10px 0 -16px -18px;
    padding: 8px 14px;
    border-radius: var(--radius-md);
    background: var(--surface-2);
    border: 1px solid var(--border);
    color: var(--text-muted); font-size: 0.92rem;
}
.tournament-detail-header.has-photo .tournament-detail-header-meta {
    background: rgba(10, 10, 42, 0.62);
    border-color: rgba(255, 255, 255, 0.14);
    backdrop-filter: blur(6px);
    text-shadow: none;
}
.tournament-detail-header-meta i { color: var(--accent-2); margin-right: 6px; }

/* «Левая колонка с кнопками» — обзор/участники/сетка/техподдержка. */
.tournament-detail-nav {
    grid-area: nav;
    display: flex; flex-direction: column; gap: 8px;
}
.tournament-nav-btn {
    display: flex; align-items: center; gap: 10px;
    padding: 12px 14px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-muted);
    font-family: var(--font-head);
    font-weight: 600;
    font-size: 0.9rem;
    text-align: left;
    cursor: pointer;
    transition: border-color var(--transition), color var(--transition), background var(--transition);
}
.tournament-nav-btn i { width: 18px; text-align: center; color: var(--accent-2); }
.tournament-nav-btn:hover { border-color: var(--accent); color: var(--text); }
.tournament-nav-btn.is-active {
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
    border-color: transparent; color: var(--on-accent);
}
.tournament-nav-btn.is-active i { color: var(--on-accent); }

.tournament-detail-content {
    grid-area: content;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 22px;
    min-height: 220px;
}
.tournament-detail-participants .participant-team:last-child { margin-bottom: 0; }

.tournament-sidebar {
    grid-area: sidebar;
    display: flex; flex-direction: column; gap: 14px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 20px;
    align-self: start;
}
.tournament-sidebar-prize {
    display: flex; flex-direction: column; gap: 4px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border);
}
.tournament-sidebar-label { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); }
.tournament-sidebar-value { font-size: 1.5rem; font-weight: 700; color: var(--gold); }

/* Распределение приза по местам — только если организатор его указал
   при создании турнира (см. форму создания ниже), иначе блок не рендерится. */
.tournament-prize-split { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; margin-top: 8px; font-size: 0.9rem; }
.tournament-prize-split .place-label { color: var(--text); font-weight: 600; }
.tournament-prize-split .place-amount { color: var(--gold); font-weight: 600; text-align: right; }
.tournament-prize-distribution { list-style: none; margin: 10px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.tournament-prize-distribution li {
    /* Три колонки: место, процент, сумма — цифры ровно друг под другом */
    display: grid; grid-template-columns: minmax(70px, 1fr) 52px minmax(90px, auto); align-items: center; gap: 10px;
    font-size: 0.86rem; color: var(--text-muted);
}
.tournament-prize-distribution .place-label { color: var(--text); font-weight: 600; }
.tournament-prize-distribution .place-amount { color: var(--gold); font-weight: 600; }
.tournament-prize-distribution li > span:nth-child(2),
.tournament-prize-distribution .place-amount { text-align: right; font-variant-numeric: tabular-nums; }

/* Краудфандинг банка турнира (Matcherino) — кто скинулся и кнопка добавить */
.prize-crowdfund { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.prize-backers { display: flex; flex-wrap: wrap; gap: -6px; }
.prize-backer {
    width: 28px; height: 28px; border-radius: 50%; overflow: hidden;
    border: 2px solid var(--surface); margin-left: -8px;
    display: inline-flex; align-items: center; justify-content: center;
}
.prize-backer:first-child { margin-left: 0; }
.prize-backer img { width: 100%; height: 100%; object-fit: cover; }

/* Кнопка «Моя команда»: логотип и название вместо голого текста —
   команду узнают по логотипу так же, как в списке команд и в сетке. */
.tournament-myteam-btn {
    justify-content: flex-start; text-align: left;
    padding: 10px 14px; gap: 12px;
}
.tournament-myteam-logo {
    flex: 0 0 auto; width: 40px; height: 40px; border-radius: 11px;
    overflow: hidden; display: flex; align-items: center; justify-content: center;
    background: var(--surface-3); border: 1px solid var(--border);
}
.tournament-myteam-logo img { width: 100%; height: 100%; object-fit: cover; }
.tournament-myteam-body {
    flex: 1 1 auto; min-width: 0;
    display: flex; flex-direction: column; gap: 1px;
}
.tournament-myteam-label {
    font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.03em;
    color: var(--text-dim); font-weight: 600;
}
.tournament-myteam-name {
    font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tournament-myteam-arrow { flex: 0 0 auto; opacity: 0.7; }

.tournament-sidebar-facts { list-style: none; margin: 0; padding: 14px 0 0; display: flex; flex-direction: column; gap: 10px; border-top: 1px solid var(--border); }
.tournament-sidebar-facts li { display: flex; align-items: center; gap: 9px; color: var(--text-muted); font-size: 0.88rem; }
.tournament-sidebar-facts i { color: var(--accent-2); width: 16px; text-align: center; }
.tournament-sidebar #tournamentSidebarCheckin .checkin-banner { margin-bottom: 0; }

@media (max-width: 1100px) {
    .tournament-page-layout {
        /* minmax(0, 1fr), не голый 1fr — иначе трек растягивается по
           min-content вложенного горизонтального списка турниров (у него
           много карточек с min-width) и вся раскладка распирает страницу
           по ширине вместо того, чтобы скроллиться внутри самого списка. */
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas:
            "header"
            "rail"
            "nav"
            "content"
            "sidebar";
    }
    /* Планшет и телефон: список «Другие турниры» не показываем */
    .tournament-page-layout { gap: 10px; }
    .tournament-rail { display: none; }
    .tournament-rail { max-height: none; overflow-y: visible; }
    .tournament-rail-list { flex-direction: row; overflow-x: auto; padding-bottom: 4px; }
    .tournament-rail-item { min-width: 200px; flex-shrink: 0; }
    .tournament-detail-nav { flex-direction: row; flex-wrap: wrap; }
    .tournament-nav-btn { flex: 1; min-width: 160px; justify-content: center; }
}

/* ---------- Окно техподдержки турнира (модалка) ---------- */

/* Переписка — главное в этом окне, поэтому оно шире обычной модалки и
   даёт ленте сообщений больше высоты: в окне на 520px разговор из
   десятка реплик читался в щёлочку. */
#tournamentSupportModal .modal-content { max-width: 720px; }

/* Одна строка кнопок над перепиской: «Call admin» и, у того, кто ведёт
   турнир, «Обращения». Прежней серой плашки с пояснением нет — текст
   переехал в подсказку кнопки. */
.support-actions {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin-bottom: 14px;
}
.support-actions:empty { display: none; }

.support-thread {
    display: flex; flex-direction: column; gap: 10px;
    max-height: 460px; min-height: 220px; overflow-y: auto;
    padding: 4px 4px 14px;
    margin-bottom: 14px;
}
.support-message {
    align-self: flex-start;
    max-width: 82%;
    background: var(--surface-3);
    border-radius: var(--radius-md, 12px);
    padding: 8px 12px;
}
.support-message.is-mine {
    align-self: flex-end;
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
    color: var(--on-accent);
}
.support-message-body { font-size: 0.92rem; white-space: pre-wrap; word-break: break-word; }
.support-message-time { font-size: 0.72rem; opacity: 0.7; margin-top: 4px; text-align: right; }

/* Поле ввода ровно в высоту кнопки отправки. Раньше это была textarea в
   две строки, и она возвышалась над кнопкой на полторы высоты — строка
   ввода выглядела как форма отзыва, а не как поле чата. Растёт под текст
   скриптом (до 120px), поэтому длинное сообщение всё равно видно целиком.
   align-items: flex-end — чтобы при росте поля кнопка оставалась внизу. */
.support-send-form { display: flex; gap: 10px; align-items: flex-end; }
.support-send-form textarea {
    flex: 1;
    resize: none;
    height: 44px; min-height: 44px; max-height: 120px;
    padding-top: 10px; padding-bottom: 10px;
    line-height: 1.35;
    overflow-y: auto;
}
.support-send-form button {
    flex-shrink: 0;
    height: 44px; width: 52px;
    display: inline-flex; align-items: center; justify-content: center;
    padding: 0;
}

/* Прикреплённое к чату матча фото ждёт отправки — маленькая полоска над
   строкой ввода с превью, именем файла и крестиком-отменой. Пока не
   нажали «отправить», файл никуда не загружен (см. openMatchChat в
   js/tournaments.js) — крестик просто забывает выбор. */
.match-chat-attach-preview {
    display: flex; align-items: center; gap: 8px;
    margin-bottom: 8px;
    padding: 6px 10px;
    background: var(--surface-3);
    border-radius: var(--radius-md, 12px);
    font-size: 0.85rem;
}
.match-chat-attach-thumb {
    width: 36px; height: 36px; border-radius: 8px; overflow: hidden; flex-shrink: 0;
}
.match-chat-attach-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.match-chat-attach-name {
    flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    color: var(--text-dim);
}
.match-chat-attach-remove {
    flex-shrink: 0; width: 28px; height: 28px; border: none; border-radius: 50%;
    background: var(--surface-2); color: var(--text-dim);
    display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
}
.match-chat-attach-remove:hover { background: var(--danger); color: #fff; }

/* Фото прямо в переписке матча — те же классы, что и в личном чате
   (.msg-image-btn/.msg-image, js/chat.js), просто внутри пузыря
   .support-message: сначала картинка, потом текст (если есть). */
.support-message .msg-image-btn { margin-bottom: 6px; }
.support-message.is-mine .msg-attachment-loading { color: var(--on-accent); opacity: 0.85; }

.support-thread-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.support-thread-item {
    display: flex; flex-direction: column; gap: 4px;
    width: 100%; text-align: left;
    padding: 10px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md, 12px);
    background: var(--surface-3);
    color: var(--text);
    cursor: pointer;
    transition: border-color var(--transition), background var(--transition);
}
.support-thread-item:hover { border-color: var(--accent); background: var(--accent-soft); }
.support-thread-name { font-weight: 600; }

/* ---------- Чат матча (аватар + игровой ник + метка «админ») ---------- */
/* Модалка чата матча — пошире обычной (520px): переписке с аватарами
   и именами тесно в стандартной ширине. */
#matchChatModal .modal-content { max-width: min(760px, 94vw); }
#matchChatModal .support-thread { min-height: 380px; max-height: 64vh; }
.match-chat-row { display: flex; align-items: flex-start; gap: 8px; }
.match-chat-row.is-mine { flex-direction: row-reverse; }
.match-chat-col { display: flex; flex-direction: column; gap: 3px; max-width: 76%; min-width: 0; }
.match-chat-row.is-mine .match-chat-col { align-items: flex-end; }
.match-chat-meta { display: flex; align-items: center; gap: 6px; font-size: 0.78rem; color: var(--text-muted); }
.match-chat-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 220px; }
.match-chat-admin-badge {
    flex: 0 0 auto;
    padding: 1px 8px; border-radius: 999px;
    background: color-mix(in srgb, var(--accent) 22%, var(--surface-2));
    color: var(--accent-2); font-size: 0.66rem; font-weight: 800; letter-spacing: 0.02em; text-transform: uppercase;
}
.match-chat-row .support-message { align-self: auto; max-width: none; }
.support-thread-preview { color: var(--text-dim); font-size: 0.85rem; }

/* ---------- Список друзей для приглашения в команду ---------- */
.friend-picker { display: flex; flex-direction: column; gap: 6px; max-height: 260px; overflow-y: auto; margin-bottom: 16px; }
.friend-picker-item {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 10px;
    border-radius: var(--radius-sm, 8px);
    background: var(--surface-3);
    cursor: pointer;
}
.friend-picker-item input { accent-color: var(--accent); }

/* ---------- Турнирная сетка ---------- */
.bracket-rounds {
    display: flex; gap: 20px;
    overflow-x: auto;
    padding-bottom: 6px;
}
.bracket-round { display: flex; flex-direction: column; gap: 14px; min-width: 220px; flex-shrink: 0; }
.bracket-round h4 { margin: 0 0 4px; color: var(--text-muted); font-size: 0.9rem; }
/* Общей плашки у пары больше нет: две команды стоят каждая своей
   кнопкой, а соединяет их квадратная скобка «]» с правой стороны —
   её рисует drawLines() в js/bracket.js (SVG поверх сетки). */
.bracket-match {
    position: relative;
    display: flex; flex-direction: column; gap: 10px;
    padding: 0;
    background: none;
    border: 0;
    box-shadow: none;
}
/* Участник в сетке нажимается: открывается состав команды или карточка
   игрока. Лицо (аватар/логотип) + имя — как в составе команды (см.
   .team-roster-item), только компактнее: тут это пара в дереве сетки,
   а не список из нескольких человек. */
.bracket-participant {
    display: flex; align-items: center; gap: 11px; width: 100%;
    padding: 9px 10px 9px 12px; border-radius: 22px;
    /* темнее прежнего: заметно отличается от узорчатого фона сетки */
    background: color-mix(in srgb, var(--surface-1, var(--surface-2)) 55%, #05051a);
    border: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
    box-shadow: 0 3px 10px rgba(0, 0, 0, .28);
    color: inherit; font: inherit; text-align: left;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease, transform .15s ease;
}
button.bracket-participant:hover { border-color: var(--accent); }
button.bracket-participant:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.bracket-participant.is-winner { background: color-mix(in srgb, var(--success) 22%, color-mix(in srgb, var(--surface-1, var(--surface-2)) 55%, #05051a)); }
.bracket-participant.is-winner .bracket-participant-name { color: var(--success); }
/* Своя команда (или сам игрок в «1 на 1») — рамка и лёгкая подложка
   акцентным цветом поверх любого другого состояния пары, включая
   победу: свою команду должно быть видно первой, даже когда она уже
   выиграла и подсвечена зелёным. */
.bracket-participant.is-mine {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 20%, color-mix(in srgb, var(--surface-1, var(--surface-2)) 55%, #05051a));
    box-shadow: inset 0 0 0 1px var(--accent);
}
.bracket-participant-who { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.bracket-participant-name {
    font-weight: 700; font-size: 1.02rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bracket-participant-sub {
    color: var(--text-muted); font-size: 0.78rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bracket-participant-trophies {
    display: inline-flex; align-items: center; gap: 5px;
    color: var(--gold); white-space: nowrap; flex: 0 0 auto;
    font-size: 0.86rem; font-weight: 800;
}
.bracket-participant-trophies .trophy-icon { width: 1.05em; height: 1.05em; }
/* Счёт пары — как на Матчерино: крупная цифра справа у каждой стороны.
   Есть, только когда по матчу уже что-то забито (см. matchHtml в
   js/tournaments.js и supabase/tournament_bracket_score.sql) — пока
   пара не сыграна, счёта нет вовсе, а не «0:0». */
.bracket-participant-score {
    flex: 0 0 auto; min-width: 44px; height: 44px; padding: 0 8px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 14px;
    background: color-mix(in srgb, var(--accent) 24%, transparent);
    border: 1px solid color-mix(in srgb, var(--accent-2) 45%, transparent);
    font-family: var(--font-head); font-weight: 800; font-size: 1.6rem; line-height: 1;
    color: var(--text);
}
.bracket-participant-score.is-winner {
    background: var(--success);
    border-color: var(--success);
    color: #06210f;
    box-shadow: 0 0 14px color-mix(in srgb, var(--success) 55%, transparent);
}
.bracket-face {
    flex: 0 0 auto; width: 48px; height: 48px; border-radius: 50%;
    overflow: hidden; display: flex; align-items: center; justify-content: center;
    background: var(--surface-1, var(--surface-2)); border: 1px solid var(--border);
}
.bracket-face img { width: 100%; height: 100%; object-fit: cover; }
.bracket-face.is-square { border-radius: 10px; }
.bracket-face .roster-face-initials, .bracket-face .team-logo-initials { font-size: 0.82rem; }
.bracket-slot-empty { color: var(--text-dim); font-style: italic; }
/* Кнопка карточки матча — компактный значок «i», а не строка текста во
   всю ширину: висит бейджем в углу пары, как на Матчерино. */
.bracket-info {
    position: absolute; top: -8px; right: -8px; z-index: 1;
    width: 22px; height: 22px; padding: 0;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%; border: 1px solid var(--border);
    background: var(--surface-2); color: var(--text-muted);
    font-size: 0.74rem; cursor: pointer;
    box-shadow: 0 2px 6px rgba(0, 0, 0, .25);
    transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.bracket-info:hover { border-color: var(--accent); color: var(--text); background: var(--surface-3); }
/* Номер пары — зеркало .bracket-info, только слева и не кнопка: просто
   подпись «№N», чтобы пары в раунде можно было различить и назвать
   вслух («сыграйте пару номер 3»), не тыча в конкретные команды. */
.bracket-match-no {
    position: absolute; top: -10px; left: -6px; z-index: 2;
    min-width: 22px; height: 22px; padding: 0 6px;
    display: flex; align-items: center; justify-content: center;
    border-radius: 11px; border: 1px solid var(--border);
    background: var(--surface-2); color: var(--text-muted);
    font-size: 0.72rem; font-weight: 700;
    box-shadow: 0 2px 6px rgba(0, 0, 0, .25);
}
/* «ТП» — пара закрыта техническим поражением, не реальным счётом
   (см. «Дать тех. поражение» в окне матча, js/tournaments.js). Тот же
   бейдж используется и в шапке модалки матча. */
.bracket-tech-tag {
    position: absolute; bottom: -9px; left: 14px; z-index: 2;
    padding: 2px 7px; border-radius: 999px;
    background: color-mix(in srgb, var(--warning) 28%, var(--surface-2));
    color: var(--warning); font-size: 0.7rem; font-weight: 800;
    border: 1px solid color-mix(in srgb, var(--warning) 45%, transparent);
}
.modal-header .bracket-tech-tag { position: static; display: inline-flex; vertical-align: middle; }
.match-tech-loss { display: flex; gap: 8px; flex-wrap: wrap; margin: 10px 0 4px; }

/* ---------- Страница турнирной сетки (pages/bracket.html) ---------- */
.container-bracket-page { max-width: 1400px; }

.bracket-page-head {
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
    margin-bottom: 16px;
}
.bracket-page-head h1 { margin: 0; font-size: 1.4rem; flex: 1 1 auto; min-width: 0; }
.bracket-page-head .back-link { flex: none; }

.bracket-toolbar {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; flex-wrap: wrap;
    margin-bottom: 14px;
}
.bracket-zoom-controls {
    display: flex; align-items: center; gap: 8px;
    background: var(--surface-3); border: 1px solid var(--border);
    border-radius: var(--radius-md, 12px); padding: 6px 10px;
}
.bracket-zoom-controls .btn-icon { width: 34px; height: 34px; font-size: 0.85rem; }
.bracket-zoom-value { min-width: 46px; text-align: center; color: var(--text-muted); font-size: 0.9rem; }

.bracket-viewport {
    position: relative;
    overflow: auto;
    max-height: 74vh;
    padding: 32px;
    border-radius: var(--radius-lg, 16px);
    background: var(--surface-2);
    border: 1px solid var(--border);
    cursor: grab;
}
.bracket-viewport.is-panning { cursor: grabbing; user-select: none; }
/* Сетку двигают перетаскиванием, колесом или пальцем; тонкая полоса
   прокрутки по краю — общая для всего сайта, просто ещё один способ
   увидеть, что сетка шире окна. */
/* Внешний sizer получает явный пиксельный размер = натуральный × zoom,
   именно он даёт viewport-у правильный скролл при масштабе — сам
   transform: scale() на layout/overflow родителя не влияет. */
.bracket-zoom-sizer { position: relative; }
.bracket-zoom-layer {
    position: absolute; top: 0; left: 0;
    transform-origin: top left;
    transition: transform 0.15s ease;
}

.bracket-tree {
    position: relative; z-index: 1;
    display: flex; align-items: stretch; gap: 72px;
}
.bracket-col { display: flex; flex-direction: column; min-width: 280px; flex: none; }
.bracket-col-title {
    margin: 0 0 14px; text-align: center;
    color: var(--text-muted); font-size: 0.88rem; text-transform: uppercase; letter-spacing: 0.04em;
}
.bracket-col-series { color: var(--accent-2); font-weight: 700; }
.bracket-col-matches { display: flex; flex-direction: column; justify-content: space-around; flex: 1; gap: 20px; }
.bracket-node { position: relative; }
/* Внутри узла — та же .bracket-match, что и раньше в модалке (см. matchHtml
   в js/tournaments.js), но пошире: свободного места на всю страницу больше. */
.bracket-node .bracket-match { min-width: 290px; }

.bracket-lines { position: absolute; top: 0; left: 0; pointer-events: none; z-index: 0; }
.bracket-line-path {
    fill: none;
    stroke: color-mix(in srgb, var(--text-muted) 60%, transparent);
    stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round;
}
.match-info-action { margin-top: 16px; justify-content: center; }

.bracket-hint {
    margin: 10px 2px 0; color: var(--text-dim); font-size: 0.85rem;
    display: flex; align-items: center; gap: 6px;
}

@media (max-width: 720px) {
    .bracket-viewport { padding: 18px; max-height: 68vh; }
    .bracket-col { min-width: 230px; }
    .bracket-node .bracket-match { min-width: 230px; }
}

/* ---------- Турнирная сетка как шторка снизу (см. js/bracket.js) ----------
   Раньше это была отдельная страница (pages/bracket.html) — переход,
   потеря места на странице турнира. Теперь по кнопке «Турнирная сетка»
   сетка выезжает снизу тем же деревом раундов, что и раньше, просто
   завёрнутым в bottom sheet поверх текущей страницы. */
.bracket-sheet-overlay {
    position: fixed; inset: 0; z-index: 1950;
    display: flex; align-items: flex-end; justify-content: center;
    background: rgba(6, 6, 26, 0);
    transition: background .25s ease;
}
.bracket-sheet-overlay.is-open { background: rgba(6, 6, 26, 0.66); }
/* Скролл самой страницы под шторкой не нужен — иначе на мобильном можно
   было утащить страницу вверх/вниз одновременно с попыткой ущипнуть
   сетку. */
body.has-bracket-sheet { overflow: hidden; }

.bracket-sheet {
    position: relative;
    width: 100%; max-width: none;
    max-height: 96vh;
    display: flex; flex-direction: column;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-bottom: none; border-left: none; border-right: none;
    border-radius: 20px 20px 0 0;
    padding: 20px 24px 16px;
    box-shadow: 0 -16px 44px rgba(0, 0, 0, .45);
    /* Появляется снизу и уходит обратно тем же путём — «эффект отката
       вниз» при закрытии — это тот же transform, просто в обратную
       сторону, а не отдельная анимация. */
    transform: translateY(100%);
    transition: transform .32s cubic-bezier(.32, .72, 0, 1);
}
.bracket-sheet-overlay.is-open .bracket-sheet { transform: translateY(0); }

.bracket-sheet-handle {
    width: 44px; height: 5px; border-radius: 999px;
    background: var(--border); margin: 0 auto 16px; cursor: pointer; flex: none;
}
.bracket-sheet-close {
    position: absolute; top: 16px; right: 18px; z-index: 1;
    width: 36px; height: 36px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    border: 1px solid var(--border); background: transparent; color: var(--text-muted);
    cursor: pointer; font-size: 0.95rem;
    transition: border-color .15s ease, color .15s ease;
}
.bracket-sheet-close:hover { border-color: var(--accent); color: var(--text); }

.bracket-sheet-head { margin-bottom: 16px; padding-right: 50px; flex: none; }
.bracket-sheet-head h2 { margin: 0 0 10px; font-size: 1.4rem; }
.bracket-sheet-head h2:last-child { margin-bottom: 0; }
.bracket-sheet-tags { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tag-series {
    padding: 4px 12px; border-radius: 999px;
    font-size: 0.8rem; font-weight: 700;
    border: 1px solid var(--accent); color: var(--accent-2);
    background: color-mix(in srgb, var(--accent) 16%, transparent);
    white-space: nowrap;
}

.bracket-sheet .bracket-toolbar { flex: none; }
.bracket-sheet .bracket-viewport { flex: 1 1 auto; min-height: 0; max-height: none; }
.bracket-sheet .bracket-hint { flex: none; }

@media (max-width: 720px) {
    .bracket-sheet { max-height: 94vh; border-radius: 16px 16px 0 0; padding: 16px 16px 12px; }
    .bracket-sheet-head { padding-right: 44px; }
    .bracket-sheet .bracket-viewport { max-height: none; }
}


/* ---------- Карточка матча ---------- */
.match-head {
    display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
    gap: 12px; margin-bottom: 18px;
}
.match-side {
    display: flex; align-items: center; gap: 10px; min-width: 0;
    padding: 10px 12px; border-radius: var(--radius-md);
    background: var(--surface-2); border: 1px solid var(--border);
}
.match-side.is-winner { border-color: var(--success); }
.match-side-name { flex: 1 1 auto; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.match-side-score { font-size: 1.4rem; font-weight: 800; color: var(--accent-2); }
.match-side.is-winner .match-side-score { color: var(--success); }
.match-vs { color: var(--text-dim); font-weight: 700; }

.match-games { display: flex; flex-direction: column; gap: 10px; margin-bottom: 18px; }
.match-game {
    padding: 10px 12px; border-radius: var(--radius-md);
    background: var(--surface-3); border: 1px solid var(--border);
}
.match-game-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.match-game-no { font-size: 0.76rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.04em; }
.match-game-map { flex: 1 1 auto; font-weight: 600; font-size: 0.9rem; }
.match-game-score { display: flex; align-items: center; gap: 6px; font-size: 1.05rem; font-weight: 700; }
.match-game-score b { color: var(--text-muted); }
.match-game-score b.is-winner { color: var(--success); }

.match-game-drafts { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 8px; }
.match-draft { display: flex; flex-wrap: wrap; gap: 5px; }
.match-draft.is-right { justify-content: flex-end; }
.draft-pick {
    padding: 2px 8px; border-radius: 999px;
    background: var(--surface-2); border: 1px solid var(--border);
    font-size: 0.74rem; color: var(--text-muted);
}

/* min-width: 0 обязателен: без него grid-колонка не сжимается уже своего
   содержимого, и карточка игрока (аватар + текст + трофеи) вылезала за
   правый край модалки, если ник или тег были чуть длиннее обычного. */
.match-rosters { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; min-width: 0; }
.match-roster { min-width: 0; }
.match-roster h5 { margin: 0 0 8px; font-size: 0.86rem; color: var(--text-muted); }

.match-game-form { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border); }
.match-game-form h5 { margin: 0 0 10px; font-size: 0.9rem; }
.match-game-form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: 10px; }
.match-game-form label, .match-game-form-wide {
    display: flex; flex-direction: column; gap: 4px;
    font-size: 0.78rem; color: var(--text-muted);
}
.match-game-form-wide { margin-top: 10px; }


@media (max-width: 640px) {
    .match-head { grid-template-columns: 1fr; }
    .match-vs { text-align: center; }
    .match-rosters, .match-game-drafts { grid-template-columns: 1fr; }
    .match-draft.is-right { justify-content: flex-start; }
}

/* ---------- Пагинация ---------- */
.pagination {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 8px;
    margin-top: 40px;
    flex-wrap: wrap;
}

.page-link {
    min-width: 42px;
    height: 42px;
    padding: 0 14px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-muted);
    font-family: var(--font-head);
    font-weight: 600;
    cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.page-link:hover:not(:disabled) { border-color: var(--accent); color: var(--accent-2); }
.page-link[aria-current="page"] {
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
    color: var(--on-accent);
    border-color: transparent;
}
.page-link:disabled { opacity: 0.45; cursor: not-allowed; }

/* ---------- Блоки статистики ---------- */
.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 20px;
}

.stats-card {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 24px;
    display: flex;
    align-items: center;
    gap: 18px;
}
.stats-icon {
    width: 54px; height: 54px; flex-shrink: 0;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--accent-2);
    display: flex; align-items: center; justify-content: center;
    font-size: 1.35rem;
}
.stats-content h3 { font-size: 0.95rem; color: var(--text-muted); font-weight: 500; margin-bottom: 4px; }
.stats-value { font-family: var(--font-head); font-size: 1.7rem; font-weight: 700; color: var(--accent-2); }
.stats-desc { color: var(--text-dim); font-size: 0.84rem; }

/* ---------- Крупные карточки трансляций ---------- */
.streams-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
    gap: 24px;
}

.stream-card-large {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
}
.stream-card-large:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: var(--accent); }

.stream-thumbnail-large {
    height: 190px;
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    position: relative;
    display: flex; align-items: flex-end; justify-content: flex-end;
    padding: 14px;
}

.stream-info-large { padding: 20px; display: flex; flex-direction: column; flex: 1; }

.streamer-info { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.streamer-details h3 { font-size: 1.05rem; color: var(--text); }
.streamer-status { color: var(--text-dim); font-size: 0.85rem; }

.stream-title { font-size: 1.1rem; color: var(--text); margin-bottom: 8px; }
.stream-description { color: var(--text-dim); font-size: 0.93rem; margin-bottom: 16px; flex: 1; }

.stream-tags { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 18px; }
/* .tag-type получает цвет по категории — правила в style.css, рядом с .tag-game */
.tag-language {
    padding: 4px 12px; border-radius: 999px;
    font-size: 0.78rem; font-weight: 600;
    background: var(--accent-soft); color: var(--accent-2);
}

/* ---------- Рекомендуемые стримеры ---------- */
.streamers-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
    gap: 20px;
}

.streamer-card {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 24px;
    text-align: center;
    transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
}
.streamer-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: var(--accent); }

.streamer-avatar-large {
    position: relative;
    width: 76px; height: 76px;
    margin: 0 auto 14px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    display: flex; align-items: center; justify-content: center;
    color: var(--on-accent); font-size: 1.7rem;
    font-family: var(--font-head); font-weight: 700;
}

.online-status {
    position: absolute; bottom: 4px; right: 4px;
    width: 15px; height: 15px; border-radius: 50%;
    background: var(--text-dim);
    border: 2px solid var(--surface-2);
}
.online-status.online { background: var(--success); }

.streamer-card h3 { font-size: 1.15rem; color: var(--text); margin-bottom: 4px; }
.streamer-game { color: var(--text-dim); font-size: 0.88rem; margin-bottom: 14px; }
.streamer-stats { display: flex; justify-content: center; gap: 16px; margin-bottom: 16px; color: var(--text-muted); font-size: 0.87rem; }
.stat-item { display: inline-flex; align-items: center; gap: 6px; }

/* ---------- Окно продажи ---------- */
.sell-preview {
    margin-top: 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    overflow: hidden;
    max-width: 220px;
}
.sell-preview img { width: 100%; display: block; }
/* Превью доп. фото при выставлении/редактировании товара (до 6 штук) —
   supabase/product_gallery.sql. */
.sell-gallery-preview {
    display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px;
}
.sell-gallery-thumb {
    width: 64px; height: 64px; border-radius: var(--radius-sm);
    overflow: hidden; border: 1px solid var(--border); flex: 0 0 auto;
}
.sell-gallery-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Превью баннера турнира в «Управлении» — та же белая обводка, что и у
   самого баннера в шапке страницы, чтобы предпросмотр не расходился
   с тем, как он будет выглядеть на самом деле. */
.manage-banner-preview { border: 2px solid #fff; max-width: 320px; }

/* ---------- Распределение призового фонда (форма создания турнира) ---------- */
.prize-distribution-form { display: flex; flex-direction: column; gap: 8px; }
.prize-distribution-row { display: flex; align-items: center; gap: 10px; }
.prize-distribution-row span:first-child { width: 70px; color: var(--text-muted); font-size: 0.9rem; flex-shrink: 0; }
.prize-distribution-row input { width: 90px; flex: 0 0 auto; }
.prize-distribution-row span:last-child { color: var(--text-dim); }

/* ---------- Ссылки капитанов (приватный турнир) ---------- */
/* Список коротких ссылок — сам по себе крохотная модалка, полоса
   прокрутки здесь только мешает: одна-две лишних строки не нуждаются
   в индикаторе. Общий стилизованный скроллбар (style.css) отключаем
   точечно только тут. */
.captain-links-list {
    display: flex; flex-direction: column; gap: 8px; max-height: 50vh; overflow-y: auto;
    scrollbar-width: none;
}
.captain-links-list::-webkit-scrollbar { width: 0; height: 0; display: none; }
.captain-link-row { display: flex; align-items: center; gap: 8px; }
.captain-link-num {
    flex: 0 0 auto; width: 22px; text-align: center;
    color: var(--text-dim); font-size: 0.8rem;
}
.captain-link-row input { flex: 1 1 auto; min-width: 0; font-size: 0.82rem; }
.captain-link-row .btn { flex: 0 0 auto; white-space: nowrap; }
/* Кнопка «Скопировать» на пару секунд превращается в галочку — видно,
   какую ссылку уже скопировали, если рассылаешь капитанам по очереди. */
.captain-link-row .btn.is-copied {
    color: var(--success); border-color: color-mix(in srgb, var(--success) 45%, transparent);
}
/* Счётчик «сколько человек уже прошли по ссылке из трёх возможных»
   (tournament_captain_link_team_join.sql) — показывается рядом с полем,
   пока ссылка ещё не заполнена и её можно копировать дальше. */
.captain-link-status {
    flex: 0 0 auto; white-space: nowrap;
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 0.78rem; color: var(--text-dim);
}
/* Ссылка, по которой набрали максимум участников: поле гасим, кнопку
   заменяем меткой «Заполнена» — копировать и раздавать её больше незачем. */
.captain-link-row--used input { opacity: 0.55; }
.captain-link-used {
    flex: 0 0 auto; white-space: nowrap;
    display: inline-flex; align-items: center; gap: 6px;
    padding: 6px 10px; border-radius: var(--radius-sm);
    font-size: 0.82rem; font-weight: 600;
    color: var(--success);
    background: color-mix(in srgb, var(--success) 14%, transparent);
    border: 1px solid color-mix(in srgb, var(--success) 35%, transparent);
}

.mini-cart {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    width: min(470px, calc(100vw - 32px));
    max-height: min(70vh, 560px);
    overflow-y: auto;
    z-index: 1200;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg, 0 18px 48px rgba(0, 0, 0, 0.45));

}
.mini-cart-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 14px 16px;
    border-bottom: 1px solid var(--border);
    position: sticky; top: 0;
    background: var(--surface);
    z-index: 1;
}
.mini-cart-head h3 { font-size: 1rem; color: var(--text); }
.mini-cart-body { padding: 12px 16px 16px; }

.mini-cart-empty {
    text-align: center; color: var(--text-dim);
    padding: 26px 10px; font-size: 0.9rem;
}
.mini-cart-empty i { display: block; font-size: 1.7rem; color: var(--accent-2); margin-bottom: 10px; }

.mini-cart-list { display: flex; flex-direction: column; gap: 8px; }
.mini-cart-row {
    display: flex; align-items: center; gap: 8px;
    padding: 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
}
.mini-cart-pick { display: flex; align-items: center; flex-shrink: 0; }
.mini-cart-pick input { width: 16px; height: 16px; accent-color: var(--accent); cursor: pointer; }

.mini-cart-image {
    width: 38px; height: 38px; flex-shrink: 0;
    border-radius: var(--radius-sm);
    background: var(--accent-soft); color: var(--accent-2);
    display: flex; align-items: center; justify-content: center;
    overflow: hidden;
}
.mini-cart-image img { width: 100%; height: 100%; object-fit: cover; display: block; }

.mini-cart-body .mini-cart-row .mini-cart-body { padding: 0; }
.mini-cart-row .mini-cart-body {
    display: flex; flex-direction: column; min-width: 0; flex: 1; padding: 0;
}
.mini-cart-title {
    font-size: 0.86rem; color: var(--text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mini-cart-unit { font-size: 0.73rem; color: var(--text-dim); }

.mini-cart-qty { display: flex; align-items: center; gap: 5px; flex-shrink: 0; }
.mini-cart-qty .quantity { min-width: 18px; text-align: center; font-size: 0.85rem; }
.mini-cart-sum {
    font-family: var(--font-head); font-weight: 700;
    font-size: 0.86rem; color: var(--accent-2);
    flex-shrink: 0; min-width: 62px; text-align: right;
}

.mini-cart-promo { display: flex; gap: 8px; margin-top: 14px; }
.mini-cart-promo .form-input { flex: 1; text-transform: uppercase; }
.mini-cart-promo-ok {
    margin-top: 8px; color: var(--success, #6bcb77);
    font-size: 0.8rem; display: flex; align-items: center; gap: 6px;
}

.mini-cart-total { margin-top: 14px; display: flex; flex-direction: column; gap: 7px; }
.mini-cart-total .summary-row { display: flex; justify-content: space-between; font-size: 0.86rem; color: var(--text-muted); }
.mini-cart-total .summary-row.total {
    border-top: 1px solid var(--border);
    padding-top: 9px; margin-top: 3px;
    color: var(--text); font-weight: 600;
}
.mini-cart-total .total-price {
    font-family: var(--font-head); font-size: 1.05rem; color: var(--accent-2);
}
.mini-cart-total .discount { color: var(--success, #6bcb77); }

.mini-cart-body .btn-block { margin-top: 14px; }
.mini-cart-note { margin-top: 8px; text-align: center; color: var(--text-dim); font-size: 0.76rem; }

@media (max-width: 768px) {
    .mini-cart { right: -60px; }
    .mini-cart-row { flex-wrap: wrap; }
    .mini-cart-sum { min-width: 0; }
}
.current-price { font-family: var(--font-head); font-size: 1.35rem; font-weight: 700; color: var(--text); }
.old-price { color: var(--text-dim); text-decoration: line-through; font-size: 0.95rem; }
.rating-count { color: var(--text-dim); margin-left: 6px; font-size: 0.85rem; }
.delivered-code {
    font-size: 1.1rem; font-weight: 700; letter-spacing: 0.04em;
    padding: 4px 10px; border-radius: var(--radius-sm); background: var(--surface-2);
}

/* ---------- Отзывы на товар ---------- */
#productReviewsSection { margin-top: 18px; border-top: 1px solid var(--border); padding-top: 14px; }
.review-list { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.review-row { display: flex; gap: 10px; }
.review-row-body { flex: 1; min-width: 0; }
.review-row-head { display: flex; align-items: center; gap: 8px; margin-bottom: 2px; }
.review-stars { color: var(--gold); font-size: 0.85rem; letter-spacing: 1px; }
.star-picker { display: flex; gap: 4px; font-size: 1.3rem; margin-bottom: 8px; }
.star-picker button { background: none; border: none; cursor: pointer; color: var(--border); padding: 0; }
.star-picker button.is-on { color: var(--gold); }
.review-form { display: flex; flex-direction: column; gap: 8px; }
.feature-tag {
    background: var(--surface-soft); color: var(--text-muted);
    padding: 3px 10px; border-radius: 999px; font-size: 0.78rem;
}

.size {
    min-width: 40px;
    padding: 6px 10px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-muted);
    font-weight: 600;
    font-size: 0.85rem;
    cursor: pointer;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.size:hover { border-color: var(--accent); color: var(--accent-2); }
.size[aria-pressed="true"] {
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    color: var(--on-accent); border-color: transparent;
}

.item-image {
    width: 56px; height: 56px; border-radius: var(--radius-sm);
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    display: flex; align-items: center; justify-content: center;
    color: var(--on-accent); font-size: 1.3rem;
}
.item-details h4 { font-size: 1rem; color: var(--text); margin-bottom: 3px; }
.item-category { color: var(--text-dim); font-size: 0.83rem; }

.item-quantity { display: flex; align-items: center; gap: 6px; }
.quantity-btn {
    width: 30px; height: 30px; border-radius: var(--radius-sm);
    border: 1px solid var(--border); background: transparent;
    color: var(--accent-2); font-size: 1rem; cursor: pointer; line-height: 1;
    transition: background var(--transition), border-color var(--transition);
}
.quantity-btn:hover:not(:disabled) { background: var(--accent-soft); border-color: var(--accent); }
.quantity-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.quantity { min-width: 26px; text-align: center; font-weight: 600; }

.item-price { font-family: var(--font-head); font-weight: 700; color: var(--text); white-space: nowrap; }

.item-remove {
    background: none; border: none; color: var(--text-dim);
    cursor: pointer; padding: 6px; border-radius: var(--radius-sm);
    transition: color var(--transition), background var(--transition);
}
.item-remove:hover { color: var(--danger); background: color-mix(in srgb, var(--danger) 12%, transparent); }
.summary-details { display: flex; flex-direction: column; gap: 11px; margin-bottom: 20px; }
.summary-row { display: flex; justify-content: space-between; color: var(--text-muted); font-size: 0.94rem; }
.summary-row .discount { color: var(--success); }
.summary-row.total {
    padding-top: 12px; border-top: 1px solid var(--border);
    color: var(--text); font-weight: 700; font-size: 1.1rem;
}
.total-price { font-family: var(--font-head); color: var(--accent-2); }

/* ---------- Новости ---------- */
.news-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 24px;
}

.news-card-large {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    display: flex; flex-direction: column;
    transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
}
.news-card-large:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: var(--accent); }

.news-image {
    height: 150px;
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    display: flex; align-items: center; justify-content: center;
    font-size: 2.6rem; color: var(--on-accent);
    transition: transform var(--transition);
}
.news-card-large:hover .news-image { transform: scale(1.04); }

.news-content { padding: 22px; display: flex; flex-direction: column; flex: 1; gap: 12px; }

.news-category {
    align-self: flex-start;
    padding: 3px 12px; border-radius: 999px;
    font-size: 0.76rem; font-weight: 600; text-transform: uppercase;
    border: 1px solid currentColor;
    background: color-mix(in srgb, currentColor 14%, transparent);
    color: var(--accent-2);
}
.news-category.tournaments { color: var(--gold); }
.news-category.releases    { color: var(--game-valorant); }
.news-category.community   { color: var(--game-dota); }
.news-category.updates     { color: var(--info); }
.news-category.esports     { color: var(--game-fortnite); }

.news-title { font-size: 1.15rem; color: var(--text); }
.news-excerpt { color: var(--text-dim); font-size: 0.93rem; flex: 1; }

.news-meta { display: flex; gap: 16px; flex-wrap: wrap; color: var(--text-muted); font-size: 0.83rem; }
.meta-item { display: inline-flex; align-items: center; gap: 6px; }

.popular-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 20px;
}
.popular-card {
    position: relative;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 24px 24px 24px 64px;
}
.popular-rank {
    position: absolute; left: 20px; top: 22px;
    width: 30px; height: 30px; border-radius: 50%;
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    color: var(--on-accent);
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-head); font-weight: 700;
}
.popular-title { font-size: 1.05rem; color: var(--text); margin-bottom: 8px; }
.popular-excerpt { color: var(--text-dim); font-size: 0.9rem; margin-bottom: 12px; }
.popular-category { color: var(--accent-2); font-size: 0.8rem; font-weight: 600; text-transform: uppercase; }

/* ---------- Чат ---------- */
.chat-modes {
    display: flex;
    align-items: center;
    padding: 0 10px;
    gap: 6px;
    height: var(--chat-head);
    flex-shrink: 0;
    border-bottom: 1px solid var(--border);
}
.chat-mode {
    flex: 1;
    padding: 7px 10px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: transparent;
    color: var(--text-muted);
    font-family: var(--font-head);
    font-weight: 600;
    font-size: 0.86rem;
    cursor: pointer;
    display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.chat-mode:hover { color: var(--accent-2); border-color: var(--accent); }
.chat-mode[aria-pressed="true"] {
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
    color: var(--on-accent);
    border-color: transparent;
}
.mode-badge {
    background: var(--danger); color: #fff;
    border-radius: 999px; padding: 0 6px;
    font-size: 0.72rem; min-width: 17px; text-align: center;
}

.dialog-peer { text-align: center; }
.dialog-peer .friend-avatar-large { margin: 0 auto 12px; }
.dialog-peer-name {
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--text);
    margin-bottom: 4px;
}

.chat-unread {
    background: var(--danger); color: #fff;
    border-radius: 999px; padding: 1px 7px;
    font-size: 0.72rem; font-weight: 700;
    font-family: var(--font-head);
    flex-shrink: 0;
}
/* Чат с выключенными уведомлениями: счётчик не кричит красным, а
   рядом стоит перечёркнутый колокольчик — как в Telegram. Сообщения
   приходят по-прежнему, молча. */
.chat-unread.is-muted { background: var(--surface-3); color: var(--text-dim); }

/* День/время последнего сообщения. .chat-time-meta — у булавки (в
   правом верхнем углу плашки, та же система координат, что и у
   .chat-pin-btn: сама плашка — position: relative), .chat-time-inline —
   в общем ряду, сразу за галочками (см. ticksHtml/lastMessageMetaHtml
   в js/chat.js). */
.chat-time-meta {
    position: absolute;
    top: 6px; right: 30px;
    color: var(--text-dim);
    font-size: 0.68rem;
    white-space: nowrap;
    pointer-events: none;
}
.chat-time-inline {
    flex-shrink: 0;
    color: var(--text-dim);
    font-size: 0.7rem;
    margin-left: 4px;
}

.chat-avatar img, .chat-avatar-small img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.chat-avatar, .chat-avatar-small { overflow: hidden; font-family: var(--font-head); font-weight: 700; }

/* Чат — единственная страница, где полезно отдать под контент всю ширину:
   три колонки в узкой полосе 1200px смотрелись зажато, а по краям пустовало
   пол-экрана. Остальные страницы остаются в обычном .container. */
.container-chat {
    max-width: min(1760px, 100%);
    padding: 0 24px;
}

.chat-container {
    display: grid;
    /* Колонок объявлено две: список и переписка. Плашка собеседника
       занимает третью, но только когда открыта, — и колонка эта
       неявная (grid-auto-columns).

       Почему неявная, а не третья объявленная нулевой ширины: между
       объявленными колонками зазор ставится всегда, даже если колонка
       пустая. Справа оставалась бы мёртвая полоса в 18px. Неявной
       колонки, пока плашка скрыта, не существует вовсе — и переписке
       достаётся вся ширина до края. */
    grid-template-columns: 330px minmax(0, 1fr);
    grid-auto-flow: column;
    grid-auto-columns: 360px;
    /* Раньше 18px — колонки стояли тремя отдельными карточками с
       промежутком. По просьбе — слитная рамка, как в Telegram: зазора
       нет, снаружи одна общая рамка, а между списком/перепиской/плашкой
       собеседника — только тонкая линия-разделитель (см. .chat-list,
       .chat-window, .chat-info-panel чуть ниже: скруглены только
       внешние углы всей группы). */
    gap: 0;

    /* Высота — всё оставшееся место: экран минус шапка и оба отступа
       .main-content (34px сверху, 20px снизу).

       Шапка берётся переменной, а не числом. Числом (84px) она была
       верна ровно при одном сочетании шрифта, масштаба и ширины окна:
       стоило поставить в браузере масштаб 110%, и шапка становилась
       выше, а вычиталось всё равно 84 — поле ввода чата уезжало под
       нижний край. Настоящую высоту меряет trackHeaderHeight() в
       js/layout.js; 84px здесь остаётся запасным значением на случай,
       если скрипт почему-то не отработал.

       dvh вместо vh: на телефоне vh считается по экрану БЕЗ адресной
       строки, и пока она видна, низ страницы за краем. */
    height: calc(100dvh - var(--site-header-h, 84px) - 34px - 10px);
    /* Потолка высоты здесь тоже больше нет. max-height: 1080px держался
       из соображения «слишком длинные плашки некрасивы», но на высоком
       мониторе именно он и оставлял внизу пустое поле в две-три сотни
       пикселей: плашки упирались в 1080 и дальше не росли. Теперь низ
       всегда в 10px от края окна, какой бы высоты оно ни было. */
    /* Нижней границы больше нет. min-height: 620px на невысоком окне
       требовал места больше, чем есть, — и возвращал ту же прокрутку,
       ради устранения которой всё и считается. */
    min-height: 0;

    /* Верхние части всех трёх колонок заканчиваются на одной высоте.
       Слева это переключатель режимов плюс поиск, в центре и справа —
       шапка панели. Меняется в одном месте. Раньше было 112px, потом
       76px — и всё равно оставался лишний воздух: две строки текста и
       аватар занимают меньше. Теперь 62px, ровно под содержимое. */
    --chat-head: 62px;
}

.chat-list, .chat-window, .chat-info-panel {
    background: var(--surface-2);
    border: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* Скруглены только внешние углы всей группы — список слева, а справа
   переписка (или плашка собеседника, когда она открыта): общая рамка
   вместо трёх отдельных карточек. Линия между соседями — одинарная:
   у левого соседа правая грань снята, у правого остаётся своя. */
.chat-list { border-top-left-radius: var(--radius-lg); border-bottom-left-radius: var(--radius-lg); border-right: none; }
.chat-window { border-top-right-radius: var(--radius-lg); border-bottom-right-radius: var(--radius-lg); }
.chat-container:has(.chat-info-panel.is-open) .chat-window {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
    border-right: none;
}
.chat-info-panel.is-open { border-top-right-radius: var(--radius-lg); border-bottom-right-radius: var(--radius-lg); }

.chat-panel-header {
    padding: 8px 14px;
    height: var(--chat-head);
    flex-shrink: 0;
    box-sizing: border-box;
    border-bottom: 1px solid var(--border);
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
}
.chat-panel-header h3 { font-size: 1.05rem; color: var(--text); }

.chat-search {
    display: flex; align-items: center;
    gap: 8px;
    padding: 0 12px;
    height: var(--chat-head);
    flex-shrink: 0;
    border-bottom: 1px solid var(--border);
}
.chat-search input {
    flex: 1; min-width: 0;
    padding: 9px 12px;
    background: var(--surface-soft); border: 1px solid var(--border);
    border-radius: var(--radius-sm); color: var(--text); font-family: var(--font-body);
}
.chat-search input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.chat-search i { color: var(--text-dim); font-size: 0.9rem; flex-shrink: 0; }
.chat-search .btn-icon { flex: 0 0 auto; width: 34px; height: 34px; border-radius: var(--radius-sm); }

/* Прокрутка колесом и с тачпада работает как раньше. */
/* ---------- Завести новый чат ----------
   Появляется вместе с поиском, тремя одинаковыми кнопками в строку.
   Не «Создать» внизу списка, как раньше: та кнопка была видна только в
   режиме комнат, а личный чат со страницы чатов начать было нечем. */
.chat-new-row {
    display: flex;
    /* С переносом: на узкой колонке (на планшете список сужается до
       240px) три подписи в строку не помещались и обрезались на
       полуслове. Лучше вторая строка, чем «Личный ч…». */
    flex-wrap: wrap;
    gap: 6px;
    padding: 8px 10px;
    flex-shrink: 0;
    border-bottom: 1px solid var(--border);
}
.chat-new-btn {
    flex: 1 1 92px; min-width: 0;
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    padding: 7px 6px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-muted);
    font-family: var(--font-head);
    font-weight: 600;
    font-size: 0.78rem;
    white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis;
    cursor: pointer;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.chat-new-btn:hover {
    background: var(--accent-soft);
    color: var(--accent-2);
    border-color: var(--accent);
}
.chat-new-btn i { font-size: 0.8rem; }

.chat-items {
    overflow-y: auto;
    flex: 1;
    /* Без боковых отступов: плашки идут от края до края, как в
       мессенджерах. Отступ по краям вместе со скруглением превращал
       список в набор отдельных карточек, а это один список. */
    padding: 0;
    display: flex; flex-direction: column; gap: 0;


    overscroll-behavior: contain;
}
/* Буст Чатов, super_rare — свой фон списка (js/chat.js,
   applyListBoosterBg()). Список длиннее экрана и скроллится, поэтому
   вуаль на самом .chat-items (как у .watch-chat.has-custom-chatbg,
   который весь помещается на экране) не годится — она проскроллила бы
   вместе с содержимым и ниже первого экрана фон остался бы непрочитан.
   Вместо этого — своя полупрозрачная подложка у каждой плашки: она
   двигается вместе со своей строкой при любой прокрутке. */
.chat-items.has-custom-listbg { background-size: cover; background-position: center; }
.chat-items.has-custom-listbg .chat-item { background: rgba(6, 6, 26, 0.45); }
.chat-items.has-custom-listbg .chat-item:hover { background: rgba(6, 6, 26, 0.6); }
.chat-items.has-custom-listbg .chat-item[aria-selected="true"],
.chat-items.has-custom-listbg .chat-item.is-pinned[aria-selected="true"] {
    background: var(--accent-soft);
}
.chat-items.has-custom-listbg .chat-item.is-pinned { background: rgba(6, 6, 26, 0.6); }
/* Плашка чата — от края до края и без скругления, как в мессенджерах.
   Выше прежней примерно в полтора раза: аватар 45px вместо 30px и
   свободнее поля. По такому списку проще попадать и глазом, и пальцем. */
.chat-item {
    display: flex; align-items: center; gap: 14px;
    /* Булавка теперь приколота к верхнему углу плашки, а не стоит в
       ряду — значит плашке нужна своя система координат. */
    position: relative;
    padding: 10px 16px;
    border-radius: 0;
    cursor: pointer;
    /* Рамки нет: выбранную плашку отмечаем полосой слева, а не
       контуром. Контур на плашке во всю ширину читается как ещё одна
       линия списка. */
    border: 0;
    border-left: 3px solid transparent;
    background: transparent; width: 100%; text-align: left;
    font-family: var(--font-body); color: inherit;
    transition: background var(--transition), border-color var(--transition);
}
.chat-item:hover { background: var(--accent-soft); }
.chat-item[aria-selected="true"] {
    background: var(--accent-soft);
    border-left-color: var(--accent);
}
.chat-item.is-pinned { background: var(--surface-soft); }
.chat-item.is-pinned[aria-selected="true"] { background: var(--accent-soft); }

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

   У обычного чата булавка проявляется по наведению, у закреплённого
   стоит всегда — как и было. */
.chat-pin-btn {
    position: absolute;
    top: 4px; right: 6px;
    width: 20px; height: 20px;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    color: var(--text-dim);
    font-size: 0.62rem;
    opacity: 0;
    transition: opacity var(--transition), color var(--transition), background var(--transition);
}
.chat-item:hover .chat-pin-btn,
.chat-item:focus-within .chat-pin-btn,
.chat-pin-btn.is-active { opacity: 1; }
.chat-pin-btn:hover { color: var(--accent-2); background: var(--surface-2); }
.chat-pin-btn.is-active { color: var(--accent); }
@media (hover: none) { .chat-pin-btn { opacity: 1; } }

/* Галочки: дошло / прочитано. Показываются только на своём последнем
   сообщении — у чужого их смысла нет, там вместо них счётчик
   непрочитанного. Две галочки внахлёст, как везде: одна значит
   «отправлено», две — «прочитано», и цветом тоже. */
.chat-ticks {
    flex-shrink: 0;
    display: flex; align-items: center;
    color: var(--text-dim);
    font-size: 0.72rem;
    line-height: 1;
}
.chat-ticks.is-read { color: var(--accent-2); }
.chat-ticks i + i { margin-left: -5px; }

.chat-avatar {
    /* В полтора раза больше прежних 30px — вместе со всей плашкой. */
    width: 45px; height: 45px; border-radius: 50%;
    background: var(--accent-soft); color: var(--accent-2);
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
    font-size: 1.05rem;
}
/* Аватар в шапке чата: крупнее, чем в списке, но не в ущерб высоте
   самой шапки — она ужалась до 62px, и 54px аватар туда уже не влезал
   вместе с отступами. */
.chat-avatar-small {
    width: 46px; height: 46px; border-radius: 50%;
    background: var(--accent-soft); color: var(--accent-2);
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0; font-size: 1.05rem;
}

.chat-info { min-width: 0; flex: 1; }
.chat-info h4 {
    font-size: 1.02rem; line-height: 1.3; color: var(--text); margin-bottom: 2px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* text-overflow работает только на блочных/inline-block элементах —
   на голом <span> (inline по умолчанию) он молча ничего не делает,
   и длинный текст просто вылезал за пределы плашки без «…». */
.chat-last-message {
    display: block; line-height: 1.3;
    color: var(--text-dim); font-size: 0.87rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Ник — ровно по середине аватарки. Титул из шапки убран: он и так
   есть в плашке собеседника, а здесь занимал вторую строку и сдвигал
   ник выше центра. */
.chat-title { display: flex; align-items: center; gap: 12px; min-width: 0; }
.chat-title > div { display: flex; flex-direction: column; justify-content: center; }
.chat-title .peer-name { font-size: 1.06rem; line-height: 1.25; }
/* Внутренняя колонка с ником, титулом и «в сети» тоже должна уметь
   сжиматься — иначе на телефоне длинный ник выпихивает шапку за экран. */
.chat-title > div { min-width: 0; }
.chat-title h3 {
    font-size: 1.05rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Ник, титул и «в сети» — каждый в одну строку с многоточием. Правило
   по всем детям колонки, а не по трём именам классов: разметка шапки
   для комнаты и для лички разная, а вести себя должна одинаково. */
.chat-title > div > * {
    max-width: 100%;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-status { color: var(--text-dim); font-size: 0.83rem; }
.chat-actions { display: flex; gap: 6px; }
.chat-actions [data-chat-action="pins"] { position: relative; }
.chat-actions [data-chat-action="settings"][aria-expanded="true"] {
    background: var(--accent-soft); color: var(--accent-2);
}

/* ---------- Настройки чата: панель у кнопки «⋮» ----------
   Раньше «⋮» открывал полноэкранную модалку. Теперь ведёт себя так же,
   как «⋮» в шапке сайта (см. .header-more-panel) — узкая панель рядом
   с кнопкой, а не оверлей на весь экран. Панель — прямой потомок
   <body> (см. js/chat-panels.js toggleSettings/positionMorePanel),
   а не шапки чата: у .chat-window стоит overflow:hidden, и абсолютно
   спозиционированную панель внутри него обрезало бы по краю окна. */
.chat-more-panel {
    position: fixed;
    z-index: 1300;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: 16px;
    overflow-y: auto;
    animation: slide-up 0.18s ease;
}
.chat-more-title {
    display: flex; align-items: center; gap: 8px;
    font-family: var(--font-head); font-weight: 700; font-size: 1rem;
    color: var(--text); margin-bottom: 12px;
}
.chat-more-title i { color: var(--accent-2); }
/* Внутри панели те же блоки, что раньше жили в .modal-body (поиск,
   обои, комната/блокировка) — своих отступов вокруг них не было,
   их давал .modal-body. Панель отступ добавляет сама (padding выше),
   поэтому только чуть поджимаем последний блок, чтобы не было лишнего
   пустого места снизу. */
.chat-more-panel > *:last-child { margin-bottom: 0; }

/* ---------- Меню настроек чата ----------
   Раньше панель была столбиком карточек с заголовком, пояснением и
   кнопкой у каждой: пять таких не помещались на экран, и до блокировки
   приходилось прокручивать. Теперь это строчки, как у колокольчика в
   шапке, — всё видно сразу. Пояснения переехали в окно подтверждения,
   которое и так открывается перед действием. */
.chat-more-panel.is-menu { padding: 10px; }
.chat-more-panel.is-menu .chat-more-title { padding: 4px 8px 8px; margin-bottom: 4px; }

.chat-menu { display: flex; flex-direction: column; }

.chat-menu-item {
    display: flex; align-items: center; gap: 12px;
    width: 100%;
    padding: 11px 10px;
    border: 0;
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--text);
    font-family: var(--font-body);
    font-size: 0.92rem;
    text-align: left;
    cursor: pointer;
    transition: background var(--transition), color var(--transition);
}
.chat-menu-item:hover, .chat-menu-item:focus-visible { background: var(--accent-soft); }
.chat-menu-item > i:first-child {
    width: 18px;
    flex-shrink: 0;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.95rem;
}
.chat-menu-item:hover > i:first-child { color: var(--accent-2); }
.chat-menu-label {
    flex: 1; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Приписка справа — имя контакта, число участников. Мелко и приглушённо:
   это уточнение к пункту, а не второй пункт. */
.chat-menu-note {
    flex-shrink: 0;
    max-width: 40%;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    color: var(--text-dim);
    font-size: 0.8rem;
}
.chat-menu-chevron { flex-shrink: 0; color: var(--text-dim); font-size: 0.72rem; }

.chat-menu-item.is-active > i:first-child { color: var(--accent-2); }
.chat-menu-item.is-danger { color: var(--danger); }
.chat-menu-item.is-danger > i:first-child { color: var(--danger); }
.chat-menu-item.is-danger:hover {
    background: color-mix(in srgb, var(--danger) 14%, transparent);
    color: var(--danger);
}

.chat-menu-sep {
    height: 1px;
    margin: 6px 10px;
    background: var(--border);
}

.chat-menu-notice {
    display: flex; align-items: flex-start; gap: 9px;
    margin: 0 4px 8px;
    padding: 9px 11px;
    border-radius: var(--radius-sm);
    background: color-mix(in srgb, var(--danger) 12%, transparent);
    color: var(--text-muted);
    font-size: 0.82rem;
}
.chat-menu-notice i { color: var(--danger); margin-top: 2px; }

/* Возврат из обоев в главное меню */
.chat-menu-back {
    display: flex; align-items: center; gap: 10px;
    width: 100%;
    padding: 6px 8px 10px;
    border: 0;
    background: transparent;
    color: var(--text);
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 1rem;
    cursor: pointer;
}
.chat-menu-back i { color: var(--accent-2); font-size: 0.85rem; }
.chat-more-panel.is-menu .wallpaper-grid { margin-bottom: 4px; }
.chat-more-panel.is-menu .form-hint { padding: 0 8px; margin-bottom: 10px; }
@media (max-width: 480px) {
    .chat-more-panel { padding: 14px; }
}
.chat-pin-count {
    position: absolute;
    top: -2px; right: -2px;
    min-width: 15px; height: 15px;
    border-radius: 999px;
    background: var(--danger);
    color: #fff;
    font-size: 0.62rem;
    font-weight: 700;
    line-height: 1;
    display: flex; align-items: center; justify-content: center;
    padding: 0 3px;
}

/* Колесо, тачпад, клавиши и перетаскивание работают как раньше.
   Низ ленты специально не останавливается над плашкой ввода — та
   снята из потока (см. .chat-input-container ниже) и лежит поверх
   стеклом, так что лента честно доезжает до самого низа окна и
   последние сообщения видны (размыто) сквозь плашку, а не обрезаны
   пустой полосой перед ней. */
.chat-messages {
    flex: 1; overflow-y: auto;
    padding: 18px;
    padding-bottom: 96px;
    display: flex; flex-direction: column; gap: 14px;


    overscroll-behavior: contain;
}
.message { display: flex; gap: 11px; max-width: 78%; }
.message.sent { margin-left: auto; flex-direction: row-reverse; }
.message.system { max-width: 100%; justify-content: center; }
.message.system .message-content {
    background: transparent; color: var(--text-dim);
    font-size: 0.85rem; text-align: center; padding: 4px 0;
}

/* Аватар в ленте: настоящая картинка, если она есть, иначе инициалы */
.message-avatar {
    width: 36px; height: 36px; border-radius: 50%;
    background: var(--accent-soft); color: var(--accent-2);
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0; font-size: 0.85rem; font-weight: 700;
    font-family: var(--font-head);
    padding: 0; border: none; cursor: pointer;
    overflow: hidden;
}
.message-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Рамка собеседника вокруг аватара — та же, что в шапке окна */
.message-avatar-frame {
    display: inline-flex;
    flex-shrink: 0;
    align-self: flex-start;
    border-radius: 50%;
    padding: 0;
}
.message-avatar-frame.has-frame { padding: 2px; }

.message-content {
    background: var(--surface-soft);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 10px 14px;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

/* Последняя строка бабла: текст слева, время справа на его уровне.
   Без текста в строке остаётся одно время и прижимается к правому краю.
   Если появились реакции, текст занимает всю ширину и уходит на свою
   строку, а чипы и время встают нижним рядом — время в любом случае
   остаётся последним элементом и держится правого нижнего угла. */
.message-line {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: flex-end;
    gap: 4px 10px;
    min-width: 0;
}
.message-line .message-time { margin-left: auto; }
.message-line:has(.message-reactions) .message-text { flex: 1 1 100%; }
.message.sent .message-content {
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    color: var(--on-accent);
    border-color: transparent;
}
.message.sent .message-sender, .message.sent .message-time { color: color-mix(in srgb, var(--on-accent) 85%, transparent); }

.message-header { display: flex; gap: 10px; align-items: baseline; margin-bottom: 4px; }
.message-sender { font-weight: 600; font-size: 0.87rem; color: var(--accent-2); }

/* Время мельче текста и не переносится */
.message-time {
    flex-shrink: 0;
    font-size: 0.68rem;
    color: var(--text-dim);
    line-height: 1.55;
    white-space: nowrap;
}
.message-text { flex: 1 1 auto; min-width: 0; }
.message-text { word-break: break-word; overflow-wrap: anywhere; }

/* Плашки-полосы больше нет вообще — ни границы, ни фона, ни
   размытия: остаются только сами кнопки и поле ввода, а обои чата
   (см. .chat-messages ниже) видны прямо сквозь этот ряд, без
   стеклянной подложки под ним. Лежит поверх ленты (см. .chat-window
   { position: relative } и .chat-messages выше), поэтому низ
   переписки всегда доходит до самого низа окна, под кнопками. */
.chat-input-container {
    display: flex; align-items: center; gap: 8px;
    padding: 12px 14px;
    border-top: none;
    position: absolute;
    left: 0; right: 0; bottom: 0;
    z-index: 3;
    background: transparent;
}
/* Поле ввода — редактируемая область, а не <input>: только так можно
   применить начертание к выделенному куску. Отсюда и подпись через
   data-атрибут вместо placeholder, и ручной запрет ввода. */
.message-input {
    flex: 1;
    min-width: 0;
    min-height: 42px;
    max-height: 140px;
    overflow-y: auto;
    padding: 11px 14px;
    background: var(--surface-soft);
    border: 1px solid var(--border);
    border-radius: 22px;
    color: var(--text);
    font-family: var(--font-body);
    font-size: 0.97rem;
    line-height: 1.35;
    word-break: break-word;

}
.message-input:empty::before {
    content: attr(data-placeholder);
    color: var(--text-dim);
    pointer-events: none;
}
.message-input.is-disabled { opacity: 0.6; cursor: not-allowed; }
.message-input code, .message-text code {
    font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
    font-size: 0.92em;
    background: rgba(127, 127, 160, 0.18);
    padding: 1px 5px;
    border-radius: 4px;
}

/* ---------- Панелька форматирования ---------- */
.format-bar {
    position: absolute;
    z-index: 30;
    display: flex;
    gap: 2px;
    padding: 4px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md, 0 8px 24px rgba(0, 0, 0, 0.35));
}
.format-btn {
    width: 30px; height: 28px;
    border: none;
    background: none;
    color: var(--text-muted);
    cursor: pointer;
    border-radius: 5px;
    font-size: 0.88rem;
    font-family: var(--font-body);
    display: flex; align-items: center; justify-content: center;
}
.format-btn:hover { background: var(--accent-soft); color: var(--accent-2); }
.format-btn.is-active { background: var(--accent-soft); color: var(--accent-2); }
.format-btn code { background: none; padding: 0; font-size: 0.82rem; }
.format-clear { color: var(--text-dim); }

/* ---------- Режим правки ---------- */
/* Полосы «Правка сообщения» над полем больше нет: она занимала целую
   строку ради одного слова и крестика. Крестик переехал в общий ряд с
   скрепкой и смайликом, а что идёт правка — видно по подсвеченному
   сообщению и по подписи в самом поле ввода. */
.composer-edit-cancel {
    color: var(--accent-2);
    background: var(--accent-soft);
}
.composer-edit-cancel:hover:not(:disabled) { color: var(--danger); }
.composer-edit-cancel[hidden] { display: none; }
.message.is-editing .message-content { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---------- Исчезновение сообщения ----------
   Как в Telegram: пузырь не пропадает рывком, а сжимается и уезжает к
   своему краю, пока соседи сходятся на освободившееся место.

   Высота анимируется отдельно от всего прочего и только потому, что
   js/chat.js перед этим проставляет ей точное значение в пикселях: от
   auto к нулю переход не считается, и сообщение исчезало бы мгновенно,
   дёргая всю ленту.

   overflow: hidden обязателен — без него содержимое торчит из
   схлопнувшейся коробки и последний кадр выглядит сломанным. */
.message.is-vanishing {
    overflow: hidden;
    pointer-events: none;
    transform-origin: left center;
    animation: messageVanish 0.24s ease-in forwards;
    transition: height 0.26s ease-in 0.08s,
                margin-top 0.26s ease-in 0.08s,
                margin-bottom 0.26s ease-in 0.08s;
}
.message.sent.is-vanishing { transform-origin: right center; }

@keyframes messageVanish {
    from { opacity: 1; transform: scale(1); }
    to   { opacity: 0; transform: scale(0.82); }
}

/* Кому анимации мешают — тому мгновенно и без движения. Это же
   условие проверяет prefersCalm() в js/chat.js, который в таком
   случае удаляет узел сразу. */
@media (prefers-reduced-motion: reduce) {
    .message.is-vanishing { animation: none; transition: none; }
}

/* Пометка о правке живёт в одной строке со временем и такая же мелкая */
.message-edited {
    flex-shrink: 0;
    font-size: 0.66rem;
    font-style: italic;
    color: var(--text-dim);
    line-height: 1.55;
    white-space: nowrap;
}
.message.sent .message-edited { color: color-mix(in srgb, var(--on-accent) 75%, transparent); }

/* Перевод сообщения — отдельной строкой под текстом, визуально как
   цитата, чтобы не путаться с оригиналом. Целиком клиентская функция
   (MyMemory API), поэтому у неё нет своего цвета «из базы» — только
   лёгкая рамка слева. */
.message-translation {
    margin-top: 4px; padding: 6px 10px;
    border-left: 2px solid var(--accent-2);
    background: var(--surface-soft);
    border-radius: 6px;
    font-size: 0.85rem; font-style: italic;
    color: var(--text-dim);
}
.message.sent .message-translation { background: color-mix(in srgb, var(--on-accent) 12%, transparent); color: color-mix(in srgb, var(--on-accent) 85%, transparent); }
.message-translation.is-loading { font-style: normal; }

/* Значок закреплённого сообщения — рядом с временем, всегда видимый
   (не только по наведению, как реакции/правка), чтобы было заметно в ленте.
   Внутри только иконка без текста — как флекс-элемент строки она без
   собственных width/height схлопнулась бы в 0×0, если шрифт иконок
   не успел или не смог загрузиться, поэтому размер задан явно. */
.message-pinned-mark {
    flex-shrink: 0;
    width: 12px; height: 12px;
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--accent-2);
    font-size: 0.72rem;
}
.message.sent .message-pinned-mark { color: color-mix(in srgb, var(--on-accent) 85%, transparent); }
.message-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.message-input:disabled { opacity: 0.6; cursor: not-allowed; }

.send-btn {
    width: 42px; height: 42px; border-radius: 50%; border: none;
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    color: var(--on-accent); cursor: pointer; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    transition: transform var(--transition), opacity var(--transition);
}
.send-btn:hover:not(:disabled) { transform: scale(1.06); }
.send-btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* Мифический буст Чатов — свой символ на кнопке отправки вместо иконки
   самолётика (js/chat.js, updateComposer()). Эмодзи крупнее одиночного
   символа/буквы, поэтому размер шрифта чуть меньше — оба варианта
   должны помещаться в те же 42px кружка, не обрезаясь. */
.send-btn-symbol { font-size: 1.1rem; line-height: 1; }

/* Плашка собеседника стоит в ряду, третьей колонкой, и появляется
   только по кнопке в шапке. Пока её нет — её нет и в сетке, и вся
   ширина у переписки.

   Не поверх чата, а рядом: так было до того, как плашку научили
   прятаться, и ничего, кроме появления, меняться не должно. */
.chat-info-panel {
    /* position: relative — без него у крестика (.chat-info-close,
       position: absolute; top/right) не было своей точки отсчёта на
       широком экране: плашка становится position:absolute только на
       узком (см. .chat-info-panel.is-open ниже, в медиа-запросе до
       1024px), а на десктопе — обычная колонка грида без position
       вовсе. Крестик в этом случае искал ближайшего позиционированного
       предка где-то выше по DOM и оказывался чёрт знает где — снаружи
       самой плашки, а то и вовсе за пределами экрана. */
    position: relative;
    padding: 0;
    overflow-y: auto;
    display: none;
}
.chat-info-panel.is-open {
    display: flex;
    animation: chatInfoIn 0.22s ease-out;
}
@keyframes chatInfoIn {
    from { transform: translateX(22px); opacity: 0; }
    to   { transform: translateX(0);    opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .chat-info-panel.is-open { animation: none; }
}
.chat-actions .btn-icon.is-active { background: var(--accent-soft); color: var(--accent-2); }
.info-section { padding: 16px; border-bottom: 1px solid var(--border); }
.info-section h4 { font-size: 0.92rem; color: var(--text-muted); margin-bottom: 10px; text-transform: uppercase; letter-spacing: 0.03em; }
.chat-description { color: var(--text-dim); font-size: 0.89rem; }
.members-list { display: flex; flex-direction: column; gap: 10px; }
.member { display: flex; align-items: center; gap: 10px; }
.member-avatar {
    position: relative; width: 32px; height: 32px; border-radius: 50%;
    background: var(--accent-soft); color: var(--accent-2);
    display: flex; align-items: center; justify-content: center; font-size: 0.78rem;
    font-family: var(--font-head); font-weight: 700; flex-shrink: 0;
}
.member-name { color: var(--text-muted); font-size: 0.9rem; }
.actions-list { display: flex; flex-direction: column; gap: 9px; }

.chat-login-notice {
    padding: 12px 14px;
    background: var(--accent-soft);
    color: var(--text-muted);
    font-size: 0.88rem;
    text-align: center;
    border-top: 1px solid var(--border);
}

/* ---------- Профиль ---------- */
.profile-section {
    background: var(--surface-2);
    border-radius: var(--radius-xl);
    padding: 28px;
    margin-bottom: 28px;
    border: 1px solid var(--border);
    box-shadow: var(--shadow-sm);
}

/* Аватар и «личность» (ник, юзернейм, титул) стоят в одной строке.
   Описание, кнопки и статистика ушли под них во всю ширину карточки.
   align-items: flex-start — аватар выравнивается по верхнему краю ника;
   её собственную высоту (и ширину, вровень — см. .profile-avatar-frame)
   держит не CSS, а js/utils.js (watchAvatarFrameHeight): чистым flexbox
   (align-self: stretch + aspect-ratio) сделать это надёжно не вышло —
   высота через aspect-ratio зависит от ширины, а ширина элемента в
   раскладке flex, в свою очередь, зависела от высоты, и по кругу браузер
   считал не то — аватар получался не квадратным. JS просто меряет высоту
   соседней колонки и ставит аватарке те же px и в ширину, и в высоту. */
/* Баннер/обложка профиля — необязательная широкая картинка над шапкой,
   как в ВК/Twitch (supabase/profile_banner.sql). Своя и чужая страница
   профиля используют один и тот же класс (см. комментарий у
   .profile-header ниже про обе страницы). */
.profile-banner {
    height: 180px;
    margin: -28px -28px 20px;
    border-radius: var(--radius-xl) var(--radius-xl) 0 0;
    background-size: cover;
    background-position: center;
    /* Пока человек не загрузил свою картинку (banner_url пуст), показываем
       не пустой прямоугольник, а фирменный градиент «Мятный кибер» — так
       профиль без баннера всё равно выглядит нарядно. Свою картинку
       js/profile.js кладёт инлайновым style="background-image", он и
       перекрывает градиент ниже — сам правило трогать для этого не нужно. */
    background-image: linear-gradient(120deg, #29e0c4 0%, #6c63ff 55%, #b46bff 100%);
    background-color: var(--surface-soft);
}

.profile-header {
    display: flex;
    align-items: flex-start;
    gap: 24px;
    margin-bottom: 20px;
}
.profile-identity { flex: 1; min-width: 0; }
.profile-identity .profile-rank { margin-bottom: 0; }

/* Аватар в профиле — главное, что человек видит на своей странице.
   186×186 здесь — то же самое «полный размер», что было раньше, и
   запасной вариант на случай, если JS ещё не отработал (см. выше);
   сам актуальный размер приходит инлайн-стилем на .profile-avatar-frame. */
.profile-avatar {
    width: 100%; height: 100%;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    display: flex; align-items: center; justify-content: center;
    font-size: 34cqh; color: var(--on-accent);
    border: 4px solid var(--accent-2);
    flex-shrink: 0; overflow: hidden;
    font-family: var(--font-head); font-weight: 700;
}
.profile-avatar img { width: 100%; height: 100%; object-fit: cover; }

.profile-identity h2 { font-size: 1.8rem; color: var(--text); margin-bottom: 8px; word-break: break-word; }

/* Юзернейм — не мелкая подпись: по нему добавляют в друзья,
   поэтому он должен читаться с первого взгляда. */
.profile-username {
    /* block + max-content: плашка занимает свою строку, но по ширине
       обжимает текст, а не растягивается на всю колонку */
    display: block;
    width: max-content;
    max-width: 100%;
    margin-bottom: 12px;
    padding: 3px 12px;
    border-radius: 999px;
    background: var(--accent-soft);
    border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
    color: var(--accent-2);
    font-family: var(--font-head);
    font-weight: 600;
    font-size: 1rem;
    letter-spacing: 0.01em;
}
.profile-username:empty { display: none; }

.profile-rank {
    display: inline-flex; align-items: center; gap: 8px;
    background: var(--accent-soft);
    padding: 6px 14px; border-radius: 999px;
    margin-bottom: 14px;
}
.profile-rank i, .profile-rank span { color: var(--rank-color, var(--gold)); font-weight: 600; }

.profile-bio {
    color: var(--text-muted); font-size: 1rem;
    margin-bottom: 18px; padding: 14px;
    background: var(--surface-soft);
    border-radius: var(--radius-md);
    border-left: 3px solid var(--accent);
    word-break: break-word;
}

.profile-actions {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 26px;   /* воздух между кнопками и карточками статистики */
}

.profile-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 18px;
}

.stat-card {
    background: var(--surface-3);
    padding: 22px;
    border-radius: var(--radius-md);
    text-align: center;
    border: 1px solid var(--border);
    transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
}
.stat-card.is-clickable { cursor: pointer; }
.stat-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-sm); border-color: var(--accent); }

.stat-icon {
    width: 42px; height: 42px; margin: 0 auto 12px;
    border-radius: 50%; background: var(--accent-soft);
    display: flex; align-items: center; justify-content: center;
    font-size: 1.15rem; color: var(--accent-2);
}
.stat-value { font-family: var(--font-head); font-size: 1.7rem; font-weight: 700; color: var(--accent-2); margin-bottom: 4px; }
.stat-label { color: var(--text-muted); font-size: 0.9rem; }
.balance-stat .stat-value { color: var(--success); }

/* ---------- Вкладка «Статистика» (js/profile-stats.js) ----------
   Плашки — те же .profile-stats/.stat-card, что наверху профиля.
   Своё здесь — только заголовки секций («Игрок»/«Креатор») и список
   мест в сезонных рейтингах (не плашки: там подпись длиннее одного
   слова, в сетке она бы обрезалась). */
.stats-section-title {
    font-size: 1.05rem;
    color: var(--text);
    margin: 28px 0 14px;
}
.stats-section-title:first-child { margin-top: 0; }

.stats-board-title {
    font-size: 1.05rem;
    color: var(--text);
    margin: 28px 0 14px;
}

.stats-board-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.stats-board-row {
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 12px 16px;
    font-size: 0.92rem;
}
.stats-board-place { font-weight: 700; color: var(--accent-2); }
.stats-board-place.is-empty { color: var(--text-dim); font-weight: 400; }

/* Аватар: клик открывает выбор файла */
.profile-avatar {
    cursor: pointer; position: relative;
    transition: box-shadow var(--transition-fast);
}
.profile-avatar:hover { box-shadow: 0 0 0 4px var(--accent-ring); }
.profile-avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar-initials { font-family: var(--font-head); font-weight: 700; line-height: 1; }

.avatar-overlay {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    background: rgba(0, 0, 0, 0.5);
    color: #fff; font-size: 1.5rem;
    opacity: 0;
    transition: opacity var(--transition);
}
.profile-avatar:hover .avatar-overlay,
.profile-avatar:focus-visible .avatar-overlay { opacity: 1; }

.profile-avatar.is-uploading { pointer-events: none; }
.profile-avatar.is-uploading .avatar-overlay { opacity: 1; }
.profile-avatar.is-uploading .avatar-overlay i { display: none; }
.profile-avatar.is-uploading .avatar-overlay::after {
    content: '';
    width: 28px; height: 28px;
    border: 3px solid rgba(255, 255, 255, 0.45);
    border-top-color: #fff;
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

/* Поле выбора аватара в формах */
.avatar-field {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
}

.avatar-field-preview {
    width: 84px; height: 84px;
    flex-shrink: 0;
    padding: 0;
    border-radius: 50%;
    border: 2px solid var(--border);
    background: var(--surface-soft);
    color: var(--accent-2);
    font-size: 1.7rem;
    cursor: pointer;
    overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    transition: border-color var(--transition), transform var(--transition);
}
.avatar-field-preview:hover { border-color: var(--accent); transform: scale(1.04); }
.avatar-field-preview img { width: 100%; height: 100%; object-fit: cover; }
/* Та же форма, что выбрана в «Форме аватарки» ниже. */
.avatar-field-preview.is-square { border-radius: var(--radius-md, 12px); }

/* Эло и ранг в карточке Brawl Stars (js/brawl-card.js). */
.brawl-pill-rank { color: var(--rank-color, var(--accent-2)); }
.brawl-pill-rank i { color: inherit; }
.brawl-panel-rank { border-color: color-mix(in srgb, var(--rank-color, var(--accent)) 45%, transparent); }
.brawl-panel-rank .brawl-panel-name { color: var(--rank-color, var(--text)); }
.brawl-rank-badge { width: 64px; height: 72px; display: block; margin: 4px auto 6px; }
/* Настоящая иконка лиги (js/brawl-card.js, LEAGUE_CDN) поверх которой
   рисуем номер дивизиона — щит выше показывается только запасным
   вариантом, если картинка с CDN не загрузилась. */
.brawl-rank-visual {
    position: relative;
    width: 64px;
    height: 72px;
    display: block;
    margin: 4px auto 6px;
}
.brawl-rank-icon { width: 100%; height: 100%; object-fit: contain; display: block; }
.brawl-rank-tier {
    position: absolute;
    left: 50%;
    bottom: 3px;
    transform: translateX(-50%);
    color: #fff;
    font-size: 1.05rem;
    font-weight: 800;
    line-height: 1;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7), 0 0 6px rgba(0, 0, 0, 0.45);
}
.brawl-elo-group { margin-top: 14px; }
.form-optional { color: var(--text-muted); font-weight: 400; font-size: 0.85rem; }

.avatar-field-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.avatar-field .form-hint { flex-basis: 100%; margin-top: 0; }

/* Форма аватарки — без собственного заголовка и разделителя: раньше
   строка-разделитель нарочно отделяла «выбрать файл» от «форма», из-за
   чего блок читался как два разных пункта настроек. Теперь это просто
   следующая строка того же блока «Аватар» (см. avatarFieldMarkup() в
   js/profile.js и DP.avatarShape.renderPicker в js/avatar-shape.js). */
.avatar-field .avatar-shape-mount {
    flex-basis: 100%;
    margin-top: 4px;
}

/* Баннер профиля в «Настройках» — тот же формат блока, что у аватара,
   только превью широкое, не круглое. */
.banner-field {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
}
.banner-field-preview {
    width: 160px; height: 64px;
    flex-shrink: 0;
    border-radius: var(--radius-sm);
    border: 2px solid var(--border);
    /* Тот же дефолтный градиент, что и у самого баннера (.profile-banner
       выше) — своя картинка приходит инлайновым style и перекрывает его. */
    background-image: linear-gradient(120deg, #29e0c4 0%, #6c63ff 55%, #b46bff 100%);
    background-color: var(--surface-soft);
    background-size: cover;
    background-position: center;
    color: rgba(255, 255, 255, 0.85);
    font-size: 1.4rem;
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
}
.banner-field-preview:hover { border-color: var(--accent); }
.banner-field-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.banner-field .form-hint { flex-basis: 100%; margin-top: 0; }
.banner-field-hide {
    display: inline-flex; align-items: center; gap: 6px;
    margin-left: 4px;
    color: var(--text-muted);
    font-size: var(--text-sm);
    cursor: pointer;
    user-select: none;
}
.banner-field-hide input { accent-color: var(--accent); cursor: pointer; }

/* Выбор обложки при создании поста (js/posts.js openComposer) */
.post-cover-picker { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.post-cover-preview {
    width: 100%;
    height: 140px;
    border-radius: var(--radius-sm);
    border: 2px solid var(--border);
    background-color: var(--surface-soft);
    background-size: cover;
    background-position: center;
}
.post-cover-picker[data-empty="1"] .post-cover-preview { display: none; }

/* Вкладки */
.profile-tabs {
    background: var(--surface-2);
    border-radius: var(--radius-xl);
    overflow: hidden;
    border: 1px solid var(--border);
}

/* Полоса вкладок — главная навигация по профилю, поэтому она
   выделена сильнее остальных плашек: своя подложка, рамка и тень. */
.tabs-nav {
    display: flex;
    background: var(--surface);
    border: 1px solid var(--border);
    border-bottom: 2px solid var(--accent);
    box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.tab-btn {
    padding: 14px 22px;
    background: none; border: none;
    color: var(--text-muted);
    font-family: var(--font-head); font-weight: 600;
    font-size: var(--text-sm);
    cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast), transform var(--transition-fast);
    white-space: nowrap;
    border-right: 1px solid var(--border);
    /* Растягиваться можно, сжиматься — нет: в админке вкладок стало
       одиннадцать, и при сжатии подписи наезжали друг на друга
       («Приём платежейРасписания»). Полоса вкладок и так умеет
       прокручиваться вбок — см. .tabs-nav, overflow-x: auto. */
    flex: 1 0 auto; min-width: 120px;
}
.tab-btn:hover { color: var(--accent-2); background: var(--accent-soft); }
.tab-btn:active { transform: scale(0.97); }
.tab-btn[aria-selected="true"] {
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
    color: var(--on-accent);
    box-shadow: 0 3px 14px color-mix(in srgb, var(--accent) 55%, transparent);
}

.tabs-content { padding: 26px; }
.tab-pane[hidden] { display: none; }
.tab-pane { animation: fade-in 0.3s ease; }
.tab-pane > h3 { margin-bottom: 20px; color: var(--text); }

.friend-avatar {
    position: relative; width: 46px; height: 46px; border-radius: 50%;
    background: var(--accent-soft); color: var(--accent-2);
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0; font-family: var(--font-head); font-weight: 700;
}

/* Достижения */
.achievements-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 18px;
}
.achievement-card {
    background: var(--surface-3);
    padding: 22px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    text-align: center;
    transition: transform var(--transition), box-shadow var(--transition);
}
.achievement-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-sm); }
.achievement-card.unlocked { border-color: var(--accent); }
.achievement-card.locked { opacity: 0.65; }
.achievement-icon { font-size: 2.4rem; color: var(--accent-2); margin-bottom: 12px; }
.achievement-card.locked .achievement-icon { color: var(--text-dim); }
.achievement-card h4 { color: var(--text); margin-bottom: 8px; font-size: 1.1rem; }
.achievement-card p { color: var(--text-dim); font-size: 0.88rem; margin-bottom: 8px; }
.achievement-date { color: var(--text-muted); font-size: 0.82rem; font-weight: 500; }
.achievement-progress { color: var(--warning); font-size: 0.82rem; font-weight: 500; }

/* ---------- Индивидуальные титулы ---------- */
.profile-rank.is-special {
    background: linear-gradient(135deg, color-mix(in srgb, var(--gold) 22%, transparent) 0%,
                                        color-mix(in srgb, var(--accent) 22%, transparent) 100%);
    border: 1px solid color-mix(in srgb, var(--gold) 55%, transparent);
}
.profile-rank.is-special i,
.profile-rank.is-special > span:first-of-type { color: var(--gold); }

.special-titles {
    background: var(--surface-3);
    border: 1px solid color-mix(in srgb, var(--gold) 40%, var(--border));
    border-radius: var(--radius-lg);
    padding: 18px 20px;
    margin-bottom: 22px;
}
.special-titles-head {
    font-size: 1rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 14px;
}
.special-titles-list { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 12px; min-width: 0; }

/* Титулы выдаёт только администрация, поэтому по умолчанию они золотые —
   --title-tint без явного класса редкости равен var(--gold). Редкость не
   подписывается текстом, а красит саму пилюлю: фон, окантовку и иконку. */
.special-title {
    --title-tint: var(--gold);
    display: inline-flex;
    align-items: center;
    /* Пилюля переносит своё содержимое и не вылезает за плашку: на телефоне
       «Основатель платформы · с 22 августа 2026 г. · В ШАПКЕ» в одну строку
       не помещается, и метка справа обрезалась по краю карточки. */
    flex-wrap: wrap;
    max-width: 100%;
    gap: 9px;
    padding: 9px 16px;
    border-radius: 999px;
    background: linear-gradient(135deg, color-mix(in srgb, var(--title-tint) 20%, transparent) 0%,
                                        color-mix(in srgb, var(--accent) 20%, transparent) 100%);
    border: 1px solid color-mix(in srgb, var(--title-tint) 55%, transparent);
    transition: border-color var(--transition), background var(--transition);
}
.special-title.is-main { box-shadow: 0 0 0 1px color-mix(in srgb, var(--title-tint) 45%, transparent); }
.special-title i { color: var(--title-tint); }

/* legendary/premium/seasonal не перечислены — все они золотые, как и дефолт. */
.special-title.rarity-common     { --title-tint: var(--text-dim); }
.special-title.rarity-rare       { --title-tint: var(--success); }
.special-title.rarity-super_rare { --title-tint: var(--info); }
.special-title.rarity-epic       { --title-tint: var(--game-fortnite); }
.special-title.rarity-mythical   { --title-tint: var(--danger); }

.special-title-badge {
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--gold);
    background: color-mix(in srgb, var(--gold) 18%, transparent);
    padding: 2px 8px;
    border-radius: 999px;
}
.special-title-badge-second { color: var(--text-dim); background: var(--surface-soft); }
.special-title-name {
    font-family: var(--font-head); font-weight: 700; color: var(--text);
    min-width: 0; overflow-wrap: anywhere;
}
.special-title-date { color: var(--text-dim); font-size: 0.82rem; }

/* Стрелки ручного порядка: какой титул считать первым (в шапке), а какой вторым */
.special-title-order { display: inline-flex; flex-direction: column; gap: 2px; margin-left: 2px; }
.special-title-order-btn {
    width: 18px; height: 14px;
    display: flex; align-items: center; justify-content: center;
    border: none; border-radius: 4px;
    background: transparent; color: var(--text-dim);
    font-size: 0.62rem; cursor: pointer;
    transition: background var(--transition), color var(--transition);
}
.special-title-order-btn:hover:not(:disabled) { background: var(--surface-2); color: var(--accent-2); }
.special-title-order-btn:disabled { opacity: 0.3; cursor: default; }

/* Пометка «за уровень» в инвентаре — отличает открытые уровнями титулы
   от золотых, выданных администрацией (у тех такой пометки нет). */
.special-title-source {
    font-size: 0.72rem;
    color: var(--text-dim);
    background: color-mix(in srgb, var(--title-tint) 16%, transparent);
    padding: 2px 8px;
    border-radius: 999px;
}

/* Витрина титулов Brawl Stars — навсегда залоченные, без взаимодействия */
.special-title.is-locked-title {
    --title-tint: var(--text-dim);
    opacity: 0.6;
    cursor: default;
    filter: grayscale(0.4);
}
.special-title.is-locked-title:hover { border-color: color-mix(in srgb, var(--title-tint) 55%, transparent); }

.inv-subhead {
    margin: 22px 0 6px;
    font-size: 1.05rem;
    color: var(--text);
}

/* Обёртка личного титула + кнопка «поставить вторым» рядом (Premium) */
.title-choice-wrap { display: inline-flex; align-items: center; gap: 4px; }
.title-second-btn {
    width: 30px; height: 30px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-dim);
    cursor: pointer;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.title-second-btn:hover { border-color: var(--gold); color: var(--gold); }
.title-second-btn.is-second { background: color-mix(in srgb, var(--gold) 20%, transparent); border-color: var(--gold); color: var(--gold); }
.title-second-btn.is-locked { cursor: pointer; opacity: 0.55; }
.title-second-btn.is-locked:hover { border-color: var(--border); color: var(--text-dim); }

/* ---------- Финальное достижение ---------- */
.crown-card {
    border-radius: var(--radius-lg);
    padding: 20px;
    margin-bottom: 22px;
    border: 1px solid var(--border);
    background: var(--surface-3);
}
.crown-card.unlocked {
    border-color: color-mix(in srgb, var(--gold) 60%, transparent);
    background: linear-gradient(135deg, color-mix(in srgb, var(--gold) 14%, var(--surface-3)) 0%,
                                        color-mix(in srgb, var(--accent) 16%, var(--surface-3)) 100%);
}

.crown-head { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }

.crown-icon {
    width: 50px; height: 50px; flex-shrink: 0;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.3rem;
    background: var(--surface-soft);
    color: var(--text-dim);
    border: 1px solid var(--border);
}
.crown-card.unlocked .crown-icon {
    background: linear-gradient(135deg, var(--gold) 0%, var(--accent-2) 100%);
    color: #1e1e38;
    border-color: transparent;
}

.crown-title { flex: 1; min-width: 0; }
/* Длинное название рвём по буквам, а не выпихиваем за карточку:
   в колонке 91px «Король платформы» иначе торчал наружу. */
.crown-title h4 { color: var(--text); font-size: 1.2rem; margin-bottom: 3px; overflow-wrap: anywhere; }
/* «100 000 ₽» пишется с неразрывными пробелами и в колонку 153px целиком
   не влезает — разрешаем перенос внутри строки награды. */
.crown-reward, .crown-reward strong { overflow-wrap: anywhere; min-width: 0; }
.crown-title p { color: var(--text-muted); font-size: 0.9rem; }

.crown-state {
    font-family: var(--font-head); font-weight: 700;
    padding: 6px 14px; border-radius: 999px;
    background: var(--surface-soft); color: var(--text-muted);
    white-space: nowrap;
}
.crown-card.unlocked .crown-state {
    background: color-mix(in srgb, var(--gold) 25%, transparent);
    color: var(--gold);
}

.crown-parts {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 10px;
    margin-top: 16px;
}
.crown-part {
    display: flex; align-items: center; gap: 9px;
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    background: var(--surface-soft);
    border: 1px solid transparent;
    color: var(--text-muted);
    font-size: 0.9rem;
}
.crown-part.done { border-color: color-mix(in srgb, var(--success) 45%, transparent); color: var(--text); }
.crown-part-name { flex: 1; min-width: 0; }
.crown-part-level { font-family: var(--font-head); font-weight: 700; color: var(--accent-2); }
.crown-part-mark { color: var(--text-dim); }
.crown-part.done .crown-part-mark { color: var(--success); }

/* ---------- Направления и уровни ---------- */
.tracks-lead { color: var(--text-dim); margin-bottom: 22px; max-width: 720px; }

/* Две группы: «для игроков» открыта сразу, «для криэйторов» — только
   после того как в первой набрано достаточно уровней (см. .tracks-locked
   ниже). Заголовок группы — обычный <h4>, не аккордеон: обе группы видно
   одновременно, просто у одной вместо карточек — плашка с условием. */
.tracks-group + .tracks-group { margin-top: 28px; }

.tracks-group-head {
    display: flex; align-items: baseline; gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}
.tracks-group-head h4 { color: var(--text); font-size: 1.45rem; }
.tracks-group-sub { color: var(--text-dim); font-size: 0.85rem; }

.tracks-grid {
    display: grid;
    /* min(320px, 100%) вместо голых 320px: на узком экране колонка иначе
       остаётся 320px шириной внутри 278px и распирает всю вкладку. */
    grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
    gap: 20px;
    align-items: stretch;
}

/* Карточка растягивается на всю высоту ряда (соседи разной длины текста
   иначе давали разную высоту плашек, см. align-items:stretch у
   .tracks-grid) — а весь её контент (шапка + полоса прогресса + список
   уровней, одним блоком, со своими межстрочными отступами как есть)
   центрируется по освободившейся высоте, а не липнет к верху с пустым
   хвостом снизу. Так «плашечки с уровнями» у короткой карточки стоят
   на таком же расстоянии от верха и низа рамки, как у самой длинной
   в ряду — та же логика, что у flex-центрирования модалок. */
.track-card { display: flex; flex-direction: column; justify-content: center; position: relative; }

/* Карточки «для криэйторов», пока группа не открыта: сами достижения и
   уровни остаются видны и читаемы целиком — просто чуть притемнены,
   с висящим замком в углу, как и было явно попрошено (в отличие от
   первой версии, где карточки на этот момент вообще не рисовались). */
.track-card.is-group-locked { opacity: 0.6; }
.track-card-lock {
    width: 26px; height: 26px; flex-shrink: 0;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--surface-soft);
    border: 1px solid var(--border);
    color: var(--text-dim);
    font-size: 0.8rem;
}

.tracks-group-lock-note {
    display: flex; align-items: center; gap: 8px;
    color: var(--text-dim); font-size: 0.85rem;
    margin-bottom: 14px;
}

.track-card {
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 20px;
}

.track-head { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }

.track-icon {
    width: 46px; height: 46px; flex-shrink: 0;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    color: var(--on-accent);
    display: flex; align-items: center; justify-content: center;
    font-size: 1.15rem;
}

/* Названия направлений («Организатор», «Комментатор») в колонку 69px
   не влезают целиком и без разрешения рвать слово торчали за карточку. */
.track-title { flex: 1; min-width: 0; }
.track-title h4 { color: var(--text); font-size: 1.15rem; margin-bottom: 3px; overflow-wrap: anywhere; }
.track-title p { color: var(--text-muted); font-size: 0.88rem; overflow-wrap: anywhere; }

.track-level {
    font-family: var(--font-head);
    font-weight: 700;
    color: var(--accent-2);
    background: var(--accent-soft);
    padding: 5px 12px;
    border-radius: 999px;
    font-size: 0.9rem;
    white-space: nowrap;
}

/* Полоса прогресса и число рядом с ней. Текст «До уровня N: …» убран —
   он повторял то, что и так написано в списке квестов ниже. */
.track-progress {
    display: flex; align-items: center; gap: 12px;
    margin-bottom: 18px;
}
.track-progress .progress-bar { flex: 1; }
.track-progress-value {
    flex-shrink: 0;
    color: var(--text-dim);
    font-size: 0.82rem;
    white-space: nowrap;
}

.progress-bar {
    height: 8px;
    background: var(--surface-soft);
    border-radius: 999px;
    overflow: hidden;
}
.progress-bar > span {
    display: block; height: 100%;
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
    border-radius: 999px;
    transition: width 0.5s ease;
}

.track-done {
    display: flex; align-items: center; gap: 8px;
    color: var(--gold); font-size: 0.9rem; font-weight: 600;
    margin-bottom: 18px;
}

.track-levels { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }

.track-level-row {
    display: flex; align-items: center; gap: 12px;
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    background: var(--surface-soft);
    border: 1px solid transparent;
}
/* Раньше был opacity: 0.55 на всю строку — а фон строки (--surface-soft)
   и так полупрозрачный, так что запертый уровень почти сливался с тем,
   что было под ним на странице (тёмный герой, картинка и т. п.). Теперь
   фон и рамка у запертой строки непрозрачные (--surface-2/--border) — сама
   карточка видна на любой подложке — а «заперто» читается по мягкому
   приглушению только содержимого (бейджа, текста, замка), а не всей строки. */
.track-level-row.locked {
    background: var(--surface-2);
    border-color: var(--border);
}
.track-level-row.locked .level-badge,
.track-level-row.locked .level-mark { opacity: 0.65; }
.track-level-row.locked .level-title { opacity: 0.8; }
.track-level-row.locked .level-goal { opacity: 0.9; }
.track-level-row.current { border-color: var(--accent); background: var(--accent-soft); }
.track-level-row.ready { opacity: 0.85; border-color: var(--warning); }
.track-level-row.ready .level-mark { color: var(--warning); }

.level-badge {
    width: 26px; height: 26px; flex-shrink: 0;
    border-radius: 50%;
    background: var(--surface-2);
    border: 1px solid var(--border);
    color: var(--text-muted);
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-head); font-weight: 700; font-size: 0.82rem;
}
.track-level-row.unlocked .level-badge {
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    color: var(--on-accent); border-color: transparent;
}

.level-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* Названия уровней бывают длиннее узкой колонки («Организатор года»,
   «Комментатор сезона») — переносим по буквам, а не выпихиваем за карточку. */
.level-title { color: var(--text); font-weight: 600; font-size: 0.94rem; overflow-wrap: anywhere; }
.level-goal { color: var(--text-dim); font-size: 0.82rem; overflow-wrap: anywhere; }

.level-rarity {
    flex-shrink: 0; font-size: 0.72rem; color: var(--text-dim);
    display: inline-flex; align-items: center; gap: 4px;
    padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border);
    white-space: nowrap;
}
.level-mark { flex-shrink: 0; color: var(--text-dim); }
.track-level-row.unlocked .level-mark { color: var(--success); }

.rank-level {
    color: var(--text-muted) !important;
    font-weight: 500 !important;
    font-size: 0.85rem;
    padding-left: 10px;
    margin-left: 6px;
    border-left: 1px solid var(--border);
}

@media (max-width: 560px) {
    .tracks-grid { grid-template-columns: 1fr; }
    /* У элемента грида min-width по умолчанию auto — это его min-content.
       Если внутри карточки есть что-то шире экрана, колонка 1fr вырастает
       до этой ширины и карточка вылезает за вкладку. Разрешаем ей сжаться:
       содержимое внутри и так умеет переноситься. */
    .track-card { min-width: 0; }
    .track-head { flex-wrap: wrap; }
}

/* Таблица истории */
.tournament-history {
    overflow-x: auto;
    background: var(--surface-3);
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    padding: 16px;
}
.tournament-table { width: 100%; border-collapse: collapse; min-width: 560px; }
.tournament-table th {
    background: var(--accent-soft);
    color: var(--text);
    padding: 13px;
    text-align: left;
    font-weight: 600;
    border-bottom: 2px solid var(--border);
}
.tournament-table td { padding: 13px; color: var(--text-muted); border-bottom: 1px solid var(--border); }
.tournament-table tr:hover td { background: var(--accent-soft); }
.tournament-table tr:last-child td { border-bottom: none; }

/* Друзья */
.friends-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 18px;
}
.friend-card {
    position: relative;
    /* Колонка + margin-top: auto у ряда кнопок (ниже): у друга с титулом
       строк на одну больше, и без этого кнопки в соседних карточках
       стояли на разной высоте. */
    display: flex;
    flex-direction: column;
    background: var(--surface-3);
    padding: 20px 16px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    text-align: center;
    overflow: hidden;
    /* Размер и положение картинки приходят в самом значении: safeCssUrl()
       в js/utils.js отдаёт «center / cover no-repeat url(...)». Задавать
       их правилом бесполезно — inline-сокращение background всё равно
       перебило бы их. */
    transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
}
.friend-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-sm); border-color: var(--accent); }

/* Фон друга может быть каким угодно — хоть залитым солнцем лугом. Ровная
   тёмная вуаль поверх делает контраст ника и кнопок независимым от
   картинки, а сама картинка остаётся видна. Тот же приём, что в карточке
   игрока (.user-card-hero.has-bg). */
.friend-card.has-bg::before {
    content: '';
    position: absolute;
    inset: 0;
    /* Готовый градиент из инвентаря и так тёмный — ему хватает лёгкой
       вуали, иначе фон превращается в чёрный прямоугольник и смысл
       «показать чужой фон» теряется. Своя картинка бывает какой угодно,
       вплоть до залитого солнцем луга, — там вуаль плотнее. */
    background: rgba(8, 8, 26, 0.32);
    pointer-events: none;
}
.friend-card.has-custom-bg::before { background: rgba(8, 8, 26, 0.5); }
/* Содержимое поднято над ссылкой-подложкой, иначе она накрыла бы кнопки
   «Написать» и «Удалить» и вместо чата открывался бы профиль. */
.friend-card > * { position: relative; z-index: 2; }

/* Ссылка во всю карточку: сама невидима, но делает кликабельной всю
   плашку, а не только ник. */
.friend-card-open {
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: inherit;
}
.friend-card-open:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: -3px;
}
.friend-card.has-bg .friend-card-name > span { color: #fff; text-shadow: 0 2px 8px rgba(0, 0, 0, 0.75); }
.friend-card.has-bg .friend-last-seen { color: rgba(255, 255, 255, 0.86); }

/* Рамка вокруг аватара — та же, что человек носит в профиле и в чате */
.friend-card-frame {
    display: flex;
    width: max-content;
    margin: 0 auto 12px;
}
.friend-card-frame > .friend-avatar-large { margin: 0; }
.friend-card-frame.is-square { border-radius: 20px; }

.friend-card-name {
    display: flex; align-items: center; justify-content: center; gap: 6px;
    flex-wrap: wrap;
}
.friend-card-title {
    display: flex; align-items: center; justify-content: center; gap: 6px;
    width: max-content; max-width: 100%;
    margin: 2px auto 4px;
    color: var(--gold);
    font-size: 0.85rem; font-weight: 600;
}
.friend-card-title i { font-size: 0.78rem; }

.friend-avatar-large {
    position: relative; width: 72px; height: 72px; margin: 0 auto 14px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    display: flex; align-items: center; justify-content: center;
    color: var(--on-accent); font-size: 1.7rem;
    font-family: var(--font-head); font-weight: 700;
    overflow: hidden;
}
/* Квадратная форма аватара задаётся и рамке, и самой картинке — иначе
   квадратный аватар остался бы в круглой рамке (см. .avatar-frame.is-square) */
.friend-avatar-large.is-square { border-radius: 18px; }
.friend-avatar-large.is-square img,
.friend-avatar-large.is-square video { border-radius: 18px; }
.friend-avatar-large video { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.friend-status {
    position: absolute; bottom: 4px; right: 4px;
    width: 15px; height: 15px; border-radius: 50%;
    border: 2px solid var(--surface-3);
    background: var(--text-dim);
}
.friend-status.online { background: var(--success); }
.friend-card h4 { color: var(--text); margin-bottom: 4px; font-size: 1.15rem; }
.friend-last-seen { color: var(--text-dim); font-size: 0.87rem; margin-bottom: 14px; }
.friend-card .friend-last-seen { margin-bottom: 12px; }

/* «Написать» и «Удалить» стоят в один ряд и делят ширину карточки поровну.
   Раньше здесь был flex-wrap: wrap — при узкой карточке кнопки срывались
   одна под другую, и карточки в сетке получались разной высоты. */
.friend-actions {
    display: flex; gap: 8px; justify-content: center;
    flex-wrap: nowrap;
    margin-top: auto;
}
.friend-actions .btn {
    flex: 1 1 0;
    min-width: 0;
    justify-content: center;
    padding: 8px 6px;
    font-size: 0.8rem;
    white-space: nowrap;
}
.friend-actions .btn i { font-size: 0.78rem; }

/* ---------- Друзья ---------- */
/* Плашка формы и строки заявок — того же цвета, что карточки друзей
   ниже (.friend-card, --surface-3): раньше стояли на --surface-4
   (светлее), и на общем фоне вкладки смотрелись чужеродно. */
.add-friend {
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 18px 20px;
    margin-bottom: 26px;
}
.add-friend-field label {
    display: block; color: var(--text); font-weight: 600;
    font-size: 0.93rem; margin-bottom: 9px;
}
.add-friend-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.add-friend-at {
    color: var(--text-dim); font-family: var(--font-head);
    font-size: 1.15rem; font-weight: 700;
}
.add-friend-row .form-input { flex: 1; min-width: 180px; }

.friends-subhead {
    color: var(--text-muted);
    font-size: 0.92rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin: 26px 0 12px;
}

.requests-list { display: flex; flex-direction: column; gap: 10px; }

.request-row {
    display: flex; align-items: center; gap: 13px;
    padding: 12px 14px;
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    flex-wrap: wrap;
}

/* Нижний список заявок упирался прямо в ряд подвкладок «Друзья /
   Подписчики / Подписки» — они читались как продолжение той же плашки.
   Отступ снизу разводит их. */
#friendRequests, #friendOutgoing { margin-bottom: 26px; }
.request-body { flex: 1; min-width: 140px; display: flex; flex-direction: column; }
.request-name { color: var(--text); font-weight: 600; }
.request-meta { color: var(--text-dim); font-size: 0.83rem; }
.request-actions { display: flex; gap: 8px; flex-wrap: wrap; }

.friend-avatar img, .friend-avatar-large img {
    width: 100%; height: 100%; object-fit: cover; border-radius: 50%;
}
.friend-avatar, .friend-avatar-large { overflow: hidden; }

/* Настройки */
.settings-form { max-width: 620px; }
.settings-form .form-group { margin-bottom: 22px; }

.balance-display {
    display: flex; align-items: center; gap: 14px;
    background: var(--surface-soft);
    padding: 14px; border-radius: var(--radius-sm);
    border: 1px solid var(--border);
}
.balance-value { font-family: var(--font-head); font-size: 1.4rem; font-weight: 700; color: var(--success); flex: 1; }

.balance-info {
    background: var(--accent-soft);
    border-radius: var(--radius-sm);
    padding: 14px; margin-bottom: 18px;
    border: 1px solid var(--border);
    color: var(--text-muted);
}
.balance-info strong { color: var(--gold); font-size: 1.15rem; }

.payment-methods { display: flex; gap: 12px; margin-top: 10px; flex-wrap: wrap; }
.payment-method {
    flex: 1; min-width: 120px;
    background: var(--surface-soft);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 14px; cursor: pointer; text-align: center;
    transition: background var(--transition), border-color var(--transition);
}
.payment-method:hover { background: var(--accent-soft); border-color: var(--accent); }
.payment-method:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
.payment-method input[type="radio"] { position: absolute; opacity: 0; pointer-events: none; }
.payment-method i { font-size: 1.4rem; color: var(--accent-2); margin-bottom: 8px; display: block; }
.payment-method span { color: var(--text-muted); font-size: 0.88rem; }

.demo-notice {
    margin-top: 18px; padding: 13px;
    background: color-mix(in srgb, var(--warning) 12%, transparent);
    border-radius: var(--radius-sm);
    border: 1px solid color-mix(in srgb, var(--warning) 40%, transparent);
    color: var(--warning);
    font-size: 0.87rem;
}
.demo-notice i { margin-right: 8px; }

/* Плашка «войдите в аккаунт» — одинаковая на всех страницах */
.auth-required {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    text-align: center;
    padding: 56px 24px;
    margin: 0 auto;
    max-width: 460px;
    min-height: 100%;
}
.auth-required i {
    width: 64px; height: 64px;
    display: flex; align-items: center; justify-content: center;
    margin-bottom: 18px;
    border-radius: 50%;
    font-size: 1.6rem;
    color: var(--accent-2);
    background: var(--accent-soft);
}
.auth-required h2 {
    font-family: var(--font-head);
    font-size: 1.3rem;
    color: var(--text);
    margin-bottom: 8px;
}
.auth-required p { color: var(--text-muted); margin-bottom: 22px; }

/* ---------- Адаптивность страниц ---------- */
@media (max-width: 1440px) {
    /* Третья колонка здесь больше не объявляется: плашка собеседника
       приходит неявной колонкой и только когда открыта. Пока это
       правило её объявляло, справа впустую стояли 320px — переписка
       не доходила до края экрана. */
    .chat-container { grid-template-columns: 290px minmax(0, 1fr); }
    .chat-container { grid-auto-columns: 320px; }
}

@media (max-width: 1024px) {
    .container-chat { padding: 0 20px; }
    /* Высота остаётся «во весь оставшийся экран», как на большом
       окне: её замеряет fitToBottom() в js/layout.js. Было height:
       auto — плашка собиралась по содержимому и кончалась заметно
       выше низа окна. */
    .chat-container { grid-template-columns: 240px minmax(0, 1fr); }
    /* На узком экране третьей колонке взяться неоткуда — плашка
       накрывает переписку целиком. Кнопка в шапке есть и здесь, и
       нажатие на неё должно что-то делать. */
    .chat-container { position: relative; }
    .chat-info-panel.is-open {
        position: absolute;
        inset: 0;
        z-index: 20;
        box-shadow: 0 0 40px rgba(0, 0, 0, 0.5);
        /* Тут плашка не сосед по строке, а перекрывающий оверлей —
           скругляем все четыре угла, а не только правые (те — для
           случая рядом с перепиской на широком экране, см. выше). */
        border-radius: var(--radius-lg);
    }
    /* Было 60vh — переписка занимала чуть больше половины экрана, а
       под ней оставалась пустота до низа плашки. Теперь во всю её
       высоту, как на большом окне. */
    .chat-window { height: 100%; }
}

@media (max-width: 768px) {
    /* На узком экране аватар и «личность» встают столбиком по центру,
       поэтому и плашки внутри выравниваем по центру, а не по левому краю. */
    .profile-header { flex-direction: column; text-align: center; gap: 18px; }
    .profile-identity .profile-name-row { justify-content: center; }
    .profile-username { margin-left: auto; margin-right: auto; }
    /* Размер аватарки на этой ширине — см. .profile-avatar-frame ниже
       (после базового правила: тот же селектор, но правило должно идти
       позже него в файле, иначе базовое перебьёт это при равном весе). */
    /* То же и с кнопками профиля: «Редактировать профиль» / «Выйти» —
       пара, а не столбик. */
    .profile-actions { flex-direction: row; flex-wrap: wrap; width: 100%; }
    .profile-actions > .btn { flex: 1 1 calc(50% - 6px); min-width: 130px; }
    .profile-stats { grid-template-columns: repeat(2, 1fr); }
    .achievements-grid, .friends-grid { grid-template-columns: 1fr; }
    .tournaments-grid, .streams-grid, .news-grid { grid-template-columns: 1fr; }
    .chat-container { grid-template-columns: 1fr; }
    .chat-list { max-height: 220px; }
    .tab-btn { min-width: 104px; padding: 12px 16px; font-size: 0.88rem; }
}

@media (max-width: 480px) {
    .profile-stats { grid-template-columns: 1fr; }
    .payment-methods { flex-direction: column; }
    /* Кнопки остаются в один ряд и на узком экране — так просил владелец
       сайта; ширину они делят поровну (см. .friend-actions выше). */
    .friend-actions { flex-direction: row; }
    .friend-actions .btn { width: auto; }
    .tournament-actions .btn { min-width: 100%; }
}


/* ============================================================
   Вложения, реакции, статусы — чат
   ============================================================ */

/* ---------- Статус «в сети» ---------- */
.presence-dot {
    width: 11px; height: 11px;
    border-radius: 50%;
    background: var(--text-dim);
    border: 2px solid var(--surface-2);
    display: inline-block;
    flex-shrink: 0;
}
.presence-dot.is-online { background: var(--success); }

.chat-avatar.has-presence,
.chat-avatar-small.has-presence,
.friend-avatar-large.has-presence { position: relative; overflow: visible; }
.chat-avatar.has-presence img,
.chat-avatar-small.has-presence img,
.friend-avatar-large.has-presence img { border-radius: 50%; }
.chat-avatar.has-presence .presence-dot,
.chat-avatar-small.has-presence .presence-dot,
.friend-avatar-large.has-presence .presence-dot {
    position: absolute; right: -1px; bottom: -1px;
}

.chat-status { display: inline-flex; align-items: center; gap: 7px; }
.chat-status.is-online { color: var(--success); }

/* Шапка чата — ссылка на профиль собеседника. Подчёркивание и цвет
   ссылки тут не нужны: это не строчка текста, а плашка с аватаркой и
   ником, и выглядеть она должна как была. */
.chat-title-btn {
    background: none; border: none; padding: 0;
    text-align: left; cursor: pointer; color: inherit;
    font-family: inherit;
    text-decoration: none;
}

.chat-title-btn:hover h3 { color: var(--accent-2); }
.dialog-peer-presence { justify-content: center; margin-top: 6px; }
.dialog-peer .btn { margin-top: 14px; }

/* ---------- Кнопки композитора ---------- */
/* position уже не отсюда: плашка сама .chat-input-container теперь
   position: absolute (стекло поверх ленты, см. выше) — этого уже
   достаточно, чтобы быть точкой отсчёта для всплывающих панелей. */
.chat-input-container { flex-wrap: wrap; }
.composer-tools { display: flex; gap: 2px; flex-shrink: 0; }
.composer-tools .btn-icon { width: 36px; height: 36px; font-size: 0.95rem; }
.composer-tools .btn-icon:disabled { opacity: 0.4; cursor: not-allowed; }

/* ---------- Панель записи ---------- */
.recorder-bar {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    padding: 12px 14px;
    border-top: 1px solid var(--border);
    background: color-mix(in srgb, var(--danger) 10%, transparent);
}
/* Предпросмотр записи — тот же кружок, что уйдёт в чат: человек сразу
   видит, как обрежется кадр, а не квадрат, который потом станет круглым. */
.recorder-preview {
    width: 96px; height: 96px;
    border-radius: 50%;
    object-fit: cover;
    background: #000;
    border: 2px solid var(--danger);
}
.recorder-dot {
    width: 12px; height: 12px; border-radius: 50%;
    background: var(--danger);
    animation: recorder-pulse 1s ease-in-out infinite;
}
@keyframes recorder-pulse { 50% { opacity: 0.25; } }
.recorder-label { color: var(--text); font-weight: 600; }
.recorder-time {
    font-family: var(--font-head); font-weight: 700;
    color: var(--danger); margin-right: auto;
}

/* ---------- Вложения в сообщении ---------- */
/* min-width: 0 — чтобы вложение могло сжаться вместе с баблом. По
   умолчанию у flex-элемента min-width: auto, то есть «не уже своего
   содержимого», и голосовое сообщение распирало бабл на телефоне. */
.message-attachment { margin-bottom: 6px; min-width: 0; }
.message-attachment:last-child { margin-bottom: 0; }

.msg-image-btn {
    padding: 0; border: none; background: none; cursor: zoom-in;
    display: block; max-width: 100%;
}
.msg-image {
    max-width: min(320px, 100%);
    max-height: 320px;
    border-radius: var(--radius-md);
    display: block;
    object-fit: cover;
}

.msg-video {
    max-width: min(320px, 100%);
    max-height: 320px;
    border-radius: var(--radius-md);
    display: block;
    background: #000;
}

/* ---------- Видеосообщение-кружок ---------- */
/* Внешний квадрат больше самого кадра на ширину поля: в этом поле и рисуется
   шкала просмотра, поэтому она идёт ровно по краю кружка, не залезая на видео
   и не отрываясь от него. */
.video-round {
    --round-size: 220px;
    --round-pad: 13px;
    position: relative;
    box-sizing: border-box;
    width: calc(var(--round-size) + var(--round-pad) * 2);
    height: calc(var(--round-size) + var(--round-pad) * 2);
    max-width: 100%;
    padding: var(--round-pad);
    flex-shrink: 0;
}
.video-round-media {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    object-fit: cover;          /* кадр обрезается по кругу без искажения */
    display: block;
    background: #000;
    cursor: pointer;
}

/* Шкала просмотра по краю кружка. Круг развёрнут так, чтобы отсчёт шёл
   с двенадцати часов по часовой стрелке. */
.video-round-ring {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    transform: rotate(-90deg);
    overflow: visible;
}
.video-ring-track, .video-ring-progress {
    fill: none;
    stroke-width: 2;
    stroke-linecap: round;
}
.video-ring-track { stroke: rgba(255, 255, 255, 0.2); }
.video-ring-progress {
    stroke: var(--accent-2);
    stroke-dasharray: 295.31;                /* 2 * PI * 47 */
    stroke-dashoffset: 295.31;
    transition: stroke-dashoffset 0.12s linear;
}
.message.sent .video-ring-progress { stroke: #fff; }

.video-round-toggle {
    position: absolute;
    inset: 0;
    margin: auto;
    width: 54px; height: 54px;
    border-radius: 50%;
    border: none;
    background: rgba(10, 10, 30, 0.5);
    color: #fff;
    font-size: 1.05rem;
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    transition: opacity var(--transition), background var(--transition);
}
.video-round-toggle:hover { background: rgba(10, 10, 30, 0.72); }

/* Во время просмотра кнопка не закрывает кадр — она проявляется
   при наведении и с клавиатуры. */
.video-round.is-playing .video-round-toggle { opacity: 0; }
.video-round.is-playing:hover .video-round-toggle,
.video-round.is-playing .video-round-toggle:focus-visible { opacity: 1; }

/* Подпись и звук лежат внутри кадра: по углам квадрата их бы срезал круг. */
.video-round-duration {
    position: absolute;
    left: 50%;
    bottom: 9%;
    transform: translateX(-50%);
    padding: 2px 9px;
    border-radius: 999px;
    background: rgba(10, 10, 30, 0.62);
    color: rgba(255, 255, 255, 0.92);
    font-size: 0.72rem;
    font-variant-numeric: tabular-nums;
    pointer-events: none;
    white-space: nowrap;
}
.video-round-duration:empty { display: none; }

.video-round-mute {
    position: absolute;
    right: 15%; top: 15%;
    width: 30px; height: 30px;
    border-radius: 50%;
    border: none;
    background: rgba(10, 10, 30, 0.55);
    color: #fff;
    font-size: 0.76rem;
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
}
.video-round-mute:hover { background: rgba(10, 10, 30, 0.75); }

/* У кружка, как и у стикера, своего «пузыря» нет: он сам по себе форма. */
.message-content:has(.video-round) {
    background: transparent !important;
    border-color: transparent !important;
    padding: 0;
}
.message-content:has(.video-round) .message-header { padding: 0 4px 4px; }
.message-content:has(.video-round) .message-line { padding: 0 4px; }
.message-content:has(.video-round) .message-time {
    padding: 2px 7px;
    border-radius: 999px;
    background: rgba(10, 10, 30, 0.55);
    color: rgba(255, 255, 255, 0.85);
}

@media (max-width: 768px) {
    .video-round { --round-size: 180px; }
}

/* ---------- Голосовое сообщение — как в Телеграме ----------
   Раньше здесь стоял голый <audio controls>: чужой плеер браузера,
   у каждого браузера свой на вид. Теперь свой плеер: круглая кнопка
   play/pause, «волна» из полосок (закрашивается по ходу воспроизведения,
   как проигранная часть) и время. Клик по волне — перемотка.
   Расшифровка в текст (Dantes Premium) добавляет вторую строку под
   плеером — .voice-message стала колонкой, а сам ряд управления вынесен
   в .voice-row с прежними свойствами. */
/* min-width задаём в процентах доступной ширины, а не в пикселях: жёсткие
   220px на экране 360 не влезали в бабл (ширина бабла там ~120-150px), и
   плеер вылезал за его правый край — на телефоне у сообщения обрезалось
   время и кнопка скорости. Теперь плеер сжимается вместе с баблом. */
.voice-message { display: flex; flex-direction: column; gap: 6px; min-width: min(220px, 100%); max-width: 100%; }
.voice-row { display: flex; align-items: center; gap: 10px; min-width: 0; }

.voice-play {
    width: 36px; height: 36px; border-radius: 50%; border: none;
    flex-shrink: 0; cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    font-size: 0.85rem;
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    color: var(--on-accent);
    transition: transform var(--transition);
}
.voice-play i { position: relative; left: 1px; }        /* оптический центр — треугольник смещён визуально */
.voice-play:has(.fa-pause) i { left: 0; }
.voice-play:hover { transform: scale(1.06); }
/* На своих сообщениях бабл уже залит тем же градиентом — кнопка тем же
   цветом слилась бы с фоном, поэтому здесь она полупрозрачная белая. */
.message.sent .voice-play { background: color-mix(in srgb, var(--on-accent) 22%, transparent); color: var(--on-accent); }

.voice-waveform {
    position: relative;
    /* min-width в пикселях не давал волне ужаться в узком бабле и выпихивал
       время со скоростью за край — берём меньшее из 90px и доступного места. */
    flex: 1 1 auto; min-width: min(90px, 100%); max-width: 200px;
    height: 26px;
    cursor: pointer;
    overflow: hidden;          /* полосок больше, чем влезает при узком бабле — обрезаем, а не сжимаем */
}
.voice-bars { position: absolute; top: 0; bottom: 0; left: 0; display: flex; align-items: center; gap: 2px; }
.voice-bars span { width: 3px; min-height: 3px; border-radius: 2px; flex-shrink: 0; background: currentColor; }
.voice-bars-bg { right: 0; color: var(--text-dim); opacity: 0.45; }
.voice-bars-fg { width: 0%; overflow: hidden; color: var(--accent-2); }
.message.sent .voice-bars-bg { color: var(--on-accent); opacity: 0.35; }
.message.sent .voice-bars-fg { color: var(--on-accent); }

.voice-time {
    color: var(--text-dim); font-size: 0.78rem; flex-shrink: 0;
    font-variant-numeric: tabular-nums;           /* цифры не «прыгают» по ширине при обновлении */
    min-width: 32px;
}
.message.sent .voice-time { color: color-mix(in srgb, var(--on-accent) 85%, transparent); }

.voice-speed {
    flex-shrink: 0;
    padding: 2px 7px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-dim);
    font-size: 0.7rem; font-weight: 700;
    cursor: pointer;
}
.message.sent .voice-speed {
    border-color: color-mix(in srgb, var(--on-accent) 35%, transparent);
    background: color-mix(in srgb, var(--on-accent) 12%, transparent);
    color: var(--on-accent);
}

/* Кнопка расшифровки — тот же стиль, что у .voice-speed, плюс свои акценты
   для «заблокировано» (не премиум) и «готово» (текст уже расшифрован). */
.voice-transcribe.is-locked { color: var(--text-dim); opacity: 0.75; cursor: pointer; }
.voice-transcribe.is-done { color: var(--accent-2); border-color: var(--accent-2); }
.message.sent .voice-transcribe.is-done { color: var(--on-accent); border-color: color-mix(in srgb, var(--on-accent) 60%, transparent); }

.voice-transcript {
    margin: 0; padding: 8px 10px;
    border-radius: 10px;
    background: var(--surface-2);
    color: var(--text);
    font-size: 0.85rem; line-height: 1.4;
    white-space: pre-wrap; word-break: break-word;
}
.message.sent .voice-transcript { background: color-mix(in srgb, var(--on-accent) 16%, transparent); color: var(--on-accent); }

.msg-sticker {
    width: 130px; height: 130px;
    object-fit: contain;
    display: block;
}

.msg-file {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 12px;
    background: var(--surface-soft);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    text-decoration: none;
    color: var(--text);
    max-width: 280px;
}
.msg-file:hover { border-color: var(--accent); }
.msg-file-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.msg-file-size { color: var(--text-dim); font-size: 0.8rem; flex-shrink: 0; }

.msg-attachment-loading, .msg-uploading {
    display: flex; align-items: center; gap: 9px;
    color: var(--text-dim); font-size: 0.88rem;
}

/* Стикер — без «пузыря» вокруг */
.message-content:has(.msg-sticker) {
    background: transparent !important;
    border-color: transparent !important;
    padding: 0;
}
.message-content:has(.msg-sticker) .message-header { padding: 0 4px 4px; }
/* У стикера бабла нет, поэтому время получает собственную подложку */
.message-content:has(.msg-sticker) .message-time {
    margin: 4px 4px 0 0;
    align-self: end;
    padding: 2px 7px;
    border-radius: 999px;
    background: rgba(10, 10, 30, 0.55);
    color: rgba(255, 255, 255, 0.85);
}

/* ---------- Реакции ---------- */
.message { position: relative; }

/* Кнопки у сообщения стоят столбиком у нижнего края бабла */
.message-tools {
    display: flex;
    gap: 4px;
    align-self: flex-end;
    flex-shrink: 0;
}

.message-react {
    align-self: flex-end;
    width: 28px; height: 28px;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text-dim);
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    font-size: 0.8rem;
    opacity: 0;
    transition: opacity var(--transition), color var(--transition), border-color var(--transition);
    flex-shrink: 0;
}
.message:hover .message-react,
.message:focus-within .message-react { opacity: 1; }
.message-react:hover { color: var(--accent-2); border-color: var(--accent); }
@media (hover: none) { .message-react { opacity: 1; } }

/* Закреплённое сообщение — кнопка остаётся видимой и подсвеченной
   даже без наведения, иначе не понять, что оно закреплено, не наведя мышь. */
.message-pin.is-active {
    opacity: 1;
    color: var(--on-accent);
    background: var(--accent);
    border-color: var(--accent);
}

/* Реакции дописываются в конец бабла и занимают всю его ширину */
.message-reactions {
    display: flex; gap: 5px; flex-wrap: wrap;
    flex: 1 1 auto;
    min-width: 0;
    margin-right: auto;
}

.reaction-chip {
    display: inline-flex; align-items: center; gap: 4px;
    padding: 2px 9px;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--surface-2);
    color: var(--text);
    font-size: 0.85rem;
    cursor: pointer;
    transition: border-color var(--transition), background var(--transition);
}
.reaction-chip:hover { border-color: var(--accent); }
.reaction-chip.is-mine { border-color: var(--accent); background: var(--accent-soft); }
.reaction-chip:active { transform: scale(0.92); }
.reaction-emoji { display: inline-block; line-height: 1; }

/* ---------- Оживление реакций ---------- */
/* Новый чип не просто возникает, а вылетает с перелётом: короткая пружина
   по той же схеме, что в телеграме. Счётчик подпрыгивает отдельно, чтобы
   было видно, что цифра именно изменилась, а не перерисовалась. */
@keyframes reaction-pop {
    0%   { transform: scale(0.2); opacity: 0; }
    55%  { transform: scale(1.18); opacity: 1; }
    78%  { transform: scale(0.94); }
    100% { transform: scale(1); }
}
@keyframes reaction-leave {
    0%   { transform: scale(1); opacity: 1; }
    100% { transform: scale(0.3); opacity: 0; }
}
@keyframes reaction-count-bump {
    0%   { transform: translateY(0) scale(1); }
    35%  { transform: translateY(-4px) scale(1.28); }
    100% { transform: translateY(0) scale(1); }
}
@keyframes reaction-fly {
    0%   { transform: translate(-50%, 0) scale(0.6); opacity: 0; }
    25%  { transform: translate(-50%, -22px) scale(1.5); opacity: 1; }
    100% { transform: translate(-50%, -74px) scale(0.75); opacity: 0; }
}

.reaction-chip.is-appearing {
    animation: reaction-pop 0.32s cubic-bezier(0.2, 0.9, 0.3, 1.4) both;
}
.reaction-chip.is-leaving {
    animation: reaction-leave 0.18s ease-in forwards;
    pointer-events: none;
}
.reaction-count.is-bumping {
    display: inline-block;
    animation: reaction-count-bump 0.34s cubic-bezier(0.3, 1.4, 0.5, 1);
}

/* Эмодзи, вылетающее вверх при собственной реакции. Живёт в body поверх всего
   и само себя убирает — на разметку сообщения не влияет. */
.reaction-fly {
    position: fixed;
    z-index: 4000;
    font-size: 1.7rem;
    line-height: 1;
    pointer-events: none;
    animation: reaction-fly 0.7s ease-out forwards;
    will-change: transform, opacity;
}

/* Кому анимации мешают — тем их не показываем */
@media (prefers-reduced-motion: reduce) {
    .reaction-chip.is-appearing,
    .reaction-chip.is-leaving,
    .reaction-count.is-bumping,
    .reaction-fly { animation: none; }
    .reaction-chip.is-leaving { opacity: 0; }
}
.reaction-count { font-size: 0.78rem; color: var(--text-muted); font-weight: 600; }

/* ---------- Выпадающие панели ---------- */
.popover-host { position: relative; }

.chat-popover {
    position: absolute;
    bottom: calc(100% + 10px);
    left: 10px;
    z-index: 1400;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    animation: slide-up 0.16s ease;
}

/* Единая панель «Эмодзи + Стикеры», структура как в Telegram: сверху
   переключатель режима, ниже — контент вкладки фиксированной высоты. */
.picker-popover { width: min(360px, calc(100vw - 32px)); }

.picker-modes { display: flex; border-bottom: 1px solid var(--border); }
.picker-mode {
    flex: 1; padding: 11px;
    background: none; border: none;
    color: var(--text-dim); cursor: pointer;
    font-size: 1.05rem;
    border-bottom: 2px solid transparent;
    transition: color var(--transition), border-color var(--transition);
}
.picker-mode:hover { color: var(--text); }
.picker-mode[aria-pressed="true"] { color: var(--accent-2); border-bottom-color: var(--accent); }

.picker-body { display: flex; flex-direction: column; height: 360px; }

/* ---------- Вкладка «Эмодзи» ----------
   Поиск сверху, сплошная прокрутка по категориям с «прилипающими»
   заголовками секций, и ряд быстрых переходов внизу — вместо прежних
   постраничных вкладок это та же структура, что у Telegram. */
.emoji-search {
    display: flex; align-items: center; gap: 8px;
    margin: 8px; padding: 7px 12px;
    border-radius: 999px;
    background: var(--surface-soft);
    border: 1px solid var(--border);
    color: var(--text-dim);
    flex-shrink: 0;
}
.emoji-search i { font-size: 0.82rem; }
.emoji-search input {
    flex: 1; min-width: 0;
    border: none; background: none; outline: none;
    color: var(--text); font-size: 0.9rem; font-family: inherit;
}
.emoji-search input::placeholder { color: var(--text-dim); }

.emoji-scroll {
    flex: 1; overflow-y: auto;
    padding: 0 8px 4px;
 overscroll-behavior: contain;
}
.emoji-section { margin-bottom: 4px; }
.emoji-section-title {
    position: sticky; top: 0; z-index: 1;
    margin: 0; padding: 6px 4px;
    font-size: 0.7rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.03em;
    color: var(--text-dim);
    background: var(--surface);
}
.emoji-section-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.emoji-cell {
    background: none; border: none; cursor: pointer;
    font-size: 1.35rem; line-height: 1;
    padding: 7px 0; border-radius: var(--radius-sm);
    display: flex; align-items: center; justify-content: center;
    transition: background var(--transition), transform var(--transition);
}
.emoji-cell:hover { background: var(--accent-soft); transform: scale(1.15); }
.emoji-empty { padding: 40px 16px; text-align: center; color: var(--text-dim); }

/* Ряд быстрых переходов по категориям — как нижняя панель эмодзи-клавиатуры
   в Telegram: клик скроллит к секции, активная подсвечивается по прокрутке. */
.emoji-catbar {
    display: flex; gap: 2px;
    padding: 6px; flex-shrink: 0;
    border-top: 1px solid var(--border);
    overflow-x: auto;
}
.emoji-catbtn {
    flex: 1 0 auto; width: 32px; height: 32px;
    border-radius: var(--radius-sm);
    border: none; background: none;
    color: var(--text-dim); cursor: pointer;
    font-size: 0.88rem;
    display: flex; align-items: center; justify-content: center;
    transition: background var(--transition), color var(--transition);
}
.emoji-catbtn:hover { background: var(--accent-soft); }
.emoji-catbtn[aria-pressed="true"] { color: var(--accent-2); background: var(--accent-soft); }

/* ---------- Вкладка «Стикеры» ----------
   Ряд обложек паков сверху (плюс синтетический пак «Недавние» первым,
   когда есть история), ниже — сетка выбранного пака, прокручивается
   отдельно от ряда обложек, который остаётся на месте. */
.picker-body-sticker { padding: 8px 8px 4px; overflow: hidden; }
.sticker-body {
    flex: 1; overflow-y: auto; padding-top: 4px;
 overscroll-behavior: contain;
}
.sticker-tabs {
    display: flex;
    gap: 4px;
    padding: 0 0 8px;
    border-bottom: 1px solid var(--border);
    overflow-x: auto;

}
.sticker-tab {
    flex: 0 0 auto;
    width: 38px; height: 38px;
    padding: 4px;
    border-radius: var(--radius-sm);
    border: 1px solid transparent;
    background: none;
    cursor: pointer;
    color: var(--text-dim);
    display: flex; align-items: center; justify-content: center;
    transition: background var(--transition), border-color var(--transition);
}
.sticker-tab img { width: 100%; height: 100%; object-fit: contain; display: block; }
.sticker-tab:hover { background: var(--accent-soft); }
.sticker-tab[aria-selected="true"] { background: var(--accent-soft); border-color: var(--accent); }
.sticker-tab-add { color: var(--accent-2); border: 1px dashed var(--border); }
.sticker-tab-add:hover { border-color: var(--accent); }

.sticker-pack-head {
    display: flex; align-items: center; gap: 8px;
    margin: 2px 0 8px;
}
.sticker-pack-name {
    color: var(--text); font-size: 0.82rem; font-weight: 600;
    font-family: var(--font-head);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Юзернейм автора — главное, что отличает пак игрока от паков платформы */
.sticker-pack-author {
    color: var(--accent-2); font-size: 0.74rem;
    background: var(--accent-soft);
    padding: 1px 7px; border-radius: 999px;
    flex-shrink: 0;
}
.sticker-pack-remove {
    margin-left: auto; flex-shrink: 0;
    background: none; border: none; cursor: pointer;
    color: var(--text-dim); font-size: 0.8rem;
    padding: 3px 5px; border-radius: var(--radius-sm);
}
.sticker-pack-remove:hover { color: var(--danger); background: var(--surface-soft); }

/* Предпросмотр будущего пака в окне создания */
.sticker-draft {
    display: flex; flex-wrap: wrap; gap: 6px;
    padding: 10px;
    background: var(--surface-soft);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    margin-bottom: 16px;
}
.sticker-draft-cell { width: 52px; height: 52px; }
.sticker-draft-cell img { width: 100%; height: 100%; object-fit: contain; display: block; }
.sticker-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.sticker-cell {
    background: none; border: 1px solid transparent; cursor: pointer;
    border-radius: var(--radius-sm); padding: 4px;
    transition: background var(--transition), border-color var(--transition), transform var(--transition);
}
.sticker-cell:hover { border-color: var(--accent); background: var(--accent-soft); transform: scale(1.08); }
.sticker-cell img { width: 100%; aspect-ratio: 1; object-fit: contain; display: block; }
.sticker-loading, .sticker-empty { padding: 24px; text-align: center; color: var(--text-dim); }
.sticker-empty i { font-size: 1.8rem; color: var(--accent-2); display: block; margin-bottom: 10px; }
.sticker-empty code {
    background: var(--surface-soft); padding: 1px 6px;
    border-radius: 4px; color: var(--accent-2);
}

.reaction-popover { padding: 6px; }
.reaction-row { display: flex; gap: 2px; }
.reaction-cell {
    background: none; border: none; cursor: pointer;
    font-size: 1.25rem; line-height: 1;
    padding: 7px; border-radius: var(--radius-sm);
    color: var(--text-dim);
}
.reaction-cell:hover { background: var(--accent-soft); transform: scale(1.15); }
.reaction-more { font-size: 0.85rem; }

/* Панель без контейнера позиционируется скриптом по координатам кнопки */
.chat-popover.is-floating { position: fixed; bottom: auto; left: 0; top: 0; }

/* ---------- Просмотр вложения ---------- */
.modal-wide .modal-content { max-width: min(900px, 94vw); }
.modal-compact .modal-content { max-width: min(420px, 90vw); }
.lightbox { display: flex; justify-content: center; }
.lightbox-media { max-width: 100%; max-height: 70vh; border-radius: var(--radius-md); }
.modal-compact .lightbox-media { max-height: 60vh; }

/* ---------- Карточка пользователя ---------- */
.user-card { text-align: center; }
.user-card-avatar {
    width: 96px; height: 96px; margin: 0 auto 14px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    color: var(--on-accent);
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-head); font-weight: 700; font-size: 2.2rem;
    overflow: hidden;
}
.user-card-avatar img { width: 100%; height: 100%; object-fit: cover; }
/* Ник и корона стоят в одну строку — как в шапке профиля */
.user-card-name-row {
    display: flex; align-items: center; justify-content: center;
    gap: 9px; flex-wrap: wrap;
    margin-bottom: 4px;
}
.user-card-name { font-family: var(--font-head); font-weight: 700; font-size: 1.3rem; color: var(--text); }

/* Юзернейм — плашка, как в профиле: по нему добавляют в друзья.
   block + max-content: занимает свою строку, но обжимает текст,
   иначе он встаёт в один ряд с титулом и меткой подписки. */
.user-card-username {
    display: block;
    width: max-content;
    max-width: 100%;
    margin: 0 auto 8px;
    padding: 2px 11px;
    border-radius: 999px;
    background: var(--accent-soft);
    border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
    color: var(--accent-2);
    font-family: var(--font-head);
    font-weight: 600;
    font-size: 0.92rem;
}
.user-card-presence {
    display: inline-flex; align-items: center; gap: 7px;
    color: var(--text-muted); font-size: 0.9rem;
}
.user-card-presence.is-online { color: var(--success); }
.user-card-bio {
    color: var(--text-muted);
    background: var(--surface-soft);
    border-radius: var(--radius-md);
    padding: 12px; margin: 14px 0;
    text-align: left;
}
.user-card-meta {
    color: var(--text-dim); font-size: 0.87rem;
    display: flex; align-items: center; justify-content: center; gap: 8px;
    margin-top: 6px;
}

@media (max-width: 768px) {
    .chat-container { height: auto; min-height: 0; }
    .chat-window { height: 70vh; }
    .emoji-section-grid { grid-template-columns: repeat(6, 1fr); }
    .chat-popover { left: 8px; right: 8px; width: auto; }
}

/* ============================================================
   Инвентарь, рамки, фон профиля, цвет ника
   ============================================================ */

/* ---------- Рамка вокруг аватара ---------- */
.avatar-frame {
    display: inline-flex;
    border-radius: 50%;
    padding: 0;
    flex-shrink: 0;
    line-height: 0;
    position: relative; /* якорь для .frame-fire-canvas, см. css/style.css */
}
.avatar-frame.has-frame { padding: 4px; }
.profile-avatar-frame.has-frame .profile-avatar {
    border: none;               /* рамка заменяет классическую обводку, а не ложится поверх */
}

/* Размер аватарки в шапке профиля (своей и чужой — .profile-header есть
   и на pages/profile.html, и на pages/user.html) считает не CSS, а
   js/utils.js (watchAvatarFrameHeight, вызывается из renderHeader/
   render в js/profile.js и js/user-profile.js): высота равна высоте
   соседней колонки .profile-identity (от верхнего края ника до нижнего
   края титула — если в колонке рядом чего-то нет, например доп.
   юзернеймов, колонка ниже, и аватарка вместе с ней меньше), а ширина
   всегда равна высоте — так гарантированно остаётся квадратом. Верхнего
   предела высоты нарочно нет нигде (см. js/utils.js) — обязана дойти
   ровно до низа титула, даже если это больше «обычных» 186px. 186×186
   здесь — только запасной размер на случай, если скрипт ещё не
   отработал или отключён. container-type: size даёт вложенному
   .profile-avatar font-size в cqh — буква инициала в пустой аватарке
   масштабируется вместе с размером сама. */.profile-avatar-frame {
    flex-shrink: 0;
    width: 186px;
    height: 186px;
    container-type: size;
}
@media (max-width: 768px) {
    /* Столбиком аватар стоит НАД «личностью», а не рядом с ней —
       подстраивать её высоту под соседнюю колонку больше не имеет
       смысла (watchAvatarFrameHeight сам ничего не трогает на этой
       ширине — см. AVATAR_FRAME_MOBILE_QUERY в js/utils.js), поэтому
       здесь фиксированный размер по центру. Это правило обязано стоять
       ПОСЛЕ базового .profile-avatar-frame выше: при равной специфичности
       побеждает то, что позже в файле. */
    .profile-avatar-frame { width: 160px; height: 160px; }
}

/* ============================================================
   Фон профиля накрывает обе плашки — и шапку, и вкладки.
   Картинка лежит на .profile-canvas (это #profileContent),
   а внутренние плашки становятся прозрачными, чтобы она
   просвечивала насквозь и не рвалась на две части.
   ============================================================ */
.profile-canvas.has-custom-bg {
    position: relative;
    border-radius: var(--radius-xl);
    border: 1px solid var(--border);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
}

/* Готовый градиент из инвентаря (не своя фотография — см. has-custom-bg
   выше) получает базовые position/overflow отдельно: класс has-cosmetic-bg
   ставится и без активной подписки на самой странице профиля быть не может
   (см. renderAll в js/profile.js), но стилям всё равно нужен свой якорь,
   потому что .has-custom-bg покрывает оба случая (и картинку, и градиент)
   на этой странице, а мерцать должен только градиент. */
.profile-canvas.has-cosmetic-bg {
    position: relative;
    border-radius: var(--radius-xl);
    overflow: hidden;
}

/* Фоны бывают и тёмные, и почти белые («Алая заря», «Изумрудный трон»).
   Чтобы белый текст читался на любом, кладём поверх картинки ровную
   тёмную вуаль. Картинка остаётся видна, а контраст перестаёт зависеть
   от того, какой фон выбрал человек. */
.profile-canvas.has-custom-bg::before {
    content: '';
    position: absolute;
    inset: 0;
    background: rgba(8, 8, 26, 0.5);
    pointer-events: none;
    z-index: 0;
}
.profile-canvas.has-custom-bg > * { position: relative; z-index: 1; }
.profile-canvas.has-custom-bg .profile-section,
.profile-canvas.has-custom-bg .profile-tabs {
    background: transparent;
    border: none;
    border-radius: 0;
    box-shadow: none;
    margin-bottom: 0;
}
/* Тонкая линия вместо зазора между шапкой и вкладками.
   Полоса вкладок тоже полупрозрачная, иначе она резала картинку тёмной лентой. */
.profile-canvas.has-custom-bg .profile-tabs { border-top: 1px solid rgba(255, 255, 255, 0.16); }
.profile-canvas.has-custom-bg .tabs-nav {
    background: rgba(8, 8, 26, 0.78);
    border-color: rgba(255, 255, 255, 0.2);
    border-bottom-color: var(--accent);
    backdrop-filter: blur(4px);
}
.profile-canvas.has-custom-bg .tab-btn { border-right-color: rgba(255, 255, 255, 0.14); }

/* На пользовательском фоне подложки делаем тёмными, иначе текст и кнопки тонут */
.profile-canvas.has-custom-bg .profile-bio,
.profile-canvas.has-custom-bg .stat-card {
    background: rgba(10, 10, 30, 0.55);
    border-color: rgba(255, 255, 255, 0.18);
    backdrop-filter: blur(2px);
}
/* Белый текст здесь лежит поверх чужой картинки — своя тёмная
   подложка (rgba(10, 10, 30, ...) выше) не везде спасает: на светлом
   участке фото текст всё равно тонет. Чёрная обводка по контуру букв
   (4 сдвинутые тени, а не один мягкий drop-shadow) держит читаемость
   на любом фото, а не только на тёмном. */
/* :not(.nick-rainbow) — переливающийся ник (.nick-rainbow в этом же
   файле) красит текст через background-clip: text и держит сам
   color: transparent, чтобы сквозь буквы был виден градиент. Это
   правило (специфичность выше, .profile-canvas.has-custom-bg —
   ДВА класса) без исключения перебивало бы тот transparent на #fff и
   поверх заливало чёрной обводкой — со стороны ник выглядел просто
   чёрным, никакого переливания. Обычный (не переливающийся) ник
   белую заливку и чёрную обводку получает как и раньше. */
.profile-canvas.has-custom-bg .profile-identity h2:not(.nick-rainbow),
.profile-canvas.has-custom-bg .stat-label,
.profile-canvas.has-custom-bg .profile-bio {
    color: #fff;
    text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
}
.profile-canvas.has-custom-bg .profile-username {
    background: rgba(10, 10, 30, 0.6);
    border-color: rgba(255, 255, 255, 0.35);
    color: #fff;
    text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
}
.profile-canvas.has-custom-bg .stat-icon { background: rgba(255, 255, 255, 0.16); color: #fff; }
.profile-canvas.has-custom-bg .profile-rank { background: rgba(10, 10, 30, 0.55); }

/* Тема Dantes Pass поверх фона из инвентаря: белые «плашки» выше глушили
   цвет темы именно на профилях с фоном (а он есть почти у всех). Когда
   тема включена, юзернейм, иконки статистики и ранг снова красятся ею —
   на тёмной подложке, чтобы текст читался на любом фоне. */
.profile-canvas.has-custom-bg.has-pass-theme .profile-username {
    background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 55%, rgba(10, 10, 30, 0.7)), color-mix(in srgb, var(--accent-2) 55%, rgba(10, 10, 30, 0.7)));
    border-color: var(--accent-2);
    color: #fff;
}
.profile-canvas.has-custom-bg.has-pass-theme .stat-icon {
    background: var(--accent-soft);
    color: var(--accent-2);
    text-shadow: none;
}
.profile-canvas.has-custom-bg.has-pass-theme .profile-rank {
    background: color-mix(in srgb, var(--accent) 22%, rgba(10, 10, 30, 0.6));
    border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
}

/* Кнопки: сплошная тёмная подложка (для читаемости на картинке), но
   цвет обводки и текста — тот же акцент, что и у обычных кнопок «Друзья»
   (.btn-secondary/.btn-small вне кастомного фона), а не белый контур. */
.profile-canvas.has-custom-bg .btn-secondary,
.profile-canvas.has-custom-bg .btn-small,
.profile-canvas.has-custom-bg .color-btn {
    background: rgba(10, 10, 30, 0.65);
    color: var(--accent-2);
    border-color: var(--accent);
}
.profile-canvas.has-custom-bg .btn-secondary:hover:not(:disabled),
.profile-canvas.has-custom-bg .btn-small:hover:not(:disabled),
.profile-canvas.has-custom-bg .color-btn:hover {
    background: rgba(10, 10, 30, 0.85);
    border-color: var(--accent-2);
    color: #fff;
}
.profile-canvas.has-custom-bg .btn-primary {
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.45);
    border-color: rgba(255, 255, 255, 0.35);
}

/* Вкладки и текст внутри них тоже лежат на картинке */
.profile-canvas.has-custom-bg .tab-btn { color: rgba(255, 255, 255, 0.75); }
.profile-canvas.has-custom-bg .tab-btn:hover { color: #fff; }
.profile-canvas.has-custom-bg .tab-pane h3,
.profile-canvas.has-custom-bg .section-head h3,
.profile-canvas.has-custom-bg .friends-subhead { color: #fff; }
.profile-canvas.has-custom-bg .tracks-lead,
.profile-canvas.has-custom-bg .form-hint,
.profile-canvas.has-custom-bg label { color: rgba(255, 255, 255, 0.82); }

/* Карточки внутри вкладок делаем плотнее, чтобы читались на картинке */
.profile-canvas.has-custom-bg .track-card,
.profile-canvas.has-custom-bg .crown-card,
.profile-canvas.has-custom-bg .friend-card,
.profile-canvas.has-custom-bg .add-friend,
.profile-canvas.has-custom-bg .request-row,
.profile-canvas.has-custom-bg .subscriber-card,
.profile-canvas.has-custom-bg .cosmetic-card,
.profile-canvas.has-custom-bg .plan-card,
.profile-canvas.has-custom-bg .pack-card,
.profile-canvas.has-custom-bg .perk,
.profile-canvas.has-custom-bg .premium-setting,
.profile-canvas.has-custom-bg .premium-hero,
.profile-canvas.has-custom-bg .coins-balance,
.profile-canvas.has-custom-bg .special-titles,
.profile-canvas.has-custom-bg .quests-box,
.profile-canvas.has-custom-bg .referral-box,
.profile-canvas.has-custom-bg .promo-code-card,
.profile-canvas.has-custom-bg .form-input,
.profile-canvas.has-custom-bg .form-textarea,
.profile-canvas.has-custom-bg .tournament-table {
    background: rgba(10, 10, 30, 0.62);
    border-color: rgba(255, 255, 255, 0.16);
    backdrop-filter: blur(2px);
}
/* border-color выше и в блоке .stat-card чуть раньше — та же
   специфичность, что и у сплошной цветной обводки сверху в конце
   файла (border-top: 3px solid var(--accent)) — перебивал её обратно
   на полупрозрачный белый именно на кастомном фоне профиля, обводка
   пропадала только там. Из всего списка выше в общую обводку сверху
   входят только эти восемь — возвращаем им верхнюю грань акцентом,
   остальные три стороны остаются белыми (нужны для контраста с
   фотофоном). */
.profile-canvas.has-custom-bg .stat-card,
.profile-canvas.has-custom-bg .track-card,
.profile-canvas.has-custom-bg .crown-card,
.profile-canvas.has-custom-bg .friend-card,
.profile-canvas.has-custom-bg .subscriber-card,
.profile-canvas.has-custom-bg .cosmetic-card,
.profile-canvas.has-custom-bg .pack-card,
.profile-canvas.has-custom-bg .promo-code-card {
    border-top-color: var(--accent);
}
/* .profile-bio красится не сверху, а слева (border-left, см. базовое
   правило выше в файле) — та же history, тот же border-color её тоже
   гасил обратно в белый на кастомном фоне. */
.profile-canvas.has-custom-bg .profile-bio {
    border-left-color: var(--accent);
}
.profile-canvas.has-custom-bg .subtab {
    background: rgba(10, 10, 30, 0.55);
    color: rgba(255, 255, 255, 0.8);
    text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
}
/* Активная вкладка — сплошной акцентный фон, а не полупрозрачный
   поверх фото: там уже гарантированный контраст через --on-accent,
   обводка тут не нужна и на светлых акцентах смотрелась бы грязным
   пятном вокруг букв. */
.profile-canvas.has-custom-bg .subtab[aria-selected="true"] { background: var(--accent); color: var(--on-accent); text-shadow: none; }

/* ---------- Ник и палитра ---------- */
.profile-name-row {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 8px;
}
.profile-name-row h2 { margin-bottom: 0; }
.color-btn { width: 34px; height: 34px; font-size: 0.9rem; }

.color-popover { padding: 12px; width: 232px; }

/* В чате поповеры раскрываются вверх — там композитор внизу экрана.
   А в профиле ник стоит у верхнего края карточки, и панель уезжала
   под липкую шапку сайта. Поэтому здесь она открывается вниз. */
.profile-name-row .color-popover {
    bottom: auto;
    top: calc(100% + 10px);
    left: 0;
}
.color-grid {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 7px;
    margin-bottom: 12px;
}
.color-cell {
    width: 100%; aspect-ratio: 1;
    border-radius: 50%;
    border: 2px solid transparent;
    cursor: pointer;
}
.color-cell:hover { border-color: var(--text); transform: scale(1.12); }

.color-custom {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; margin-bottom: 10px;
    color: var(--text-muted); font-size: 0.88rem;
}
.color-custom input[type="color"] {
    width: 46px; height: 30px; padding: 0;
    border: 1px solid var(--border); border-radius: var(--radius-sm);
    background: none; cursor: pointer;
}

/* ---------- Сетка предметов ---------- */
.cosmetic-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: 16px;
    margin-bottom: 8px;
}

.cosmetic-card {
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 12px;
    text-align: center;
    display: flex;
    flex-direction: column;
    /* Раньше был единый flex gap между всеми блоками — из-за него
       нельзя было отдельно увеличить только пару конкретных промежутков.
       Теперь расстояния заданы явными margin у каждого блока: карточка
       в целом стала ниже (меньше padding и превью), а вокруг описания
       и перед кнопкой «Надеть» — наоборот, просторнее, чем было. */
}
.cosmetic-card.is-equipped { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent-ring); }
.cosmetic-card.is-locked { opacity: 0.55; }

.cosmetic-preview { display: flex; justify-content: center; margin-bottom: 5px; }

/* Образец крупнее прежнего: пять рамок одной редкости различаются
   устройством кольца (сегменты, пунктир, половинки), а на 48 пикселях с
   тонкой обводкой эта разница просто не читалась. */
.cosmetic-frame-preview {
    width: 58px; height: 58px;
    border-radius: 50%;
    padding: 0;
    display: inline-flex;
    border: 2px solid var(--accent);
    background: none;
}
/* Рамка заменяет классическую фиолетовую обводку, а не ложится поверх */
.cosmetic-frame-preview.has-frame { border: none; padding: 6px; }

.cosmetic-avatar {
    flex: 1;
    border-radius: 50%;
    overflow: hidden;
    background: var(--surface-2);
    display: flex; align-items: center; justify-content: center;
}
.cosmetic-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cosmetic-initials {
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 1.05rem;
    color: var(--accent-2);
}

.cosmetic-bg-preview {
    width: 100%; height: 46px;
    border-radius: var(--radius-sm);
    display: block;
    /* Светлее и с белой рамкой — только вид превью в инвентаре, сам
       фон при надевании применяется исходным цветом без изменений. */
    border: 1px solid rgba(255, 255, 255, 0.65);
    filter: brightness(1.18) saturate(1.05);
}

.cosmetic-name { color: var(--text); font-size: 1rem; margin: 0 0 3px; }
.cosmetic-desc { color: var(--text-dim); font-size: 0.82rem; flex: 1; margin: 6px 0 12px; }

.cosmetic-rarity {
    align-self: center;
    padding: 2px 10px;
    margin-bottom: 10px;
    border-radius: 999px;
    font-size: 0.74rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    border: 1px solid currentColor;
    background: color-mix(in srgb, currentColor 14%, transparent);
}
.rarity-common     { color: var(--text-dim); }
.rarity-rare       { color: var(--success); }
.rarity-super_rare { color: var(--info); }
.rarity-epic       { color: var(--game-fortnite); }
.rarity-mythical   { color: var(--danger); }
.rarity-legendary  { color: var(--gold); }
.rarity-premium    { color: var(--gold); }
.rarity-seasonal   { color: var(--gold); }
/* Pass Premium — вершина шкалы редкости, только с золотой дорожки
   Dantes Pass (уровни 15/25, supabase/pass_premium_rarity.sql). Бейдж
   пульсирует тем же --glow-premium, что и активная плашка подписки —
   сама вещь (рамка/фон) анимирована отдельно, это только бейдж. */
@keyframes rarity-pass-premium-pulse {
    0%, 100% { box-shadow: 0 0 0 0 transparent; }
    50%      { box-shadow: var(--glow-premium); }
}
.rarity-pass_premium {
    color: var(--gold);
    animation: rarity-pass-premium-pulse 2.4s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .rarity-pass_premium { animation: none; }
}

.cosmetic-locked {
    display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    color: var(--text-dim); font-size: 0.85rem; padding: 8px 0;
}

/* ---------- Уровни в карточке игрока ---------- */
.user-card-hero {
    position: relative;
    border-radius: var(--radius-lg);
    padding: 22px 18px;
    margin-bottom: 16px;
    background: var(--surface-3);
    overflow: hidden;
}

/* Фон собеседника может быть каким угодно — хоть залитым солнцем лугом.
   Ровная тёмная вуаль поверх картинки делает контраст независимым от неё,
   а сама картинка остаётся видна. Та же приёмка, что в профиле. */
.user-card-hero.has-bg::before {
    content: '';
    position: absolute;
    inset: 0;
    background: rgba(8, 8, 26, 0.5);
    pointer-events: none;
}
.user-card-hero > * { position: relative; }
.user-card-hero .avatar-frame {
    display: flex;
    width: max-content;          /* без этого кольцо растягивается на всю плашку */
    margin: 0 auto 14px;
}
.user-card-hero .user-card-avatar { margin: 0; }

.user-card-subhead {
    color: var(--text-muted);
    font-size: 0.82rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 10px;
}

.user-card-levels {
    text-align: left;
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
}

.card-level-row {
    display: flex; align-items: center; gap: 12px;
    padding: 9px 0;
}
.card-level-icon {
    width: 34px; height: 34px; flex-shrink: 0;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--accent-2);
    display: flex; align-items: center; justify-content: center;
    font-size: 0.9rem;
}
.card-level-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.card-level-name { color: var(--text); font-weight: 600; font-size: 0.92rem; }
.card-level-title { color: var(--text-dim); font-size: 0.82rem; }
.card-level-value {
    font-family: var(--font-head); font-weight: 700;
    color: var(--accent-2); flex-shrink: 0;
}

.card-crown {
    display: flex; align-items: center; gap: 8px;
    margin-top: 10px; padding-top: 10px;
    border-top: 1px solid var(--border);
    color: var(--gold); font-weight: 600;
}

.user-card-footer { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }

@media (max-width: 560px) {
    .cosmetic-grid { grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); }
    .color-popover { width: 208px; }
}


/* ---------- Выбор титула в инвентаре ---------- */
.title-choice {
    cursor: pointer;
    font-family: var(--font-body);
    text-align: left;
}
.title-choice:hover { border-color: var(--gold); transform: translateY(-1px); }
.title-choice[aria-pressed="true"] { box-shadow: 0 0 0 2px color-mix(in srgb, var(--gold) 55%, transparent); }

.level-title-colored { font-weight: 600; }


/* ============================================================
   Настройки: подразделы, Premium, монеты, история
   ============================================================ */

/* ---------- Переключатель подразделов ---------- */
.subtabs {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 22px;
    padding-bottom: 14px;
    /* Раньше линия была почти не видна (особенно в светлой теме) —
       делаем её толще и подсвечиваем акцентным цветом. */
    border-bottom: 2px solid color-mix(in srgb, var(--accent) 35%, var(--border));
}

.subtab {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 9px 16px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-3);
    color: var(--text-dim);
    font-family: var(--font-body);
    font-size: 0.9rem;
    font-weight: 500;
    cursor: pointer;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.subtab:hover { color: var(--text); border-color: var(--accent); }
.subtab[aria-selected="true"] {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}
.subtab i { font-size: 0.85rem; }

.subtab-pane { animation: fade-in 0.25s ease; }

/* ---------- Шапка Premium ---------- */
.premium-hero {
    display: flex; align-items: center; gap: 16px;
    padding: 20px;
    margin-bottom: 22px;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface-3);
    transition: border-color var(--transition-slow), background var(--transition-slow), box-shadow var(--transition-slow);
}
.premium-hero.is-active {
    border-color: color-mix(in srgb, var(--gold) 55%, transparent);
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--gold) 12%, var(--surface-3)),
        var(--surface-3));
    box-shadow: var(--glow-premium);
}
.premium-hero > i {
    width: 52px; height: 52px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%;
    font-size: 1.3rem;
    color: var(--gold);
    background: color-mix(in srgb, var(--gold) 16%, transparent);
    transition: box-shadow var(--transition-slow);
}
.premium-hero.is-active > i {
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--gold) 40%, transparent),
                0 0 18px -2px color-mix(in srgb, var(--gold) 55%, transparent);
}
.premium-hero > div { flex: 1; min-width: 0; }
.premium-hero h4 {
    font-family: var(--font-head);
    color: var(--text);
    margin-bottom: 4px;
}
.premium-hero p { color: var(--text-dim); font-size: 0.9rem; margin: 0; }

.premium-state {
    flex-shrink: 0;
    padding: 5px 13px;
    border-radius: 999px;
    font-size: 0.78rem; font-weight: 600;
    color: var(--text-dim);
    border: 1px solid var(--border);
    background: var(--surface-2);
}
.premium-hero.is-active .premium-state {
    color: var(--gold);
    border-color: color-mix(in srgb, var(--gold) 50%, transparent);
    background: color-mix(in srgb, var(--gold) 14%, transparent);
}

/* ---------- Что входит в подписку ---------- */
.perk-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 12px;
    margin-bottom: 26px;
}
.perk {
    display: flex; align-items: flex-start; gap: 12px;
    padding: 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
}
.perk > i {
    width: 34px; height: 34px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%;
    font-size: 0.9rem;
    color: var(--accent-2);
    background: var(--accent-soft);
}
.perk > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.perk strong { color: var(--text); font-size: 0.93rem; }
.perk span { color: var(--text-dim); font-size: 0.83rem; }

/* ---------- Тарифы и пакеты монет ----------
   Пакеты монет за рубли с сайта убраны (см. js/profile.js и
   supabase/disable_coin_purchase.sql), и правила .pack-* больше никем не
   используются. Не удаляем их только потому, что почти все они общие с
   .plan-* — тарифами Premium, которые на месте: разбирать общий селектор
   ради пары мёртвых строк — лишний риск сломать живое. */
.plan-grid,
.pack-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 16px;
    margin-bottom: 14px;
}

.plan-card,
.pack-card {
    position: relative;
    display: flex; flex-direction: column; gap: 6px;
    padding: 20px 16px 16px;
    text-align: center;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
    transition: border-color var(--transition), transform var(--transition);
}
.plan-card:hover,
.pack-card:hover { border-color: var(--accent); transform: translateY(-2px); }

.plan-card h5,
.pack-card h5 {
    font-family: var(--font-head);
    color: var(--text);
    font-size: 1rem;
}

.plan-badge {
    position: absolute; top: -10px; right: 12px;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 0.74rem; font-weight: 700;
    color: #fff;
    background: var(--success);
    box-shadow: var(--shadow-sm);
}

.plan-price,
.pack-coins {
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 1.25rem;
    color: var(--gold);
    margin: 0;
}
.plan-per-month {
    color: var(--text-dim);
    font-size: 0.8rem;
    margin: 0 0 10px;
}

.pack-card > i {
    align-self: center;
    width: 44px; height: 44px;
    display: flex; align-items: center; justify-content: center;
    margin-bottom: 4px;
    border-radius: 50%;
    font-size: 1.1rem;
    color: var(--gold);
    background: color-mix(in srgb, var(--gold) 15%, transparent);
}
.pack-card .btn { margin-top: 10px; }

/* ---------- Премиум-настройки ---------- */
.premium-settings { display: flex; flex-direction: column; gap: 12px; }

.premium-setting {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    flex-wrap: wrap;
    padding: 14px 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
}
.premium-setting > div:first-child { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.premium-setting strong { color: var(--text); font-size: 0.93rem; }
.premium-setting span { color: var(--text-dim); font-size: 0.83rem; }
.premium-setting-actions { display: flex; gap: 8px; flex-shrink: 0; }

/* ---------- Баланс монет ---------- */
.coins-balance {
    display: flex; align-items: center; gap: 16px;
    padding: 20px;
    margin-bottom: 24px;
    border: 1px solid color-mix(in srgb, var(--gold) 40%, var(--border));
    border-radius: var(--radius-lg);
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--gold) 12%, var(--surface-3)),
        var(--surface-3));
}
.coins-balance > i {
    width: 52px; height: 52px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%;
    font-size: 1.3rem;
    color: var(--gold);
    background: color-mix(in srgb, var(--gold) 18%, transparent);
}
.coins-balance > div { display: flex; flex-direction: column; }
.coins-balance-label { color: var(--text-dim); font-size: 0.85rem; }
.coins-balance-value {
    font-family: var(--font-head);
    font-size: 1.6rem;
    color: var(--gold);
    line-height: 1.2;
}

.demo-notice {
    display: flex; align-items: flex-start; gap: 9px;
    padding: 11px 14px;
    margin-bottom: 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    color: var(--text-dim);
    font-size: 0.84rem;
}
.demo-notice i { color: var(--info); margin-top: 2px; }

/* ---------- Подарок монет ---------- */
.gift-form .add-friend-row { flex-wrap: wrap; }
.gift-amount { max-width: 130px; flex: 0 1 130px; }

/* ---------- История операций ---------- */
.tx-kind { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; }
.tx-kind i { color: var(--text-dim); font-size: 0.82rem; }

.tx-amount { font-weight: 700; white-space: nowrap; }
.tx-amount.is-in  { color: var(--success); }
.tx-amount.is-out { color: var(--danger); }

/* ---------- Переливающийся ник ---------- */
.nick-rainbow {
    background: linear-gradient(90deg,
        #ff6b6b, #ffd93d, #6bcb77, #4d96ff, #b06bff, #ff6b6b);
    background-size: 300% 100%;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
    animation: nick-shimmer 6s linear infinite;
}
@keyframes nick-shimmer {
    to { background-position: -300% 0; }
}
@media (prefers-reduced-motion: reduce) {
    .nick-rainbow { animation: none; }
}

/* Скин поверх .nick-rainbow (турниры: переливающееся название,
   лидерборд: переливающийся ник — оба выбираются из открытых
   редкостей, см. js/boosters.js/skinPickerHtml). У легендарной
   отдельного варианта нет — ей и так достаётся полный радужный
   градиент по умолчанию выше, это её собственный, самый богатый вид.

   -webkit-background-clip/background-clip повторены здесь явно, а не
   унаследованы из .nick-rainbow — это и была причина бага «ник и
   название сплошным цветом» в лидерборде/турнирах (там, где скин
   вообще применяется). Свойство background — сокращённая запись:
   когда её задают повторно с бОльшей специфичностью (два класса
   здесь против одного у .nick-rainbow), она молча сбрасывает ВСЕ
   свои подсвойства к начальным, включая background-clip — обратно на
   border-box. Текст при этом всё ещё color:transparent, поэтому
   градиент просто заливал всю прямоугольную область элемента, а не
   контур букв. */
.nick-rainbow.booster-skin-rare       { background: linear-gradient(90deg, #aab4c6, #e3e7ee, #aab4c6); background-size: 300% 100%; -webkit-background-clip: text; background-clip: text; }
.nick-rainbow.booster-skin-super_rare { background: linear-gradient(90deg, #4fc3f7, #b3e5fc, #4fc3f7); background-size: 300% 100%; -webkit-background-clip: text; background-clip: text; }
.nick-rainbow.booster-skin-epic       { background: linear-gradient(90deg, #b388ff, #e1bee7, #b388ff); background-size: 300% 100%; -webkit-background-clip: text; background-clip: text; }
.nick-rainbow.booster-skin-mythical   { background: linear-gradient(90deg, #ff7043, #ffccbc, #ff7043); background-size: 300% 100%; -webkit-background-clip: text; background-clip: text; }


@media (max-width: 560px) {
    .subtabs { gap: 6px; }
    .subtab { padding: 8px 12px; font-size: 0.85rem; }
    .premium-hero, .coins-balance { flex-wrap: wrap; }
    .premium-state { order: 3; }
    .plan-grid, .pack-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
    .gift-amount { max-width: none; flex: 1 1 100%; }
}


/* ============================================================
   Внешний вид собеседника в чате: рамка, титул, премиум-метка
   ============================================================ */

/* Рамка вокруг аватарки в плашке чата */
.chat-avatar-frame {
    display: inline-flex;
    border-radius: 50%;
    padding: 0;
    flex-shrink: 0;
}
.chat-avatar-frame.has-frame { padding: 3px; }
.chat-avatar-frame > .chat-avatar-small,
.chat-avatar-frame > .friend-avatar-large { margin: 0; }

.dialog-peer .chat-avatar-frame { margin: 0 auto 12px; }
.dialog-peer .peer-title,
.dialog-peer .premium-mark { display: flex; width: max-content; margin: 0 auto 6px; }

/* Титул, юзернейм и метка Premium раньше шли отдельными строками одна
   под другой — с одинаковым нижним отступом, но разной шириной каждая
   строка «гуляла» от центра по-своему, и вся плашка выглядела как
   набор случайных надписей, а не карточка одного человека. Теперь это
   один ряд чипов, как в других мессенджерах: центрируется целиком,
   переносится на телефоне, а margin:0 auto у каждого чипа (см. выше)
   здесь же и убираем — внутри flex-ряда он не нужен. */
.peer-badges {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
    gap: 6px;
    margin: 0 0 10px;
}
.peer-badges .peer-title,
.peer-badges .peer-username,
.peer-badges .premium-mark { margin: 0; width: auto; }

/* В плашке собеседника — столбиком: титул, под ним юзернейм. Рядом они
   читались как два равных чипа, хотя это разные вещи — звание и адрес. */
.peer-badges.is-stacked { flex-direction: column; gap: 8px; }

/* Ник собеседника: и в шапке (h3), и в панели справа (p) */
.peer-name {
    font-family: var(--font-head);
    font-weight: 700;
    color: var(--text);
    margin: 0 0 2px;
}
h3.peer-name { font-size: 1.05rem; }
p.peer-name  { font-size: 1.1rem; margin-bottom: 4px; }

/* Юзернейм собеседника — плашкой, как в профиле и в карточке игрока */
.peer-username {
    display: block;
    width: max-content;
    max-width: 100%;
    margin: 0 auto 6px;
    padding: 2px 11px;
    border-radius: 999px;
    background: var(--accent-soft);
    border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
    color: var(--accent-2);
    font-family: var(--font-head);
    font-weight: 600;
    font-size: 0.88rem;
}
.info-body-peer.has-bg .peer-username {
    background: rgba(8, 8, 26, 0.72);
    border-color: rgba(255, 255, 255, 0.4);
    color: #fff;
}

/* Титул под ником */
.peer-title {
    display: inline-flex; align-items: center; gap: 6px;
    margin: 0 0 4px;
    color: var(--gold);
    font-size: 0.83rem;
    font-weight: 600;
}
.peer-title i { font-size: 0.78rem; }

/* Метка подписки */
.premium-mark {
    display: inline-flex; align-items: center; gap: 6px;
    margin: 0 0 6px;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.75rem; font-weight: 600;
    color: var(--gold);
    border: 1px solid color-mix(in srgb, var(--gold) 50%, transparent);
    background: color-mix(in srgb, var(--gold) 13%, transparent);
    box-shadow: 0 0 10px -4px color-mix(in srgb, var(--gold) 60%, transparent);
}
.premium-mark-inline { margin: 0 0 0 auto; align-self: center; flex-shrink: 0; }

.chat-title-btn { display: flex; align-items: center; gap: 12px; width: 100%; }

/* Фон собеседника растянут на всю правую панель (а не только на верхнюю
   карточку) — весь блок справа должен читаться как профиль. Класс has-bg
   ставится и для градиента, и для своей картинки, вуаль покрывает всю
   прокручиваемую область, поэтому текст не тонет независимо от раздела. */
.info-body-peer { padding-top: 0; position: relative; }
/* Раньше .dialog-peer была обычной секцией списка — тот же тонкий
   border-bottom, что и у «Блокировки» ниже, из-за чего аватар, ник и
   чипы читались как несколько разрозненных строк на пустом фоне, а не
   одна карточка. Теперь у неё своя рамка, скругление и фон — она
   визуально «отклеивается» от списка секций и держится вместе. */
.info-body-peer .dialog-peer {
    margin: 14px 14px 18px;
    padding: 24px 16px 18px;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--surface-soft);
    box-shadow: 0 10px 26px rgba(0, 0, 0, 0.16);
}
/* Свой фон собеседника (has-bg) растянут на всю панель — карточка поверх
   него становится полупрозрачным «стеклом», а не сплошной заливкой,
   иначе фон под ней вообще не было бы видно. */
.info-body-peer.has-bg .dialog-peer {
    /* border-color для .has-bg уже задаёт общее правило
       .info-body-peer.has-bg .info-section чуть ниже по файлу —
       здесь трогаем только фон и стекло. */
    background: rgba(10, 8, 26, 0.4);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}
.info-body-peer.has-bg {
    position: relative;
    overflow: hidden;
}
.info-body-peer.has-bg::before {
    content: '';
    position: absolute;
    inset: 0;
    background: rgba(8, 8, 26, 0.5);
    pointer-events: none;
}

/* ---------- Переливающиеся фоны Premium ----------
   Готовые градиенты из инвентаря (не своя загруженная картинка — та
   остаётся неподвижной, чтобы не портить чужое фото) получают бегущий
   по диагонали блик, как переливы на фольге. Один и тот же приём
   применяется везде, где рисуется .has-bg: карточка игрока в чате,
   панель собеседника, шапка стрима и сама страница профиля (там своего
   класса has-bg нет — вместо него отдельный has-cosmetic-bg, см. выше). */
.user-card-hero.has-bg:not(.has-custom-bg)::after,
.info-body-peer.has-bg:not(.has-custom-bg)::after,
.watch-streamer.has-bg:not(.has-custom-bg)::after,
.profile-canvas.has-cosmetic-bg::after {
    content: '';
    position: absolute;
    top: -30%;
    left: -35%;
    width: 35%;
    height: 160%;
    background: linear-gradient(75deg,
        transparent 0%, rgba(255, 255, 255, 0.16) 45%,
        rgba(255, 255, 255, 0.34) 50%, rgba(255, 255, 255, 0.16) 55%, transparent 100%);
    pointer-events: none;
    z-index: 0;
    animation: premium-bg-shimmer 4s linear infinite;
}
/* Раньше блик 50% времени цикла стоял неподвижно за краями контейнера
   (0-15% и 65-100% — одно и то же значение transform), из-за чего
   казалось, что анимация фона периодически «останавливается». Убрали
   паузу, но с ease-in-out блик всё равно ощутимо тормозил у границ
   каждого витка (это встроенное свойство самого easing — скорость
   стремится к нулю на обоих концах) и на стыке витков «замирал» на
   мгновение перед скачком обратно к началу. linear даёт постоянную
   скорость без замедления — блик всегда именно «уходит», а не стоит.
   Отдельная и более серьёзная ошибка в самих значениях translateX:
   проценты в translateX считаются от ширины САМОГО элемента (35% от
   контейнера), а не от ширины контейнера — 320% сдвигали блик всего на
   320%×35%≈112% ширины контейнера, а не на 320%. Из-за этого к концу
   витка левый край блика оставался на ~89% контейнера — то есть блик
   ещё на две трети торчал внутри рамки, когда анимация мгновенно
   прыгала обратно к началу: выглядело как обрыв на полпути, а не как
   уход за край. -20%/450% (от ширины самого блика) гарантированно
   уводят его целиком за оба края контейнера с запасом, независимо от
   размера контейнера — расчёт проверен на реальных пикселях страницы. */
@keyframes premium-bg-shimmer {
    0%   { transform: translateX(-20%) rotate(10deg); }
    100% { transform: translateX(450%) rotate(10deg); }
}
@media (prefers-reduced-motion: reduce) {
    .user-card-hero.has-bg:not(.has-custom-bg)::after,
    .info-body-peer.has-bg:not(.has-custom-bg)::after,
    .watch-streamer.has-bg:not(.has-custom-bg)::after,
    .profile-canvas.has-cosmetic-bg::after {
        animation: none;
        display: none;
    }
}
.info-body-peer.has-bg > * { position: relative; }
.info-body-peer.has-bg .info-section { border-color: rgba(255, 255, 255, 0.18); }
.info-body-peer.has-bg .peer-name { text-shadow: 0 2px 8px rgba(0, 0, 0, 0.75); }
.info-body-peer.has-bg .peer-name,
.info-body-peer.has-bg .chat-description,
.info-body-peer.has-bg .chat-status,
.info-body-peer.has-bg h4 { color: #fff; }
.info-body-peer.has-bg .peer-title,
.info-body-peer.has-bg .premium-mark {
    background: rgba(10, 10, 30, 0.6);
    color: #ffd766;
    border-color: rgba(255, 255, 255, 0.35);
    padding: 2px 10px;
    border-radius: 999px;
}
.info-body-peer.has-bg .btn {
    background: rgba(10, 10, 30, 0.68);
    color: #fff;
    border-color: rgba(255, 255, 255, 0.55);
}
.info-body-peer.has-bg .btn:hover:not(:disabled) {
    background: rgba(10, 10, 30, 0.88);
    border-color: #fff;
}

/* Титул и подписка в карточке игрока */
.user-card-title {
    display: flex; align-items: center; justify-content: center; gap: 6px;
    width: max-content; max-width: 100%;
    margin: 2px auto 6px;
    color: var(--gold);
    font-size: 0.9rem; font-weight: 600;
}
.user-card-hero .premium-mark { display: flex; width: max-content; margin: 0 auto 6px; }

/* Ник и юзернейм должны читаться и на светлой картинке */
.user-card-hero.has-bg .user-card-name {
    color: #fff;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.75);
}
.user-card-hero.has-bg .user-card-presence { color: #fff; }
.user-card-hero.has-bg .user-card-username {
    background: rgba(8, 8, 26, 0.72);
    border-color: rgba(255, 255, 255, 0.4);
    color: #fff;
}
.user-card-hero.has-bg .user-card-title,
.user-card-hero.has-bg .premium-mark {
    background: rgba(10, 10, 30, 0.6);
    color: #ffd766;
    border: 1px solid rgba(255, 255, 255, 0.35);
    padding: 2px 10px;
    border-radius: 999px;
}

/* Перелив внутри строки-сообщения */
.message-sender.nick-rainbow { font-weight: 700; }


/* ============================================================
   Комнаты по приглашению, настройки чата, история и поиск
   ============================================================ */

/* ---------- Переключатель режимов с кнопкой переименования ---------- */
.chat-modes .btn-icon {
    flex: 0 0 auto;
    width: 34px; height: 34px;
    border-radius: var(--radius-sm);
}
.mode-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---------- Кнопки под списком чатов ---------- */
.chat-list-actions {
    display: flex; gap: 8px;
    padding: 10px;
    flex-shrink: 0;
    border-top: 1px solid var(--border);
}
.chat-list-actions .btn { flex: 1; justify-content: center; }

.rooms-hint { text-align: center; padding: 0 14px 10px; }

/* Число участников в строке комнаты */
.chat-room-meta {
    display: inline-flex; align-items: center; gap: 4px;
    flex-shrink: 0;
    color: var(--text-dim);
    font-size: 0.76rem;
}

/* ---------- Панель справа: шапка не уезжает при прокрутке ---------- */
.chat-info-panel { padding: 0; overflow: hidden; }
.info-body { flex: 1; overflow-y: auto; }

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

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

   Свои обои (настройки чата) кладутся в style.background и перекрывают
   это целиком — ничего специально отключать не нужно. */
.chat-messages,
.bracket-viewport {
    background-color: var(--surface-3);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200' viewBox='0 0 200 200'%3E%3Cg fill='none' stroke='rgba(150,142,255,0.14)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M32 20l3.4 6.9 7.6 1.1-5.5 5.4 1.3 7.6-6.8-3.6-6.8 3.6 1.3-7.6-5.5-5.4 7.6-1.1z'/%3E%3Cpath d='M104 26c-3-5.6-11.6-4.6-11.6 1.9 0 5.6 7.7 10.3 11.6 13.1 3.9-2.8 11.6-7.5 11.6-13.1 0-6.5-8.6-7.5-11.6-1.9z'/%3E%3Cpath d='M166 16l-9.5 15h7.2l-4.2 13.5 10.5-16h-7.1z'/%3E%3Crect x='20' y='88' width='32' height='19' rx='9.5'/%3E%3Cpath d='M28 94v6M25 97h6'/%3E%3Ccircle cx='44' cy='95.5' r='2'/%3E%3Ccircle cx='40' cy='100' r='2'/%3E%3Cpath d='M94 84h16v9a8 8 0 0 1-16 0z'/%3E%3Cpath d='M94 86h-5a5 5 0 0 0 5 5'/%3E%3Cpath d='M110 86h5a5 5 0 0 1-5 5'/%3E%3Cpath d='M98 102h8'/%3E%3Cpath d='M95 108h14'/%3E%3Cpath d='M152 84h24a5 5 0 0 1 5 5v13a5 5 0 0 1-5 5h-13l-8 6v-6h-3a5 5 0 0 1-5-5V89a5 5 0 0 1 5-5z'/%3E%3Crect x='22' y='150' width='22' height='22' rx='6'/%3E%3Ccircle cx='28.5' cy='156.5' r='1.7'/%3E%3Ccircle cx='37.5' cy='165.5' r='1.7'/%3E%3Cpath d='M90 168l3.5-13 6.5 7.5 6.5-7.5 3.5 13z'/%3E%3Cpath d='M91 171h18'/%3E%3Ccircle cx='164' cy='158' r='11'/%3E%3Ccircle cx='164' cy='158' r='4.5'/%3E%3C/g%3E%3C/svg%3E"), url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200' viewBox='0 0 200 200'%3E%3Cg fill='none' stroke='rgba(150,142,255,0.14)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M32 20l3.4 6.9 7.6 1.1-5.5 5.4 1.3 7.6-6.8-3.6-6.8 3.6 1.3-7.6-5.5-5.4 7.6-1.1z'/%3E%3Cpath d='M104 26c-3-5.6-11.6-4.6-11.6 1.9 0 5.6 7.7 10.3 11.6 13.1 3.9-2.8 11.6-7.5 11.6-13.1 0-6.5-8.6-7.5-11.6-1.9z'/%3E%3Cpath d='M166 16l-9.5 15h7.2l-4.2 13.5 10.5-16h-7.1z'/%3E%3Crect x='20' y='88' width='32' height='19' rx='9.5'/%3E%3Cpath d='M28 94v6M25 97h6'/%3E%3Ccircle cx='44' cy='95.5' r='2'/%3E%3Ccircle cx='40' cy='100' r='2'/%3E%3Cpath d='M94 84h16v9a8 8 0 0 1-16 0z'/%3E%3Cpath d='M94 86h-5a5 5 0 0 0 5 5'/%3E%3Cpath d='M110 86h5a5 5 0 0 1-5 5'/%3E%3Cpath d='M98 102h8'/%3E%3Cpath d='M95 108h14'/%3E%3Cpath d='M152 84h24a5 5 0 0 1 5 5v13a5 5 0 0 1-5 5h-13l-8 6v-6h-3a5 5 0 0 1-5-5V89a5 5 0 0 1 5-5z'/%3E%3Crect x='22' y='150' width='22' height='22' rx='6'/%3E%3Ccircle cx='28.5' cy='156.5' r='1.7'/%3E%3Ccircle cx='37.5' cy='165.5' r='1.7'/%3E%3Cpath d='M90 168l3.5-13 6.5 7.5 6.5-7.5 3.5 13z'/%3E%3Cpath d='M91 171h18'/%3E%3Ccircle cx='164' cy='158' r='11'/%3E%3Ccircle cx='164' cy='158' r='4.5'/%3E%3C/g%3E%3C/svg%3E");
    background-size: 260px 260px, 173px 173px;
    background-position: 0 0, 86px 52px;
    background-repeat: repeat, repeat;
}
:root[data-theme="light"] .chat-messages,
:root[data-theme="light"] .bracket-viewport {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200' viewBox='0 0 200 200'%3E%3Cg fill='none' stroke='rgba(90,80,190,0.13)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M32 20l3.4 6.9 7.6 1.1-5.5 5.4 1.3 7.6-6.8-3.6-6.8 3.6 1.3-7.6-5.5-5.4 7.6-1.1z'/%3E%3Cpath d='M104 26c-3-5.6-11.6-4.6-11.6 1.9 0 5.6 7.7 10.3 11.6 13.1 3.9-2.8 11.6-7.5 11.6-13.1 0-6.5-8.6-7.5-11.6-1.9z'/%3E%3Cpath d='M166 16l-9.5 15h7.2l-4.2 13.5 10.5-16h-7.1z'/%3E%3Crect x='20' y='88' width='32' height='19' rx='9.5'/%3E%3Cpath d='M28 94v6M25 97h6'/%3E%3Ccircle cx='44' cy='95.5' r='2'/%3E%3Ccircle cx='40' cy='100' r='2'/%3E%3Cpath d='M94 84h16v9a8 8 0 0 1-16 0z'/%3E%3Cpath d='M94 86h-5a5 5 0 0 0 5 5'/%3E%3Cpath d='M110 86h5a5 5 0 0 1-5 5'/%3E%3Cpath d='M98 102h8'/%3E%3Cpath d='M95 108h14'/%3E%3Cpath d='M152 84h24a5 5 0 0 1 5 5v13a5 5 0 0 1-5 5h-13l-8 6v-6h-3a5 5 0 0 1-5-5V89a5 5 0 0 1 5-5z'/%3E%3Crect x='22' y='150' width='22' height='22' rx='6'/%3E%3Ccircle cx='28.5' cy='156.5' r='1.7'/%3E%3Ccircle cx='37.5' cy='165.5' r='1.7'/%3E%3Cpath d='M90 168l3.5-13 6.5 7.5 6.5-7.5 3.5 13z'/%3E%3Cpath d='M91 171h18'/%3E%3Ccircle cx='164' cy='158' r='11'/%3E%3Ccircle cx='164' cy='158' r='4.5'/%3E%3C/g%3E%3C/svg%3E"), url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200' viewBox='0 0 200 200'%3E%3Cg fill='none' stroke='rgba(90,80,190,0.13)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M32 20l3.4 6.9 7.6 1.1-5.5 5.4 1.3 7.6-6.8-3.6-6.8 3.6 1.3-7.6-5.5-5.4 7.6-1.1z'/%3E%3Cpath d='M104 26c-3-5.6-11.6-4.6-11.6 1.9 0 5.6 7.7 10.3 11.6 13.1 3.9-2.8 11.6-7.5 11.6-13.1 0-6.5-8.6-7.5-11.6-1.9z'/%3E%3Cpath d='M166 16l-9.5 15h7.2l-4.2 13.5 10.5-16h-7.1z'/%3E%3Crect x='20' y='88' width='32' height='19' rx='9.5'/%3E%3Cpath d='M28 94v6M25 97h6'/%3E%3Ccircle cx='44' cy='95.5' r='2'/%3E%3Ccircle cx='40' cy='100' r='2'/%3E%3Cpath d='M94 84h16v9a8 8 0 0 1-16 0z'/%3E%3Cpath d='M94 86h-5a5 5 0 0 0 5 5'/%3E%3Cpath d='M110 86h5a5 5 0 0 1-5 5'/%3E%3Cpath d='M98 102h8'/%3E%3Cpath d='M95 108h14'/%3E%3Cpath d='M152 84h24a5 5 0 0 1 5 5v13a5 5 0 0 1-5 5h-13l-8 6v-6h-3a5 5 0 0 1-5-5V89a5 5 0 0 1 5-5z'/%3E%3Crect x='22' y='150' width='22' height='22' rx='6'/%3E%3Ccircle cx='28.5' cy='156.5' r='1.7'/%3E%3Ccircle cx='37.5' cy='165.5' r='1.7'/%3E%3Cpath d='M90 168l3.5-13 6.5 7.5 6.5-7.5 3.5 13z'/%3E%3Cpath d='M91 171h18'/%3E%3Ccircle cx='164' cy='158' r='11'/%3E%3Ccircle cx='164' cy='158' r='4.5'/%3E%3C/g%3E%3C/svg%3E");
}
/* Свои обои — сплошная заливка, узор под ними не нужен. */
.chat-messages.has-wallpaper { background-image: none; background-attachment: local; }

.wallpaper-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
    gap: 10px;
    margin-bottom: 20px;
}
.wallpaper-cell {
    display: flex; flex-direction: column; gap: 6px;
    padding: 6px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
    cursor: pointer;
    font-family: var(--font-body);
    transition: border-color var(--transition), transform var(--transition);
}
.wallpaper-cell:hover { border-color: var(--accent); transform: translateY(-1px); }
.wallpaper-cell.is-active { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-ring); }
.wallpaper-preview {
    height: 56px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    display: block;
}
.wallpaper-name { color: var(--text-dim); font-size: 0.78rem; text-align: center; }

/* ---------- Выбор из нескольких вариантов ----------
   Окно для вопросов, у которых больше двух ответов: удалить у себя или
   у обоих, очистить историю себе или обоим. Каждый вариант — строка с
   названием и пояснением под ним: пояснение здесь и нужно, потому что
   разница между вариантами именно в последствиях. */
.choose-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; }

.choose-item {
    display: flex; align-items: flex-start; gap: 13px;
    width: 100%;
    padding: 13px 15px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
    color: var(--text);
    font-family: var(--font-body);
    text-align: left;
    cursor: pointer;
    transition: border-color var(--transition), background var(--transition);
}
.choose-item:hover, .choose-item:focus-visible {
    border-color: var(--accent);
    background: var(--accent-soft);
}
.choose-item > i:first-child {
    width: 20px;
    flex-shrink: 0;
    margin-top: 2px;
    text-align: center;
    color: var(--accent-2);
}
.choose-item-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.choose-item-label { font-weight: 600; }
.choose-item-hint { color: var(--text-dim); font-size: 0.82rem; line-height: 1.45; }

.choose-item.is-danger > i:first-child { color: var(--danger); }
.choose-item.is-danger .choose-item-label { color: var(--danger); }
.choose-item.is-danger:hover {
    border-color: var(--danger);
    background: color-mix(in srgb, var(--danger) 12%, transparent);
}

/* ---------- Выбор значка комнаты ---------- */
.icon-picker {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(46px, 1fr));
    gap: 8px;
}
.icon-cell {
    height: 44px;
    display: flex; align-items: center; justify-content: center;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-3);
    color: var(--text-dim);
    cursor: pointer;
    transition: color var(--transition), border-color var(--transition);
}
.icon-cell:hover { color: var(--accent-2); border-color: var(--accent); }
.icon-cell.is-active {
    color: var(--on-accent);
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    border-color: transparent;
}

/* ---------- Ссылка-приглашение ---------- */
.invite-box {
    padding: 12px 14px;
    margin: 12px 0;
    border: 1px dashed var(--accent);
    border-radius: var(--radius-md);
    background: var(--surface-3);
}
.invite-link {
    display: block;
    color: var(--accent-2);
    font-size: 0.86rem;
    word-break: break-all;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

/* ---------- Участники комнаты ---------- */
.members-grid { display: flex; flex-direction: column; gap: 8px; }

.member-row {
    display: flex; align-items: center; gap: 12px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
}
.member-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.member-name { color: var(--text); font-weight: 600; font-size: 0.93rem; }
.member-meta { color: var(--text-dim); font-size: 0.8rem; }
.member-title { color: var(--gold); }

.member-role {
    flex-shrink: 0;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.74rem; font-weight: 600;
    border: 1px solid currentColor;
    background: color-mix(in srgb, currentColor 13%, transparent);
}
.role-owner  { color: var(--gold); }
.role-admin  { color: var(--info); }
.role-member { color: var(--text-dim); }

.member-actions { display: flex; gap: 6px; flex-shrink: 0; }
.btn-icon-danger:hover { color: var(--danger); border-color: var(--danger); }

/* ---------- Поиск по сообщениям ---------- */
.search-results { display: flex; flex-direction: column; gap: 8px; max-height: 420px; overflow-y: auto; }

.search-hit {
    display: flex; flex-direction: column; gap: 4px;
    padding: 11px 13px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
    text-align: left;
    cursor: pointer;
    font-family: var(--font-body);
    transition: border-color var(--transition);
}
.search-hit:hover { border-color: var(--accent); }
.search-hit-head {
    display: flex; justify-content: space-between; gap: 10px;
    color: var(--text-dim); font-size: 0.79rem;
}
.search-hit-head strong { color: var(--accent-2); }
.search-hit-body { color: var(--text); font-size: 0.9rem; word-break: break-word; }
.search-hit mark { background: color-mix(in srgb, var(--gold) 35%, transparent); color: inherit; border-radius: 3px; }

/* Найденное сообщение мигает в ленте */
.message.is-found .message-content {
    box-shadow: 0 0 0 2px var(--gold);
    transition: box-shadow 0.4s ease;
}

/* ---------- Закреплённые сообщения ---------- */
.pinned-list { display: flex; flex-direction: column; gap: 8px; max-height: 420px; overflow-y: auto; }

.pinned-row {
    display: flex; align-items: center; gap: 8px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
}

.pinned-row-body {
    flex: 1; min-width: 0;
    display: flex; flex-direction: column; gap: 4px;
    padding: 11px 13px;
    text-align: left;
    cursor: pointer;
    font-family: var(--font-body);
    background: transparent;
}
.pinned-row-body strong { color: var(--accent-2); font-size: 0.79rem; }
.pinned-row-body span {
    color: var(--text); font-size: 0.9rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pinned-row .btn-icon { flex-shrink: 0; width: 32px; height: 32px; font-size: 0.85rem; margin-right: 8px; }

/* ---------- История чата ---------- */
.subtab-count {
    display: inline-block;
    margin-left: 4px;
    padding: 0 6px;
    border-radius: 999px;
    background: var(--surface);
    color: inherit;
    font-size: 0.72rem;
}

.history-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 10px;
    max-height: 460px; overflow-y: auto;
}
.history-tile {
    position: relative;
    padding: 0; border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--surface-3);
    cursor: pointer;
    aspect-ratio: 1;
}
.history-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
.history-tile-date {
    position: absolute; left: 0; right: 0; bottom: 0;
    padding: 4px 6px;
    background: rgba(10, 10, 30, 0.7);
    color: #fff; font-size: 0.72rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.history-rows, .history-links {
    display: flex; flex-direction: column; gap: 8px;
    max-height: 460px; overflow-y: auto;
}

.history-row {
    display: flex; align-items: center; gap: 12px;
    padding: 11px 13px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
}
.history-row-icon {
    width: 36px; height: 36px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: var(--accent-soft); color: var(--accent-2);
}
.history-row-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.history-row-name { color: var(--text); font-size: 0.92rem; word-break: break-word; }
.history-row-meta { color: var(--text-dim); font-size: 0.79rem; }

.history-link {
    display: flex; align-items: center; gap: 11px;
    padding: 11px 13px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
    color: var(--text);
    text-decoration: none;
    transition: border-color var(--transition);
}
.history-link:hover { border-color: var(--accent); }
.history-link i { color: var(--accent-2); flex-shrink: 0; }
.history-link-url { flex: 1; min-width: 0; color: var(--accent-2); font-size: 0.87rem; word-break: break-all; }
.history-link-date { color: var(--text-dim); font-size: 0.78rem; flex-shrink: 0; }

@media (max-width: 768px) {
    .member-row { flex-wrap: wrap; }
    .member-actions { margin-left: auto; }
    .wallpaper-grid { grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); }
    .history-grid { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
}


/* ============================================================
   Лента постов
   ============================================================ */
.container-narrow { max-width: 780px; }
/* Сама лента по ширине — как раньше, .container-narrow (780px), и по
   центру страницы, а не по центру пары «сайдбар+лента» — иначе сайдбар
   слева перетягивал бы центр вправо. Колонка друзей/подписок поэтому
   не в общей сетке с лентой, а зафиксирована рядом (.feed-sidebar,
   position: fixed) — см. ниже. */
.container-feed { max-width: 780px; }

.feed-layout { position: relative; }

/* ---------- Слева: друзья и подписки ---------- */
.feed-sidebar {
    position: fixed;
    /* 140px = высота шапки (84px) + верхний отступ .main-content (56px,
       см. css/style.css) — тот же уровень, на котором начинается верхний
       ряд кнопок ленты («Всё» / «Написать пост»), а не подобранное на
       глаз число. */
    top: 140px;
    /* .container центрируется через margin:0 auto — левый край центра
       страницы минус половина ширины ленты (780/2), минус отступ,
       минус собственная ширина сайдбара. Так колонка встаёт вплотную
       слева от ленты, а не смещает её центровку. */
    left: calc(50% - 390px - 20px - 220px);
    width: 220px;
    /* При скролле верх сайдбара доезжает до 0 (см. updateSidebarStick()
       в js/posts.js) — вплотную к самому краю экрана, поверх липкой
       шапки сайта (у неё z-index: 1000, см. css/style.css), а не под ней. */
    z-index: 1001;
    display: flex;
    flex-direction: column;
    gap: 4px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 12px;
    /* Отступ снизу до края страницы — такой же, как сверху (140px),
       чтобы коробка не растягивалась ниже собственного содержимого и
       не вылезала за низ экрана. Длинные списки не скроллятся внутри
       этой коробки — вместо этого в конце длинной группы появляется
       кнопка «Показать ещё» (см. .feed-sidebar-more). */
    max-height: calc(100vh - 280px);
    max-height: calc(100dvh - 280px);
    /* auto, не hidden: «Показать ещё» покрывает обычный случай (список
       вмещается без скролла), а overflow-y тут — просто подстраховка на
       случай совсем невысокого окна или уже раскрытого большого списка,
       чтобы содержимое не обрезалось без возможности его увидеть. */
    overflow-y: auto;
    /* top и max-height обновляет JS на каждом кадре скролла
       (updateSidebarStick() в js/posts.js: «прилипание» к верху и
       подрезание высоты, чтобы не наезжать на футер снизу). Без
       transition каждое обновление было мгновенным скачком — с ним
       коробка плавно доезжает до новой позиции следом за скроллом. */
    transition: top 0.25s ease, max-height 0.25s ease;
}
.feed-sidebar-title {
    margin: 10px 0 2px;
    padding: 0 8px;
    color: var(--text-muted);
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.feed-sidebar-title:first-child { margin-top: 0; }
.feed-sidebar-item {
    display: flex; align-items: center; gap: 9px;
    width: 100%;
    padding: 7px 8px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--text);
    font-family: var(--font-body);
    font-size: 0.86rem;
    text-align: left;
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition);
}
.feed-sidebar-item:hover { background: var(--surface-3); }
.feed-sidebar-item.is-active {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 14%, transparent);
}
.feed-sidebar-avatar {
    width: 28px; height: 28px;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
    background: var(--accent-soft);
    color: var(--accent-2);
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-head); font-weight: 700; font-size: 0.72rem;
}
.feed-sidebar-avatar img { width: 100%; height: 100%; object-fit: cover; }
.feed-sidebar-all { background: var(--accent); color: var(--on-accent); }
.feed-sidebar-name {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.feed-sidebar-empty {
    padding: 4px 8px; margin: 0; color: var(--text-dim); font-size: 0.8rem;
}
.feed-sidebar-more {
    display: block;
    width: 100%;
    padding: 6px 8px;
    margin-top: 2px;
    border: none;
    background: none;
    color: var(--accent-2);
    font-family: var(--font-body);
    font-size: 0.8rem;
    font-weight: 600;
    text-align: left;
    cursor: pointer;
}
.feed-sidebar-more:hover { color: var(--accent); text-decoration: underline; }

/* ---------- Бейдж «сейчас смотрите ленту такого-то» ---------- */
.feed-filter-status {
    display: flex; align-items: center; justify-content: space-between;
    gap: 12px; flex-wrap: wrap;
    padding: 10px 14px;
    margin-bottom: 16px;
    border: 1px solid var(--accent);
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--accent) 10%, transparent);
    font-size: 0.88rem;
}

.feed-head {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 10px 16px; flex-wrap: wrap;
    margin-bottom: 22px;
}
.feed-head .btn { flex-shrink: 0; }
/* flex-basis: 100% — известный приём, чтобы элемент во flex-wrap занял
   всю строку целиком и всё, что идёт следом, гарантированно перешло на
   новую строку — иначе категории и «Друзья/Подписки» из двух рядов
   макета (см. pages/news.html) при достаточной ширине просто съезжались
   бы в один ряд вместо чёткого разделения на два. */
#feedFilters, #feedScopeFilters { flex: 1 0 100%; }

/* ---------- Ряд «таблеток» (категории, доступ) ---------- */
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; }

.chip {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 8px 14px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-3);
    color: var(--text-dim);
    font-family: var(--font-body);
    font-size: 0.87rem;
    cursor: pointer;
    transition: color var(--transition), border-color var(--transition), background var(--transition);
}
.chip:hover { color: var(--text); border-color: var(--accent); }
.chip.is-active {
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
    border-color: transparent;
    color: var(--on-accent);
}
.chip i { font-size: 0.82rem; }

/* ---------- Карточка поста ---------- */
.feed { display: flex; flex-direction: column; gap: 18px; }
#feedList { display: flex; flex-direction: column; gap: 18px; }

.post-card {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 18px;
    display: flex; flex-direction: column; gap: 12px;
}

.post-author { display: flex; align-items: center; gap: 12px; }
.post-avatar-btn {
    background: none; border: none; padding: 0; cursor: pointer; flex-shrink: 0;
    border-radius: 50%;
    transition: box-shadow var(--transition-fast), transform var(--transition-fast);
}
.post-avatar-btn:hover { box-shadow: 0 0 0 2px var(--accent-ring); transform: scale(1.05); }
.post-avatar-btn:active { transform: scale(0.96); }
.post-avatar-btn:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }

.post-avatar {
    width: 46px; height: 46px;
    border-radius: 50%;
    overflow: hidden;
    background: var(--accent-soft);
    color: var(--accent-2);
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-head); font-weight: 700;
    flex: 1;
}
.post-avatar img { width: 100%; height: 100%; object-fit: cover; }

.post-author-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }

.post-author-name {
    border: none; padding: 0;
    text-align: left; cursor: pointer;
    font-family: var(--font-head); font-weight: 700;
    font-size: 1rem;
}
/* :not(.nick-rainbow) — переливающийся ник (.nick-rainbow, ниже в этом
   же файле) красит текст через background-clip: text и держит сам
   color: transparent, а под буквами должен быть виден градиентный
   background. Это правило (та же специфичность, но объявлено ПОЗЖЕ
   .nick-rainbow в файле — при равном весе выигрывает более позднее)
   без исключения перебивало бы оба свойства: color на var(--text) и,
   что хуже, background на none — заливка глазами видна не была бы
   (color всё равно проигрывает -webkit-text-fill-color: transparent,
   который никто больше не трогает), а градиенту, который должен
   просвечивать сквозь прозрачные буквы, просто неоткуда взяться —
   ник у поста/комментария выглядел полностью невидимым. */
.post-author-name:not(.nick-rainbow) { background: none; color: var(--text); }
.post-author-name:not(.nick-rainbow):hover { color: var(--accent-2); }

.post-meta { color: var(--text-dim); font-size: 0.8rem; }
.post-title-badge { color: var(--gold); }

.post-friend-mark {
    display: inline-flex; align-items: center; gap: 6px;
    flex-shrink: 0;
    color: var(--success);
    font-size: 0.8rem; font-weight: 600;
}
.post-subscribe { flex-shrink: 0; }

/* Обложка поста — крупное фото сразу под шапкой автора, до текста
   (supabase/post_cover_image.sql). Не путать с .draft-media/attachments —
   те встроенные фото/видео поста, рендерятся сеткой ниже текста. */
.post-cover {
    margin: 0 -18px;
    overflow: hidden;
    max-height: 420px;
    background: var(--surface-soft);
}
.post-cover img { width: 100%; height: 100%; max-height: 420px; object-fit: cover; display: block; }

/* ---------- Метки категории и доступа ---------- */
.post-tags { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.post-category, .post-visibility {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 3px 11px;
    border-radius: 999px;
    font-size: 0.76rem; font-weight: 600;
    border: 1px solid currentColor;
    background: color-mix(in srgb, currentColor 12%, transparent);
}
.post-category.cat-platform    { color: var(--gold); }
.post-category.cat-life        { color: var(--game-fortnite); }
.post-category.cat-esports     { color: var(--info); }
.post-category.cat-tournaments { color: var(--success); }
.post-visibility { color: var(--text-dim); }

.post-delete { margin-left: auto; }

/* ---------- Тело поста ---------- */
.post-body {
    color: var(--text);
    line-height: 1.6;
    word-break: break-word;
    overflow-wrap: anywhere;
}
.post-body p { margin: 0 0 8px; }
.post-body p:last-child { margin-bottom: 0; }
.post-body ul, .post-body ol { margin: 0 0 8px 20px; }
.post-body blockquote {
    margin: 0 0 8px;
    padding-left: 12px;
    border-left: 3px solid var(--accent);
    color: var(--text-dim);
}

/* Гарнитура на весь пост */
.font-body { font-family: var(--font-body); }
.font-head { font-family: var(--font-head); }
.font-mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }

/* Размеры и цвета — только из белого списка в sanitizeRichText */
.post-lg { font-size: 1.15rem; }
.post-xl { font-size: 1.4rem; font-weight: 700; }

.post-ce8e8ff { color: #e8e8ff; }
.post-cff6b6b { color: #ff6b6b; }
.post-cffd93d { color: #ffd93d; }
.post-c6bcb77 { color: #6bcb77; }
.post-c4d96ff { color: #4d96ff; }
.post-cb06bff { color: #b06bff; }
.post-cff9f45 { color: #ff9f45; }
.post-c9aa0b5 { color: #9aa0b5; }

/* ---------- Вложения поста ---------- */
.post-media {
    display: grid;
    gap: 6px;
    border-radius: var(--radius-md);
    overflow: hidden;
}
.post-media.count-1 { grid-template-columns: 1fr; }
.post-media.count-2 { grid-template-columns: 1fr 1fr; }
.post-media.count-3,
.post-media.count-4 { grid-template-columns: 1fr 1fr; }

.post-media-cell {
    position: relative;
    padding: 0; border: none;
    background: var(--surface-3);
    cursor: pointer;
    overflow: hidden;
    max-height: 420px;
    display: flex;
}
.post-media-cell img,
.post-media-cell video { width: 100%; max-height: 420px; object-fit: cover; display: block; }
.post-media.count-1 .post-media-cell img,
.post-media.count-1 .post-media-cell video { object-fit: contain; background: #0c0c1e; }
.post-media-cell video { cursor: default; }

/* ---------- Лайк и комментарии ---------- */
.post-actions {
    display: flex; gap: 8px;
    padding-top: 6px;
    border-top: 1px solid var(--border);
}

.post-action {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 12px;
    border: 1px solid transparent;
    border-radius: 999px;
    background: transparent;
    color: var(--text-dim);
    font-family: var(--font-body);
    font-size: 0.85rem;
    cursor: pointer;
    transition: color var(--transition), background var(--transition);
}
.post-action:hover { color: var(--text); background: var(--surface-3); }
.post-action.is-active { color: var(--danger); }
.post-action.is-bookmarked { color: var(--accent); }
.post-count { font-weight: 600; }

/* ---------- Репост: пометка сверху + цитата оригинала ---------- */
.post-repost-mark {
    display: flex; align-items: center; gap: 8px;
    color: var(--text-dim); font-size: 0.82rem; font-weight: 600;
    margin-bottom: 4px;
}
.post-repost-mark .fa-retweet { color: var(--accent); }

.post-repost-quote {
    display: block;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 12px;
    margin: 4px 0 10px;
    text-decoration: none;
    color: inherit;
    background: var(--surface-2);
    transition: background var(--transition);
}
.post-repost-quote:hover { background: var(--surface-3); }
.post-repost-quote-author {
    display: flex; align-items: center; gap: 8px;
    font-weight: 700; font-size: 0.9rem;
    margin-bottom: 6px;
}
.post-repost-quote-author .avatar,
.post-repost-quote-author img { width: 26px; height: 26px; border-radius: 50%; }
.post-repost-quote-body {
    color: var(--text-dim); font-size: 0.9rem;
    max-height: 120px; overflow: hidden;
}

/* Просмотры — не кнопка, просто счётчик, курсор и ховер как у лайков
   с комментариями ей ни к чему. */
.post-views-count { cursor: default; margin-left: auto; }
.post-views-count:hover { color: var(--text-dim); background: transparent; }

.post-comments { border-top: 1px solid var(--border); padding-top: 12px; }
.comment-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 12px; }

.comment { display: flex; align-items: flex-start; gap: 10px; }
.comment-avatar {
    width: 34px; height: 34px;
    border-radius: 50%;
    overflow: hidden;
    background: var(--accent-soft); color: var(--accent-2);
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-head); font-weight: 700; font-size: 0.8rem;
    flex: 1;
}
.comment-avatar img { width: 100%; height: 100%; object-fit: cover; }

.comment-body { flex: 1; min-width: 0; }
.comment-head { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
.comment-name {
    border: none; padding: 0; cursor: pointer;
    font-family: var(--font-body); font-weight: 600; font-size: 0.88rem;
}
/* Тот же переливающийся ник и та же ловушка специфичности, что и у
   .post-author-name чуть выше — см. комментарий там. */
.comment-name:not(.nick-rainbow) { background: none; color: var(--accent-2); }
.comment-time { color: var(--text-dim); font-size: 0.76rem; }
.comment-text { color: var(--text); font-size: 0.92rem; margin: 2px 0 0; word-break: break-word; }

.comment-form { display: flex; gap: 8px; }
.comment-form .form-input { flex: 1; }

/* ============================================================
   Редактор поста
   ============================================================ */
.editor-toolbar {
    display: flex; flex-wrap: wrap; gap: 10px;
    padding: 8px;
    border: 1px solid var(--border);
    border-bottom: none;
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    background: var(--surface-3);
}
.editor-group { display: flex; align-items: center; gap: 4px; }

.editor-btn {
    width: 32px; height: 32px;
    display: flex; align-items: center; justify-content: center;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-dim);
    cursor: pointer;
    transition: color var(--transition), background var(--transition);
}
.editor-btn:hover { color: var(--text); background: var(--surface); }
.editor-btn.is-active {
    color: var(--on-accent);
    background: var(--accent);
    border-color: transparent;
}

.editor-select {
    padding: 6px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    font-family: var(--font-body);
    font-size: 0.85rem;
    cursor: pointer;
}

.editor-colors { gap: 5px; }
.editor-color {
    width: 22px; height: 22px;
    border-radius: 50%;
    border: 1px solid var(--border);
    cursor: pointer;
    padding: 0;
    transition: transform var(--transition);
}
.editor-color:hover { transform: scale(1.15); }

.editor-area {
    min-height: 170px;
    max-height: 380px;
    overflow-y: auto;
    padding: 14px;
    border: 1px solid var(--border);
    border-radius: 0 0 var(--radius-sm) var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    line-height: 1.6;
}
.editor-area:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
.editor-area:empty::before {
    content: attr(data-placeholder);
    color: var(--text-dim);
    pointer-events: none;
}
.editor-area p { margin: 0 0 8px; }

/* ---------- Черновики файлов ---------- */
.draft-media {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
    gap: 8px;
    margin-top: 10px;
}
.draft-cell {
    position: relative;
    aspect-ratio: 1;
    border-radius: var(--radius-sm);
    overflow: hidden;
    border: 1px solid var(--border);
    background: var(--surface-3);
}
.draft-cell img, .draft-cell video { width: 100%; height: 100%; object-fit: cover; display: block; }
.draft-remove {
    position: absolute; top: 4px; right: 4px;
    width: 22px; height: 22px;
    display: flex; align-items: center; justify-content: center;
    border: none; border-radius: 50%;
    background: rgba(10, 10, 30, 0.8);
    color: #fff;
    cursor: pointer;
    font-size: 0.75rem;
}
.draft-remove:hover { background: var(--danger); }

/* ============================================================
   Подписчики в профиле
   ============================================================ */
.subhead-count {
    display: inline-block;
    margin-left: 6px;
    padding: 0 8px;
    border-radius: 999px;
    background: var(--accent-soft);
    color: var(--accent-2);
    font-size: 0.78rem;
}

.subscriber-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 10px;
    margin-bottom: 8px;
}

.subscriber-card {
    display: flex; align-items: center; gap: 11px;
    padding: 11px 13px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
}
.subscriber-avatar {
    width: 40px; height: 40px;
    border-radius: 50%;
    overflow: hidden;
    background: var(--accent-soft); color: var(--accent-2);
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-head); font-weight: 700; font-size: 0.85rem;
    flex: 1;
}
.subscriber-avatar img { width: 100%; height: 100%; object-fit: cover; }

.subscriber-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.subscriber-name {
    background: none; border: none; padding: 0; cursor: pointer;
    text-align: left;
    font-family: var(--font-body); font-weight: 600; font-size: 0.92rem;
    color: var(--text);
}
.subscriber-name:hover { color: var(--accent-2); }
.subscriber-meta  { color: var(--text-dim); font-size: 0.79rem; }
.subscriber-since { color: var(--text-muted); font-size: 0.74rem; }

@media (max-width: 1300px) {
    /* Сайдбар зафиксирован в левом «зазоре» страницы (см. .feed-sidebar
       выше) — этого зазора хватает только на широких экранах. Дальше
       он либо налез бы на ленту, либо вышел за левый край viewport,
       поэтому ниже этой ширины кладём его узкой горизонтальной полосой
       над лентой, обычным потоком. */
    .feed-sidebar {
        position: static;
        left: auto;
        width: auto;
        flex-direction: row;
        flex-wrap: nowrap;
        overflow-x: auto;
        overflow-y: visible;
        max-height: none;
        margin-bottom: 16px;
    }
    .feed-sidebar-title { display: none; }
    .feed-sidebar-item { flex: 0 0 auto; width: auto; }
    .feed-sidebar-name { max-width: 110px; }
}

@media (max-width: 560px) {
    .feed-head { flex-direction: column; align-items: stretch; }
    .feed-head .btn { width: 100%; justify-content: center; }
    .post-card { padding: 14px; }
    .post-cover { margin: 0 -14px; max-height: 260px; }
    .post-cover img { max-height: 260px; }
    .post-media.count-3, .post-media.count-4 { grid-template-columns: 1fr; }
    .editor-toolbar { gap: 6px; }
    .subscriber-grid { grid-template-columns: 1fr; }
}


/* ============================================================
   Корона подписчика, рублёвый кошелёк
   ============================================================ */

/* Корона у ника — знак активной подписки. Одна и та же везде.
   Без подложки: сам значок и так заметен, а кружок делал его мельче. */
.premium-crown {
    display: inline-flex; align-items: center; justify-content: center;
    flex-shrink: 0;
    color: var(--gold);
    font-size: 1.05rem;
    vertical-align: middle;
    filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.45));
}
.premium-crown-lg { font-size: 1.4rem; margin-top: 4px; }

/* ---------- Уровень траты монет ----------
   Открытый рейтинг рядом с ником, как «уровень по звёздам» в Telegram
   (см. supabase/coin_level.sql — там же оговорка про приближённость
   формулы). Число — сам уровень; по клику — окно с прогрессом и суммой
   трат (js/coin-level.js), тоже открытое — видно и в чужом профиле. */
.coin-level-badge {
    display: inline-flex; align-items: center; gap: 4px;
    flex-shrink: 0;
    padding: 2px 8px 2px 7px;
    border-radius: 999px;
    font-size: 0.78rem; font-weight: 700;
    line-height: 1.5;
    color: #1a1230;
    background: linear-gradient(135deg, #8ecbff, #6f7bff);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    vertical-align: middle;
}
.coin-level-badge i { font-size: 0.85em; }
#profileCoinLevel, #userCoinLevel {
    font-size: 0.85rem;
    cursor: pointer;
    border: none;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}
#profileCoinLevel:hover, #userCoinLevel:hover {
    transform: translateY(-1px);
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.35);
}

.coin-level-progress { margin: 12px 0 18px; }
.coin-level-progress-text {
    display: flex; justify-content: space-between; gap: 10px;
    font-size: 0.82rem; color: var(--text-muted);
    margin-bottom: 6px; flex-wrap: wrap;
}
.coin-level-progress-text b { color: var(--text); }
.coin-level-progress-text i.fa-bolt { color: #6f7bff; }

/* ---------- Окно уровня (клик по бейджу) ----------
   1в1 по реальному скриншоту уровня в Telegram: не отдельная
   табличка над шкалой, а сама шкала — единая скруглённая полоса в
   два тона, и дробь написана прямо на ней, ровно на границе
   заливки. Подписи «Уровень N» / «Уровень N+1» — простым текстом
   над полосой по краям, без бейджей-пилюль. */
.coin-level-modal { padding: 4px 2px 2px; }

.coin-level-modal-meter { margin: 4px 0 14px; }

.coin-level-modal-levels {
    display: flex; justify-content: space-between; align-items: baseline;
    gap: 10px; margin: 0 3px 8px;
}
.coin-level-modal-levellabel { font-size: 0.82rem; font-weight: 600; color: var(--text-muted); }
.coin-level-modal-levellabel.is-next { color: var(--text-dim); }

/* Сама полоса: тёмный фон — незакрашенная часть, поверх него —
   растущий по width заливочный слой того же скругления. Текст —
   отдельным слоем НАД обоими, во всю ширину полосы (см. ниже). */
/* Фон полосы и обе копии текста — фиксированные тёмные/светлые тона,
   НЕ через переменные темы: у полосы всегда должен быть тёмный
   фон, чтобы белый текст поверх неё читался что в тёмной, что в
   светлой теме сайта — так же, как в самом Telegram этот элемент
   не перекрашивается под системную тему. */
.coin-level-modal-bar {
    position: relative;
    height: 34px;
    border-radius: 999px;
    background: #201d3a;
    overflow: hidden;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}
.coin-level-modal-bar-fill {
    position: absolute; inset: 0; right: auto;
    background: linear-gradient(135deg, #4fa8ff, #6f7bff);
    border-radius: inherit;
    transition: width 0.35s ease;
}

/* Дробь написана дважды, идеально друг на друге, во всю ширину
   полосы: тусклая копия снизу, ровно поверх неё — яркая копия, но
   обрезанная clip-path'ом по проценту заливки. Между слоями не
   остаётся зазора и не нужно мерить пиксели в JS — на границе
   заливки цвет текста просто «переключается». */
.coin-level-modal-bar-label { position: absolute; inset: 0; }
.coin-level-modal-bar-label-dim,
.coin-level-modal-bar-label-bright {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center; gap: 5px;
    font-size: 0.92rem; font-weight: 700; white-space: nowrap;
}
.coin-level-modal-bar-label-dim { color: rgba(255, 255, 255, 0.5); }
.coin-level-modal-bar-label-bright { color: #fff; }
.coin-level-modal-bar-label i { font-size: 0.9em; }

.coin-level-modal-total {
    text-align: center; font-size: 0.86rem; color: var(--text-muted);
    margin: 0 0 14px;
}
.coin-level-modal-total b { color: var(--gold, #ffd93d); }
.coin-level-modal-hint { margin: 0; text-align: center; }

/* В шапке профиля корона крупнее — она стоит рядом с большим ником */
#profileCrown { font-size: 1.5rem; }

.name-with-crown { display: inline-flex; align-items: center; gap: 7px; min-width: 0; }
.peer-name .premium-crown { margin-left: 6px; }

/* ---------- День рождения ----------
   Чисто визуальная кастомизация, включается сама по дню рождения
   (см. isBirthdayToday в profile.js) — ничего заводить или покупать
   не нужно, работает у любого, кто указал birth_date в настройках. */
.birthday-badge {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 12px;
    border-radius: 999px;
    font-size: 0.85rem; font-weight: 600;
    color: #2a1a00;
    background: linear-gradient(135deg, #ffd76a, #ff9f5a);
    box-shadow: 0 2px 8px rgba(255, 159, 90, 0.4);
    animation: birthday-badge-pop 1.8s ease-in-out infinite;
}
.birthday-badge i { font-size: 0.95rem; }

@keyframes birthday-badge-pop {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.06); }
}

/* Праздничное кольцо вокруг аватара вместо обычной рамки-инвентаря —
   если у человека есть купленная/выданная рамка (.has-frame), день
   рождения временно перекрывает её этим градиентом, а на следующий
   день вернётся как было, ничего не перезаписывая в базе. */
.profile-avatar-frame.is-birthday {
    padding: 4px;
    background: conic-gradient(from 0deg, #ff9f5a, #ffd76a, #6c63ff, #ff6ad5, #ff9f5a);
    animation: birthday-ring-spin 6s linear infinite;
}
.profile-avatar-frame.is-birthday .profile-avatar { border: none; }

@keyframes birthday-ring-spin {
    to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .birthday-badge, .profile-avatar-frame.is-birthday { animation: none; }
}

/* ---------- Два баланса рядом ---------- */
.balance-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 14px;
    margin-bottom: 24px;
}
.balance-row .coins-balance { margin-bottom: 0; }

.coins-balance.is-rub {
    border-color: color-mix(in srgb, var(--success) 40%, var(--border));
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--success) 10%, var(--surface-3)),
        var(--surface-3));
}
.coins-balance.is-rub > i { color: var(--success); background: color-mix(in srgb, var(--success) 16%, transparent); }
.coins-balance.is-rub .coins-balance-value { color: var(--success); }
.coins-balance .btn { margin-left: auto; flex-shrink: 0; }

/* Карточка Dantes Coins в шапке профиля — золотая, как монеты */
.coins-stat .stat-value { color: var(--gold); }
.coins-stat .stat-icon  { color: var(--gold); background: color-mix(in srgb, var(--gold) 15%, transparent); }

/* ---------- Две кнопки оплаты в тарифе ---------- */
.plan-buttons { display: flex; flex-direction: column; gap: 6px; margin-top: 10px; }
.plan-buttons .btn { margin-top: 0; }

@media (max-width: 560px) {
    .balance-row { grid-template-columns: 1fr; }
}


/* ---------- Награда за «Короля платформы» ---------- */
.crown-reward {
    display: flex; align-items: flex-start; gap: 13px;
    margin: 14px 0 16px;
    padding: 13px 15px;
    border: 1px solid color-mix(in srgb, var(--gold) 40%, var(--border));
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--gold) 9%, transparent);
}
.crown-reward > i {
    width: 38px; height: 38px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%;
    color: var(--gold);
    background: color-mix(in srgb, var(--gold) 16%, transparent);
}
.crown-reward > div { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.crown-reward strong { color: var(--gold); font-size: 1.05rem; font-family: var(--font-head); }
.crown-reward span   { color: var(--text-dim); font-size: 0.84rem; }

.crown-reward.is-paid {
    border-color: color-mix(in srgb, var(--success) 45%, var(--border));
    background: color-mix(in srgb, var(--success) 9%, transparent);
}
.crown-reward.is-paid > i { color: var(--success); background: color-mix(in srgb, var(--success) 16%, transparent); }
.crown-reward.is-paid strong { color: var(--success); }

/* ============================================================
   Страница трансляции
   ============================================================ */
.back-link {
    display: inline-flex; align-items: center; gap: 8px;
    color: var(--text-muted); text-decoration: none;
    font-size: 0.9rem; margin-bottom: 18px;
}
.back-link:hover { color: var(--accent-2); }

/* На странице трансляции верхний отступ .main-content (56px) держит
   плеер и плашки слишком далеко от шапки сайта. Сокращаем его именно
   здесь, не трогая отступ на остальных страницах. */
.main-content:has(.watch-layout) { padding-top: 22px; padding-bottom: 24px; }

/* На странице чатов между шапкой сайта и плашками получался слишком
   большой зазор — сокращаем его так же, не трогая остальные страницы. */
.main-content:has(.chat-container) { padding-top: 34px; padding-bottom: 10px; }
/* Вся страница чатов помещается в экран, прокручивать нечего: внутри
   прокручиваются список и лента сообщений, каждый сам по себе. */
body:has(.chat-container) { overflow: hidden; }

/* Обе страницы задуманы как «приложение на весь экран»: плашки должны
   целиком помещаться в высоту окна без прокрутки САМОЙ страницы —
   прокручивается только содержимое внутри плашек (сообщения, чат).
   Внизу для этого лишний футер с картой сайта тоже не нужен — на
   обычных страницах он уместен, а здесь только добавляет прокрутку. */
body:has(.chat-container) #site-footer,
body:has(.watch-layout) #site-footer {
    display: none;
}

/* Раньше колонки просто выравнивались по верху (align-items: start) —
   у левой высоту задавало содержимое (плашка + плеер 16:9), у правой
   отдельно посчитанная высота (60vh у чата) с ней никак не связана,
   так что низ плашек расходился на глаз. Теперь высота всего блока
   считается от реально оставшегося места на экране — так же, как
   у чатов — и обе колонки тянутся (stretch) ровно на эту высоту:
   низ у них теперь совпадает при любом размере окна. */
.watch-layout {
    display: grid;
    /* Ширина правой колонки — переменной: её же берёт верхний ряд
       (.watch-top), чтобы две сетки не разъезжались при правке одной. */
    --watch-side-w: 360px;
    grid-template-columns: minmax(0, 1fr) var(--watch-side-w);
    /* Одна строка: верхний ряд с описанием и стримером уехал во
       всплывающую плашку под плеером. */
    grid-template-rows: minmax(0, 1fr);
    gap: 20px;
    align-items: stretch;
    /* 84 — шапка сайта, 22+24 — отступы .main-content сверху/снизу,
       41 — ссылка «Все трансляции» над блоком (23px строка + 18px
       отступ под ней). Пропустили это в первом заходе — плашки совпали
       по низу друг с другом, но обе вместе вылезали за экран ровно
       на эту ссылку. */
    height: min(calc(100dvh - var(--site-header-h, 84px) - 22px - 24px - 41px - 8px), 900px);
    min-height: 480px;
}

/* ---------- Экран: плеер и приросшая к нему полоса ----------
   Полоса — она же кнопка: открывает плашку с описанием эфира и
   карточкой стримера. Раньше это были две плашки НАД плеером; они
   занимали верх экрана, а нужны по одному разу. */
.watch-screen {
    position: relative;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* Полоса прирощена к плееру без зазора — вместе они читаются как один
   экран, и нажатие по ней воспринимается как нажатие по экрану. */
.watch-handle {
    display: flex; align-items: center; gap: 12px;
    width: 100%;
    padding: 10px 14px;
    border: 1px solid var(--border); border-top: 0;
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    background: var(--surface-2);
    color: inherit; text-align: left; cursor: pointer;
    font-family: var(--font-body);
    transition: background var(--transition);
}
.watch-handle:hover { background: var(--surface-3); }
.watch-handle-main {
    display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1;
}
.watch-handle-title {
    font-family: var(--font-head); font-weight: 600; color: var(--text);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.watch-handle .stream-live-badge { position: static; flex-shrink: 0; }
.watch-handle-stats { display: flex; align-items: center; gap: 12px; flex-shrink: 0; }
.watch-handle-arrow {
    color: var(--text-dim); font-size: 0.8rem; flex-shrink: 0;
    transition: transform var(--transition);
}
.watch-screen.is-open .watch-handle-arrow { transform: rotate(180deg); }

/* Плашка всплывает ВВЕРХ от полосы и ложится поверх низа кадра.
   Поверх, а не в потоке, ради двух вещей сразу: кадр не меняет размер
   (видео не дёргается и не перезапускается), и высота экрана остаётся
   равной высоте чата — открытая плашка её не двигает. */
.watch-dock { position: relative; flex-shrink: 0; z-index: 3; }
.watch-sheet {
    position: absolute; left: 0; right: 0; bottom: 100%;
    max-height: min(62vh, 520px);
    overflow-y: auto;
    padding: 16px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-bottom: 0;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    box-shadow: 0 -12px 32px rgba(0, 0, 0, 0.45);
    animation: watchSheetUp 0.18s ease-out;
}
@keyframes watchSheetUp {
    from { transform: translateY(12px); opacity: 0; }
    to   { transform: translateY(0);    opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .watch-sheet { animation: none; }
}
.watch-sheet > .watch-streamer { margin-bottom: 0; }
.watch-sheet-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; flex-wrap: wrap; margin-top: 14px;
}
.watch-sheet-row:empty { display: none; }
.watch-sheet-tools { display: flex; gap: 8px; flex-wrap: wrap; }
.watch-sheet-tools:empty { display: none; }

/* Всё, что под сеткой: опрос, клипы, соведущие, прошлые эфиры. */
.watch-below { margin-top: 20px; }
.watch-below > div:not(:empty) { margin-bottom: 18px; }

/* Смайлы канала — у поля ввода чата, а не под плеером: они вставляют
   код в это самое поле. */
.chat-emote-btn {
    width: 38px; height: 38px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    border: 1px solid var(--border); border-radius: var(--radius-md);
    background: var(--surface-2); color: var(--text-dim);
    cursor: pointer; transition: color var(--transition), border-color var(--transition);
}
.chat-emote-btn:hover { color: var(--accent-2); border-color: var(--accent); }

.watch-chat-tools { display: flex; align-items: center; gap: 8px; }
.watch-chat-tools:empty { display: none; }

/* Экран и чат — единственные в строке сетки, и оба тянутся на всю её
   высоту. Отсюда и равенство: низ плеера совпадает с низом поля ввода
   чата при любом размере окна. Всё остальное (клипы, прошлые эфиры)
   вынесено под сетку — иначе оно забирало бы высоту у одной колонки
   и не забирало у другой. */
.watch-main { display: flex; flex-direction: column; min-height: 0; height: 100%; }
.watch-side { display: flex; flex-direction: column; min-height: 0; height: 100%; }

.watch-player {
    /* aspect-ratio раньше единолично задавал высоту плеера от ширины.
       Теперь она только «предлагается» — flex:1 в колонке-флексе тянет
       плеер на всё оставшееся под плашкой место, а не на то, что выйдет
       из ширины. Кадр внутри всё равно вписан через object-fit:contain
       (см. .watch-frame), так что если после растяжения пропорция уже
       не 16:9, сверху и снизу просто останутся чёрные поля — как на
       видеосайтах, а не искажённая картинка. */
    /* Пропорция — только пожелание: высоту задаёт строка сетки, общая
       с чатом. Кадр внутри вписан через object-fit:contain, поэтому
       при другой пропорции сверху и снизу просто чёрные поля, как на
       видеосайтах, а не растянутая картинка. */
    aspect-ratio: 16 / 9;
    flex: 1;
    min-height: 0;
    background: #000;
    border: 1px solid var(--border);
    /* Снизу скругления нет: там к плееру прирастает полоса. */
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    overflow: hidden;
}
.watch-frame { width: 100%; height: 100%; border: 0; display: block; object-fit: contain; background: #000; }

/* Пока ссылки нет — честная заглушка, а не вечная крутилка */
.watch-placeholder {
    width: 100%; height: 100%;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: 12px;
    color: var(--text-dim); text-align: center; padding: 20px;
}
.watch-placeholder i { font-size: 2.6rem; color: var(--accent-2); }

/* Свой поток у зрителя: видео идёт заглушенным (иначе браузер не даст
   автовоспроизведение со звуком), рядом плавающая кнопка включить звук —
   тот же приём, что и на видеосайтах. */
.watch-native-wrap { position: relative; width: 100%; height: 100%; }
.watch-native-unmute {
    position: absolute; right: 12px; bottom: 12px;
    width: 40px; height: 40px;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: rgba(10, 10, 26, 0.72);
    border: 1px solid rgba(255, 255, 255, 0.25);
    color: #fff; font-size: 1.05rem;
    cursor: pointer; transition: background var(--transition);
}
.watch-native-unmute:hover { background: rgba(10, 10, 26, 0.9); }

/* Плашка с названием и статами трансляции стоит первой в колонке —
   на одном уровне с карточкой стримера в соседней колонке, а не ниже
   высокого плеера, как раньше. */
.watch-meta {
    margin-bottom: 16px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 18px;
}
.watch-title-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
/* В карточке значок LIVE лежит поверх обложки и потому absolute. Здесь он
   стоит в строке рядом с заголовком, так что возвращаем обычный поток. */
.watch-title-row .stream-live-badge { position: static; }
.watch-title { font-family: var(--font-head); font-size: 1.25rem; color: var(--text); margin: 0; }
.watch-tags { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.watch-stat { color: var(--text-dim); font-size: 0.85rem; display: inline-flex; align-items: center; gap: 5px; }
/* Лайк стоит сразу за счётчиком зрителей, а не в дальнем углу строки */
.watch-tags .watch-like { padding: 5px 12px; }

/* Легендарный буст Стримов — реакция вместо лайка (js/watch.js,
   reactionPickerHtml()). Те же пропорции, что у .watch-like, но пять
   кнопок в ряд вместо одной, каждая с собственным счётчиком. */
.watch-reactions { display: inline-flex; align-items: center; gap: 2px; flex-wrap: wrap; }
.watch-reaction-btn {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 5px 10px;
    border: 1px solid transparent;
    border-radius: 999px;
    background: transparent;
    color: var(--text-dim);
    font-family: var(--font-body);
    font-size: 0.85rem;
    cursor: pointer;
    transition: color var(--transition), background var(--transition);
}
.watch-reaction-btn:hover { color: var(--text); background: var(--surface-3); }
.watch-reaction-btn.is-active { color: var(--accent); background: var(--accent-soft); }

/* Свой фон чата эфира (мифич, boost_chatbg) — та же тёмная вуаль поверх
   картинки/градиента, что и у .has-bg в других местах сайта (панель
   собеседника, карточка стримера), чтобы текст сообщений не терялся. */
.watch-chat.has-custom-chatbg {
    position: relative;
    background-size: cover;
    background-position: center;
}
.watch-chat.has-custom-chatbg::before {
    content: '';
    position: absolute;
    inset: 0;
    background: rgba(6, 6, 26, 0.55);
    pointer-events: none;
    z-index: 0;
    border-radius: inherit;
}
.watch-chat.has-custom-chatbg > * { position: relative; z-index: 1; }
/* Кнопка завершения переехала в саму строку статов — на то место,
   где раньше был прижатый вправо лайк, — и больше не отдельная строка. */
.watch-tags .watch-stop { margin-left: auto; }
.watch-description { color: var(--text-muted); font-size: 0.92rem; margin-bottom: 14px; }

/* ---------- Стример ---------- */
.watch-streamer {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 16px;
    margin-bottom: 16px;
}

/* Фон профиля — своя картинка (премиум) или градиент из инвентаря,
   тот же приём, что в карточке игрока и в панели собеседника чата.
   Тёмная вуаль сверху держит контраст на любой картинке. */
.watch-streamer.has-bg {
    position: relative;
    overflow: hidden;
}
.watch-streamer.has-bg::before {
    content: '';
    position: absolute; inset: 0;
    background: rgba(8, 8, 26, 0.55);
    pointer-events: none;
}
.watch-streamer.has-bg > * { position: relative; z-index: 1; }
.watch-streamer.has-bg .watch-streamer-name {
    color: #fff; text-shadow: 0 2px 8px rgba(0, 0, 0, 0.75);
}
.watch-streamer.has-bg .watch-streamer-username,
.watch-streamer.has-bg .watch-streamer-followers,
.watch-streamer.has-bg .watch-streamer-bio {
    background: rgba(10, 10, 30, 0.6);
    border-color: rgba(255, 255, 255, 0.4);
    color: #fff;
}
.watch-streamer.has-bg .btn-secondary {
    background: rgba(10, 10, 30, 0.68);
    color: #fff;
    border-color: rgba(255, 255, 255, 0.55);
}
.watch-streamer.has-bg .btn-secondary:hover:not(:disabled) {
    background: rgba(10, 10, 30, 0.88);
    border-color: #fff;
}

/* Вся шапка — кнопка на всю плашку: клик по аватарке, нику или био
   открывает ту же карточку игрока, что и ник в чате. Отрицательные
   поля равны внутреннему отступу карточки — фон наведения растягивается
   до самых краёв плашки, а не только вокруг аватарки с ником. Внутри —
   колонка из двух рядов: аватар+ник сверху, био на всю ширину снизу. */
.watch-streamer-head {
    display: flex; flex-direction: column; gap: 12px;
    width: calc(100% + 32px);
    margin: -16px -16px 0;
    padding: 16px 16px 14px;
    background: none; border: none;
    font: inherit; color: inherit; text-align: left;
    cursor: pointer;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    transition: background var(--transition);
}
.watch-streamer-head:disabled { cursor: default; }

/* Наведение затемняет ВСЮ карточку, а не одну кнопку внутри неё.
   Раньше подсвечивался только верх с аватаркой и ником, и выходило,
   будто у карточки две разные половины: одна отзывается на мышь,
   другая нет.

   Делаем внутренней тенью, а не подложкой: ::before и ::after у этой
   карточки уже заняты фоном профиля, а тень ничего не перекрывает и
   не мешает нажимать кнопки внутри. */
.watch-streamer:hover {
    box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.26);
    border-color: var(--accent);
}
@media (prefers-reduced-motion: no-preference) {
    .watch-streamer { transition: box-shadow var(--transition), border-color var(--transition); }
}
/* align-items: flex-start — верхний край аватарки вровень с ником,
   а не по центру всего блока (ник+юз+подписчики). */
.watch-streamer-top { display: flex; align-items: flex-start; gap: 14px; }
/* Раньше аватар был жёстко заперт в 52px — теперь в 1.5 раза крупнее
   (78px). Пробовали тянуть его по высоте всей шапки через aspect-ratio,
   но на реальных карточках (длинное био, значки в два ряда) высота
   шапки скачет — и круг раздувался вместе с ней, вплоть до размеров
   всей плашки. Фиксированный размер этого не допускает. */
.watch-streamer-avatar {
    width: 78px; height: 78px; flex: 0 0 78px;
    border-radius: 50%;
    background: var(--accent-soft); color: var(--accent-2);
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-head); font-weight: 700; font-size: 1.6rem;
    overflow: hidden; flex-shrink: 0;
}
.watch-streamer-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.watch-streamer-who { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 0; }
.watch-streamer-name {
    font-family: var(--font-head); font-weight: 700; font-size: 1.05rem;
    color: var(--text); display: inline-flex; align-items: center; gap: 6px;
}
/* Юзернейм и число подписчиков подняты плашками — та же выделка,
   что у юзернейма в карточке игрока, вместо тихого серого текста. */
.watch-streamer-username,
.watch-streamer-followers {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 2px 10px;
    border-radius: 999px;
    font-family: var(--font-head);
    font-weight: 600;
    font-size: 0.78rem;
}
.watch-streamer-username {
    background: var(--accent-soft);
    border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
    color: var(--accent-2);
}
.watch-streamer-followers {
    background: color-mix(in srgb, var(--gold) 13%, transparent);
    border: 1px solid color-mix(in srgb, var(--gold) 45%, transparent);
    color: var(--gold);
}
/* Био — той же плашкой, что юзернейм и подписчики, но на всю ширину
   карточки снизу, а не тесной строкой рядом с аватаркой. */
.watch-streamer-bio {
    display: block;
    padding: 8px 14px;
    border-radius: 999px;
    background: var(--accent-soft);
    border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
    color: var(--text);
    font-family: var(--font-body);
    font-size: 0.85rem;
    line-height: 1.4;
}
.watch-streamer-actions { display: flex; gap: 8px; margin-top: 14px; flex-wrap: wrap; }
.watch-streamer-actions .btn { flex: 1; }

/* Донат — акцентный розовый, чтобы не путался с обычными secondary-кнопками. */
.btn-donate { border-color: #ff5c8a; color: #ff5c8a; background: transparent; }
.btn-donate:hover:not(:disabled) { background: #ff5c8a; color: #fff; }

.donate-presets { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 16px; }
.donate-presets .btn { flex: 1; min-width: 64px; }

/* ---------- Чат трансляции ---------- */
.watch-chat {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    display: flex; flex-direction: column;
    /* Раньше была своя высота (min(60vh,520px)), никак не связанная
       с левой колонкой. Теперь .watch-side — флекс-колонка на всю
       высоту .watch-layout, и чат просто дотягивает её до конца,
       вместо того чтобы отчитывать свою собственную долю экрана. */
    flex: 1;
    min-height: 0;
    overflow: hidden;
}
.watch-chat-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 10px; padding: 13px 16px;
    border-bottom: 1px solid var(--border);
}
.watch-chat-head { justify-content: flex-end; }
.watch-chat-head:has(.watch-chat-tools:empty) { display: none; }
.watch-chat-head h3 { font-size: 0.98rem; color: var(--text); display: flex; align-items: center; gap: 8px; }
.watch-chat-count { color: var(--text-dim); font-size: 0.76rem; }

.watch-chat-messages {
    flex: 1; overflow-y: auto;
    padding: 12px 16px;
    display: flex; flex-direction: column; gap: 9px;

    overscroll-behavior: contain;
}
.watch-chat-empty { color: var(--text-dim); font-size: 0.87rem; text-align: center; padding: 20px 0; }

.watch-msg { font-size: 0.88rem; line-height: 1.45; word-break: break-word; }
.watch-msg-name {
    background: none; border: none; padding: 0; cursor: pointer;
    font-family: var(--font-body); font-weight: 600;
    color: var(--accent-2); margin-right: 6px;
}
.watch-msg-name:hover { text-decoration: underline; }
.watch-msg-body { color: var(--text); }
.watch-msg-time { color: var(--text-dim); font-size: 0.7rem; margin-left: 6px; white-space: nowrap; }

/* Мут/бан в чате трансляции — видно только хозяину, рядом с чужими
   сообщениями (moderate_stream_chat(), премиум тут ни при чём — это
   просто модерация своего эфира). */
.watch-msg-mod { margin-left: 6px; display: none; gap: 4px; }
.watch-msg-mod.is-open { display: inline-flex; animation: msgToolsIn .16s ease-out; }
@keyframes msgToolsIn { from { opacity: 0; transform: translateX(-4px); } to { opacity: 1; transform: none; } }
.watch-msg-mod-btn {
    background: none; border: 1px solid var(--border); border-radius: 6px;
    padding: 1px 5px; font-size: 0.7rem; color: var(--text-dim); cursor: pointer;
}
.watch-msg-mod-btn:hover { color: var(--text); border-color: var(--accent); }
.watch-msg-mod-btn.is-active { color: var(--danger); border-color: var(--danger); }

.watch-chat-input {
    display: flex; align-items: center; gap: 8px;
    padding: 12px 14px;
    border-top: 1px solid var(--border);
}
.watch-chat-input .form-input { flex: 1; border-radius: 999px; }

/* ============================================================
   Главная трансляций
   ============================================================ */
.streams-head {
    display: flex; align-items: flex-start; gap: 16px;
    margin-bottom: 28px;
}
.stream-cats { display: flex; flex-wrap: wrap; gap: 10px; flex: 1; }
.stream-head-actions { display: flex; gap: 10px; flex-shrink: 0; flex-wrap: wrap; }
.stream-start-btn { flex-shrink: 0; }

/* ---------- Статистика трансляций ---------- */
.stream-stats { display: flex; flex-direction: column; gap: 12px; }
.stats-row {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-soft);
    padding: 14px 16px;
}
.stats-row-top {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 12px; flex-wrap: wrap; margin-bottom: 8px;
}
.stats-row-title-block { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.stats-row-title { font-family: var(--font-head); font-weight: 700; color: var(--text); font-size: 1rem; }
.stats-row-title-block .stream-live-badge { position: static; }
.stats-row-date {
    color: var(--text-dim); font-size: 0.8rem;
    display: inline-flex; align-items: center; gap: 5px; white-space: nowrap;
}
.stats-row-tags { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.stats-row-metrics { display: flex; gap: 14px; flex-wrap: wrap; margin-bottom: 12px; }
.stats-metric {
    display: inline-flex; align-items: center; gap: 6px;
    color: var(--text-muted); font-size: 0.85rem; font-weight: 600;
}
.stats-metric i { color: var(--accent-2); }
.stats-loading { padding: 24px; text-align: center; color: var(--text-dim); }

@media (max-width: 480px) {
    .stats-row-metrics { gap: 10px 16px; }
}

/* Обложка карточки стала ссылкой — при наведении показываем «плей».
   display оставляем flex: на нём держится раскладка значков LIVE
   и числа зрителей внутри обложки. */
.stream-thumbnail-large { text-decoration: none; }

/* Одна подписка не должна растягиваться на всю ширину строки */
#subsGrid { grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); }
.stream-play {
    position: absolute; inset: 0; margin: auto;
    width: 54px; height: 54px; border-radius: 50%;
    background: rgba(10, 10, 30, 0.55); color: #fff;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.1rem;
    opacity: 0; transition: opacity var(--transition);
}
/* :hover-only — на тачскрине нечем навести, кнопка воспроизведения могла
   остаться невидимой (или мигнуть на долю секунды при тапе). Те же
   условия, что и у похожих карточек выше (.chat-pin-btn, .message-react):
   :focus-within — для клавиатуры, (hover: none) — держим её видимой
   всегда, раз мышью навести и увидеть тут всё равно нельзя. */
.stream-card-large:hover .stream-play,
.stream-card-large:focus-within .stream-play { opacity: 1; }
@media (hover: none) {
    .stream-play { opacity: 1; }
}

.streamer-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block; }
.streamer-name-btn {
    background: none; border: none; padding: 0; cursor: pointer;
    text-align: left; font-family: inherit; color: inherit;
}
.streamer-name-btn:hover h3 { color: var(--accent-2); }
.stream-title a { color: inherit; text-decoration: none; }
.stream-title a:hover { color: var(--accent-2); }

/* ---------- Выбор источника картинки ---------- */
.source-picker { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; margin-bottom: 12px; }
.source-option {
    display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
    padding: 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-soft);
    cursor: pointer; text-align: left;
    font-family: var(--font-body); color: var(--text-muted);
    transition: border-color var(--transition), background var(--transition);
}
.source-option i { font-size: 1.15rem; color: var(--accent-2); }
.source-option:hover { border-color: var(--accent); }
.source-option.is-active { border-color: var(--accent); background: var(--accent-soft); }
.source-name { font-weight: 600; color: var(--text); font-size: 0.9rem; }
.source-hint { font-size: 0.76rem; color: var(--text-dim); }
.source-preview {
    width: 100%; max-height: 200px; margin-top: 10px;
    border-radius: var(--radius-sm); background: #000; display: block;
    object-fit: contain;
}

@media (max-width: 1024px) {
    /* На узком экране колонки складываются в одну — «влезать без
       прокрутки страницы» здесь уже не требование (сама страница
       и раньше прокручивалась на телефоне/планшете), поэтому высоту
       и растягивание, нужные только для стола рядом на десктопе,
       возвращаем к естественным. */
    .watch-layout { grid-template-columns: 1fr; grid-template-rows: none; height: auto; align-items: start; }
    .watch-screen { flex: none; }
    .watch-player { flex: none; aspect-ratio: 16 / 9; }
    .watch-chat { flex: none; height: 420px; }
    /* На телефоне плашка не висит поверх, а раздвигает страницу:
       экрана мало, и перекрывать им же клипы под ним незачем.

       column-reverse тут обязателен. В разметке плашка идёт ПЕРЕД
       полосой (так она на большом экране висит под ней, отсчитывая
       положение от её низа), и в обычном потоке она встала бы над
       полосой — то есть раскрывалась бы вверх. Переворот ставит их в
       нужном порядке, не трогая разметку. */
    .watch-dock { display: flex; flex-direction: column-reverse; }
    .watch-sheet {
        position: static;
        max-height: none;
        box-shadow: none;
        border-top: 0;
        border-bottom: 1px solid var(--border);
        border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    }
    /* Раскрытая вниз плашка — продолжение полосы, а не отдельная плитка. */
    .watch-screen.is-open .watch-handle { border-radius: 0; }
    /* Статы на полосе прячем: на узкой полосе они вытесняют название,
       а название важнее. В плашке они всё равно есть. */
    .watch-handle-stats { display: none; }
}
@media (max-width: 768px) {
    .streams-head { flex-direction: column; align-items: stretch; }
    .stream-head-actions { flex-direction: column; }
    .stream-start-btn { width: 100%; }
    .source-picker { grid-template-columns: 1fr; }
}

/* Видеоаватар (Dantes Premium, avatarMarkup() в js/utils.js рисует
   <video> вместо <img>, когда avatar_kind === 'video'). Один общий
   селектор вместо дублирования object-fit/border-radius в каждом из
   полутора десятков мест, где отображается чужой аватар — контейнеры
   уже сами обрезают контент через overflow:hidden + border-radius. */
[class*="avatar"] video {
    width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block;
}

/* ============================================================
   NFT-подарки и покупные юзернеймы (supabase/gifts_and_usernames.sql)
   ============================================================ */
.gift-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 16px;
    margin-bottom: 8px;
}

.gift-card {
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 16px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    position: relative;
    overflow: hidden;
}
/* Редкость подарка красит рамку карточки тем же цветом, что и
   .cosmetic-rarity — единая палитра редкостей на весь сайт. */
.gift-card.rarity-common     { border-color: var(--text-dim); }
.gift-card.rarity-rare       { border-color: var(--success); }
.gift-card.rarity-super_rare { border-color: var(--info); }
.gift-card.rarity-epic       { border-color: var(--game-fortnite); }
.gift-card.rarity-mythical   { border-color: var(--danger); }
.gift-card.rarity-legendary,
.gift-card.rarity-premium,
.gift-card.rarity-seasonal   { border-color: var(--gold); }

.gift-card.is-pinned { box-shadow: 0 0 0 1px var(--accent-ring); }
.gift-card.is-locked { opacity: 0.55; }

/* «Уникальная» версия — тонкий переливающийся блик по краю карточки,
   тот же приём, что у премиум-фонов профиля (premium-bg-shimmer), но
   компактнее и только по периметру, а не во весь фон. */
.gift-card.is-unique::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 1px;
    background: linear-gradient(120deg, transparent 20%, var(--gold) 50%, transparent 80%);
    background-size: 220% 220%;
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask-composite: exclude;
    animation: gift-unique-shimmer 3.5s linear infinite;
    pointer-events: none;
}
@keyframes gift-unique-shimmer {
    0%   { background-position: 0% 50%; }
    100% { background-position: 200% 50%; }
}
@media (prefers-reduced-motion: reduce) {
    .gift-card.is-unique::before { animation: none; }
}

.gift-emoji { font-size: 2.6rem; line-height: 1; }
.gift-name { color: var(--text); font-size: 1rem; margin: 0; }
/* Метка лимитированных подарков (total_supply задан у каталожной
   позиции) — независимо от их обычного 8-уровневого rarity: можно
   и обычной, и высокой редкости позицию сделать лимитированной. */
.gift-collectible-badge {
    display: inline-flex; align-items: center; justify-content: center;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #1a1300;
    background: linear-gradient(120deg, #ffd76a, #ffb347 55%, #ffd76a);
}
.gift-sub { color: var(--text-dim); font-size: 0.82rem; margin: 0; }
.gift-from { color: var(--accent-2); font-size: 0.78rem; margin: 0; }

.gift-actions, .gift-buy-prices {
    display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-top: 6px;
}

.pinned-gift-badge {
    display: inline-flex; align-items: center; justify-content: center;
    font-size: 1.1rem;
}
.profile-pinned-gifts {
    display: flex; gap: 4px; flex-wrap: wrap; margin-top: 4px;
}
.profile-pinned-gifts:empty { display: none; }

/* Купленные юзернеймы у шапки профиля — визуально отдельные «чипы»,
   не спутать с основным @username (.profile-username). Раньше фон был
   почти прозрачным (14%) — на фоне кастомной картинки профиля чипы
   было плохо видно; теперь сплошной градиент, тот же, что у аватарки,
   так что чип читается на любом фоне. */
.profile-extra-usernames {
    display: flex; gap: 6px; flex-wrap: wrap; margin: 2px 0 12px;
}
.profile-extra-usernames:empty { display: none; }
.extra-username-chip {
    display: inline-flex; align-items: center;
    padding: 3px 12px;
    border-radius: 999px;
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--on-accent);
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    border: 1px solid color-mix(in srgb, var(--accent-2) 60%, transparent);
    box-shadow: var(--shadow-sm);
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
    font-family: inherit;
    line-height: 1.4;
}
/* На своём профиле чип — кнопка (клик открывает «когда и за сколько
   куплен»); на чужом остаётся обычным span без действия. */
button.extra-username-chip {
    cursor: pointer;
    transition: transform var(--transition), box-shadow var(--transition), filter var(--transition);
}
button.extra-username-chip:hover { transform: translateY(-1px); filter: brightness(1.08); box-shadow: 0 4px 14px var(--accent-ring); }
button.extra-username-chip:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
.extra-username-chip.is-static { cursor: default; font-size: 1.05rem; padding: 6px 18px; }

/* Модалка справки по юзернейму */
.username-info { display: flex; flex-direction: column; gap: 10px; }
.username-info-hero { display: flex; justify-content: center; padding: 6px 0 10px; }
.username-info-row {
    display: grid; grid-template-columns: 34px 1fr auto; align-items: center; gap: 12px;
    padding: 10px 12px;
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
.username-info-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 34px; height: 34px; border-radius: 50%;
    background: var(--accent-soft); color: var(--accent-2);
}
.username-info-label { color: var(--text-muted); white-space: nowrap; }
.username-info-value { text-align: right; color: var(--text); }
.username-info-value small { color: var(--text-muted); font-weight: 400; }

.username-create-row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.username-at {
    display: inline-flex; align-items: center; justify-content: center;
    color: var(--text-dim); font-family: var(--font-head);
    font-size: 1.15rem; font-weight: 700;
}
.username-create-row .form-input { flex: 1; min-width: 180px; }

.username-grid {
    /* Раньше была CSS grid с одинаковой шириной колонок на весь ряд —
       из-за этого длинный юзернейм не мог раздвинуть свою карточку, не
       раздвинув заодно и все остальные в этом ряду, и обрезался
       многоточием. По просьбе сделали наоборот: карточки лежат во
       flex-wrap и каждая сама шириной по своему содержимому — у кого
       юзернейм не влезает, у того и растягивается плашка. */
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 16px;
}
.username-card {
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 14px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    text-align: center;
    flex: 0 0 auto;
    min-width: 170px;
    max-width: 100%;
}
.username-card.is-equipped { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent-ring); }
.username-value-frame {
    display: inline-flex;
    max-width: 100%;
    padding: 5px 14px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--accent);
    background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.username-value {
    /* Без переноса и без обрезки — покупной юзернейм максимум 20 символов
       (maxlength в pages/profile.html), рамка вокруг него в худшем случае
       станет чуть шире, но не разъедется на всю ширину экрана. */
    font-weight: 700;
    color: var(--text);
    white-space: nowrap;
}
.username-actions { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; }

@media (max-width: 640px) {
    .gift-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
    .username-card { min-width: 140px; }
}

/* ---------- Личные промокоды (Инвентарь → «Промокоды») ---------- */
.promo-code-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    margin-top: 16px;
}
.promo-code-card {
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 14px 16px;
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 0 0 auto;
    min-width: 220px;
}
.promo-code-card > .fa-ticket { color: var(--accent); font-size: 1.2em; }
.promo-code-card.is-spent { opacity: .55; }
.promo-code-body { display: flex; flex-direction: column; gap: 2px; flex: 1 1 auto; }
.promo-code-value {
    font-weight: 700;
    letter-spacing: .03em;
    color: var(--text);
}
.promo-code-percent { color: var(--accent); font-weight: 600; font-size: .9em; }
.promo-code-state { color: var(--text-muted); font-size: .8em; }

/* ============================================================
   Правовые страницы (соглашение, конфиденциальность, cookies) —
   обычный текстовый документ поверх тёмной темы сайта.
   ============================================================ */
.legal-page { padding: 40px 0 64px; }
.legal-header { margin-bottom: 28px; }
/* «Политика конфиденциальности» — одно слово шире экрана 360px.
   Переносим по буквам, иначе заголовок торчит за край. */
.legal-header h1 { margin: 0 0 10px; font-size: 1.8rem; overflow-wrap: anywhere; }
.legal-updated { color: var(--text-dim); font-size: 0.9rem; margin: 0; }
.legal-notice {
    display: flex;
    gap: 12px;
    align-items: flex-start;
    background: color-mix(in srgb, var(--accent) 10%, transparent);
    border: 1px solid var(--accent);
    border-radius: var(--radius-md);
    padding: 14px 16px;
    margin: 20px 0 32px;
}
.legal-notice i { color: var(--accent); margin-top: 2px; }
.legal-notice p { margin: 0; font-size: 0.92rem; line-height: 1.55; color: var(--text); }
.legal-content {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 32px clamp(18px, 4vw, 40px);
    line-height: 1.7;
    color: var(--text);
}
.legal-content h2 {
    font-size: 1.2rem;
    margin: 32px 0 12px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
}
.legal-content h2:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.legal-content h3 { font-size: 1rem; margin: 20px 0 8px; color: var(--text); }
.legal-content p { margin: 0 0 14px; color: var(--text-dim); }
.legal-content ul, .legal-content ol { margin: 0 0 14px; padding-left: 22px; color: var(--text-dim); }
.legal-content li { margin-bottom: 6px; }
.legal-content a { color: var(--accent-2); }
.legal-content a:hover { text-decoration: underline; }
.legal-content strong { color: var(--text); }
/* Таблица «какие ключи хранит сайт» на телефоне не помещается никак:
   три колонки с описаниями в 360px не сожмёшь. Поэтому она едет вбок
   внутри своей обёртки — а не обрезается по краю экрана, как раньше
   (у html и body стоит overflow-x: hidden, и правая колонка просто
   пропадала без всякой возможности до неё добраться). */
.legal-table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    margin: 0 0 16px;
    /* Тень у края подсказывает, что там ещё есть содержимое */
    background:
        linear-gradient(to right, var(--surface-2) 30%, transparent),
        linear-gradient(to left,  var(--surface-2) 30%, transparent) 100% 0,
        radial-gradient(farthest-side at 0 50%, rgba(0,0,0,0.4), transparent),
        radial-gradient(farthest-side at 100% 50%, rgba(0,0,0,0.4), transparent) 100% 0;
    background-repeat: no-repeat;
    background-size: 40px 100%, 40px 100%, 14px 100%, 14px 100%;
    background-attachment: local, local, scroll, scroll;
}
.legal-content table { width: 100%; border-collapse: collapse; margin: 0 0 16px; font-size: 0.9rem; }
.legal-table-scroll table { margin: 0; min-width: 460px; }
.legal-content th, .legal-content td {
    text-align: left;
    padding: 8px 10px;
    border: 1px solid var(--border);
    color: var(--text-dim);
    vertical-align: top;
}
.legal-content th { color: var(--text); background: var(--surface-3); }
.legal-toc {
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 16px 20px;
    margin-bottom: 28px;
}
.legal-toc h2 { margin: 0 0 10px; font-size: 1rem; border: none; padding: 0; }
.legal-toc ol { margin: 0; padding-left: 20px; columns: 2; column-gap: 24px; }
.legal-toc a { color: var(--text-dim); font-size: 0.9rem; }
.legal-toc a:hover { color: var(--accent-2); }

@media (max-width: 640px) {
    .legal-content { padding: 22px 16px; }
    .legal-toc ol { columns: 1; }
    .legal-header h1 { font-size: 1.45rem; }
}

/* ============================================================
   Знакомства (pages/dating.html, js/dating.js).
   ============================================================ */
.dating-page { max-width: 760px; margin: 0 auto; padding: 4px 0 24px; }

.dating-gate { text-align: center; padding: 48px 24px; }
.dating-gate i { font-size: 2.4rem; color: var(--accent); margin-bottom: 14px; }
.dating-gate h2 { margin: 0 0 10px; font-size: 1.4rem; }
.dating-gate p { color: var(--text-muted); max-width: 440px; margin: 0 auto 22px; line-height: 1.55; }

/* Одна строка, без переноса: вкладок теперь шесть («Взаимные»
   добавились) плюс у каждой ещё и цифра — по ширине это уже не всегда
   влезает, а перенос ронял последнюю кнопку («Просмотренные») сиротой
   на отдельную строку. Вместо переноса — горизонтальная прокрутка;
   Правка от 25.09: раньше был flex-wrap:nowrap + горизонтальная
   прокрутка со скрытой полосой — расчёт был, что соседняя кнопка чуть
   виднеется у края и подсказывает «прокрути дальше». С добавлением
   «Просмотренные» и «Модерация» вкладок стало 7 — при max-width:640px
   у .dating-page они перестали даже частично влезать в край, и
   прокрутка была не то что неочевидна, а вообще незаметна (особенно с
   мышью на десктопе — тронуть нечего, полоса скрыта). Из-за этого
   администратор физически не видел кнопку «Модерация», хотя в коде она
   отрисовывалась исправно. Меняем на перенос строк: так все вкладки
   гарантированно видны при любой ширине экрана и любом их количестве —
   без скрытой прокрутки, о которой нужно догадаться. */
.dating-tabs {
    display: flex;
    flex-wrap: nowrap;
    gap: 2px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
    scrollbar-color: rgba(139,123,255,.28) transparent;
    border-bottom: 1px solid var(--border);
    margin-bottom: 0;
    padding-bottom: 2px;
    flex: 1; min-width: 0;
}
.dating-tabs::-webkit-scrollbar { height: 3px; }
.dating-tabs::-webkit-scrollbar-track { background: transparent; }
.dating-tabs::-webkit-scrollbar-thumb { background: rgba(139,123,255,.28); border-radius: 999px; }
.dating-tabs::-webkit-scrollbar-thumb:hover { background: rgba(139,123,255,.55); }
.dating-tabs::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
.dating-tab {
    flex: 0 0 auto;
    white-space: nowrap;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    padding: 10px 11px;
    font-family: inherit;
    font-size: 0.92rem;
    font-weight: 600;
    color: var(--text-muted);
    cursor: pointer;
    transition: color var(--transition), border-color var(--transition);
}
.dating-tab:hover { color: var(--text); }
.dating-tab.active { color: var(--accent-2); border-bottom-color: var(--accent-2); }
/* Цифра — сколько анкет в этой вкладке (get_dating_counts). Отдельным
   кружком после подписи, а не просто числом в скобках: так её видно
   с первого взгляда. */
.dating-tab-count {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 18px; height: 18px; padding: 0 5px; margin-left: 6px;
    border-radius: 999px;
    background: var(--surface-3);
    color: var(--text-dim);
    font-size: 0.72rem; font-weight: 700;
    vertical-align: middle;
}
.dating-tab.active .dating-tab-count { background: var(--accent-2); color: var(--on-accent); }

.dating-browse-head { display: flex; justify-content: flex-end; margin-bottom: 12px; }

.dating-filters {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 16px;
    margin-bottom: 18px;
}

.dating-swipe-area { display: flex; flex-direction: column; align-items: center; gap: 16px; }

.dating-card {
    width: 100%;
    max-width: 520px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
}
/* Два кадра анкеты рядом: личное фото и профиль в игре. Решение о лайке
   принимают по обоим сразу, поэтому прятать второй за ссылку нельзя. */
.dating-card-photos {
    position: relative;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2px;
    background: var(--surface-3);
}
.dating-card-shot {
    position: relative;
    display: block;
    width: 100%;
    aspect-ratio: 3 / 5;
    overflow: hidden;
    background: var(--surface-3);
    /* Раньше это была <a href target="_blank"> — теперь <button>,
       открывающий фото оверлеем на этой же странице, а не в новой
       вкладке. Сбрасываем то, что браузер добавляет кнопкам сам. */
    padding: 0; border: none; cursor: pointer; font: inherit; text-align: left;
}
.dating-card-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.dating-card-shot span {
    position: absolute;
    inset: auto 0 0 0;
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 16px 8px 6px;
    font-size: 0.72rem;
    font-weight: 600;
    color: #fff;
    background: linear-gradient(transparent, rgba(0, 0, 0, 0.75));
}
.dating-card-shot:hover img { transform: scale(1.02); }
.dating-card-shot img { transition: transform var(--transition); }
/* Бейдж («Взаимно», «Дизлайк») — сверху: снизу уже подписи кадров. */
.dating-card-overlay { position: absolute; inset: 0 0 auto 0; padding: 10px; display: flex; justify-content: center; }
.dating-card-body { padding: 16px; }
.dating-card-body h3 { margin: 0 0 6px; font-size: 1.1rem; }
.dating-card-meta { margin: 0 0 10px; color: var(--text-muted); font-size: 0.9rem; display: flex; align-items: center; gap: 6px; }
/* Строка состояния под формой анкеты: «сжимаем фото», «сохраняем» —
   чтобы долгая загрузка двух фото не выглядела зависшей кнопкой. */
.dating-form-progress {
    margin: 10px 0 0;
    color: var(--text-dim);
    font-size: 0.85rem;
    min-height: 1.2em;
}

.dating-swipe-actions { display: flex; gap: 22px; }
.dating-swipe-actions .btn {
    width: 64px; height: 64px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-size: 1.3rem; padding: 0;
}
.dating-btn-like { background: var(--accent); color: var(--on-accent); border: none; }
.dating-btn-dislike { background: var(--surface-3); color: var(--text-muted); border: 1px solid var(--border); }
.dating-btn-like:hover { filter: brightness(1.08); }
.dating-btn-dislike:hover { color: var(--text); }

.dating-queue-hint { color: var(--text-dim); font-size: 0.85rem; margin: 0; }

.dating-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 16px;
}

.dating-badge {
    display: inline-flex; align-items: center; gap: 6px;
    background: color-mix(in srgb, var(--accent) 85%, black 0%);
    color: var(--on-accent);
    font-size: 0.82rem; font-weight: 600;
    padding: 6px 12px;
    border-radius: 999px;
}
.dating-badge-match { background: var(--accent); }
.dating-badge-dislike { background: var(--surface-3); color: var(--text-muted); border: 1px solid var(--border); }
.dating-badge-likeback { border-radius: 999px; padding: 8px 14px; font-size: 0.85rem; }
/* Юзернейм во «Взаимных» — единственной вкладке, где он вообще известен
   (get_dating_matches подтягивает его из profiles, у самой анкеты
   знакомств своего username нет). */
.dating-card-username { margin: 0 0 10px; color: var(--text-dim); font-size: 0.85rem; }

.dating-my-profile { display: flex; flex-direction: column; align-items: center; gap: 16px; }

/* «О себе» из анкеты — короткий текст в карточке, поэтому переносы строк
   из формы сохраняем, а длину ограничивает сама форма (500 символов). */
.dating-card-about {
    margin: 0 0 10px;
    color: var(--text);
    font-size: 0.9rem;
    line-height: 1.5;
    white-space: pre-line;
}

/* Сообщение, пришедшее вместе с лайком (премиум). Оно живёт внутри
   Знакомств, а не в личных сообщениях, поэтому и оформлено репликой в
   карточке, а не элементом чата. */
.dating-message {
    margin: 10px 0 0;
    padding: 10px 12px;
    background: color-mix(in srgb, var(--accent) 12%, transparent);
    border-left: 3px solid var(--accent);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    font-size: 0.88rem;
    line-height: 1.5;
    color: var(--text);
    white-space: pre-line;
}
.dating-message span { display: block; color: var(--text-dim); font-size: 0.78rem; margin-bottom: 2px; }
.dating-message-mine { background: var(--surface-3); border-left-color: var(--border); }

/* Поле «написать вместе с лайком» и его заблокированный вид без премиума */
.dating-message-box { width: 100%; max-width: 520px; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.dating-message-btn { border-radius: 999px; padding: 9px 20px; }
.dating-message-btn.is-open { border-color: var(--accent-2); color: var(--accent-2); }
.dating-message-box [hidden] { display: none !important; }
.dating-message-composer { width: 100%; }
.dating-message-composer label {
    display: block;
    margin-bottom: 6px;
    font-size: 0.88rem;
    font-weight: 600;
    color: var(--text);
}
.dating-message-composer textarea { resize: vertical; min-height: 60px; }
.dating-message-lock {
    width: 100%;
    max-width: 360px;
    display: flex;
    gap: 10px;
    align-items: flex-start;
    background: var(--surface-3);
    border: 1px dashed var(--border);
    border-radius: var(--radius-md);
    padding: 12px 14px;
}
.dating-message-lock i { color: var(--accent-2); margin-top: 2px; }
.dating-message-lock p { margin: 0; font-size: 0.85rem; line-height: 1.5; color: var(--text-muted); }
.dating-message-lock a { color: var(--accent-2); }
.dating-message-lock a:hover { text-decoration: underline; }

.dating-reply-input { margin-top: 10px; resize: vertical; min-height: 54px; font-size: 0.85rem; }

/* Кнопки внутри карточек в сетке («лайкнуть в ответ», «передумать») — на
   всю ширину карточки, чтобы в сетке они не прыгали по длине текста. */
.dating-grid .dating-card-body .btn { width: 100%; margin-top: 10px; }

.dating-stop-btn { border-radius: 999px; padding: 8px 18px; font-size: 0.88rem; }
.dating-stopped i { font-size: 2rem; color: var(--accent-2); margin-bottom: 12px; }

/* Техническая расшифровка ошибки загрузки раздела — мельче и тусклее
   основного текста: обычному человеку она не мешает, а владельцу сайта
   сразу говорит, что чинить. */
.dating-error-detail {
    margin: 8px auto 0;
    max-width: 560px;
    color: var(--text-dim);
    font-size: 0.85rem;
    line-height: 1.5;
}
.dating-error-detail code {
    background: var(--surface-3);
    border-radius: 4px;
    padding: 1px 6px;
    font-size: 0.85em;
}

@media (max-width: 480px) {
    .dating-page { padding: 20px 0 48px; }
    .dating-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   Brawl Stars: кнопка в шапке профиля и карточка игрового профиля
   (pages/profile.html, js/brawl.js). Карточка повторяет вид игровой
   статистики: тёмные панели, «таблетки» с цифрами, два крупных значка
   и ряд из четырёх чисел.
   ============================================================ */
.profile-section { position: relative; }

/* Иконка игрового профиля в углу карточки. 52px было мало: рисунок
   игровой иконки на таком размере не разобрать, а она тут и есть главное —
   по ней человек и узнаёт, что аккаунт привязан. */
.brawl-hero-btn,
.royale-hero-btn {
    position: absolute;
    top: 16px;
    right: 16px;
    width: 78px;
    height: 78px;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 18px;
    border: 1px solid var(--border);
    background: var(--surface-3);
    color: var(--text-muted);
    font-size: 1.5rem;
    cursor: pointer;
    overflow: hidden;
    transition: transform var(--transition), border-color var(--transition), color var(--transition);
    z-index: 2;
}
.brawl-hero-btn:hover,
.royale-hero-btn:hover { transform: translateY(-2px); border-color: var(--accent); color: var(--accent-2); }
/* После привязки внутри стоит иконка из игры — рамку делаем золотой,
   как рамка иконки в самом Brawl Stars. */
.brawl-hero-btn.is-linked,
.royale-hero-btn.is-linked {
    border: 2px solid var(--gold, #ffd93d);
    background: var(--surface-2);
}
.brawl-hero-btn img,
.royale-hero-btn img { width: 100%; height: 100%; object-fit: cover; display: block; }

@media (max-width: 640px) {
    .brawl-hero-btn,
    .royale-hero-btn { top: 10px; right: 10px; width: 58px; height: 58px; border-radius: 14px; }
}

.brawl-link p { margin: 0 0 16px; color: var(--text-muted); line-height: 1.55; }
.brawl-link-row { display: flex; gap: 10px; flex-wrap: wrap; }
.brawl-link-row .form-input { flex: 1; min-width: 160px; text-transform: uppercase; }

/* ---------- Карточка ---------- */
.brawl-card {
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 14px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    /* Фон — своя же игровая аватарка, во всю карточку, приглушённая:
       .brawl-card-bg лежит абсолютно и на -1 внутри собственного
       стекингового контекста (isolation), так что перекрывает только
       фон карточки и не съезжает поверх текста и плашек. */
    position: relative;
    overflow: hidden;
    isolation: isolate;
}
.brawl-card-bg {
    position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: cover; object-position: center 30%;
    opacity: 0.5; z-index: -1;
    pointer-events: none; user-select: none;
}

/* Модалка привязки Brawl Stars — светлее общего фона модалок сайта,
   только для неё, чтобы не затронуть остальные модалки. Карточка внутри
   тоже светлеет на ступень, чтобы не слиться с посветлевшим фоном модалки. */
#brawlModal .modal-content { background: var(--surface-2); }
#brawlModal .brawl-card { background: var(--surface); }
.brawl-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.brawl-club { font-weight: 700; font-size: 1rem; }
.brawl-club-none { color: var(--text-dim); font-weight: 500; }
.brawl-tag {
    border: 1px solid var(--gold, #ffd93d);
    color: var(--gold, #ffd93d);
    border-radius: 999px;
    padding: 3px 12px;
    font-size: 0.82rem;
    font-weight: 600;
    white-space: nowrap;
}

.brawl-player {
    display: flex;
    align-items: center;
    gap: 14px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 12px;
}
.brawl-player-icon {
    width: 68px;
    height: 68px;
    flex-shrink: 0;
    border-radius: 12px;
    border: 2px solid var(--gold, #ffd93d);
    /* Иконки Brawlify — квадратный PNG с прозрачным полем вокруг самого
       значка (не рамка CSS). При object-fit:cover это поле обрезалось
       по кругу, а не по краю картинки, и из-под него было видно
       непрозрачный var(--surface-3) — тёмный «квадрат» по углам поверх
       круглого значка, тот самый «чёрный фон». object-fit:contain
       показывает иконку целиком, без обрезки, а прозрачный background
       отдаёт эти поля фону карточки, а не отдельному тёмному цвету. */
    object-fit: contain;
    background: transparent;
    padding: 3px;
    box-sizing: border-box;
}
.brawl-player-icon-empty {
    border-style: dashed; border-color: var(--border);
    background: var(--surface-3);
}
.brawl-player-info { min-width: 0; }
.brawl-player-name { display: block; font-size: 1.15rem; margin-bottom: 8px; word-break: break-word; }

.brawl-pills { display: flex; gap: 8px; flex-wrap: wrap; }
.brawl-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 4px 12px;
    font-size: 0.88rem;
    font-weight: 600;
}
.brawl-pill i { font-size: 0.85rem; color: var(--text-dim); }
.brawl-pill-gold { color: var(--gold, #ffd93d); }
.brawl-pill-gold i { color: var(--gold, #ffd93d); }

/* Две крупные плитки — на месте значков рангов из игрового дизайна.
   Рангов официальное API не отдаёт (см. шапку js/brawl.js), поэтому
   здесь два лучших бравлера с их настоящими иконками. */
.brawl-panels { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.brawl-panel {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 12px 10px;
    text-align: center;
}
.brawl-panel-label {
    display: block;
    font-size: 0.7rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 8px;
}
.brawl-panel-img { width: 72px; height: 72px; object-fit: contain; display: block; margin: 0 auto 6px; }
.brawl-panel-empty { height: 72px; display: flex; align-items: center; justify-content: center; color: var(--text-dim); }
.brawl-panel-name { display: block; font-size: 0.95rem; }
.brawl-panel-meta { display: block; color: var(--text-dim); font-size: 0.8rem; margin-top: 2px; }
.brawl-panel-meta i { color: var(--gold, #ffd93d); }

.brawl-cells { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.brawl-cell {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 10px 6px;
    text-align: center;
}
/* Значок режима — настоящая игровая картинка; запасной глиф встаёт на
   её место только если картинка не дошла (см. bindIconFallbacks). */
.brawl-cell-icon {
    display: block;
    width: 34px;
    height: 34px;
    object-fit: contain;
    margin: 0 auto 6px;
}
/* Нарисованный значок «VS» — та же посадка, что у картинок с CDN. */
.brawl-cell-svg {
    display: block;
    width: 38px;
    height: 28px;
    margin: 3px auto 6px;
}
.brawl-cell i { display: block; font-size: 1.05rem; color: var(--accent-2); margin-bottom: 6px; }
.brawl-cell b { display: block; font-size: 1.2rem; line-height: 1.2; font-variant-numeric: tabular-nums; }

/* Все действия карточки — иконки без подписи, в один ряд, включая
   проверку ключа API у администратора (раньше стояла отдельно, за
   пунктирным разделителем). flex-wrap на случай совсем узкого экрана —
   тогда ряд переносится, а не сжимает иконки в кашу. */
.brawl-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.brawl-synced { margin: 0; color: var(--text-dim); font-size: 0.8rem; }

/* Фиксированные тёмные цвета, а не var(--surface-*): у сайта есть
   светлая тема, и токены поверхности в ней светлые — кнопка, «тёмная»
   только в тёмной теме, не была бы тем, о чём просили. */
.btn-icon-dark {
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; padding: 0;
    border-radius: var(--radius-sm);
    border: 1px solid rgba(255, 255, 255, 0.08);
    background: rgba(12, 12, 22, 0.92);
    color: rgba(255, 255, 255, 0.85);
    font-size: 1rem;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.btn-icon-dark:hover {
    background: #000; color: #fff; border-color: var(--accent, rgba(255,255,255,0.25));
}
.btn-icon-dark:active { transform: translateY(1px); }

#brawlCheckResult { margin-top: 8px; }

/* ============================================================
   Clash Royale: карточка игрового профиля (pages/profile.html,
   js/royale.js, разметка в js/royale-card.js). Посадка повторяет
   карточку Brawl Stars выше — те же панели, «таблетки» и ряд чисел, —
   чтобы два игровых профиля на сайте выглядели родственно, а не как
   работа двух разных людей.

   Отличий два, и оба из-за самой игры:
   * фона-аватарки нет — в Clash Royale аватарки не существует, поэтому
     .royale-card не заводит .brawl-card-bg;
   * зато есть колода из восьми карт, ряда с картами в Brawl Stars нет.
   ============================================================ */

/* ---------- Знамя: рамка (фон, во всю ширину) + узор (поверх, в правой
   части) — два независимых слоя одной картинки, посадка как в самой
   игре: узор сидит справа на рамке, а не по центру. .royale-banner —
   базовый блок; -lg используется в самой карточке и в превью пикера. */
.royale-banner {
    position: relative;
    width: 100%;
    aspect-ratio: 4 / 1;
    overflow: hidden;
    background: var(--surface-3);
}
.royale-banner-frame {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
    display: block;
}
.royale-banner-decoration {
    position: absolute;
    top: 50%;
    right: 4%;
    transform: translateY(-50%);
    max-width: 52%;
    max-height: 92%;
    object-fit: contain;
    display: block;
}
.royale-banner-lg {
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    margin-bottom: 12px;
}

/* Кнопка в шапке у Clash Royale — широкая, по форме самого знамени
   (не квадратная иконка, как у Brawl Stars): значений top/right и
   формы достаточно унаследовать от общего правила выше, а вот размер
   и радиус — свои, под пропорции 4:1 рамки. */
.royale-hero-btn {
    width: 336px;
    height: 84px;
    border-radius: 12px;
    box-sizing: border-box;
    padding: 0;
}
/* Без рамки и фона: знамя (рамка+узор) занимает кнопку целиком, край в
   край — никакой золотой обводки или подложки поверх картинки, только
   скругление углов через overflow:hidden с базового правила. */
.royale-hero-btn.is-linked { border: 0; background: transparent; }
.royale-hero-btn .royale-banner { position: absolute; inset: 0; aspect-ratio: auto; }
.royale-hero-btn .royale-banner-frame { object-fit: cover; }
.royale-hero-btn .royale-banner-decoration { max-width: 44%; right: 6px; }

@media (max-width: 640px) {
    .royale-hero-btn { width: 232px; height: 58px; border-radius: 10px; }
    .royale-hero-btn .royale-banner-decoration { max-width: 42%; right: 4px; }
}

.royale-link p { margin: 0 0 16px; color: var(--text-muted); line-height: 1.55; }
.royale-link-row { display: flex; gap: 10px; flex-wrap: wrap; }
.royale-link-row .form-input { flex: 1; min-width: 160px; text-transform: uppercase; }
.royale-link .form-hint { margin-top: 10px; }

/* ---------- Карточка ---------- */
.royale-card {
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 14px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}
/* Модалка — светлее общего фона модалок сайта, как и у Brawl Stars;
   карточка внутри светлеет на ступень, чтобы не слиться с фоном. */
#royaleModal .modal-content { background: var(--surface-2); }
#royaleModal .royale-card { background: var(--surface); }

.royale-card-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.royale-clan { font-weight: 700; font-size: 1rem; min-width: 0; }
.royale-clan-none { color: var(--text-dim); font-weight: 500; }
/* nowrap, иначе точка-разделитель остаётся висеть в конце строки с названием
   клана, а роль уезжает на следующую — выглядит как опечатка. */
.royale-clan-role { color: var(--text-dim); font-weight: 500; font-size: 0.85rem; white-space: nowrap; }
.royale-tag {
    border: 1px solid var(--gold, #ffd93d);
    color: var(--gold, #ffd93d);
    border-radius: 999px;
    padding: 3px 12px;
    font-size: 0.82rem;
    font-weight: 600;
    white-space: nowrap;
}

.royale-player {
    display: flex;
    align-items: center;
    gap: 14px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 12px;
}
.royale-player-info { min-width: 0; }
.royale-player-name { display: block; font-size: 1.15rem; margin-bottom: 8px; word-break: break-word; }

.royale-pills { display: flex; gap: 8px; flex-wrap: wrap; }
.royale-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 4px 12px;
    font-size: 0.88rem;
    font-weight: 600;
}
.royale-pill i { font-size: 0.85rem; color: var(--text-dim); }
.royale-pill-gold, .royale-pill-gold i { color: var(--gold, #ffd93d); }
.royale-pill-king, .royale-pill-king i { color: #f2c53d; }

/* ---------- Плитка карты ----------
   Рамка красится по редкости (--rarity-color задаёт разметка), уровень
   стоит цифрой снизу, стоимость эликсира — капля в левом верхнем углу,
   как в самой игре. */
.royale-card-tile {
    position: relative;
    display: block;
    aspect-ratio: 5 / 6;
    border-radius: 8px;
    border: 1px solid var(--rarity-color, var(--border));
    background: var(--surface-3);
    overflow: hidden;
}
.royale-card-tile img { width: 100%; height: 100%; object-fit: contain; display: block; }
.royale-card-tile-empty { border-style: dashed; border-color: var(--border); }
.royale-card-blank {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    color: var(--text-dim); font-size: 1.1rem;
}
.royale-card-tile-lg { width: 76px; flex-shrink: 0; border-width: 2px; border-radius: 10px; }
.royale-card-elixir {
    position: absolute; top: 2px; left: 2px;
    min-width: 17px; height: 17px;
    display: flex; align-items: center; justify-content: center;
    border-radius: 999px;
    background: #b565f0;
    color: #fff;
    font-size: 0.66rem; font-weight: 800; line-height: 1;
    box-shadow: 0 0 0 1.5px rgba(0, 0, 0, 0.45);
}
.royale-card-level {
    position: absolute; bottom: 0; left: 0; right: 0;
    background: rgba(8, 10, 20, 0.82);
    color: #fff;
    font-size: 0.7rem; font-weight: 700;
    text-align: center;
    padding: 1px 0;
    font-variant-numeric: tabular-nums;
}

/* ---------- Две крупные панели ---------- */
.royale-panels { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.royale-panel {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 12px 10px;
    text-align: center;
}
.royale-panel .royale-card-tile-lg { margin: 0 auto 6px; }
.royale-panel-label {
    display: block;
    font-size: 0.7rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 8px;
}
.royale-panel-empty { height: 92px; display: flex; align-items: center; justify-content: center; color: var(--text-dim); }
.royale-panel-name { display: block; font-size: 0.95rem; }
.royale-panel-meta { display: block; color: var(--text-dim); font-size: 0.8rem; margin-top: 2px; }
.royale-panel-meta i { color: var(--gold, #ffd93d); }

.royale-panel-league { border-color: color-mix(in srgb, var(--league-color, var(--accent)) 45%, transparent); }
.royale-panel-league .royale-panel-name { color: var(--league-color, var(--text)); }
/* Иконок лиг Пути легенд в открытом доступе нет (API отдаёт только номер),
   поэтому корона в круге цвета лиги — а не выдуманный чужой значок. */
.royale-league-badge {
    width: 66px; height: 66px;
    margin: 0 auto 6px;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%;
    border: 2px solid var(--league-color, var(--border));
    background: color-mix(in srgb, var(--league-color, var(--surface-3)) 18%, transparent);
    color: var(--league-color, var(--text-muted));
    font-size: 1.5rem;
}
.royale-league-badge-plain {
    border-color: var(--border);
    background: var(--surface-3);
    color: var(--text-muted);
}

/* ---------- Колода ---------- */
.royale-deck {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 10px;
}
.royale-deck-label {
    display: block;
    font-size: 0.7rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-dim);
    margin-bottom: 8px;
}
/* Восемь карт в два ряда по четыре — ровно как окно колоды в игре.
   Одним рядом из восьми карты выходили бы слишком мелкими на телефоне. */
.royale-deck-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }

/* ---------- Ряд чисел и донаты ---------- */
.royale-cells { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.royale-cell {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 10px 6px;
    text-align: center;
}
.royale-cell i { display: block; font-size: 1.05rem; color: var(--accent-2); margin-bottom: 6px; }
.royale-cell b { display: block; font-size: 1.2rem; line-height: 1.2; font-variant-numeric: tabular-nums; }

.royale-extra {
    display: flex; gap: 14px; flex-wrap: wrap;
    color: var(--text-dim); font-size: 0.85rem;
}
.royale-extra span { display: inline-flex; align-items: center; gap: 6px; }
.royale-extra i { color: var(--accent-2); }

.royale-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.royale-synced { margin: 0; color: var(--text-dim); font-size: 0.8rem; }
#royaleCheckResult { margin-top: 8px; }

/* ---------- Выбор значка и выбор знамени (окна royaleBadgeModal и
   royaleFlagModal, js/royale.js) ----------
   Сетка и плитка общие для обоих окон: у значка — квадратная игровая
   иконка (плитка похожа на .royale-card-tile, но шире, снизу подпись с
   названием вместо уровня); у знамени (рамка/узор) — та же плитка, но
   картинка внутри своей естественной формы, см. переопределения ниже. */
.royale-banner-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
    gap: 8px;
    margin-top: 4px;
}
.royale-banner-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 10px 6px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: border-color var(--transition), background var(--transition);
}
.royale-banner-tile:hover { border-color: var(--accent); }
.royale-banner-tile.is-current {
    border-color: var(--gold, #ffd93d);
    background: color-mix(in srgb, var(--gold, #ffd93d) 12%, var(--surface-2));
}
.royale-banner-tile img { width: 48px; height: 48px; object-fit: contain; display: block; }
.royale-banner-tile i { font-size: 1.6rem; color: var(--text-dim); }
.royale-banner-tile-name {
    font-size: 0.72rem;
    text-align: center;
    color: var(--text-muted);
    line-height: 1.25;
    /* Названия знамён бывают длинными («Путь легенд — Абсолютный чемпион»);
       две строки с обрезкой третьей — компромисс между читаемостью подписи
       и одинаковой высотой всех плиток в сетке. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.royale-banner-clear { margin-top: 12px; }

/* Пикер знамени — рамка широкая, узор ближе к квадрату; плитки под их
   собственную форму, а не общий квадрат 48×48. */
.royale-banner-picker-preview { margin-bottom: 4px; }
.royale-banner-picker-label {
    display: block;
    margin: 14px 0 6px;
    font-size: 0.85rem;
    color: var(--text-muted);
}
.royale-banner-picker-label:first-of-type { margin-top: 4px; }
.royale-banner-grid-frames { grid-template-columns: repeat(auto-fill, minmax(128px, 1fr)); }
.royale-banner-grid-frames .royale-banner-tile img { width: 100%; height: 32px; object-fit: cover; border-radius: 4px; }
.royale-banner-grid-decorations .royale-banner-tile img { width: 64px; height: 64px; }

/* На узком экране панели встают друг под друга, а числа — в два ряда:
   четыре плитки в одну строку на телефоне сжимаются до нечитаемых. */
@media (max-width: 480px) {
    .royale-panels { grid-template-columns: 1fr; }
    .royale-cells { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 480px) {
    .brawl-cells { grid-template-columns: repeat(2, 1fr); }
    .brawl-player { flex-direction: column; text-align: center; }
    .brawl-pills { justify-content: center; }
}

/* Строка под формой анкеты в режиме ошибки: тем же местом, где шёл
   прогресс загрузки, объясняем причину отказа — тост исчезает, а
   разбираться с причиной человеку нужно спокойно. */
.dating-form-progress.is-error {
    color: var(--danger, #ff6b6b);
    font-size: 0.88rem;
    line-height: 1.5;
}

/* ---------- Каталог игровых иконок как аватарки (js/brawl-icons.js) ---------- */
.brawl-icons-search { margin: 0 0 14px; max-width: 320px; }
.brawl-icons-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
    gap: 10px;
    margin-bottom: 16px;
}
.brawl-icon {
    position: relative;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
    cursor: pointer;
    aspect-ratio: 1 / 1;
    overflow: hidden;
    transition: border-color var(--transition), transform var(--transition);
}
.brawl-icon:hover { border-color: var(--gold, #ffd93d); transform: translateY(-2px); }
.brawl-icon:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.brawl-icon img { width: 100%; height: 100%; object-fit: contain; display: block; }
.brawl-icon.is-busy { opacity: 0.5; pointer-events: none; }
/* Карточка иконки, чья картинка не загрузилась: показываем название —
   выбрать иконку всё равно можно, файл копирует сервер. */
.brawl-icon.is-imageless {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 6px;
}
.brawl-icon.is-imageless span {
    font-size: 0.7rem;
    line-height: 1.25;
    color: var(--text-muted);
    text-align: center;
    word-break: break-word;
}

/* ---------- Форма аватарки: круглая или квадратная (js/avatar-shape.js) ---------- */
/* Скругление задано и у рамки, и у самого аватара, поэтому класс вешается
   на оба — иначе квадратная картинка осталась бы в круглой рамке. */
.avatar-frame.is-square { border-radius: 20px; }
.profile-avatar.is-square { border-radius: 18px; }

.avatar-shape-choice { display: flex; gap: 10px; flex-wrap: wrap; }
.avatar-shape-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    color: var(--text-muted);
    font-family: inherit;
    font-size: 0.9rem;
    cursor: pointer;
    transition: border-color var(--transition), color var(--transition);
}
.avatar-shape-btn:hover { color: var(--text); border-color: var(--accent); }
.avatar-shape-btn.is-active { border-color: var(--accent); color: var(--text); }
.avatar-shape-btn i { font-size: 0.8rem; }
.avatar-shape-preview {
    width: 20px;
    height: 20px;
    background: linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%);
    flex-shrink: 0;
}
.avatar-shape-circle { border-radius: 50%; }
.avatar-shape-square { border-radius: 5px; }
/* Сетка иконок в режиме «ничего не нашлось» — обычный текст, без колонок */
.brawl-icons-grid.is-empty { display: block; }
.brawl-icons-search .form-hint { margin-top: 6px; }

/* Игровая иконка как аватар: у картинки с CDN своя чёрная кайма, нарисованная
   прямо в файле. В рамке сайта она читается как пустое кольцо, поэтому
   слегка увеличиваем картинку — кайма уходит за край и обрезается. */
.profile-avatar { overflow: hidden; }
.avatar-frame { overflow: hidden; }
img.is-game-icon { transform: scale(1.1); }

/* ---------- Каталог лобби-фонов из игры (js/brawl-backgrounds.js) ----------
   Карточки широкие, 16:9 — фон должен быть узнаваем с первого взгляда,
   квадратная плитка от него оставляет середину и врёт о том, как он
   ляжет на страницу. */
.brawl-bg-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 12px;
    margin-bottom: 16px;
}
.brawl-bg-grid.is-empty { display: block; }
.brawl-bg {
    position: relative;
    display: block;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
    cursor: pointer;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    transition: border-color var(--transition), transform var(--transition);
}
.brawl-bg:hover { border-color: var(--gold, #ffd93d); transform: translateY(-2px); }
.brawl-bg:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.brawl-bg img { width: 100%; height: 100%; object-fit: cover; display: block; }
.brawl-bg.is-busy { opacity: 0.5; pointer-events: none; }

/* Название лежит поверх картинки на затемнении: под картинкой оно ломало бы
   пропорции 16:9, а без подложки нечитаемо на светлых фонах. */
.brawl-bg-name {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 14px 8px 6px;
    background: linear-gradient(to top, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0));
    color: #fff;
    font-size: 0.78rem;
    line-height: 1.25;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Картинка с чужой вики не загрузилась — карточку оставляем, выбрать фон
   всё равно можно (файл копирует сервер), просто название занимает её всю. */
.brawl-bg.is-imageless .brawl-bg-name {
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 8px;
    background: none;
    color: var(--text-muted);
    text-align: center;
    white-space: normal;
}

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

   Кадры при этом задаются высотой, а не пропорцией 3:4: у широкой карточки
   пропорция растянула бы их вниз, и кнопка «Редактировать анкету» ушла бы
   за нижний край экрана — ровно то, на что жаловались. */
.dating-my-profile { gap: 14px; }
.dating-my-profile .dating-card { max-width: 560px; }
.dating-my-profile .dating-card-shot { aspect-ratio: auto; height: 300px; }
/* Отступ сверху у .form-actions рассчитан на формы; здесь он только
   отодвигает кнопку от карточки. */
.dating-my-profile .form-actions { margin-top: 0; }

/* На узком экране два кадра по 300px в высоту превращаются в две
   вертикальные полоски — снижаем. */
@media (max-width: 640px) {
    .dating-my-profile .dating-card-shot { height: 210px; }
}

/* Статус проверки над анкетой на вкладке «Моя анкета» — тот же .confirm-text,
   что и в формах, просто по ширине карточки и с иконкой слева. */
.dating-moderation-banner {
    max-width: 560px; width: 100%;
    display: flex; align-items: flex-start; gap: 8px;
    text-align: left;
}
.dating-moderation-banner i { margin-top: 2px; flex: none; }

/* Список анкет на вкладке «Модерация» — карточки друг под другом, той же
   ширины, что и «Моя анкета», с кнопками решения внизу каждой. */
.dating-moderation-list {
    display: flex; flex-direction: column; align-items: center; gap: 18px;
}
.dating-moderation-list .dating-card { max-width: 560px; width: 100%; }
.dating-moderation-list .dating-card-shot { aspect-ratio: auto; height: 260px; }
.dating-moderation-list .form-actions { margin-top: 12px; }

@media (max-width: 640px) {
    .dating-moderation-list .dating-card-shot { height: 200px; }
}

/* Знакомства начинаются сразу с вкладок, без заголовка страницы, поэтому
   общий верхний отступ в 56px здесь только гонит содержимое вниз. */
body[data-page="dating"] .main-content { padding-top: 24px; }

/* Профиль (свой и чужой) — та же история: карточка профиля начинается
   сразу под шапкой, общий отступ в 56px выглядел как лишний пустой
   зазор до баннера/аватара. */
body[data-page="profile"] .main-content,
body[data-page="user"] .main-content { padding-top: 20px; }

/* ---------- Ящики за уровни (js/boxes.js) ----------
   Цвет ящика — цвет его ключа и цвет уровня: 1 зелёный, 2 синий,
   3 фиолетовый, 4 красный, 5 жёлтый. Тот же набор, что и LEVEL_COLORS
   в js/levels.js — если менять, менять в обоих местах. */
.boxes-lead { margin: 0 0 18px; max-width: 640px; }

.boxes-group { margin-bottom: 26px; }
.boxes-group-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 12px;
}
.boxes-group-head h4 { margin: 0; font-size: 1.05rem; }
.boxes-group-count { color: var(--text-muted); font-size: 0.85rem; }

.boxes-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
    gap: 12px;
}

.box-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 16px 14px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-top: 3px solid var(--box-color, var(--border));
    border-radius: var(--radius-md);
}
.box-art {
    font-size: 1.9rem;
    line-height: 1;
    color: var(--box-color, var(--text-muted));
}
/* Картинка ящика вместо шрифтового значка. Свечение под цвет ящика —
   чтобы на тёмной плашке она не выглядела наклейкой; сам рисунок и так
   светится изнутри. */
.box-art-img {
    display: block;
    width: 84px; height: 84px;
    object-fit: contain;
    filter: drop-shadow(0 4px 10px color-mix(in srgb, var(--box-color, #000) 45%, transparent));
    transition: transform var(--transition);
}
.box-card:hover .box-art-img { transform: translateY(-2px) scale(1.04); }
/* Закрытый без ключа ящик обесцвечиваем — видно, что до него ещё не
   добрались. Не затемняем: вся плашка и так приглушена до 0.62, и вместе
   с затемнением ящик превращался в тёмное пятно без деталей. */
.box-card.is-locked .box-art-img { filter: grayscale(0.55); }

/* Ключ-картинка: и в строке «0/1», и на кнопке «Открыть», и рядом с
   уровнем достижений. Размер в em — чтобы ключ рос вместе с текстом,
   рядом с которым стоит. */
.key-art {
    width: 1.5em; height: 1.5em;
    object-fit: contain;
    vertical-align: -0.35em;
    flex-shrink: 0;
}
.box-keys .key-art { width: 1.7em; height: 1.7em; }
/* Ключа нет — показываем его тенью, чтобы было понятно, чего не хватает. */
.box-card.is-locked .key-art { filter: grayscale(1); opacity: 0.75; }
.level-title .key-art { width: 1.35em; height: 1.35em; vertical-align: -0.3em; }
.track-level-row.locked .key-art { filter: grayscale(1); opacity: 0.55; }
.box-name { margin: 4px 0 0; font-size: 0.98rem; display: flex; align-items: center; gap: 7px; }
.box-name i { color: var(--text-muted); font-size: 0.85em; }
.box-level { margin: 0; color: var(--text-muted); font-size: 0.82rem; }

/* «0/1 🔑» — единственный способ понять, есть ли ключ именно от этого
   ящика, поэтому надпись крупная и всегда на виду. */
.box-keys {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 6px 0 0;
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--text-muted);
}
.box-card.is-ready .box-keys,
.box-card.is-open .box-keys { color: var(--box-color, var(--text)); }

.box-hint { margin: 2px 0 0; color: var(--text-muted); font-size: 0.8rem; }
.box-reward { margin: 2px 0 0; font-size: 0.84rem; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.box-reward i { color: var(--box-color, var(--gold, #ffd93d)); }
.box-coins { color: var(--gold, #ffd93d); font-weight: 700; }
.box-done { margin: 10px 0 0; color: var(--text-muted); font-size: 0.84rem; display: flex; align-items: center; gap: 6px; }
.box-card .btn { margin-top: 10px; width: 100%; }

/* Закрытый без ключа — приглушён, но читаем: это цель, а не мусор */
.box-card.is-locked { opacity: 0.62; }
.box-card.is-ready { border-color: var(--box-color, var(--accent)); }
.box-card.is-open .box-art { opacity: 0.8; }

.box-green  { --box-color: #4cd964; }
.box-blue   { --box-color: #4aa3f0; }
.box-purple { --box-color: #b060d0; }
.box-red    { --box-color: #ff4757; }
.box-gold   { --box-color: #ffd700; }

/* Заперта вся группа криэйторов — это не «не хватает уровня», а другой
   замок, и выглядит он иначе: приглушены все ящики группы разом. */
.boxes-gate { display: flex; align-items: center; gap: 8px; margin: -8px 0 16px; }
.box-card.is-group-locked { opacity: 0.5; }

/* Образец рамки в инвентаре повторяет форму аватарки из настроек
   (js/avatar-shape.js): круглый образец при квадратном аватаре показывал
   бы не то, что человек увидит у себя в профиле. */
.cosmetic-frame-preview.is-square,
.cosmetic-profile-frame-preview.is-square { border-radius: 12px; }
.cosmetic-avatar.is-square { border-radius: 9px; }

/* ---------- Бустеры (js/boosters.js, supabase/boosters.sql) ----------
   Категории — те же «пилюли», что у Настроек аккаунта чуть выше на
   странице (переиспользуем .subtabs/.subtab как есть, отдельного
   класса под них не заводим); .booster-category-tabs только убирает
   нижнюю линию-разделитель — под пилюлями сразу идут купоны, а не
   отдельная панель со своей рамкой.

   Купон редкости внутри выбранной категории — карточка в духе
   .promo-code-card (тот же приём: иконка-билет слева, тело с
   заголовком/описанием, действия справа), только шире и с двумя
   кнopками — тратит бустер («Активировать») или пополняет запас
   («Купить», сейчас только у Редкого). */
.booster-lead { margin-bottom: 14px; }

.booster-category-tabs { border-bottom: none; margin-bottom: 18px; }

.booster-target-status { margin: 0 0 14px; font-size: 0.85rem; color: var(--text-muted); }
.booster-target-status.is-active { color: var(--success); }
.booster-target-status.is-active i { margin-right: 4px; }

.booster-coupons { display: flex; flex-direction: column; gap: 10px; }

.booster-coupon {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 16px;
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-left: 3px solid currentColor;
    border-radius: var(--radius-md);
    flex-wrap: wrap;
}
/* Раньше тут была одна фиксированная .fa-ticket на все категории —
   теперь у каждой свой значок (js/boosters.js, CATEGORIES/couponHtml),
   поэтому класс общий, а не по имени иконки. */
.booster-coupon-icon { color: currentColor; font-size: 1.3em; flex-shrink: 0; }

.booster-coupon-body { display: flex; flex-direction: column; gap: 2px; flex: 1 1 220px; min-width: 0; }
.booster-coupon-title { margin: 0; font-size: 0.98rem; color: var(--text); }
.booster-coupon-desc { margin: 0; font-size: 0.82rem; color: var(--text-muted); }
.booster-coupon-qty { font-size: 0.8rem; font-weight: 600; }

/* Купон эффекта, который ещё не сделан (kind:'soon' в EFFECTS,
   js/boosters.js) — приглушаем целиком, чтобы не выглядел как рабочая
   кнопка с недостатком запаса, а сразу читался как «сюда рано». */
.booster-coupon.is-soon { opacity: 0.6; border-left-color: var(--text-dim); }

.booster-effect-state {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 0.8rem; color: var(--text-muted); margin: 2px 0;
}
.booster-effect-state.is-active { color: var(--success); }
.booster-effect-state.is-soon { color: var(--text-dim); }

.booster-effect-option {
    display: flex; align-items: center; gap: 8px;
    margin-top: 6px; max-width: 320px;
}
.booster-effect-option .form-input { flex: 1; padding: 6px 10px; font-size: 0.85rem; }

/* Выбор дизайна (скина) рамки/фона из тех редкостей, что игрок
   когда-либо разблокировал в этой категории (supabase/booster_skins.sql,
   get_booster_unlocks()) — кружок закрашен темой редкости, серый и
   недоступен для клика, если ещё не открыт. */
.booster-skin-picker {
    display: flex; flex-wrap: wrap; align-items: center;
    gap: 7px; margin-top: 6px;
}
.booster-skin-swatch {
    width: 26px; height: 26px; border-radius: 50%;
    border: 2px solid var(--border);
    padding: 0; cursor: pointer;
    background: var(--booster-skin-a, var(--text-dim));
}
.booster-skin-swatch.is-selected { border-color: var(--text); box-shadow: 0 0 0 2px var(--surface-3); }
.booster-skin-swatch:disabled { opacity: 0.28; cursor: not-allowed; filter: grayscale(0.6); }
.booster-skin-swatch[data-skin="legendary"] {
    background: linear-gradient(135deg, #ffd54f 0%, #ff91d2 55%, #4fc3f7 100%);
}

/* Тот же приём — набор иконок кнопки отправки (только Чаты, mythical). */
.booster-icon-picker {
    display: flex; flex-wrap: wrap; gap: 7px; margin-top: 6px;
}
.booster-icon-swatch {
    width: 32px; height: 32px; border-radius: 8px;
    border: 1px solid var(--border); background: var(--surface-2);
    color: var(--text-muted); cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    font-size: 0.9rem;
}
.booster-icon-swatch.is-selected { border-color: var(--accent-2); color: var(--accent-2); background: var(--accent-soft); }
.booster-icon-swatch:disabled { opacity: 0.28; cursor: not-allowed; }

.booster-coupon-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    flex-shrink: 0;
}
.booster-coupon-hint {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.78rem;
    color: var(--text-muted);
    max-width: 180px;
}

/* ---------- Команды турнира: составы и приглашения (js/tournaments.js) ---------- */
/* Ответ по каждому введённому юзернейму отдельно: «приглашено 2 из 5»
   не объясняет, где опечатка, а где человек уже в другой команде. */
.invite-results { list-style: none; margin: 4px 0 14px; padding: 0; display: grid; gap: 6px; }
.invite-results li {
    display: flex;
    justify-content: space-between;
    gap: 10px;
    padding: 7px 10px;
    border-radius: var(--radius-sm);
    background: var(--surface-3);
    font-size: 0.86rem;
}
.invite-results li.is-ok  { color: var(--success); }
.invite-results li.is-bad { color: var(--text-muted); }

/* ---------- Команды турнира: сетка карточек ----------
   Составы всех команд разом превращали вкладку в простыню. Теперь
   сначала сами команды — логотипом и названием, а состав открывается
   нажатием. */
.tournament-teams-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    align-content: start;
    gap: 12px;
    /* max-height подгоняется в js/tournament-detail.js (syncTeamsGridHeight)
       под фактическую высоту правой колонки — команд может быть больше,
       чем помещается, и тогда список не должен растягивать страницу
       ниже сайдбара, а должен скроллиться сам. */
    overflow-y: auto;
    padding-right: 6px;
}
.team-card {
    display: flex; align-items: center; gap: var(--space-3);
    width: 100%; padding: var(--space-3) var(--space-4);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-xs);
    color: inherit; font: inherit; text-align: left;
    cursor: pointer;
    transition: border-color var(--transition-fast), transform var(--transition-fast), box-shadow var(--transition-fast);
}
.team-card:hover { border-color: var(--accent); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.team-card:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
.team-card.is-mine { border-color: var(--accent); background: var(--surface-3); }

.team-card-logo {
    flex: 0 0 auto;
    width: 48px; height: 48px;
    border-radius: 12px;
    overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    background: var(--surface-3);
    border: 1px solid var(--border);
}
.team-card-logo img { width: 100%; height: 100%; object-fit: cover; }
/* В заголовке окна состава логотип был размером с иконку и терялся
   рядом с названием. Делаем его заметным — команду узнают по логотипу. */
.team-card-logo-small { width: 44px; height: 44px; border-radius: 11px; vertical-align: middle; display: inline-flex; }
.team-logo-initials { font-weight: 700; color: var(--text-muted); font-size: 0.95rem; }
.team-card-logo-small .team-logo-initials { font-size: 0.72rem; }

.team-card-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.team-card-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.team-card-count { color: var(--text-muted); font-size: 0.82rem; }
.team-card-arrow { color: var(--text-dim); flex: 0 0 auto; }

/* Старый плоский список оставлен: им ещё пользуются вкладки, куда
   двухуровневый вид не завезли. */
.tournament-teams-list { display: grid; gap: 14px; }
.tournament-team-card {
    padding: var(--space-4) var(--space-5);
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-xs);
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.tournament-team-card.is-mine { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent-ring); }
.tournament-team-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
}
.tournament-team-head h4 { margin: 0; font-size: 1rem; }
.tournament-team-count { color: var(--text-muted); font-size: 0.84rem; }

/* Игровой ник — крупно: именно по нему соперника ищут в игре. Ник сайта
   и тег строкой ниже, мельче. */
.team-roster-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
/* Длинный игровой ник/тег внутри узкой колонки (например, в паре 1 на 1
   в карточке матча) не должен раздвигать строку до переполнения — обрезаем
   многоточием, как и в остальных местах сайта с именами переменной длины. */
.team-roster-game, .team-roster-site {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.team-roster-game { font-weight: 600; }
.team-roster-site { color: var(--text-muted); font-size: 0.78rem; }

/* На узком экране полноразмерный аватар забрал бы половину ширины шапки
   профиля — там он заметно меньше и растёт вместе с основным. Размер задаём
   рамке (.profile-avatar-frame), а не самой .profile-avatar — она теперь
   всегда 100% рамки; шрифт инициала пересчитается сам (font-size в cqh). */
@media (max-width: 640px) {
    .profile-avatar-frame { width: 136px; height: 136px; }
}


/* ============================================================
   Планшеты и телефоны: убираем то, что заставляет их перерисовывать
   экран без остановки.

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

     1) backdrop-filter — размытие того, что ЗА панелью. Браузер обязан
        пересчитывать его при любом сдвиге содержимого, а на профиле с
        пользовательским фоном таких панелей полтора десятка сразу.
     2) filter: blur() на подложках карточек товара — по одному размытию
        на карточку, и все они живут одновременно в витрине.
     3) Анимация background-position на тексте с background-clip: text
        (переливающийся ник). Композитору её отдать нельзя, поэтому
        браузер заново растрирует текст каждый кадр — и так у каждого
        ника в списке, пока страница открыта.

   Целимся по pointer: coarse — это «палец, а не мышь», то есть ровно
   планшеты и телефоны. Внешний вид почти не меняется: вместо размытия
   плотнее фон, вместо бегущего перелива — тот же градиент, но
   неподвижный.
   ============================================================ */
@media (pointer: coarse) {
    /* .premium-hero и .coins-balance добавлены позже, при следующем
       мобильном проходе: они той же семьи (тот же rgba(10,10,30,…) +
       backdrop-filter: blur(2px), см. .profile-canvas.has-custom-bg …
       .premium-hero, .coins-balance выше в файле), но в этот список
       тогда не попали — просто недосмотр. */
    .profile-canvas.has-custom-bg .tabs-nav,
    .profile-canvas.has-custom-bg .profile-bio,
    .profile-canvas.has-custom-bg .stat-card,
    .profile-canvas.has-custom-bg .premium-hero,
    .profile-canvas.has-custom-bg .coins-balance,
    .profile-canvas.has-custom-bg .special-titles,
    .profile-canvas.has-custom-bg .quests-box,
    .profile-canvas.has-custom-bg .referral-box,
    .profile-canvas.has-custom-bg .promo-code-card,
    .profile-canvas.has-custom-bg .form-input,
    .profile-canvas.has-custom-bg .form-textarea,
    .profile-canvas.has-custom-bg .tournament-table {
        backdrop-filter: none;
        /* Размытие держало текст читаемым поверх пёстрой картинки. Без него
           эту работу берёт на себя более плотная подложка. */
        background-color: rgba(10, 10, 30, 0.82);
    }

    .nick-rainbow { animation: none; }
}

/* ============================================================
   Планшеты и телефоны: зона попадания пальцем у мелких кнопок.

   Несколько круглых кнопок по сайту нарисованы под курсор мыши —
   20–28px, размер значка, без запаса. Мышью в такую легко попасть
   точно по пикселю, пальцем — нет (Apple/Google рекомендуют от
   ~40–44px на прикосновение). Сам значок и его видимый размер не
   трогаем — нигде в макете вокруг него нет места на кружок покрупнее
   без сдвига соседей (булавка чата, например, стоит вплотную к
   отметке дня/времени — .chat-time-meta). Вместо этого невидимым
   псевдоэлементом расширяем именно ОБЛАСТЬ КЛИКА за пределы видимого
   кружка — сам вид кнопки не меняется вовсе.

   .chat-pin-btn, .bracket-info, .draft-remove, .match-chat-attach-remove —
   одинокие значки-бэйджи: в своей строке/углу карточки это единственная
   кликабельная кнопка, соседей того же типа рядом нет — псевдоэлементу
   есть куда расти (или почти есть, см. булавку ниже).

   .message-react и .editor-color — другой случай: это НЕ одинокие
   кнопки, а элементы тесного ряда — до 5 подряд в .message-tools
   (gap: 4px) и до 8 подряд в .editor-colors (gap: 5px). Невидимый
   ::after с inset: -10px у каждой такой кнопки перекрыл бы область
   соседних кнопок в ряду — тап у границы двух кнопок иногда попадал
   бы не туда, куда палец целился, то есть стало бы хуже, а не лучше.
   Для них вместо перекрывающихся невидимых зон увеличен НАСТОЯЩИЙ
   отступ между кнопками (см. отдельный блок ниже) — это и расширяет
   зазор безопасно (не съедая соседей), и не требует лишней разметки. */
@media (pointer: coarse) {
    .draft-remove::after,
    .match-chat-attach-remove::after {
        content: '';
        position: absolute;
        inset: -10px;
    }
    .match-chat-attach-remove { position: relative; }

    /* Бейдж «i» стоит в верхнем углу карточки матча (top: -8px), а
       карточки в .bracket-round идут с gap: 14px — расширь зону вверх
       на те же -10px, что и с других сторон, и она заедет на нижний
       край карточки матча РАУНДОМ ВЫШЕ. Сверху растим меньше (-4px,
       то есть до -12px от карточки), с трёх остальных сторон — как
       у .draft-remove. */
    .bracket-info::after {
        content: '';
        position: absolute;
        top: -4px; right: -10px; bottom: -10px; left: -10px;
    }

    /* Булавка чата — не поровну со всех сторон: сверху рядом с ней
       (padding самой плашки .chat-item) всего 4px до верхнего края, а
       строки списка стоят вплотную друг к другу (.chat-items, gap: 0).
       Расширь зону кликабельности сверху так же, как с других сторон —
       и она заедет на нижний край строки НАД этой, а тап у самой
       границы двух чатов иногда открывал бы не тот чат. Сверху растим
       только на 2px (запас внутри чужого паддинга остаётся), с трёх
       остальных сторон — как у всех. */
    .chat-pin-btn::after {
        content: '';
        position: absolute;
        top: -2px; right: -8px; bottom: -8px; left: -8px;
    }

    /* Ряд кнопок у сообщения (ответить/реакция/закреп/править/перевод):
       на мышь достаточно 4px между кружками 28×28, пальцем между ними
       легко промахнуться. .message-tools ужимается за счёт .message-content
       (flex: 1 1 auto по соседству), так что рост зазора не обрезает
       кнопки — просто чуть теснее самому тексту сообщения. */
    .message-tools { gap: 10px; }

    /* Палитра цветов текста в редакторе поста: кружки 22px с зазором
       всего 5px — на пальце соседние цвета сливаются в один тап.
       .editor-colors лежит внутри .editor-toolbar (flex-wrap: wrap),
       поэтому и увеличенный зазор, и чуть более крупный кружок просто
       перетекут на следующую строку тулбара при нехватке места —
       ничего не обрежется и не наедет на соседний блок. */
    .editor-colors { gap: 10px; }
    .editor-color { width: 26px; height: 26px; }

    /* Палитра темы шапки (.palette-swatch, css/style.css): кружки 26px
       в ряд с зазором 8px — свой плавающий попап поверх всего
       остального (z-index: 1210), так что расти можно свободно, без
       риска задеть чужой контент под ним, только соседний кружок в
       этом же ряду. */
    .palette-swatches { gap: 12px; }
}


/* ============================================================
   Телефон: витрина в две колонки

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

   Две колонки — то, как устроены все мобильные витрины, и причина
   та же: на экран попадает четыре товара вместо одного. Карточка
   становится вдвое уже, поэтому внутренности тоже ужимаем — иначе
   заголовок в две строки и кнопка продавца съедят выигрыш.
   ============================================================ */
@media (max-width: 560px) {

    /* ---------- Профиль ---------- */
    /* «Редактировать профиль» и «Выйти» стояли двумя полосами: правило
       на 768px разворачивало ряд в колонку. Это пара кнопок, они
       помещаются рядом. */
    .profile-actions { flex-direction: row; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
    /* Кегль ниже базового не для красоты: при 0.92rem «Редактировать»
       не помещалось в половину ширины и рвалось посреди слова —
       «Редактироват / ь профиль». */
    .profile-actions > .btn {
        flex: 1 1 calc(50% - 4px); min-width: 120px;
        font-size: 0.8rem; padding: 9px 8px;
    }

    /* Статистика в одну колонку растягивалась на семь сотен пикселей.
       В карточке две строки — число и подпись, в половине ширины они
       читаются без переносов. */
    .profile-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
    .stat-card { padding: 12px 10px; }
    .stat-value { font-size: 1.3rem; }
    .stat-label { font-size: 0.76rem; }

    .profile-section { padding: 16px; }
    .profile-banner { height: 120px; margin: -16px -16px 16px; }
    .profile-bio { margin-bottom: 14px; padding: 10px 12px; font-size: 0.92rem; }
}


/* ------------------------------------------------------------
   Ленты фильтров: повтор для классов, которые заводит pages.css

   Общее правило лежит в style.css, но .categories-nav, .subtabs и
   .tabs-nav объявлены здесь с flex-wrap: wrap, а pages.css подключается
   последним — при равной специфичности выигрывает он, и лента
   продолжала переноситься в три строки. Дублируем именно эти три
   селектора; остальные (.notif-tabs и прочие из style.css) работают
   оттуда и нужны на главной, где pages.css не подключён.
   ------------------------------------------------------------ */
@media (max-width: 820px) {
    .categories-nav,
    .subtabs,
    .tabs-nav {
        display: flex;
        flex-wrap: nowrap;
        justify-content: flex-start;
        overflow-x: auto;
        scroll-snap-type: x proximity;
        -webkit-overflow-scrolling: touch;

        gap: 6px;
    }
.categories-nav > *,
    .subtabs > *,
    .tabs-nav > *,
    /* .tabs-nav-extra сама невидима для layout (display: contents, см.
       блок «Турниры: кнопка «Создать турнир»» выше) — комбинатор >
       её пропускает, и без строки ниже «Создать турнир» на телефоне
       остался бы без flex: 0 0 auto/scroll-snap-align среди чипов. */
    .tabs-nav-extra > * { flex: 0 0 auto; scroll-snap-align: start; }
}


/* ------------------------------------------------------------
   Свёрнутые фильтры на телефоне

   На широком экране кнопки нет вовсе и панель выглядит как раньше:
   правило целиком живёт внутри медиазапроса, а сама кнопка на десктопе
   просто не показывается.
   ------------------------------------------------------------ */
.filters-toggle { display: none; }

@media (max-width: 820px) {
    .filters { padding: 10px 12px; margin-bottom: 14px; }

    .filters-toggle {
        display: flex; align-items: center; gap: 8px;
        width: 100%; padding: 8px 4px;
        background: none; border: none; cursor: pointer;
        font-family: var(--font-head); font-weight: 600; font-size: 0.95rem;
        color: var(--text);
    }
    /* Стрелка прижата вправо: так кнопка читается как «раскрыть», а не
       как ещё один пункт в ряду. */
    .filters-caret { margin-left: auto; font-size: 0.8rem; color: var(--text-muted); }

    .filters-count {
        background: var(--accent); color: var(--on-accent);
        border-radius: 999px; min-width: 20px; padding: 1px 6px;
        font-size: 0.75rem; line-height: 1.5; text-align: center;
    }

    .filters .filters-grid { display: none; }
    .filters.is-open .filters-grid {
        display: grid;
        /* Две колонки вместо четырёх строк: подписи короткие, селекты
           в 170px читаются целиком. */
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 10px;
        margin-top: 10px;
    }
    /* Кнопка сброса — во всю ширину под селектами. */
    .filters.is-open .filters-grid > .filter-group:last-child:nth-child(odd) { grid-column: 1 / -1; }
}


/* ------------------------------------------------------------
   Пин бойца вместо значка у титула Brawl Stars

   Пин — это цветная картинка, а не шрифтовая иконка, поэтому ей нужен
   свой размер: в строку с текстом она встаёт по высоте прописной буквы,
   иначе титул раздувается и ряд титулов теряет ровную линию.
   ------------------------------------------------------------ */
.special-title-pin {
    width: 30px; height: 30px;
    flex-shrink: 0;
    object-fit: contain;
    /* Пины нарисованы с полями; отрицательный отступ подтягивает рисунок
       к тексту и не даёт им раздуть высоту чипа — поля срезаются, сама
       картинка остаётся крупной. */
    margin: -8px -3px -8px -5px;
}

/* У закрытого титула пин приглушён: раздел листают, чтобы понять, что
   ещё можно выбить, и открытое от закрытого должно отличаться сразу. */
.special-title-pin.is-dim { opacity: 0.38; filter: grayscale(1); }

/* Титулы бойцов идут в своём разделе и не спорят цветом с наградами
   администрации: у них спокойная фиолетовая подложка. */
.special-title.is-brawler-title { --title-tint: var(--accent-2); }

/* Тот же пин в шапке профиля, где стоит выбранный титул. */
.rank-pin {
    width: 27px; height: 27px;
    flex-shrink: 0;
    object-fit: contain;
    vertical-align: -0.42em;
    margin: -6px -2px;
}
/* Вторая строка мельче основной — пин в ней тоже. */
.rank-pin.is-second { width: 21px; height: 21px; vertical-align: -0.32em; margin-right: 3px; }

@media (max-width: 560px) {
    .special-title-pin { width: 26px; height: 26px; margin: -7px -3px -7px -4px; }
    .rank-pin { width: 23px; height: 23px; }
    .rank-pin.is-second { width: 18px; height: 18px; }
}


/* Дата рождения в шапке профиля — строкой под юзернеймом, тем же
   спокойным тоном: это справка, а не заголовок. Отступ одинаковый
   сверху и снизу (было только margin-top, и строка проседала ближе к
   соседу снизу, чем к юзернейму сверху) и чуть меньше, чем раньше. */
.profile-birthday {
    display: inline-flex; align-items: center; gap: 6px;
    margin: 4px 0;
    color: var(--text-muted);
    font-size: 0.85rem;
}
.profile-birthday i { color: var(--accent-2); }

/* ============================================================
   Открытие ящика: объёмная сцена (js/box-open.js)

   Объём настоящий, браузерный: у сцены есть камера (perspective),
   слои разнесены по Z, крышка поворачивается вокруг своего нижнего
   края (rotateX), тень лежит отдельной плоскостью, положенной в
   горизонт. WebGL и 3D-модель для этого не нужны.

   Крышка и корпус — одна и та же картинка ящика, обрезанная по-разному
   через clip-path (доля шва приходит в --seam из js/box-open.js).
   Поэтому анимация не тянет за собой ни одного нового файла и любой
   новый цвет ящика заработает сам.
   ============================================================ */
.bo-scene {
    position: fixed;
    inset: 0;
    /* Выше модалок (2000), но ниже всплывающих сообщений (10000):
       тост «Открыт ящик» должен оставаться читаемым. */
    z-index: 9500;
    display: flex;
    align-items: center;
    justify-content: center;
    --seam: 0.415;
}
body.bo-locked { overflow: hidden; }

.bo-backdrop {
    position: absolute;
    inset: 0;
    background: radial-gradient(circle at 50% 45%,
                rgba(30, 24, 80, 0.72) 0%, rgba(4, 4, 20, 0.93) 70%);
    backdrop-filter: blur(6px);
    animation: bo-fade 0.28s ease both;
}
.bo-scene.is-leaving { animation: bo-fade 0.24s ease reverse both; }
@keyframes bo-fade { from { opacity: 0; } to { opacity: 1; } }

/* ---------- Камера ----------
   Одна perspective на всю сцену: и крышка, и пол, и карточки наград
   считаются в одном объёме, поэтому они выглядят снятыми одним
   объективом, а не склеенными из трёх разных. */
.bo-stage {
    position: relative;
    width: min(560px, 92vw);
    height: min(560px, 76vh);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    perspective: 900px;
    perspective-origin: 50% 42%;
    transform-style: preserve-3d;
}

/* ---------- Ящик ---------- */
/* Спокойное положение ящика задано ЗДЕСЬ, а не концом анимации падения.
   Свойство animation одно на элемент: когда включается встряска, правило
   с bo-shake целиком заменяет правило с bo-land, и вместе с ним пропадает
   его forwards-заливка. Раньше на этом ящик исчезал в момент первой
   встряски. Поэтому покой — в базовом правиле, а анимации только уводят
   из него и возвращают обратно. */
.bo-chest {
    position: relative;
    width: min(260px, 56vw);
    aspect-ratio: 1;
    transform-style: preserve-3d;
    opacity: 1;
    transform: none;
}
/* До первого кадра ящика ещё нет — он только летит сверху */
.bo-scene:not(.is-landing) .bo-chest { opacity: 0; }
.bo-part {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: contain;
    /* Обе половины — один и тот же файл; разница только в обрезке */
    filter: drop-shadow(0 12px 22px rgba(0, 0, 0, 0.55));
}
/* Верх картинки — крышка, низ — корпус. Полтора процента внахлёст,
   иначе в закрытом положении между ними просвечивала бы щель. */
.bo-lid  { clip-path: inset(0 0 calc((1 - var(--seam)) * 100%) 0); }
.bo-body { clip-path: inset(calc(var(--seam) * 100% - 1.5%) 0 0 0); }

/* Ось поворота крышки — её нижний край, как настоящая петля */
.bo-lid {
    transform-origin: 50% calc(var(--seam) * 100%);
    transform: rotateX(0deg);
}

/* Свет, растущий изнутри ящика по мере встряски */
.bo-glow {
    position: absolute;
    left: 50%;
    top: calc(var(--seam) * 100%);
    width: 62%;
    height: 30%;
    transform: translate(-50%, -40%) scale(0.2);
    border-radius: 50%;
    background: radial-gradient(circle, var(--bo-light) 0%, transparent 70%);
    opacity: 0;
    filter: blur(6px);
}
/* Тонкая полоса света ровно по шву — то, что видно раньше всего */
.bo-seam {
    position: absolute;
    left: 22%;
    right: 22%;
    top: calc(var(--seam) * 100%);
    height: 3px;
    border-radius: 3px;
    background: var(--bo-light);
    box-shadow: 0 0 14px 4px var(--bo-light);
    opacity: 0;
}

/* ---------- Пол ----------
   Отдельная плоскость, положенная в горизонт: тень не «нарисована под
   картинкой», а лежит на полу и живёт вместе с прыжком ящика. */
.bo-floor {
    position: absolute;
    left: 50%;
    top: 62%;
    width: min(260px, 56vw);
    height: min(260px, 56vw);
    transform: translate(-50%, -50%) rotateX(72deg);
    transform-style: preserve-3d;
    pointer-events: none;
}
.bo-shadow {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 74%;
    height: 74%;
    transform: translate(-50%, -50%) scale(0.2);
    border-radius: 50%;
    background: radial-gradient(circle, rgba(0, 0, 0, 0.65) 0%, transparent 70%);
    opacity: 0;
}

/* ---------- Лучи и столб света ---------- */
.bo-rays, .bo-beam {
    position: absolute;
    left: 50%;
    top: 44%;
    pointer-events: none;
    opacity: 0;
}
.bo-rays {
    width: 780px;
    height: 780px;
    transform: translate(-50%, -50%) rotate(0deg);
    background: repeating-conic-gradient(from 0deg,
                var(--bo-light) 0deg 5deg, transparent 5deg 18deg);
    -webkit-mask-image: radial-gradient(circle, #000 12%, transparent 62%);
            mask-image: radial-gradient(circle, #000 12%, transparent 62%);
    mix-blend-mode: screen;
}
/* Конус, а не колонна: узкий у ящика, широкий вверху, и с растворением
   к вершине. Прямоугольник с градиентом читался как серая полоса поперёк
   экрана, а не как свет, бьющий из ящика. */
.bo-beam {
    width: 300px;
    height: 420px;
    transform: translate(-50%, -78%) scaleY(0.1);
    background: linear-gradient(to top,
                var(--bo-light) 0%, rgba(255, 255, 255, 0.7) 30%, transparent 100%);
    clip-path: polygon(38% 100%, 62% 100%, 100% 0%, 0% 0%);
    -webkit-mask-image: linear-gradient(to top, #000 0%, rgba(0,0,0,0.35) 55%, transparent 100%);
            mask-image: linear-gradient(to top, #000 0%, rgba(0,0,0,0.35) 55%, transparent 100%);
    filter: blur(12px);
    opacity: 0;
    mix-blend-mode: screen;
}

/* ---------- Искры ---------- */
.bo-sparks {
    position: absolute;
    left: 50%;
    top: 44%;
    width: 0; height: 0;
    pointer-events: none;
}
.bo-spark {
    position: absolute;
    width: var(--s); height: var(--s);
    margin: calc(var(--s) / -2);
    border-radius: 50%;
    background: var(--bo-light);
    box-shadow: 0 0 10px 2px var(--bo-light);
    opacity: 0;
}

/* ============================================================
   Кадры сцены. Классы вешает js/box-open.js по таймеру.
   ============================================================ */

/* 1. Падение и приземление */
.bo-scene.is-landing .bo-chest { animation: bo-land 0.62s cubic-bezier(.5,1.6,.6,1) forwards; }
.bo-scene.is-landing .bo-shadow { animation: bo-shadow-in 0.62s cubic-bezier(.5,1.6,.6,1) forwards; }
@keyframes bo-land {
    0%   { opacity: 0; transform: translate3d(0, -260px, 0) scale(0.7) rotateX(18deg); }
    55%  { opacity: 1; transform: translate3d(0, 14px, 0) scale(1.06) rotateX(-6deg); }
    75%  { opacity: 1; transform: translate3d(0, -10px, 0) scale(0.98) rotateX(2deg); }
    100% { opacity: 1; transform: none; }
}
@keyframes bo-shadow-in {
    0%   { opacity: 0; transform: translate(-50%, -50%) scale(0.2); }
    55%  { opacity: 0.9; transform: translate(-50%, -50%) scale(1.1); }
    100% { opacity: 0.7; transform: translate(-50%, -50%) scale(1); }
}

/* 2. Три нарастающих встряски. Ящик по-настоящему разворачивается в
      объёме (rotateY/rotateZ), а не просто дёргается влево-вправо. */
.bo-scene.is-shaking .bo-chest { animation: bo-shake 1.04s ease-in-out forwards; }
.bo-scene.is-shaking .bo-seam  { animation: bo-seam-grow 1.04s ease-in forwards; }
.bo-scene.is-shaking .bo-glow  { animation: bo-glow-grow 1.04s ease-in forwards; }
@keyframes bo-shake {
    0%,  100% { transform: none; }
    8%   { transform: translate3d(-6px,-4px,10px) rotateZ(-3deg) rotateY(6deg) scale(1.02); }
    16%  { transform: translate3d(6px,0,0) rotateZ(3deg) rotateY(-6deg) scale(1.01); }
    24%  { transform: translate3d(0,0,0) rotateZ(0deg) rotateY(0deg) scale(1); }
    40%  { transform: translate3d(-9px,-8px,20px) rotateZ(-5deg) rotateY(10deg) scale(1.05); }
    50%  { transform: translate3d(9px,0,0) rotateZ(5deg) rotateY(-10deg) scale(1.03); }
    58%  { transform: translate3d(0,0,0) rotateZ(0deg) rotateY(0deg) scale(1); }
    76%  { transform: translate3d(-13px,-14px,40px) rotateZ(-8deg) rotateY(14deg) scale(1.1); }
    88%  { transform: translate3d(13px,-6px,20px) rotateZ(8deg) rotateY(-14deg) scale(1.07); }
}
@keyframes bo-seam-grow {
    0%   { opacity: 0; transform: scaleX(0.2); }
    40%  { opacity: 0.5; transform: scaleX(0.7); }
    100% { opacity: 1; transform: scaleX(1); }
}
@keyframes bo-glow-grow {
    0%   { opacity: 0; transform: translate(-50%, -40%) scale(0.2); }
    100% { opacity: 0.9; transform: translate(-50%, -45%) scale(1.15); }
}

/* 3. Вспышка: крышка откидывается на петле и улетает назад-вверх */
.bo-scene.is-open .bo-lid    { animation: bo-lid-open 0.95s cubic-bezier(.25,.85,.35,1) forwards; }
.bo-scene.is-open .bo-body   { animation: bo-body-settle 0.7s ease-out forwards; }
.bo-scene.is-open .bo-glow   { animation: bo-glow-burst 0.7s ease-out forwards; }
.bo-scene.is-open .bo-seam   { opacity: 0; }
.bo-scene.is-open .bo-beam   { animation: bo-beam-up 0.9s cubic-bezier(.2,.9,.3,1) forwards; }
.bo-scene.is-open .bo-rays   { animation: bo-rays-spin 6s linear forwards; }
.bo-scene.is-open .bo-spark  { animation: bo-spark-fly 0.9s ease-out var(--t) forwards; }
.bo-scene.is-open .bo-stage  { animation: bo-kick 0.34s ease-out; }

/* Крышку должно быть ВИДНО, как она откидывается: первые два кадра
   держат её в наклоне, где она ещё читается лицом к зрителю, и только
   потом она перекидывается через петлю и улетает назад-вверх. Раньше
   она за 250 мс уходила сразу за 90° — то есть вставала к камере ребром
   и просто пропадала, и «открытия» никто не видел. */
@keyframes bo-lid-open {
    0%   { transform: rotateX(0deg) translate3d(0,0,0); opacity: 1; }
    16%  { transform: rotateX(-32deg) translate3d(0,-8px,16px); opacity: 1; }
    42%  { transform: rotateX(-74deg) translate3d(0,-22px,34px); opacity: 1; }
    64%  { transform: rotateX(-128deg) translate3d(0,-70px,10px) scale(0.94); opacity: 0.9; }
    100% { transform: rotateX(-205deg) translate3d(0,-210px,-140px) scale(0.68); opacity: 0; }
}
@keyframes bo-body-settle {
    0%   { transform: translate3d(0,0,0) scale(1); }
    30%  { transform: translate3d(0,10px,0) scale(1.06, 0.94); }
    100% { transform: translate3d(0,0,0) scale(1); }
}
@keyframes bo-glow-burst {
    0%   { opacity: 0.9; transform: translate(-50%, -45%) scale(1.15); }
    25%  { opacity: 1; transform: translate(-50%, -55%) scale(2.6); }
    100% { opacity: 0.75; transform: translate(-50%, -50%) scale(1.6); }
}
@keyframes bo-beam-up {
    0%   { opacity: 0; transform: translate(-50%, -78%) scaleY(0.1); }
    22%  { opacity: 0.9; transform: translate(-50%, -78%) scaleY(1.15); }
    100% { opacity: 0.45; transform: translate(-50%, -78%) scaleY(1); }
}
@keyframes bo-rays-spin {
    0%   { opacity: 0; transform: translate(-50%, -50%) rotate(0deg) scale(0.4); }
    12%  { opacity: 0.5; transform: translate(-50%, -50%) rotate(40deg) scale(1); }
    100% { opacity: 0.28; transform: translate(-50%, -50%) rotate(360deg) scale(1); }
}
@keyframes bo-spark-fly {
    0%   { opacity: 1; transform: rotate(var(--a)) translateX(0) scale(1); }
    100% { opacity: 0; transform: rotate(var(--a)) translateX(var(--d)) scale(0.2); }
}
/* Короткий толчок камеры — тот самый «удар» в момент открытия */
@keyframes bo-kick {
    0%, 100% { transform: translate3d(0,0,0); }
    25%      { transform: translate3d(0,7px,0) scale(1.012); }
    60%      { transform: translate3d(0,-4px,0) scale(0.996); }
}

/* 4. Награды вылетают по одной и встают в ряд */
.bo-rewards {
    position: absolute;
    left: 50%;
    bottom: 4%;
    transform: translateX(-50%);
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
    list-style: none;
    margin: 0;
    padding: 0;
    width: 100%;
}
.bo-reward {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 14px 9px 10px;
    border-radius: var(--radius-md);
    background: rgba(10, 10, 30, 0.72);
    border: 1px solid var(--bo-light);
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.5), 0 0 18px -6px var(--bo-light);
    backdrop-filter: blur(3px);
    opacity: 0;
    /* Старт — из середины ящика, лицом от зрителя: карточка вылетает и
       разворачивается к камере, а не просто проявляется. */
    transform: translate3d(0, -190px, -180px) rotateY(90deg) scale(0.5);
}
.bo-scene.is-giving .bo-reward {
    animation: bo-reward-fly 0.62s cubic-bezier(.2,.9,.3,1.2) calc(var(--i) * 0.16s) forwards;
}
@keyframes bo-reward-fly {
    0%   { opacity: 0; transform: translate3d(0, -190px, -180px) rotateY(90deg) scale(0.5); }
    60%  { opacity: 1; transform: translate3d(0, 14px, 60px) rotateY(-12deg) scale(1.08); }
    100% { opacity: 1; transform: translate3d(0, 0, 0) rotateY(0deg) scale(1); }
}
.bo-reward-icon {
    width: 34px; height: 34px;
    flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: var(--bo-light);
    color: #0b0b22;
    font-size: 0.95rem;
}
.bo-reward-text { display: flex; flex-direction: column; min-width: 0; }
.bo-reward-kind {
    color: rgba(255, 255, 255, 0.7);
    font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.05em;
}
.bo-reward-name {
    color: #fff; font-weight: 700; font-size: 0.95rem;
    font-family: var(--font-head);
}

.bo-take {
    position: absolute;
    left: 50%;
    bottom: -46px;
    transform: translateX(-50%);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--transition);
}
.bo-scene.is-done .bo-take { opacity: 1; pointer-events: auto; }

/* Настройка «меньше движения»: показываем результат без полёта */
.bo-scene.is-instant .bo-chest { opacity: 1; transform: none; animation: none; }
.bo-scene.is-instant .bo-lid { opacity: 0; animation: none; }
.bo-scene.is-instant .bo-glow { opacity: 0.8; animation: none; }
.bo-scene.is-instant .bo-shadow { opacity: 0.7; transform: translate(-50%, -50%) scale(1); animation: none; }
.bo-scene.is-instant .bo-reward { opacity: 1; transform: none; animation: none; }
.bo-scene.is-instant .bo-rays,
.bo-scene.is-instant .bo-beam { opacity: 0.3; animation: none; }

/* Цвет свечения — по редкости ящика, ровно как у самой картинки */
.bo-green  { --bo-light: #4ade80; }
.bo-blue   { --bo-light: #38bdf8; }
.bo-purple { --bo-light: #c084fc; }
.bo-red    { --bo-light: #fb7185; }
.bo-gold   { --bo-light: #fbbf24; }
/* Осенний бокс (Dantes Pass) — тот же движок, свой цвет свечения под
   бронзово-золотую расцветку сундука. */
.bo-autumn { --bo-light: #f59e0b; }

@media (max-width: 620px) {
    .bo-stage { height: min(520px, 82vh); }
    .bo-rays { width: 560px; height: 560px; }
    .bo-reward { padding: 7px 11px 7px 8px; }
    .bo-reward-name { font-size: 0.86rem; }
    .bo-reward-icon { width: 28px; height: 28px; font-size: 0.82rem; }
}


/* ============================================================
   Чат на телефоне
   ============================================================ */
@media (max-width: 560px) {
    /* 78% от 360px — это 280px, и за вычетом аватара с отступами на сам
       бабл остаётся 230. Плееру голосового столько мало, он вылезал за
       край. Даём баблу больше ширины и убираем аватар у СВОИХ сообщений:
       они и так справа, лицо отправителя там ничего не сообщает. */
    .message { max-width: 88%; gap: 8px; }
    .message.sent .message-avatar { display: none; }

    /* Плеер голосового ужимается: волна может быть короткой, лишь бы
       кнопка, время и скорость остались на месте. */
    .voice-row { gap: 6px; }
    .voice-waveform { min-width: 40px; }
    .voice-time { min-width: 30px; font-size: 0.72rem; }
    .voice-play { width: 32px; height: 32px; font-size: 0.78rem; }

    /* Реакции переносятся на свою строку, а не выпирают из бабла */
    .message-reactions { flex-wrap: wrap; }
}

/* Ряд кнопок сбоку от сообщения (ответить, реакция, закрепить, править,
   перевести) на телефоне не нужен и вреден: наведения там нет, кнопки
   стоят в потоке всегда и съедали до 156px из 275 — баблу оставалось
   меньше половины, и текст рвался по два слова в строку.

   Кнопки не удаляем, а только убираем из раскладки: лист долгого
   нажатия (js/chat-hold.js) нажимает именно их, поэтому поведение
   действий остаётся единым для телефона и компьютера. */
@media (max-width: 768px), (hover: none) {
    .message-tools { display: none; }
    .message { max-width: 84%; }
}

/* ============================================================
   Долгое нажатие на сообщение (js/chat-hold.js)

   Тот же жест, что в Telegram: палец лежит на сообщении — фон гаснет,
   сообщение остаётся на своём месте поверх завесы, сверху ряд быстрых
   реакций, снизу список действий.
   ============================================================ */
.hold-sheet { position: fixed; inset: 0; z-index: 8000; }
.hold-veil {
    position: absolute; inset: 0;
    background: rgba(6, 6, 24, 0.62);
    backdrop-filter: blur(3px);
    animation: hold-fade 0.18s ease both;
}
.hold-sheet.is-leaving .hold-veil { animation: hold-fade 0.16s ease reverse both; }
@keyframes hold-fade { from { opacity: 0; } to { opacity: 1; } }

/* Сообщение поднимается над завесой, не сдвигаясь с места — именно
   поэтому жест не сбивает с толку: видно, что открыли, и что именно. */
.message.is-held { position: relative; z-index: 8001; }
.message.is-holding .message-content { transform: scale(0.97); transition: transform 0.18s ease; }
.message.is-held .message-content {
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
}

.hold-body {
    position: absolute;
    left: 50%;
    width: min(300px, calc(100vw - 32px));
    transform: translateX(-50%) scale(0.94);
    opacity: 0;
    transition: opacity 0.16s ease, transform 0.16s cubic-bezier(.2,.9,.3,1.2);
    display: flex; flex-direction: column; gap: 8px;
}
.hold-body.is-in { opacity: 1; transform: translateX(-50%) scale(1); }

.hold-reactions {
    display: flex; align-items: center; justify-content: center; gap: 2px;
    padding: 6px 8px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 999px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
    overflow-x: auto;

}
.hold-reaction {
    flex: 0 0 auto;
    width: 38px; height: 38px;
    border: none; border-radius: 50%;
    background: transparent;
    font-size: 1.25rem; line-height: 1;
    cursor: pointer;
    transition: transform var(--transition), background var(--transition);
}
.hold-reaction:hover, .hold-reaction:active { transform: scale(1.18); background: var(--surface-3); }
.hold-reaction-more { font-size: 0.85rem; color: var(--text-dim); }

.hold-actions {
    list-style: none; margin: 0; padding: 6px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 12px 34px rgba(0, 0, 0, 0.5);
}
.hold-action {
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    width: 100%;
    padding: 11px 12px;
    border: none; border-radius: 8px;
    background: transparent;
    color: var(--text);
    font-family: var(--font-body); font-size: 0.95rem;
    text-align: left;
    cursor: pointer;
}
.hold-action i { color: var(--text-dim); font-size: 0.95rem; }
.hold-action:hover, .hold-action:active { background: var(--surface-3); }
.hold-action.is-danger { color: var(--danger); }
.hold-action.is-danger i { color: var(--danger); }

body.hold-open { overflow: hidden; }

/* ---------- Свайп вправо = ответить ---------- */
.message.is-swiping { transition: none; }
.message.is-swiping::before {
    content: '\f3e5';                    /* fa-reply */
    font-family: 'Font Awesome 6 Free'; font-weight: 900;
    position: absolute; left: -34px; top: 50%;
    transform: translateY(-50%);
    color: var(--text-dim); font-size: 0.95rem;
    transition: color var(--transition);
}
.message.is-swipe-ready::before { color: var(--accent-2); }

/* ---------- Цитата ответа внутри бабла ---------- */
.message-reply {
    display: flex; flex-direction: column; gap: 1px;
    width: 100%;
    margin-bottom: 6px;
    padding: 5px 9px;
    border: none;
    border-left: 3px solid var(--accent-2);
    border-radius: 5px;
    background: color-mix(in srgb, var(--accent) 14%, transparent);
    color: inherit;
    text-align: left;
    font: inherit;
    cursor: pointer;
    min-width: 0;
}
.message-reply:hover { background: color-mix(in srgb, var(--accent) 24%, transparent); }
.message-reply-who { font-weight: 700; font-size: 0.8rem; color: var(--accent-2); }
.message-reply-text {
    font-size: 0.82rem; color: var(--text-dim);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.message.sent .message-reply { border-left-color: color-mix(in srgb, var(--on-accent) 75%, transparent); }
.message.sent .message-reply-who { color: var(--on-accent); }
.message.sent .message-reply-text { color: color-mix(in srgb, var(--on-accent) 85%, transparent); }

/* Подсветка сообщения, к которому перешли по цитате */
.message.is-flashed .message-content {
    animation: msg-flash 1.6s ease;
}
@keyframes msg-flash {
    0%, 100% { box-shadow: 0 0 0 0 transparent; }
    15%      { box-shadow: 0 0 0 3px var(--accent-2); }
    60%      { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent-2) 40%, transparent); }
}

/* ---------- Строка «отвечаю на…» над полем ввода ---------- */
.reply-notice {
    display: flex; align-items: center; gap: 10px;
    flex: 1 1 100%;
    padding: 7px 10px;
    margin-bottom: 8px;
    border-left: 3px solid var(--accent-2);
    border-radius: 6px;
    background: var(--surface-soft);
    min-width: 0;
}
.reply-notice > i { color: var(--accent-2); flex-shrink: 0; }
.reply-notice-body { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.reply-notice-who { font-weight: 700; font-size: 0.82rem; color: var(--accent-2); }
.reply-notice-text {
    font-size: 0.84rem; color: var(--text-dim);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------- Кнопка «вниз» со счётчиком пропущенного ---------- */
.chat-jump {
    position: absolute;
    right: 16px; bottom: 92px;
    width: 44px; height: 44px;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--surface-3);
    color: var(--text-muted);
    display: flex; align-items: center; justify-content: center;
    cursor: pointer;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
    z-index: 5;
}
.chat-jump:hover { color: var(--text); border-color: var(--accent); }
.chat-jump-count {
    position: absolute; top: -5px; right: -5px;
    min-width: 20px; height: 20px; padding: 0 5px;
    border-radius: 999px;
    background: var(--accent);
    color: var(--on-accent); font-size: 0.7rem; font-weight: 700;
    display: flex; align-items: center; justify-content: center;
}
.chat-window { position: relative; }

/* Стрелка «назад» нужна только там, где список чатов уехал с экрана */
.chat-back { display: none; flex-shrink: 0; }

/* ============================================================
   Чат на телефоне: два экрана вместо двух колонок

   На планшете и десктопе список чатов и переписка стоят рядом, как и
   раньше (пробовали прятать список на планшете тем же переключателем,
   что и на телефоне — попросили вернуть как было, обе колонки видны
   одновременно; см. слитную рамку между ними чуть выше — .chat-list,
   .chat-window, .chat-info-panel — это и есть замена тесноте). На
   телефоне так не выходит: список и переписка по очереди, как в
   Telegram — сначала список во весь экран, выбрал собеседника,
   открылась переписка со стрелкой «назад». Признак того, что открыто,
   ставит js/chat.js в data-chat-view на <body> (там же и setMode() —
   переключатель «Личные»/«Комнаты» проверяет ту же границу 768px
   через matchMedia, чтобы при смене вкладки на телефоне показывался
   список новой вкладки, а не чей-то открытый диалог). */
@media (max-width: 768px) {
    .chat-container {
        grid-template-columns: 1fr;
        /* Во весь оставшийся экран: шапка сайта 84px, отступы 34 + 10.

           100svh, не 100dvh: dvh следит за адресной строкой телефона в
           реальном времени — как только она прячется при скролле внутри
           списка, dvh тут же подрастает, а вместе с ним и вся плашка,
           хотя пользователь просто листал список сообщений внутри неё.
           Именно это и было «растягивается при скролле». svh — высота
           экрана с ВИДИМОЙ адресной строкой (меньшее из двух значений) и
           не меняется при скролле вовсе — плашка держит один и тот же
           размер, а список внутри неё (chat-items, overflow-y: auto)
           прокручивается сам, никак не влияя на размер снаружи. */
        height: calc(100svh - var(--site-header-h, 84px) - 34px - 10px);
        min-height: 0;
    }
    .chat-list { max-height: none; height: 100%; }

    /* Виден ровно один экран из двух */
    body[data-chat-view="dialog"] .chat-list { display: none; }
    body:not([data-chat-view="dialog"]) .chat-window { display: none; }

    /* Выше, в общей рамке для планшета/десктопа, у списка и переписки
       скруглены и обведены только «внешние» стороны — расчёт на то, что
       сосед стоит вплотную и делить с ним общую грань. На телефоне
       соседа не видно совсем (виден один экран из двух), так что каждая
       сторона — внешняя: возвращаем полное скругление и правую грань
       списку (её убирали только ради слитного шва с перепиской). */
    .chat-list, .chat-window {
        border-radius: var(--radius-lg);
        border-right: 1px solid var(--border);
    }

    .chat-window { height: 100%; }
    .chat-back { display: inline-flex; }

    /* Кнопка «вниз» ниже: композитор на телефоне ниже и уже */
    .chat-jump { bottom: 78px; right: 12px; width: 40px; height: 40px; }

    /* Безопасная зона снизу на iPhone: без этого поле ввода прячется
       под системной полоской-«домиком». */
    .chat-input-container { padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px)); gap: 5px; }

    /* Четыре кнопки вложений + отправка съедали столько, что на само поле
       оставалась полоска в 128px и подпись «Введите сообщение» не влезала.
       Кнопки ужимаем, а полю даём право уйти на свою строку целиком:
       контейнер и так с переносом, и полноширинное поле под рядом кнопок
       читается лучше, чем щель между ними. */
    /* Всё в одну строку, как в мессенджерах: кнопки вложений, поле,
       отправка. Без nowrap кнопка отправки срывалась на вторую строку
       и висела там одна. */
    .chat-input-container { flex-wrap: nowrap; }
    .composer-tools { gap: 3px; }
    .composer-tools .btn-icon { width: 32px; height: 32px; font-size: 0.88rem; }
    .message-input { flex: 1 1 0; min-width: 0; min-height: 38px; padding: 9px 12px; }
    .send-btn { width: 36px; height: 36px; flex-shrink: 0; }
    /* Короткая подпись: полная «Введите сообщение…» в оставшуюся щель
       не помещается и обрывается на полуслове. */
    .message-input:empty::before { content: 'Сообщение…'; }

    /* Строка «отвечаю на…» и панель правки идут отдельной строкой над
       всем рядом — им nowrap не мешает. */
    .reply-notice, .edit-notice { flex: 1 0 100%; }
}

/* ============================================================
   Галочки, «печатает…» и подгрузка истории (v181)
   ============================================================ */

/* Одна галочка — доставлено, две — прочитано. Только в личной переписке:
   в комнате «прочитано» означало бы «всеми», а это другой вопрос. */
.message-ticks { color: color-mix(in srgb, var(--on-accent) 60%, transparent); font-size: 0.7rem; margin-left: 2px; }
.message-ticks.is-read { color: #7dd3fc; }
.message.received .message-ticks { display: none; }

/* Строка «печатает…» живёт над полем ввода и не двигает ленту:
   она вне потока, чтобы появление надписи не сдвигало сообщения. */
.chat-typing {
    position: absolute;
    left: 16px; bottom: 74px;
    display: flex; align-items: center; gap: 7px;
    margin: 0;
    padding: 4px 10px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--surface) 88%, transparent);
    border: 1px solid var(--border);
    color: var(--text-dim); font-size: 0.8rem;
    pointer-events: none;
    z-index: 4;
}
.typing-dots { display: inline-flex; gap: 3px; }
.typing-dots i {
    width: 4px; height: 4px; border-radius: 50%;
    background: var(--accent-2);
    animation: typing-bounce 1.1s infinite ease-in-out;
}
.typing-dots i:nth-child(2) { animation-delay: 0.15s; }
.typing-dots i:nth-child(3) { animation-delay: 0.3s; }
@keyframes typing-bounce {
    0%, 60%, 100% { transform: translateY(0); opacity: 0.45; }
    30%           { transform: translateY(-4px); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .typing-dots i { animation: none; opacity: 0.8; }
}

/* Полоска «грузим, что было раньше» у верхнего края ленты */
.chat-messages.is-loading-older { background-image: linear-gradient(var(--accent-soft), transparent 34px); }

/* Обратный отсчёт до чек-ина (js/tournaments.js, countdownTick) */
.checkin-left { font-variant-numeric: tabular-nums; color: var(--text-muted); }
.checkin-left.is-urgent { color: var(--danger); }
.checkin-left.is-over { color: var(--text-dim); }

/* Кнопки «Поделиться» и «В календарь» в шапке турнира */
.tournament-share {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 5px 11px;
    border: 1px solid rgba(255, 255, 255, 0.28);
    border-radius: 999px;
    background: rgba(10, 10, 30, 0.5);
    color: inherit;
    font: inherit; font-size: 0.84rem;
    cursor: pointer;
    transition: border-color var(--transition), background var(--transition);
}
.tournament-share:hover { border-color: #fff; background: rgba(10, 10, 30, 0.75); }

/* ============================================================
   Счёт матча от игроков (js/tournaments.js, renderMatchResult)
   ============================================================ */
.match-report {
    margin: 14px 0;
    padding: 13px 15px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    background: var(--surface-3);
    font-size: 0.92rem;
}
.match-report p { margin: 0 0 8px; }
.match-report p:last-child { margin-bottom: 0; }
.match-report.is-done { border-color: var(--success); color: var(--text); }
.match-report.is-done i { color: var(--success); }
.match-report.is-waiting i { color: var(--gold); }
.match-report.is-disputed { border-color: var(--danger); }
.match-report.is-disputed > p i { color: var(--danger); }

.match-report-claims { margin: 0 0 10px; padding-left: 18px; color: var(--text-muted); }
.match-report-claims li { margin-bottom: 4px; }

.match-report-form { display: flex; flex-direction: column; gap: 12px; }
.match-report-scores {
    display: flex; align-items: flex-end; justify-content: center; gap: 12px;
    flex-wrap: wrap;
}
.match-report-scores label {
    display: flex; flex-direction: column; gap: 5px;
    flex: 1 1 120px; min-width: 0;
    color: var(--text-muted); font-size: 0.84rem;
    text-align: center;
}
.match-report-scores input {
    text-align: center; font-family: var(--font-head); font-weight: 700; font-size: 1.3rem;
    font-variant-numeric: tabular-nums;
}
.match-report-colon {
    font-family: var(--font-head); font-weight: 700; font-size: 1.4rem;
    color: var(--text-dim); padding-bottom: 10px;
}
.match-report-proof {
    display: flex; flex-direction: column; gap: 8px; align-items: flex-start;
    color: var(--text-muted); font-size: 0.84rem;
}
.match-report-proof-preview {
    position: relative; display: inline-block;
    border: 1px solid var(--border); border-radius: var(--radius-md, 12px); overflow: hidden;
}
.match-report-proof-preview img { display: block; max-width: 100%; max-height: 160px; }
.match-report-proof-preview .btn-icon {
    position: absolute; top: 6px; right: 6px;
    background: rgba(0, 0, 0, .65); color: #fff; border-radius: 50%;
}

/* «Ваш матч» в сетке: рамка и бейдж на всей паре. Пока матч не сыгран —
   мягкая пульсация, чтобы глаз находил его первым при любом масштабе. */
.bracket-match.is-my-match {
    border-radius: 26px;
    outline: 2px solid var(--accent);
    outline-offset: 5px;
    background: color-mix(in srgb, var(--accent) 8%, transparent);
}
.bracket-match.is-my-live { animation: myMatchPulse 2.2s ease-in-out infinite; }
@keyframes myMatchPulse {
    0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 45%, transparent); }
    50% { box-shadow: 0 0 22px 4px color-mix(in srgb, var(--accent) 55%, transparent); }
}
.bracket-my-tag {
    position: absolute; top: -17px; left: 14px; z-index: 2;
    display: inline-flex; align-items: center; gap: 5px;
    padding: 2px 10px; border-radius: 999px;
    background: var(--accent); color: var(--on-accent, #fff);
    font-size: .72rem; font-weight: 800; letter-spacing: .02em;
}
@media (prefers-reduced-motion: reduce) { .bracket-match.is-my-live { animation: none; } }

/* ============================================================
   Задания дня и приглашение друга (js/quests.js)
   ============================================================ */
.quests-box, .referral-box {
    background: var(--surface-3);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 18px 20px;
    margin-bottom: 22px;
}
.quests-head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 12px; flex-wrap: wrap; margin-bottom: 14px;
}
.quests-head h4 { color: var(--text); font-size: 1.05rem; }
.quests-note { color: var(--text-dim); font-size: 0.85rem; }

.quests-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
    gap: 12px;
}
.quest-card {
    display: flex; align-items: center; gap: 14px;
    padding: 12px 14px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    background: var(--surface-2);
    min-width: 0;
}
.quest-card.is-ready { border-color: var(--success); }
.quest-card.is-claimed { opacity: 0.6; }
.quest-body { flex: 1; min-width: 0; }
.quest-body h5 {
    color: var(--text); font-size: 0.92rem; margin: 0 0 7px;
    overflow-wrap: anywhere;
}
.quest-bar {
    height: 6px; border-radius: 999px;
    background: var(--surface-soft); overflow: hidden;
}
.quest-bar span {
    display: block; height: 100%;
    background: linear-gradient(90deg, var(--accent) 0%, var(--accent-2) 100%);
    transition: width var(--transition);
}
.quest-card.is-ready .quest-bar span { background: var(--success); }
.quest-progress { color: var(--text-dim); font-size: 0.78rem; margin: 5px 0 0; }

.quest-reward {
    display: flex; flex-direction: column; align-items: flex-end; gap: 6px;
    flex-shrink: 0;
}
.quest-coins {
    font-family: var(--font-head); font-weight: 700;
    color: var(--gold); font-size: 1rem;
    font-variant-numeric: tabular-nums;
}
.quest-done { color: var(--success); font-size: 0.76rem; }
.quest-wait { color: var(--text-dim); font-size: 0.76rem; }

.referral-box h4 { color: var(--text); font-size: 1.05rem; margin-bottom: 6px; }
.referral-row {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin: 12px 0 10px;
}
.referral-code {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 1.15rem; font-weight: 700; letter-spacing: 0.12em;
    color: var(--accent-2);
    background: var(--surface-soft);
    border: 1px dashed var(--accent);
    border-radius: var(--radius-sm);
    padding: 7px 14px;
}
.referral-stats { color: var(--text-muted); font-size: 0.87rem; margin: 0; }
.referral-stats b { color: var(--text); }

.referral-tiers {
    list-style: none; margin: 0 0 12px; padding: 0;
    display: flex; flex-wrap: wrap; gap: 6px;
}
.referral-tier-row {
    display: flex; align-items: center; gap: 6px;
    background: var(--surface-soft); border: 1px solid var(--border);
    border-radius: var(--radius-sm); padding: 5px 10px;
    font-size: 0.78rem; color: var(--text-muted);
}
.referral-tier-row.is-current {
    border-color: var(--accent); color: var(--text);
    background: var(--surface-highlight, var(--surface-soft));
    box-shadow: 0 0 0 1px var(--accent) inset;
}
.referral-tier-level { font-weight: 700; color: var(--text); }
.referral-tier-range { color: var(--text-dim); }
.referral-tier-coins { color: var(--gold, #ffd93d); font-weight: 600; }
.referral-tier-coins i { font-size: 0.85em; }

/* ---------- Переслать сообщение ---------- */
.forward-list {
    display: flex; flex-direction: column; gap: 6px;
    max-height: 50vh; overflow-y: auto;
}
.forward-item {
    display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
    width: 100%;
    padding: 10px 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    color: var(--text);
    text-align: left;
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition);
}
.forward-item:hover, .forward-item:active { background: var(--surface-3); border-color: var(--accent); }
.forward-item-title { font-weight: 600; font-size: 0.95rem; }
.forward-item-sub { color: var(--text-dim); font-size: 0.78rem; }

/* ---------- Наказания на своём аккаунте ---------- */
.sanction-banner {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 12px 14px;
    margin: 0 0 14px;
    background: rgba(255, 71, 87, 0.1);
    border: 1px solid var(--danger);
    border-radius: var(--radius-md);
    color: var(--text);
}
.sanction-banner i { color: var(--danger); margin-top: 2px; flex-shrink: 0; }
.sanction-banner strong { display: block; margin-bottom: 2px; }
.sanction-banner p { margin: 0; color: var(--text-muted); font-size: 0.87rem; }
.sanction-mount:not(:empty) { margin: 0 0 10px; }
#userReportBtn { color: var(--text-dim); }
#userReportBtn:hover { color: var(--danger); }

/* ---------- Низ вкладки «Настройки» ----------
   «Выйти» и «Сохранить изменения» стоят в одной строке, но по разным
   краям: сохранение — в правом нижнем углу, где его ищут по привычке,
   выход — далеко слева, чтобы его не задевали мимоходом. На узком
   экране строка переворачивается, и сохранение оказывается сверху:
   на телефоне до нижней кнопки тянуться дальше всего, а нажимают чаще
   именно её. */
.settings-actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-top: 26px;
    padding-top: 18px;
    border-top: 1px solid var(--border);
}
.settings-actions #saveSettingsBtn { margin-left: auto; }

@media (max-width: 560px) {
    .settings-actions { flex-direction: column-reverse; align-items: stretch; }
    .settings-actions .btn { width: 100%; justify-content: center; }
    .settings-actions #saveSettingsBtn { margin-left: 0; }
}

/* ---------- Удаление аккаунта ----------
   Нарочно вынесена подальше от формы и её кнопок: рамка того же цвета,
   что и сама кнопка, — единственное необратимое действие на странице
   не должно теряться среди обычных настроек. Фон — var(--surface-3),
   тот же непрозрачный цвет, что у остальных плашек страницы (карточки
   друзей, «Добавить по юзернейму» и т. д., см. .friend-card/.add-friend
   выше) — раньше был полупрозрачным в цвет опасности и на фоне своей
   картинки профиля (.profile-canvas.has-custom-bg) просвечивал ею
   неровным пятном, выделяясь не так, как остальные плашки. */
.danger-zone {
    margin-top: 26px;
    padding: 18px 20px;
    background: var(--surface-3);
    border: 1px solid color-mix(in srgb, var(--danger) 55%, transparent);
    border-radius: var(--radius-md);}
.danger-zone h4 {
    display: flex; align-items: center; gap: 8px;
    margin: 0 0 8px;
    color: var(--danger);
    font-size: 1.05rem;
}
.danger-zone .form-hint { color: var(--text-muted); margin-bottom: 14px; }

/* ---------- Статус привязки Telegram в настройках ----------
   Раньше была просто строка текста без оформления — терялась рядом
   с остальными полями формы. Теперь плашка в цветах Telegram, той же
   тяжести, что и другие статусные плашки на странице (например
   .danger-zone) — сразу видно, что это готовое состояние, а не поле
   для заполнения. */
#telegramLinkStatus {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    border-radius: 999px;
    background: color-mix(in srgb, #29a9eb 14%, transparent);
    border: 1px solid color-mix(in srgb, #29a9eb 40%, transparent);
    color: var(--success, #2ecc71);
    font-weight: 600;
}
#telegramLinkStatus i { color: #29a9eb; font-size: 1.05rem; }

/* ---------- Кнопка «Добавить/изменить почту» ----------
   Поле #settingsEmail всегда disabled (это просто витрина текущего
   значения) — сама кнопка стоит сразу под ним, перед подсказкой. */
#changeEmailBtn { margin-top: 8px; }

/* ============================================================
   Трансляции: режимы чата, опросы, теги
   (js/watch.js + supabase/stream_twitch_features.sql)
   ============================================================ */

/* ---------- Теги ---------- */
.watch-tag-row {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 8px 0 4px;
}
.stream-tag {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--surface-soft);
    border: 1px solid var(--border);
    color: var(--text-muted);
    font-size: 0.78rem;
    text-decoration: none;
    transition: color var(--transition), border-color var(--transition);
}
.stream-tag:hover { color: var(--accent-2); border-color: var(--accent); }
.stream-tag.is-edit { background: transparent; cursor: pointer; font-family: var(--font-body); }

/* ---------- Режимы чата ---------- */
.watch-chat-modes {
    display: flex;
    align-items: flex-end;
    gap: 10px;
    flex-wrap: wrap;
    padding: 10px 12px;
    border-bottom: 1px solid var(--border);
}
.watch-mode-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 0.76rem;
    color: var(--text-dim);
}
.watch-mode-field .form-input { padding: 5px 8px; font-size: 0.84rem; }

/* ---------- Закреплённое сообщение ---------- */
.watch-pinned {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 9px 12px;
    background: color-mix(in srgb, var(--accent) 12%, transparent);
    border-bottom: 1px solid var(--border);
    font-size: 0.85rem;
}
.watch-pinned > i { color: var(--accent-2); margin-top: 3px; }
.watch-pinned-body { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.watch-pinned-body b { color: var(--accent-2); margin-right: 5px; }

/* ---------- Опрос ---------- */
.stream-poll {
    margin-top: 14px;
    padding: 16px 18px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
.stream-poll.is-closed { opacity: 0.85; }
.stream-poll-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 12px;
}
.stream-poll-head h4 { margin: 0; font-size: 1rem; display: flex; align-items: center; gap: 8px; }
.stream-poll-head i { color: var(--accent-2); }
.stream-poll-meta { color: var(--text-dim); font-size: 0.78rem; }

.stream-poll-options { list-style: none; display: flex; flex-direction: column; gap: 8px; margin: 0 0 12px; padding: 0; }
.stream-poll-vote { width: 100%; justify-content: center; }

/* Результат — полоса заполнения под текстом, а не отдельная диаграмма:
   так проценты читаются, не отрывая взгляд от самого варианта. */
.stream-poll-result {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 9px 12px;
    border-radius: var(--radius-sm);
    background: var(--surface-3);
    border: 1px solid var(--border);
    overflow: hidden;
}
.stream-poll-result.is-mine { border-color: var(--accent); }
.stream-poll-fill {
    position: absolute;
    inset: 0 auto 0 0;
    background: color-mix(in srgb, var(--accent) 30%, transparent);
    transition: width 0.4s ease;
}
.stream-poll-label, .stream-poll-value { position: relative; z-index: 1; }
.stream-poll-value { font-weight: 700; font-variant-numeric: tabular-nums; }

/* ---------- Таймаут ---------- */
.timeout-options { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }

/* ---------- Прошлые эфиры ---------- */
.past-streams { margin-top: 18px; }
.past-streams h3 { font-size: 1rem; display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.past-streams h3 i { color: var(--text-dim); }
.past-stream-list { list-style: none; display: grid; gap: 8px; margin: 0; padding: 0; }
.past-stream-list a {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 14px;
    border-radius: var(--radius-sm);
    background: var(--surface-2);
    border: 1px solid var(--border);
    text-decoration: none;
    color: var(--text);
    transition: border-color var(--transition);
}
.past-stream-list a:hover { border-color: var(--accent); }
.past-stream-title { font-weight: 600; font-size: 0.92rem; }
.past-stream-meta { color: var(--text-dim); font-size: 0.78rem; }

/* Панель тегов над каталогом трансляций */
.streams-tag-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 16px;
}
.streams-tag-bar .stream-tag { cursor: pointer; font-family: var(--font-body); }
.streams-tag-bar .stream-tag.is-active {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}
.stream-tag-count { color: var(--text-dim); font-size: 0.72rem; }
.streams-tag-bar .stream-tag.is-active .stream-tag-count { color: rgba(255, 255, 255, 0.75); }

/* ---------- Настройки трансляции ---------- */
.watch-settings-btn {
    margin-left: auto;
    color: var(--text-dim);
}
.watch-settings-btn:hover { color: var(--accent-2); }

.stream-settings { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.stream-settings li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
    padding: 12px 14px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}
.stream-settings b { display: block; margin-bottom: 2px; }
.stream-settings .form-hint { margin: 0; }

/* Кнопка без подписи — квадратная, чтобы значок стоял по центру, а не
   болтался в кнопке, растянутой под несуществующий текст. */
.btn.is-icon-only {
    padding-left: 12px;
    padding-right: 12px;
}
.btn.is-icon-only i { margin: 0; }

/* ============================================================
   Уведомления, сезон и панель администратора (рост платформы, ч.1)
   ============================================================ */

/* ---------- Настройки уведомлений ---------- */
.notify-channels { display: grid; gap: 10px; margin-bottom: 22px; }
.notify-channel, .notify-reasons li, .notify-install {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
    padding: 13px 16px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
.notify-channel b, .notify-reasons b, .notify-install b { display: block; margin-bottom: 2px; }
.notify-channel .form-hint, .notify-reasons .form-hint, .notify-install .form-hint { margin: 0; }
.notify-subhead { font-size: 1rem; margin: 0 0 10px; }
.notify-reasons { list-style: none; margin: 0 0 22px; padding: 0; display: grid; gap: 8px; }
.notify-install { border-style: dashed; }

/* ---------- Сезон ---------- */
.season-hero {
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--accent) 22%, var(--surface-2)), var(--surface-2));
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 26px 28px;
    margin-bottom: 22px;
}
.season-eyebrow {
    margin: 0 0 6px;
    font-size: 0.78rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--accent-2);
}
.season-hero h2 { margin: 0 0 4px; font-size: clamp(1.5rem, 4vw, 2rem); }
.season-dates { margin: 0 0 14px; color: var(--text-dim); font-size: 0.88rem; }

.season-me {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 16px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    width: max-content;
    max-width: 100%;
}
.season-me-place {
    font-family: var(--font-head);
    font-weight: 800;
    font-size: 1.6rem;
    color: var(--gold);
    font-variant-numeric: tabular-nums;
}

/* ---------- Лидерборд: переключатель «за всё время / сезонный» ---------- */
/* Крупнее обычных .subtab — это главный переключатель страницы, а не
   один из многих подразделов, поэтому оформлен как отдельный блок над
   остальными подвкладками. */
.leaderboard-scope {
    display: flex;
    gap: 8px;
    margin-bottom: 14px;
}
.leaderboard-scope-btn {
    flex: 1;
    display: flex; align-items: center; justify-content: center; gap: 8px;
    padding: 12px 16px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-2);
    color: var(--text-dim);
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 0.95rem;
    cursor: pointer;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.leaderboard-scope-btn:hover { color: var(--text); border-color: var(--accent); }
.leaderboard-scope-btn[aria-selected="true"] {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}
@media (max-width: 480px) {
    .leaderboard-scope-btn { padding: 10px 8px; font-size: 0.86rem; }
}

/* ---------- Лидерборд: категории и подгруппы ---------- */
/* Две ступени вкладок. Верхняя — раздел сайта (турниры, стримы…),
   нижняя — величина внутри раздела. Разного веса намеренно: категория
   крупная и с иконкой, подгруппа — небольшая «таблетка», потому что
   переключают её чаще, а места она занимать не должна. */
.lb-cats {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 8px;
    margin-bottom: 12px;
}
.lb-cat {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 11px 6px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--surface-3);
    color: var(--text-dim);
    font-family: var(--font-body);
    font-size: 0.85rem;
    line-height: 1.2;
    text-align: center;
    cursor: pointer;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.lb-cat i { font-size: 1rem; }
.lb-cat:hover { color: var(--text); border-color: var(--accent); background: var(--surface-2); }
.lb-cat[aria-selected="true"] {
    color: var(--text);
    border-color: var(--accent);
    background: var(--accent-soft);
    font-weight: 600;
}

.lb-metrics {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 10px;
}
.lb-metric {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 7px 14px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface-2);
    color: var(--text-dim);
    font-size: 0.85rem;
    cursor: pointer;
    transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.lb-metric i { font-size: 0.8rem; }
.lb-metric:hover { color: var(--text); border-color: var(--accent); }
.lb-metric[aria-selected="true"] {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
    font-weight: 600;
}
.lb-hint { margin: 0 0 16px; }

@media (max-width: 720px) {
    .lb-cats { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 480px) {
    .lb-cats { grid-template-columns: repeat(2, 1fr); }
    .lb-cats .lb-cat:last-child { grid-column: 1 / -1; }
    .lb-cat { font-size: 0.8rem; }
}

/* ---------- Лидерборд: сами места ---------- */
/* Строка устроена как в игре: место, лицо, имя, одно число справа.
   Колонок ровно три, поэтому на телефоне ничего не приходится прятать —
   строка просто сжимается. */
.lb-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.lb-row {
    display: grid;
    grid-template-columns: 46px minmax(0, 1fr) auto;
    align-items: center;
    gap: 12px;
    padding: 9px 14px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
.lb-row.is-skeleton {
    height: 54px;
    border-style: dashed;
    opacity: 0.5;
}
/* Тройку призёров отмечаем цветом номера и окантовкой, без заливки:
   заливка спорит с игровой иконкой, у которой свой яркий фон. */
.lb-row.is-medal { border-color: color-mix(in srgb, var(--gold) 45%, var(--border)); }
.lb-row.is-place-1 .lb-place { color: var(--gold); }
.lb-row.is-place-2 .lb-place { color: color-mix(in srgb, var(--text) 70%, #c0c6d4); }
.lb-row.is-place-3 .lb-place { color: #cd7f32; }
.lb-row.is-me {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.lb-place {
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 1.05rem;
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
    text-align: center;
}

.lb-player {
    display: flex; align-items: center; gap: 11px;
    min-width: 0;
    text-decoration: none;
    color: var(--text);
}
.lb-face {
    width: 38px; height: 38px;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    background: var(--surface-3);
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 0.8rem;
    color: var(--text-dim);
}
.lb-face.is-square { border-radius: 11px; }
.lb-face img, .lb-face video { width: 100%; height: 100%; object-fit: cover; }
/* Иконки Brawl Stars приходят с нарисованной каймой — тот же приём, что
   и в остальных местах сайта: подрезаем её масштабом. */
.lb-face img.is-game-icon { transform: scale(1.18); }

.lb-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
}
.lb-player:hover .lb-name { color: var(--accent-2); }

/* Значок величины и число — как трофеи в карточке игрока: сначала
   понятно «чего», потом «сколько». */
.lb-value {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-family: var(--font-head);
    font-weight: 700;
    font-size: 1.02rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: var(--text);
    white-space: nowrap;
}
.lb-value i {
    font-size: 0.85rem;
    color: var(--accent-2);
}
.lb-row.is-medal .lb-value i { color: var(--gold); }
.lb-value b { font-weight: 700; min-width: 3ch; text-align: right; }

/* Своя строка под списком — когда до топа не дотянул. Прилипает к низу
   экрана: прокручивая двухсотый список, человек всё время видит, где он. */
.lb-mine {
    position: sticky;
    bottom: 8px;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px dashed var(--border);
    background: var(--bg);
}
.lb-foot { margin-top: 14px; }

.lb-soon {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 40px 20px;
    text-align: center;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
.lb-soon i { font-size: 2rem; color: var(--text-dim); }
.lb-soon h3 { margin: 0; }
.lb-soon p { max-width: 460px; }

@media (max-width: 480px) {
    .lb-row { grid-template-columns: 34px minmax(0, 1fr) auto; gap: 9px; padding: 8px 11px; }
    .lb-face { width: 34px; height: 34px; }
    .lb-place { font-size: 0.95rem; }
    .lb-value { font-size: 0.95rem; }
}

.season-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.season-row {
    display: grid;
    grid-template-columns: 44px minmax(0, 1fr) auto auto 72px;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
/* Тройку призёров подсвечиваем окантовкой, а не заливкой: заливка
   спорит с фоном профиля у тех, кто поставил свой. */
.season-row.is-top { border-color: color-mix(in srgb, var(--gold) 55%, var(--border)); }
.season-place {
    font-family: var(--font-head);
    font-weight: 700;
    color: var(--text-dim);
    font-variant-numeric: tabular-nums;
    text-align: center;
}
.season-row.is-top .season-place { color: var(--gold); }
.season-player { display: flex; align-items: center; gap: 10px; min-width: 0; text-decoration: none; color: var(--text); }
.season-avatar { width: 34px; height: 34px; border-radius: 50%; overflow: hidden; flex-shrink: 0; }
.season-avatar img { width: 100%; height: 100%; object-fit: cover; }
.season-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.season-player:hover .season-name { color: var(--accent-2); }
.season-stat { color: var(--text-dim); font-size: 0.84rem; white-space: nowrap; }
.season-points {
    font-family: var(--font-head);
    font-weight: 700;
    text-align: right;
    font-variant-numeric: tabular-nums;
}
.season-rules { margin-top: 14px; }

@media (max-width: 620px) {
    .season-row { grid-template-columns: 34px minmax(0, 1fr) 64px; }
    .season-stat { display: none; }
}

/* ---------- Панель администратора ---------- */
.admin-stats {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 10px;
    margin: 18px 0 24px;
}
.admin-stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 14px 16px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
.admin-stat i { color: var(--accent-2); font-size: 0.95rem; margin-bottom: 4px; }
.admin-stat b {
    font-family: var(--font-head);
    font-size: 1.35rem;
    font-variant-numeric: tabular-nums;
}
.admin-stat span { color: var(--text-dim); font-size: 0.8rem; }

.admin-pane { margin-top: 18px; }
.admin-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.admin-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
    padding: 13px 16px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
.admin-row-body { min-width: 0; flex: 1 1 260px; }
.admin-row-body b { display: block; overflow-wrap: anywhere; }
.admin-row-body .form-hint { margin: 2px 0 0; }
.admin-row-actions { display: flex; gap: 8px; flex-wrap: wrap; }

.admin-search { display: flex; gap: 10px; flex-wrap: wrap; margin-bottom: 16px; }
.admin-search .form-input { flex: 1 1 240px; }

.admin-note {
    padding: 18px 20px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}
.admin-note p { margin: 0 0 8px; }
.admin-note p:last-child { margin-bottom: 0; }

/* ============================================================
   Рост платформы v189: команды, клипы, лента, поиск, сделки,
   пропуск, витрина, репутация, что нового, группы и нижняя сетка.
   ============================================================ */

/* ---------- Команды ---------- */
.team-grid {
    display: grid; gap: 12px;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
}
.team-card {
    display: flex; align-items: center; gap: var(--space-3); text-align: left;
    padding: var(--space-3) var(--space-4); border: 1px solid var(--border); border-radius: var(--radius-lg);
    box-shadow: var(--shadow-xs);
    background: var(--surface); color: inherit; cursor: pointer; width: 100%;
    transition: border-color var(--transition-fast), transform var(--transition-fast), box-shadow var(--transition-fast);
}
.team-card:hover { border-color: var(--accent); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.team-card:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
.team-card.is-mine { border-color: var(--accent); background: var(--surface-3); }
.team-card-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.team-card-body b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.team-emblem {
    width: 46px; height: 46px; flex: 0 0 46px;
    display: grid; place-items: center; font-size: 1.5rem;
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--team-color, var(--accent)) 22%, var(--surface-2));
    border: 1px solid color-mix(in srgb, var(--team-color, var(--accent)) 45%, transparent);
}
.team-emblem-lg { width: 74px; height: 74px; flex-basis: 74px; font-size: 2.2rem; }
.team-tag { color: var(--text-dim); font-size: 0.85em; margin-left: 6px; }

.team-detail {
    margin: 18px 0; padding: 16px;
    border: 1px solid var(--border); border-radius: var(--radius-lg);
    background: var(--surface);
}
.team-head { display: flex; align-items: flex-start; gap: 14px; }
.team-head h2 { margin: 0 0 4px; }
.team-head-actions { display: flex; gap: 8px; margin-left: auto; flex-shrink: 0; }
.team-members { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 8px; }
.team-member {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 10px; border-radius: var(--radius-md); background: var(--surface-soft);
}
.team-member.is-invited { opacity: 0.65; }
.team-member a { display: flex; align-items: center; gap: 10px; color: inherit; text-decoration: none; }
.team-role { margin-left: auto; font-size: 0.8rem; color: var(--text-dim); }
.team-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; align-items: center; }
.team-invite-form { display: flex; gap: 8px; flex: 1 1 260px; }
.team-invite-form input {
    flex: 1; padding: 8px 12px; border-radius: var(--radius-md);
    border: 1px solid var(--border); background: var(--surface-2); color: var(--text);
}
.team-invites { margin-bottom: 18px; }
.team-invite {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 10px; border-radius: var(--radius-md);
    background: var(--accent-soft); border: 1px solid var(--accent-ring);
}
.team-invite-actions { margin-left: auto; display: flex; gap: 8px; }

/* ---------- Лента друзей ---------- */
.feed-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.feed-item {
    display: flex; gap: 12px; padding: 12px;
    border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface);
}
.feed-avatar { flex: 0 0 auto; }
.feed-body { min-width: 0; flex: 1; }
.feed-meta {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    margin: 0 0 6px; font-size: 0.85rem; color: var(--text-dim);
}
.feed-meta b { color: var(--text); }
.feed-kind { display: inline-flex; align-items: center; gap: 5px; }
.feed-text { color: var(--text); text-decoration: none; display: block; }
.feed-text:hover { color: var(--accent-2); }
.feed-tournament_win .feed-kind { color: var(--gold); }
.feed-stream .feed-kind { color: var(--danger); }
.load-more { display: flex; justify-content: center; margin: 18px 0; }

/* ---------- Клипы ---------- */
.clip-grid {
    display: grid; gap: 12px;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}
.clip-card {
    border: 1px solid var(--border); border-radius: var(--radius-lg);
    background: var(--surface); overflow: hidden;
}
.clip-open {
    position: relative; display: grid; place-items: center;
    aspect-ratio: 16 / 9; text-decoration: none;
    background: linear-gradient(135deg, var(--surface-2), var(--surface-3));
}
.clip-play {
    width: 46px; height: 46px; display: grid; place-items: center;
    border-radius: 50%; background: var(--accent); color: var(--on-accent);
}
.clip-time {
    position: absolute; right: 8px; bottom: 8px;
    padding: 2px 7px; border-radius: 6px; font-size: 0.78rem;
    background: rgba(0, 0, 0, 0.6); color: #fff;
}
.clip-body { padding: 10px 12px 12px; }
.clip-title { margin: 0 0 4px; font-size: 0.95rem; }
.clip-strip { list-style: none; margin: 0; padding: 0; display: flex; gap: 10px; overflow-x: auto; }
.clip-chip {
    display: flex; flex-direction: column; gap: 2px; min-width: 170px;
    padding: 9px 11px; border-radius: var(--radius-md);
    border: 1px solid var(--border); background: var(--surface-2);
    color: inherit; text-decoration: none; position: relative;
}
.clip-chip:hover { border-color: var(--accent); }
.clip-chip .clip-time { position: static; align-self: flex-start; background: var(--accent-soft); color: var(--accent-2); }

/* ---------- Эфир: рейд, соведущие, смайлы ---------- */
.raid-banner {
    display: flex; align-items: center; gap: 12px;
    margin-bottom: 14px; padding: 12px 14px;
    border-radius: var(--radius-lg);
    background: linear-gradient(135deg, var(--accent-soft), transparent);
    border: 1px solid var(--accent-ring);
}
.raid-banner > span { display: flex; flex-direction: column; }
.raid-close {
    margin-left: auto; background: none; border: 0; cursor: pointer;
    color: var(--text-dim); font-size: 1.3rem; line-height: 1;
}
/* .watch-extras больше нет: кнопки переехали во всплывающую плашку
   под плеером (.watch-sheet-tools выше). */
.raid-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; max-height: 50vh; overflow-y: auto; }
.raid-target {
    width: 100%; text-align: left; display: flex; flex-direction: column; gap: 2px;
    padding: 10px 12px; border-radius: var(--radius-md);
    border: 1px solid var(--border); background: var(--surface-2); color: inherit; cursor: pointer;
}
.raid-target:hover { border-color: var(--accent); }
.cohost-list { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 8px; }
.cohost {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 8px 10px; border-radius: var(--radius-md); background: var(--surface-soft);
}
.cohost.is-invited { opacity: 0.7; }
.cohost > a { display: flex; align-items: center; gap: 9px; color: inherit; text-decoration: none; }
.cohost .form-hint { margin-left: auto; }
.emote-grid {
    display: grid; gap: 10px;
    grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
}
.emote-cell {
    position: relative; display: flex; flex-direction: column; align-items: center; gap: 5px;
    padding: 10px 6px; border-radius: var(--radius-md);
    border: 1px solid var(--border); background: var(--surface-2); color: inherit; cursor: pointer;
}
.emote-cell img { width: 40px; height: 40px; object-fit: contain; }
.emote-cell span { font-size: 0.76rem; color: var(--text-dim); }
.emote-cell.is-locked { opacity: 0.45; cursor: not-allowed; }
.emote-cell.is-locked i { position: absolute; right: 6px; top: 6px; font-size: 0.7rem; }

/* ---------- Сделки ---------- */
.deal-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.deal-row {
    padding: 12px 14px; border-radius: var(--radius-lg);
    border: 1px solid var(--border); background: var(--surface);
    border-left: 3px solid var(--border);
}
.deal-row.is-funded  { border-left-color: var(--info); }
.deal-row.is-sent    { border-left-color: var(--warning); }
.deal-row.is-dispute { border-left-color: var(--danger); }
.deal-row.is-done    { border-left-color: var(--success); opacity: 0.75; }
.deal-main { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.deal-status { font-size: 0.76rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim); }
.deal-title { flex: 1; min-width: 0; }
.deal-sum { font-weight: 700; color: var(--gold); }
.deal-meta { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.deal-dispute { margin: 8px 0 0; font-size: 0.85rem; color: var(--danger); }
.deal-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }

/* ---------- Доверие к другой стороне сделки ---------- */
.deal-trust {
    display: inline-flex; align-items: center; gap: 6px;
    font-size: 0.78rem; color: var(--text-dim);
    margin-left: auto; white-space: nowrap;
}
.deal-trust.is-good { color: var(--success); }
.deal-trust.is-bad  { color: var(--danger); }
.deal-trust-dot { font-size: 0.5rem; color: var(--text-dim); }
.deal-trust-dot.is-online { color: var(--success); }

/* ---------- Обмен косметикой (js/cosmetic-trades.js) ---------- */
.trade-row {
    display: flex; flex-direction: column; gap: 8px;
    padding: 12px 14px; border-radius: var(--radius-lg);
    border: 1px solid var(--border); background: var(--surface);
}
.trade-row-parties { display: flex; align-items: center; gap: 8px; }
.trade-row-swap { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.trade-item {
    display: inline-flex; padding: 3px 10px; border-radius: 999px;
    font-size: 0.82rem; font-weight: 600;
    background: var(--surface-2); border: 1px solid var(--border);
}
.trade-items-list { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0; }
.trade-item-choice { background: none; border: none; padding: 0; cursor: pointer; }
.trade-item-choice.is-selected .trade-item { border-color: var(--accent); color: var(--accent); }

/* ---------- Вывод и наказания ---------- */
.payout-list, .sanction-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.payout-row, .sanction-row {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 10px 12px; border-radius: var(--radius-md);
    background: var(--surface-soft); border: 1px solid var(--border);
}
.payout-sum { font-weight: 700; color: var(--gold); }
.payout-status { font-size: 0.8rem; }
.payout-row.is-paid     { border-color: color-mix(in srgb, var(--success) 45%, transparent); }
.payout-row.is-rejected { opacity: 0.7; }
.sanction-row.is-active { border-color: color-mix(in srgb, var(--danger) 45%, transparent); }
.sanction-row.is-past   { opacity: 0.65; }
.sanction-kind { font-weight: 600; }
.sanction-reason { flex: 1; min-width: 140px; }
.sanction-appeal { display: flex; flex-direction: column; font-size: 0.8rem; margin-left: auto; }
.sanction-appeal.is-upheld   { color: var(--success); }
.sanction-appeal.is-rejected { color: var(--text-dim); }
.appeal-text {
    margin: 6px 0; padding: 8px 10px; border-radius: var(--radius-md);
    background: var(--surface-2); font-size: 0.88rem;
}

/* ---------- Витрина и репутация ---------- */
.showcase-grid {
    display: grid; gap: 10px;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
.showcase-cell {
    display: flex; flex-direction: column; align-items: center; gap: 6px; text-align: center;
    padding: 14px 10px; border-radius: var(--radius-lg);
    background: var(--surface-2); border: 1px solid var(--border);
}
.showcase-cell i { font-size: 1.3rem; color: var(--accent-2); }
.showcase-cell.rarity-legendary { border-color: var(--gold); }
.showcase-cell.rarity-epic      { border-color: #b06cff; }
.showcase-cell.rarity-mythical  { border-color: #ff5fa2; }
.showcase-options { max-height: 40vh; overflow-y: auto; margin-bottom: 12px; }
.showcase-grid.is-public { margin: 12px 0; }

.reputation {
    display: flex; align-items: center; gap: 14px; margin: 12px 0;
    padding: 12px 14px; border-radius: var(--radius-lg);
    background: var(--surface); border: 1px solid var(--border); border-left-width: 3px;
}
.reputation.is-good   { border-left-color: var(--success); }
.reputation.is-normal { border-left-color: var(--info); }
.reputation.is-shaky  { border-left-color: var(--warning); }
.reputation.is-bad    { border-left-color: var(--danger); }
.reputation-score { display: flex; flex-direction: column; align-items: center; line-height: 1.1; }
.reputation-score b { font-size: 1.6rem; }
.reputation-score span { font-size: 0.72rem; color: var(--text-dim); }
.reputation-body { display: flex; flex-direction: column; }

/* ---------- Сезонный пропуск ---------- */
.pass-hero { text-align: left; }
.pass-bar {
    position: relative; height: 34px; margin: 12px 0;
    border-radius: 999px; background: var(--surface-2); overflow: hidden;
}
.pass-bar-fill {
    position: absolute; inset: 0 auto 0 0;
    background: linear-gradient(90deg, var(--accent), var(--accent-2));
    box-shadow: 0 0 16px -2px var(--accent-ring);
    transition: width var(--transition-slow);
}
.pass-bar-text {
    position: relative; display: block; line-height: 34px;
    text-align: center; font-size: 0.85rem; font-weight: 600;
}
.pass-owned {
    color: var(--gold); font-weight: 600;
    text-shadow: 0 0 12px color-mix(in srgb, var(--gold) 45%, transparent);
}
.pass-head-row, .pass-tier {
    display: grid; gap: 10px; align-items: center;
    grid-template-columns: 110px 1fr 1fr;
}
.pass-head-row {
    padding: 0 10px 6px; font-size: 0.78rem;
    text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-dim);
}
.pass-tiers { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.pass-tier {
    padding: 8px 10px; border-radius: var(--radius-md);
    background: var(--surface-soft); border: 1px solid var(--border);
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.pass-tier.is-reached { border-color: var(--accent-ring); box-shadow: var(--glow-accent); }
.pass-level { display: flex; flex-direction: column; }
.pass-level b { font-size: 1.1rem; }
.pass-cell {
    display: block; width: 100%; padding: 9px 10px; text-align: center;
    border-radius: var(--radius-md); border: 1px solid var(--border);
    background: var(--surface-2); color: var(--text); font: inherit;
    transition: border-color var(--transition-fast), background var(--transition-fast),
                box-shadow var(--transition-fast), transform var(--transition-fast);
}
.pass-cell.is-ready { border-color: var(--accent); cursor: pointer; }
.pass-cell.is-ready:hover { background: var(--accent-soft); transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.pass-cell.is-ready:active { transform: translateY(0) scale(0.97); }
.pass-cell.is-ready:focus-visible { outline: 2px solid var(--accent-2); outline-offset: 2px; }
.pass-cell.is-locked { opacity: 0.45; }
.pass-cell.is-claimed { color: var(--success); border-color: color-mix(in srgb, var(--success) 40%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--success) 30%, transparent); }
.pass-cell.is-empty { opacity: 0.3; }

/* ---------- Что нового ---------- */
.updates-list { display: grid; gap: 12px; }
.update-entry {
    padding: 14px 16px; border-radius: var(--radius-lg);
    background: var(--surface); border: 1px solid var(--border); border-left-width: 3px;
}
.update-entry.is-feature { border-left-color: var(--accent); }
.update-entry.is-fix     { border-left-color: var(--info); }
.update-entry.is-balance { border-left-color: var(--warning); }
.update-entry.is-event   { border-left-color: var(--gold); }
.update-entry.is-unseen  { box-shadow: 0 0 0 1px var(--accent-ring); }
.update-entry h3 { margin: 8px 0 6px; }
.update-entry p { margin: 0; color: var(--text-muted); }
.update-head {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    font-size: 0.8rem; color: var(--text-dim);
}
.update-kind { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; }
.update-version { padding: 1px 7px; border-radius: 6px; background: var(--surface-2); }
.update-new { padding: 1px 7px; border-radius: 6px; background: var(--accent); color: var(--on-accent); }
.update-draft { padding: 1px 7px; border-radius: 6px; background: var(--warning); color: #1a1a3a; }
.update-actions { display: flex; gap: 8px; margin-top: 10px; }

/* ---------- Групповой этап и нижняя сетка ---------- */
.bracket-groups { display: grid; gap: 16px; margin: 14px 0; }
.group-block {
    padding: 14px; border-radius: var(--radius-lg);
    background: var(--surface); border: 1px solid var(--border);
}
.group-block h3 { margin: 0 0 10px; }
/* Чёткие границы таблицы: раньше строки разделяла только тонкая линия
   сверху, а сама таблица и столбцы не были очерчены — на пестром фоне
   строки визуально сливались. Теперь у таблицы есть свой контур, у
   каждой ячейки — граница, а шапка отделена более заметной линией. */
.group-table {
    width: 100%; border-collapse: collapse; font-size: 0.88rem;
    border: 1px solid var(--border);
}
.group-table th, .group-table td {
    padding: 6px 8px; text-align: left;
    border: 1px solid var(--border-soft);
}
.group-table th { color: var(--text-dim); font-weight: 500; font-size: 0.78rem; border-bottom: 1px solid var(--border); }
.group-table tbody tr:first-child td { border-top: none; }
/* Команды, прошедшие в плей-офф (топ-2 группы), — подсветка сильнее
   обычной строки: не просто лёгкий тон фона, а цветная полоса слева,
   жирные место и очки цветом успеха, плюс явный текстовый бейдж —
   цвет один в один сливается для дальтоников и на маленьком экране. */
.group-table tbody tr.is-top {
    background: color-mix(in srgb, var(--success) 16%, var(--surface-soft));
    box-shadow: inset 3px 0 0 var(--success);
}
.group-table tbody tr.is-top td:first-child { color: var(--success); font-weight: 800; }
.group-table tbody tr.is-top td:last-child b { color: var(--success); }
.group-playoff-badge {
    display: inline-flex; align-items: center; margin-left: 6px;
    padding: 1px 8px; border-radius: 999px;
    background: color-mix(in srgb, var(--success) 22%, transparent);
    color: var(--success); font-size: 0.72rem; font-weight: 700;
    white-space: nowrap; vertical-align: middle;
}
.group-matches { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 6px; }
.group-match {
    display: grid; gap: 10px; align-items: center;
    grid-template-columns: 1fr 70px 1fr auto;
    padding: 7px 10px; border-radius: var(--radius-md); background: var(--surface-soft);
}
.group-match.is-played { opacity: 0.85; }
/* Строка матча кликабельна (открывает заявку/подтверждение счёта — см.
   openGroupMatchModal в js/bracket.js), только когда обе стороны уже
   известны — data-match-id пустой, пока соперник не определён. */
.group-match[data-match-id]:not([data-match-id=""]) { cursor: pointer; }
.group-match[data-match-id]:not([data-match-id=""]):hover { background: var(--surface-3); }
.group-score { text-align: center; font-weight: 700; }
/* Рядом с «Изменить»/«Счёт» — «Чат» (видна только участникам матча и
   админу турнира, см. loadGroups в js/bracket.js). Две кнопки в ряд,
   без переноса — на мобильном .group-match и так уже сжимается в
   несколько строк своей grid-раскладкой выше. */
.group-match-actions { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }

/* ---------- Окно счёта группового матча (openGroupScoreModal) ----------
   Раньше — одно поле ввода на манер «2:1» и подсказка над ним. Теперь —
   по стороне на каждую команду: сверху цифра счёта, под ней аватар и
   название — команду узнают с первого взгляда, не вчитываясь в подпись. */
.group-score-sides {
    display: flex; align-items: flex-start; justify-content: center;
    gap: 18px; margin: 4px 0 6px;
}
.group-score-side {
    display: flex; flex-direction: column; align-items: center; gap: 8px;
    flex: 1 1 0; min-width: 0;
}
.group-score-input {
    width: 76px; height: 58px; text-align: center;
    font-family: var(--font-head); font-size: 1.6rem; font-weight: 800;
    border-radius: var(--radius-md);
    background: var(--surface-2); border: 1px solid var(--border); color: inherit;
}
.group-score-avatar {
    width: 48px; height: 48px; border-radius: 50%; overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    background: var(--surface-1, var(--surface-2)); border: 1px solid var(--border);
}
.group-score-avatar img { width: 100%; height: 100%; object-fit: cover; }
.group-score-name {
    font-size: 0.84rem; font-weight: 600; text-align: center;
    max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.group-score-colon {
    align-self: center; margin-top: 18px;
    font-family: var(--font-head); font-size: 1.4rem; font-weight: 800; color: var(--text-dim);
}

.bracket-stream { display: flex; gap: var(--bracket-gap, 28px); }
.bracket-stream.is-lower { margin-top: 26px; }
.bracket-stream.is-final { margin-top: 26px; }
.bracket-col.is-losers .bracket-col-title { color: var(--warning); }
.bracket-col.is-grand .bracket-col-title { color: var(--gold); }
.bracket-node.is-void { opacity: 0.3; }
.bracket-node.is-walkover { border-style: dashed; }
.bracket-void {
    display: grid; place-items: center; min-height: 60px;
    border: 1px dashed var(--border); border-radius: var(--radius-md);
    color: var(--text-dim); font-size: 0.8rem;
}
.bracket-generate { display: flex; gap: 8px; flex-wrap: wrap; }

/* ---------- Приглашения на турнир ---------- */
.invite-banner {
    margin-bottom: 18px; padding: 14px 16px; border-radius: var(--radius-lg);
    background: var(--accent-soft); border: 1px solid var(--accent-ring);
}
.invite-banner h3 { margin: 0 0 10px; font-size: 1rem; }
.invite-banner ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.invite-banner li { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.invite-banner li > span:first-child { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.invite-actions { display: flex; gap: 8px; margin-left: auto; }
.invite-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; max-height: 50vh; overflow-y: auto; }
.invite-list li { display: flex; align-items: center; gap: 10px; }
.invite-person { display: flex; align-items: center; gap: 9px; flex: 1; min-width: 0; }
/* Размер аватарки нигде здесь не задавался: avatarMarkup() сама по себе
   отдаёт голый <img>/<video> без габаритов (это дело контекста), а тут
   его ничего не ограничивало, кроме общего img{max-width:100%} —
   поэтому фото рассаживались во всю доступную ширину строки вместо
   маленького кружка. Тот же приём, что у .friend-avatar. */
.invite-avatar {
    position: relative; width: 36px; height: 36px; flex-shrink: 0;
    border-radius: 50%; overflow: hidden;
    background: var(--accent-soft); color: var(--accent-2);
    display: flex; align-items: center; justify-content: center;
    font-family: var(--font-head); font-weight: 700; font-size: 0.85rem;
}
.invite-avatar img, .invite-avatar video { width: 100%; height: 100%; object-fit: cover; }
/* Все три действия — «Поделиться», «Напоминание», «Позвать друзей» —
   в один ряд, без подписи: значками, как в остальном интерфейсе.
   Раньше подписи растягивали блок на несколько строк, хотя действия
   равнозначны и второстепенны — сама кнопка регистрации важнее. */
.tournament-extras { display: flex; gap: 8px; margin-top: 12px; }
.tournament-extras-btn {
    flex: 1 1 0; min-width: 0;
    display: flex; align-items: center; justify-content: center;
    padding: 0; height: 40px;
    font-size: 0.95rem;
}

/* ---------- Админка: сводка, расписания ---------- */
.digest-grid {
    display: grid; gap: 10px; margin: 14px 0;
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
}
.digest-card {
    display: flex; flex-direction: column; gap: 3px;
    padding: 12px 14px; border-radius: var(--radius-lg);
    background: var(--surface); border: 1px solid var(--border);
}
.digest-label { font-size: 0.78rem; color: var(--text-dim); }
.digest-value { font-size: 1.5rem; }
.digest-delta { font-size: 0.76rem; }
.digest-delta.is-up   { color: var(--success); }
.digest-delta.is-down { color: var(--danger); }
.digest-delta.is-flat { color: var(--text-dim); }
.digest-attention {
    padding: 12px 14px; border-radius: var(--radius-lg);
    background: color-mix(in srgb, var(--warning) 12%, transparent);
    border: 1px solid color-mix(in srgb, var(--warning) 35%, transparent);
}
.digest-attention.is-calm {
    background: color-mix(in srgb, var(--success) 10%, transparent);
    border-color: color-mix(in srgb, var(--success) 30%, transparent);
    display: flex; align-items: center; gap: 9px;
}
.digest-attention h4 { margin: 0 0 8px; font-size: 0.95rem; display: flex; align-items: center; gap: 8px; }
.digest-attention ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.admin-row.is-off { opacity: 0.55; }
.backup-tables { max-height: 320px; overflow-y: auto; }
.day-picker { display: flex; gap: 6px; flex-wrap: wrap; }
.day-chip {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 5px 9px; border-radius: 999px;
    background: var(--surface-2); border: 1px solid var(--border); cursor: pointer;
}
.checkbox-row { display: flex; align-items: center; gap: 8px; margin: 6px 0; cursor: pointer; }

/* ---------- Телефон ---------- */
@media (max-width: 640px) {
    .team-grid, .clip-grid { grid-template-columns: 1fr; }
    .pass-head-row, .pass-tier { grid-template-columns: 78px 1fr 1fr; gap: 6px; }
    .pass-cell { padding: 8px 6px; font-size: 0.82rem; }
    .group-match { grid-template-columns: 1fr auto 1fr; }
    .group-match .btn { grid-column: 1 / -1; }
    .bracket-stream { flex-direction: column; }
    .deal-main { gap: 6px; }
    .invite-actions { margin-left: 0; width: 100%; }
    .invite-actions .btn { flex: 1; }
    .showcase-grid { grid-template-columns: repeat(2, 1fr); }
    .digest-grid { grid-template-columns: repeat(2, 1fr); }
    .team-head-actions { position: absolute; right: 12px; top: 12px; }
    .team-detail { position: relative; }
}

/* ------------------------------------------------------------
   Страницы возврата после оплаты (/payments/success, /payments/fail).
   Один экран с одним сообщением: человек пришёл сюда узнать ровно
   одну вещь — дошли деньги или нет.
   ------------------------------------------------------------ */
.pay-result-slot { padding: 40px 0 60px; }
.pay-result {
    display: flex; flex-direction: column; align-items: center; text-align: center;
    gap: 14px; padding: 36px 24px;
    border: 1px solid var(--border); border-radius: var(--radius-lg);
    background: var(--surface);
}
.pay-result h2 { margin: 0; }
.pay-text { color: var(--text-muted); max-width: 46ch; }
.pay-text p { margin: 0 0 10px; }
.pay-text p:last-child { margin-bottom: 0; }
.pay-amount {
    font-family: Montserrat, sans-serif; font-weight: 800;
    font-size: 2rem; color: var(--gold);
}
.pay-icon {
    width: 84px; height: 84px; display: grid; place-items: center;
    border-radius: 50%; font-size: 2.2rem;
}
.pay-ok   .pay-icon { background: color-mix(in srgb, var(--success) 18%, transparent); color: var(--success); }
.pay-fail .pay-icon { background: color-mix(in srgb, var(--danger) 18%, transparent);  color: var(--danger); }
.pay-wait .pay-icon { background: var(--accent-soft); color: var(--accent-2); }

/* Пока ждём вебхук — часы медленно качаются. Спиннер здесь врал бы:
   он читается как «идёт загрузка страницы», а мы ждём чужой сервер. */
.pay-wait .pay-icon i { animation: pay-tick 1.6s ease-in-out infinite; }
@keyframes pay-tick {
    0%, 100% { transform: rotate(-12deg); }
    50%      { transform: rotate(12deg); }
}
@media (prefers-reduced-motion: reduce) {
    .pay-wait .pay-icon i { animation: none; }
}

.pay-actions { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin-top: 6px; }

@media (max-width: 640px) {
    .pay-result { padding: 28px 18px; }
    .pay-icon { width: 68px; height: 68px; font-size: 1.8rem; }
    .pay-actions { width: 100%; }
    .pay-actions .btn { flex: 1 1 100%; justify-content: center; }
}

/* ------------------------------------------------------------
   Пополнение баланса и приём платежей
   ------------------------------------------------------------ */
.topup-presets { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.topup-chip {
    padding: 7px 14px; border-radius: 999px; cursor: pointer;
    border: 1px solid var(--border); background: var(--surface-2); color: var(--text);
    font: inherit;
}
.topup-chip:hover { border-color: var(--accent); background: var(--accent-soft); }

.topup-methods { display: grid; gap: 8px; }
.topup-method { display: block; cursor: pointer; }
.topup-method input { position: absolute; opacity: 0; pointer-events: none; }
.topup-method > span {
    display: grid; gap: 2px 12px; align-items: center;
    grid-template-columns: 34px 1fr;
    padding: 10px 12px; border-radius: var(--radius-md);
    border: 1px solid var(--border); background: var(--surface-2);
}
.topup-method i { grid-row: span 2; font-size: 1.2rem; color: var(--accent-2); text-align: center; }
.topup-method small { color: var(--text-dim); }
.topup-method input:checked + span { border-color: var(--accent); background: var(--accent-soft); }
.topup-method input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }

.topup-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.topup-row {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 9px 12px; border-radius: var(--radius-md);
    background: var(--surface-soft); border: 1px solid var(--border);
    border-left: 3px solid var(--border);
}
.topup-row.is-paid       { border-left-color: var(--success); }
.topup-row.is-created,
.topup-row.is-processing { border-left-color: var(--warning); }
.topup-row.is-expired,
.topup-row.is-canceled,
.topup-row.is-failed     { border-left-color: var(--border); opacity: 0.7; }
.topup-row.is-chargeback { border-left-color: var(--danger); }
/* Заявки на вывод рублей (js/rub-payout.js) переиспользуют эту же
   вёрстку истории — свои статусы, те же цветовые роли. */
.topup-row.is-done       { border-left-color: var(--success); }
.topup-row.is-contacted  { border-left-color: var(--warning); }
.topup-row.is-rejected   { border-left-color: var(--border); opacity: 0.7; }
.topup-sum { font-weight: 700; color: var(--gold); }
.topup-method-name { color: var(--text-muted); }
.topup-status { font-size: 0.82rem; color: var(--text-dim); margin-left: auto; }

.pay-config {
    margin: 16px 0; padding: 14px 16px;
    border-radius: var(--radius-lg); border: 1px solid var(--border); background: var(--surface);
}
.admin-row.is-mismatch { border-color: color-mix(in srgb, var(--warning) 55%, transparent); }
.form-hint.is-warn { color: var(--warning); }

@media (max-width: 640px) {
    .topup-row { gap: 6px; }
    .topup-status { margin-left: 0; }
    .topup-presets .topup-chip { flex: 1 1 calc(33% - 8px); text-align: center; }
}

/* Крестик внутри плашки собеседника. Поверх содержимого и фона —
   плашка бывает с картинкой на всю высоту, и кнопка должна читаться
   на любой. */
.chat-info-close {
    position: absolute;
    top: 12px; right: 12px;
    z-index: 5;
    background: rgba(10, 10, 26, 0.55);
    border-color: rgba(255, 255, 255, 0.18);
    color: #fff;
}
.chat-info-close:hover { background: rgba(10, 10, 26, 0.8); }

/* ============================================================
   Админка: цифры, ошибки, фоновые задачи (js/admin-insights.js)
   ============================================================ */
.ins-head { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
.ins-period { display: flex; gap: 6px; flex-wrap: wrap; }
.ins-block { margin-top: 22px; }
.ins-subhead {
    font-family: var(--font-head);
    font-size: 0.95rem;
    color: var(--text);
    margin-bottom: 10px;
}

/* Столбики по дням: простая шкала без библиотек — здесь важно увидеть
   форму («в выходные пусто»), а не точное значение, оно во всплывашке. */
.ins-days {
    display: flex; align-items: flex-end; gap: 4px;
    height: 120px;
    padding: 8px 0;
    border-bottom: 1px solid var(--border);
    overflow-x: auto;

}
.ins-day { flex: 1 0 22px; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; gap: 4px; }
.ins-day-bar {
    width: 100%;
    max-width: 26px;
    border-radius: 4px 4px 0 0;
    background: linear-gradient(180deg, var(--accent), var(--accent-2));
    transition: filter var(--transition);
}
.ins-day:hover .ins-day-bar { filter: brightness(1.2); }
.ins-day small { font-size: 0.62rem; color: var(--text-dim); white-space: nowrap; }

/* Воронка: каждая ступень — своя полоса, ширина считается от первой. */
.ins-funnel { display: flex; flex-direction: column; gap: 12px; }
.ins-funnel-head { display: flex; justify-content: space-between; gap: 10px; font-size: 0.88rem; }
.ins-funnel-head b { color: var(--accent-2); }
.ins-funnel-step small { display: block; margin-top: 4px; font-size: 0.72rem; color: var(--text-dim); }
.ins-bar {
    height: 10px;
    border-radius: 999px;
    background: var(--surface-soft);
    overflow: hidden;
}
.ins-bar span {
    display: block; height: 100%;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--accent), var(--accent-2));
}

.ins-table { width: 100%; border-collapse: collapse; font-size: 0.86rem; }
.ins-table th {
    text-align: left;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-dim);
    padding: 6px 8px;
    border-bottom: 1px solid var(--border);
}
.ins-table td { padding: 8px; border-bottom: 1px solid var(--border); }
.ins-table tr.is-stale td { color: var(--danger); }
.ins-tag {
    display: inline-flex; align-items: center;
    padding: 1px 8px;
    border-radius: 999px;
    font-size: 0.72rem; font-weight: 600;
}
.ins-tag.is-ok { background: color-mix(in srgb, var(--success) 18%, transparent); color: var(--success); }
.ins-tag.is-bad { background: color-mix(in srgb, var(--danger) 18%, transparent); color: var(--danger); }

/* Ошибки браузера */
.ins-errors { display: flex; flex-direction: column; gap: 10px; }
.ins-error {
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-left: 3px solid var(--danger);
    border-radius: var(--radius-md);
    background: var(--surface-soft);
}
.ins-error.is-resolved { border-left-color: var(--text-dim); opacity: 0.6; }
.ins-error-top { display: flex; justify-content: space-between; gap: 10px; align-items: flex-start; }
.ins-error-top b { font-size: 0.9rem; overflow-wrap: anywhere; }
.ins-hits {
    flex-shrink: 0;
    font-size: 0.78rem; font-weight: 700;
    color: var(--danger);
}
.ins-error-meta {
    display: flex; flex-wrap: wrap; gap: 10px;
    margin: 8px 0 10px;
    font-size: 0.75rem; color: var(--text-dim);
}
.ins-error-meta code { font-size: 0.72rem; color: var(--accent-2); }

/* Плашки состояния расписаний */
.ins-alarm, .ins-ok {
    display: flex; gap: 12px; align-items: flex-start;
    padding: 14px 16px;
    border-radius: var(--radius-md);
    margin-bottom: 16px;
}
.ins-alarm {
    border: 1px solid color-mix(in srgb, var(--danger) 45%, transparent);
    background: color-mix(in srgb, var(--danger) 10%, transparent);
}
.ins-ok {
    border: 1px solid color-mix(in srgb, var(--success) 40%, transparent);
    background: color-mix(in srgb, var(--success) 8%, transparent);
}
.ins-alarm i { color: var(--danger); font-size: 1.1rem; }
.ins-ok i { color: var(--success); font-size: 1.1rem; }
.ins-alarm b, .ins-ok b { display: block; margin-bottom: 2px; }
.ins-alarm span, .ins-ok span { font-size: 0.82rem; color: var(--text-muted); }

@media (max-width: 560px) {
    .ins-table { font-size: 0.78rem; }
    .ins-table th:last-child, .ins-table td:last-child { display: none; }
}

/* ---------- Шторка турнира: шапка, группы, скролл ---------- */

/* Атрибут hidden должен прятать всегда: у .bracket-groups свой display,
   и без этого он перебил бы hidden. */
.bracket-sheet [hidden] { display: none !important; }

/* Шапка: слева название и тег игры, справа кнопки и масштаб */
.bracket-sheet .bracket-sheet-head {
    display: flex; align-items: flex-start; justify-content: space-between;
    flex-wrap: wrap; gap: 12px 16px;
}
.bracket-sheet-titles { min-width: 0; }
.bracket-head-tools {
    display: flex; align-items: center; flex-wrap: wrap;
    gap: 10px; margin-left: auto;
}
.bracket-head-actions { display: flex; align-items: center; gap: 10px; }
.bracket-head-actions:empty { display: none; }
.bracket-head-actions .btn.is-active {
    background: var(--accent-soft); border-color: var(--accent); color: var(--text);
}

/* Выбор формата турнира занимает место только когда в нём что-то есть */
.bracket-sheet .bracket-toolbar-actions { flex: none; margin-bottom: 14px; }
.bracket-sheet .bracket-toolbar-actions:empty { display: none; }

/* Группы прокручиваются сами. Показаны они вместо сетки, поэтому
   занимают всё свободное место шторки. */
.bracket-sheet .bracket-groups {
    flex: 1 1 auto; min-height: 0; align-content: start;
    grid-template-columns: minmax(0, 1fr);
    overflow-y: auto; overscroll-behavior: contain;

}
/* Кнопка «Продвинуть победителя» в окне матча */
.match-advance { margin: 4px 0 14px; }
.match-advance .form-hint { margin: 8px 0 0; }

/* Отступ под кнопкой «Чат с соперником»: без него карточка первой карты
   вплотную прилипала к кнопке. Пустой блок (чата нет) места не занимает. */
#matchChatActions:not(:empty) { margin-bottom: 18px; }

/* Маппул матча в окне «i»: заголовок раздела и картинка карты в строке игры */
.match-section-title { margin: 0 0 8px; font-size: 0.9rem; }
.match-game-thumb {
    flex: 0 0 auto; width: 36px; aspect-ratio: 3 / 4; object-fit: cover;
    border-radius: 6px; background: var(--surface-2);
}
.match-game-thumb.is-empty {
    display: flex; align-items: center; justify-content: center;
    color: var(--text-dim); font-size: 0.8rem;
}
.match-game-thumb.is-broken { visibility: hidden; }

/* Чемпион турнира: победитель финала в сетке. Золото перебивает зелёное
   «победил», корона стоит перед названием. */
.bracket-participant.is-champion {
    background: color-mix(in srgb, var(--gold) 16%, var(--surface-2));
    border-color: color-mix(in srgb, var(--gold) 65%, transparent);
    box-shadow: 0 0 14px color-mix(in srgb, var(--gold) 28%, transparent);
}
.bracket-participant.is-champion .bracket-participant-name { color: var(--gold); }
.bracket-participant.is-champion .bracket-participant-score.is-winner { color: var(--gold); }
.bracket-crown { color: var(--gold); margin-right: 2px; filter: drop-shadow(0 0 4px color-mix(in srgb, var(--gold) 55%, transparent)); }

@media (max-width: 720px) {
    .bracket-sheet .group-block { padding: 12px 10px; }
    .bracket-sheet .group-table { font-size: 0.8rem; }
    .bracket-sheet .group-table th, .bracket-sheet .group-table td { padding: 6px 3px; }
}

/* ============================================================
   Планшетная версия (769–1240px) — та же граница, что у бургер-меню и
   «...» в шапке (css/style.css). Блок в конце файла — pages.css
   подключается последним (см. комментарий у @media (max-width: 820px)
   выше), и здесь это удобно: правила ниже нарочно перебивают более
   ранние (в т.ч. свои же, 820px) при той же специфичности.
   ============================================================ */
@media (min-width: 769px) and (max-width: 1240px) {
    /* ---------- Вкладки — во всю ширину, без горизонтальной прокрутки ----------
       Правило на 820px чуть выше превращает .tabs-nav в ленту
       нерастягивающихся чипов с прокруткой вбок — на планшете вкладки
       (профиль, турниры) вместо этого делят строку поровну. */
    .tabs-nav { flex-wrap: nowrap; overflow-x: auto; }
    .tabs-nav > .tab-btn { flex: 1 1 0; min-width: 0; }
    /* «Создать турнир» — не прямой ребёнок .tabs-nav (лежит в
       .tabs-nav-extra, см. выше), поэтому предыдущее правило (по
       комбинатору >) его не затрагивает — без этой строки на планшете
       у него остался бы min-width: 120px, а у двух других вкладок
       min-width: 0, и ширины снова разъехались бы. */
    .tabs-nav[aria-label="Разделы турниров"] .tabs-nav-extra > .tab-btn { flex: 1 1 0; min-width: 0; }

    /* ---------- Профиль: 4 карточки статистики — 2 в ряд ---------- */
    .profile-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ============================================================
   Тач-цели: невидимая расширенная область нажатия для мелких иконок-кнопок

   Базовый .btn-icon (css/style.css) — 44×44px, это ок. Но в нескольких
   плотных рядах он переопределён меньше (30–36px): зум сетки турнира,
   поиск в чате, переключатель режимов чата, закреплённые сообщения,
   тулбар композера (на узком экране — вообще 32px, см. правило чуть
   выше в этом файле). Уменьшать их дальше некуда — ряд не влезет,
   но и раздувать визуально не нужно: значок и так на своём месте.

   Решение — псевдоэлемент с отрицательным inset поверх кнопки: он не
   участвует в раскладке (position: absolute, вне потока), но клик по
   нему засчитывается самой кнопке (псевдоэлемент не отдельная цель для
   хит-теста), так что фактическая область нажатия становится ближе к
   44px, а визуально ничего не меняется и соседние кнопки в ряду не
   задевает — отступ подобран с запасом. Только на грубом указателе
   (палец): мышью тут и так легко попасть, раздувать нечего. */
@media (pointer: coarse) {
    .bracket-zoom-controls .btn-icon,
    .chat-search .btn-icon,
    .chat-modes .btn-icon,
    .pinned-row .btn-icon,
    .composer-tools .btn-icon,
    .quantity-btn,
    .format-btn,
    .title-second-btn {
        position: relative;
    }
    .bracket-zoom-controls .btn-icon::after,
    .chat-search .btn-icon::after,
    .chat-modes .btn-icon::after,
    .pinned-row .btn-icon::after,
    .composer-tools .btn-icon::after,
    .quantity-btn::after,
    .format-btn::after,
    .title-second-btn::after {
        content: '';
        position: absolute;
        inset: -6px;
    }
}

/* ============================================================
   Цветная обводка сверху — у всех карточек-«плашек» сайта, не
   только в профиле (просили распространить вид .stat-card на весь
   сайт). Отдельным блоком в самом конце файла — так правило точно
   стоит в каскаде позже любого из этих классов и переопределяет
   верхнюю границу их обычного border: 1px solid var(--border),
   не трогая остальные три стороны. Радиус углов у border-top и так
   сам повторяет border-radius карточки — ничего досчитывать не
   нужно. Сознательно не включены .user-card (это круглый аватар,
   не плашка) и .roster-player-card/.brawl-public-card (строки без
   своей рамки — верхняя линия у них смотрелась бы посторонней). */
.stat-card, .stats-card, .post-card, .tournament-card,
.stream-card, .team-card, .achievement-card, .pack-card, .cosmetic-card,
.box-card, .quest-card, .dating-card, .friend-card, .streamer-card,
.clip-card, .digest-card, .popular-card, .subscriber-card, .crown-card,
.track-card, .username-card, .gift-card, .promo-code-card,
.my-tournament-card, .tournament-team-card  {
    border-top: 3px solid var(--accent);
}

/* ============================================================
   Бустеры (supabase/booster_effects.sql) — общий визуальный язык на
   всех шести разделах: одна и та же «особая рамка» и один и тот же
   переливающийся блик, что бы они ни украшали — карточку анкеты,
   турнира, эфира, товара или плашку чата. Переливающийся ник/название
   переиспользует уже существующий .nick-rainbow (см. выше в файле) —
   отдельного класса под него здесь нет.
   ============================================================ */

/* Особая рамка — двойной контур: тонкая цветная обводка плюс мягкое
   свечение вокруг неё, ощутимо отличается от .border-top обычных
   карточек выше, но не спорит с ним (тот остаётся на своём месте). */
.booster-frame {
    position: relative;
    outline: 2px solid var(--accent-2);
    outline-offset: 2px;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 0 16px rgba(108, 99, 255, 0.45);
}
.chat-item.booster-frame {
    outline-offset: -2px;
}

/* Переливающийся блик по тексту — тот же приём диагонального блика,
   что и premium-bg-shimmer у фонов Premium (см. выше), только не по
   фону карточки целиком, а по её текстовому блоку, и класс свой —
   чтобы не завязываться на .has-bg/.has-custom-bg, которые тут ни при
   чём. */
.booster-shimmer-surface {
    position: relative;
    overflow: hidden;
}
.booster-shimmer-surface::after {
    content: '';
    position: absolute;
    top: -30%;
    left: -35%;
    width: 35%;
    height: 160%;
    background: linear-gradient(75deg,
        transparent 0%, rgba(255, 255, 255, 0.20) 45%,
        rgba(255, 255, 255, 0.40) 50%, rgba(255, 255, 255, 0.20) 55%, transparent 100%);
    pointer-events: none;
    z-index: 1;
    animation: premium-bg-shimmer 4s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
    .booster-shimmer-surface::after { animation: none; }
}

/* Мифический буст Знакомств — анимация лайка/дизлайка на самой
   анкете (js/dating.js, swipe()). Сердце для лайка, лёгкое встряхивание
   и уход в сторону для дизлайка — коротко, карточка тут же сменяется
   следующей. */
.booster-swipe-anim { position: relative; }
.booster-swipe-anim.is-like {
    animation: booster-like-pop 0.5s ease;
}
.booster-swipe-anim.is-like::before {
    content: '\f004';
    font-family: 'Font Awesome 6 Free';
    font-weight: 900;
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 5rem;
    color: var(--danger);
    text-shadow: 0 0 24px rgba(255, 255, 255, 0.6);
    z-index: 5;
    animation: booster-like-burst 0.55s ease forwards;
    pointer-events: none;
}
.booster-swipe-anim.is-dislike {
    animation: booster-dislike-shake 0.5s ease;
}
@keyframes booster-like-pop {
    0% { transform: scale(1); }
    30% { transform: scale(1.04); }
    100% { transform: scale(1); }
}
@keyframes booster-like-burst {
    0% { opacity: 0; transform: scale(0.4); }
    40% { opacity: 1; transform: scale(1.15); }
    100% { opacity: 0; transform: scale(1.5); }
}
@keyframes booster-dislike-shake {
    0%, 100% { transform: translateX(0); }
    20% { transform: translateX(-10px) rotate(-1.5deg); }
    40% { transform: translateX(8px) rotate(1.5deg); }
    60% { transform: translateX(-6px) rotate(-1deg); }
    80% { transform: translateX(4px) rotate(1deg); }
}
@media (prefers-reduced-motion: reduce) {
    .booster-swipe-anim.is-like,
    .booster-swipe-anim.is-dislike { animation: none; }
    .booster-swipe-anim.is-like::before { animation: none; opacity: 0.9; }
}

/* ------------------------------------------------------------
   Скины бустеров (supabase/booster_skins.sql): один и тот же
   слот — рамка, мерцающий фон/текст, заливка — теперь может
   выглядеть по-разному в зависимости от того, какую редкость
   игрок когда-либо разблокировал в этой категории и выбрал в
   настройках бустеров (js/boosters.js). Пять цветовых тем по
   редкости, общих для всех мест применения.

   Два отдельных семейства классов, а не одно — потому что в двух
   местах (строка лидерборда: мерцающий фон + рамка; чат эфира:
   рамка + свой фон) рамка и заливка/блик стоят НА ОДНОМ элементе
   и могут быть выбраны игроком в РАЗНЫЕ темы одновременно:
     .booster-frameskin-<редкость>  — только для .booster-frame;
     .booster-skin-<редкость>       — для .booster-shimmer-surface,
                                       .booster-bg-fill и .nick-rainbow.
   Без выбранного скина всё выглядит как раньше (значения по
   умолчанию заданы прямо в .booster-frame/.booster-shimmer-surface). */
.booster-frameskin-rare       { --booster-frame-a: #aab4c6; --booster-frame-b: rgba(170, 180, 198, 0.5); }
.booster-frameskin-super_rare { --booster-frame-a: #4fc3f7; --booster-frame-b: rgba(79, 195, 247, 0.5); }
.booster-frameskin-epic       { --booster-frame-a: #b388ff; --booster-frame-b: rgba(179, 136, 255, 0.5); }
.booster-frameskin-mythical   { --booster-frame-a: #ff7043; --booster-frame-b: rgba(255, 112, 67, 0.55); }
.booster-frameskin-legendary  { --booster-frame-a: #ffd54f; --booster-frame-b: rgba(255, 213, 79, 0.55); }

.booster-skin-rare       { --booster-skin-a: #aab4c6; --booster-skin-b: rgba(170, 180, 198, 0.5); }
.booster-skin-super_rare { --booster-skin-a: #4fc3f7; --booster-skin-b: rgba(79, 195, 247, 0.5); }
.booster-skin-epic       { --booster-skin-a: #b388ff; --booster-skin-b: rgba(179, 136, 255, 0.5); }
.booster-skin-mythical   { --booster-skin-a: #ff7043; --booster-skin-b: rgba(255, 112, 67, 0.55); }
.booster-skin-legendary  { --booster-skin-a: #ffd54f; --booster-skin-b: rgba(255, 213, 79, 0.55); }

.booster-frame {
    outline-color: var(--booster-frame-a, var(--accent-2));
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 0 16px var(--booster-frame-b, rgba(108, 99, 255, 0.45));
}
.booster-frameskin-legendary.booster-frame {
    outline-image: none;
    animation: booster-legendary-glow 2.6s ease-in-out infinite;
}
@keyframes booster-legendary-glow {
    0%, 100% { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 0 16px rgba(255, 213, 79, 0.55); }
    50%      { box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12), 0 0 22px rgba(255, 145, 210, 0.6); }
}
@media (prefers-reduced-motion: reduce) {
    .booster-frameskin-legendary.booster-frame { animation: none; }
}

/* Мерцающий блик перекрашивается под тему скина той же диагональю,
   что и обычный .booster-shimmer-surface — меняется только цвет. */
.booster-skin-rare.booster-shimmer-surface::after       { background: linear-gradient(75deg, transparent 0%, rgba(170, 180, 198, 0.25) 45%, rgba(170, 180, 198, 0.5) 50%, rgba(170, 180, 198, 0.25) 55%, transparent 100%); }
.booster-skin-super_rare.booster-shimmer-surface::after { background: linear-gradient(75deg, transparent 0%, rgba(79, 195, 247, 0.25) 45%, rgba(79, 195, 247, 0.5) 50%, rgba(79, 195, 247, 0.25) 55%, transparent 100%); }
.booster-skin-epic.booster-shimmer-surface::after       { background: linear-gradient(75deg, transparent 0%, rgba(179, 136, 255, 0.25) 45%, rgba(179, 136, 255, 0.5) 50%, rgba(179, 136, 255, 0.25) 55%, transparent 100%); }
.booster-skin-mythical.booster-shimmer-surface::after   { background: linear-gradient(75deg, transparent 0%, rgba(255, 112, 67, 0.28) 45%, rgba(255, 112, 67, 0.52) 50%, rgba(255, 112, 67, 0.28) 55%, transparent 100%); }
.booster-skin-legendary.booster-shimmer-surface::after  { background: linear-gradient(75deg, transparent 0%, rgba(255, 213, 79, 0.3) 40%, rgba(255, 145, 210, 0.5) 50%, rgba(255, 213, 79, 0.3) 60%, transparent 100%); }

/* Заливка сплошным фоном по теме скина — стрим-чат (мифический),
   фон списка чатов (супер-редкий), превью продавца (мифический
   в Магазине). Раньше это был свободный ввод цвета — теперь
   выбор одной из пяти готовых тем тут же в инвентаре. */
.booster-bg-fill { background-size: cover; background-position: center; }
.booster-bg-fill.booster-skin-rare       { background: linear-gradient(135deg, #232b3d 0%, #3a4358 100%); }
.booster-bg-fill.booster-skin-super_rare { background: linear-gradient(135deg, #0d2a3d 0%, #1c5a7a 100%); }
.booster-bg-fill.booster-skin-epic       { background: linear-gradient(135deg, #2a1a3d 0%, #5a2d8a 100%); }
.booster-bg-fill.booster-skin-mythical   { background: linear-gradient(135deg, #3d1a12 0%, #8a3d1f 100%); }
.booster-bg-fill.booster-skin-legendary  {
    background: linear-gradient(120deg, #3d3110 0%, #8a6d1f 45%, #7a2d5a 75%, #3d3110 100%);
    background-size: 220% 220%;
    animation: booster-legendary-shift 8s ease infinite;
}
@keyframes booster-legendary-shift {
    0%, 100% { background-position: 0% 50%; }
    50%      { background-position: 100% 50%; }
}
@media (prefers-reduced-motion: reduce) {
    .booster-bg-fill.booster-skin-legendary { animation: none; }
}

/* ---------- Роли в чате, валюта канала, настройки чата (v338) ---------- */
.chat-role {
    display: inline-flex; align-items: center; gap: 4px;
    margin: 0 6px 0 4px; padding: 1px 7px; border-radius: 999px;
    font-size: 0.68rem; font-weight: 700; line-height: 1.5; vertical-align: middle;
}
.chat-role-owner { color: #ffb020; background: rgba(255, 176, 32, 0.16); }
.chat-role-mod { color: #35d07f; background: rgba(53, 208, 127, 0.16); }
.chat-role-cohost { color: var(--accent-2, #8f88ff); background: rgba(143, 136, 255, 0.16); }

.slow-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.slow-chip {
    padding: 5px 12px; border-radius: 999px; border: 1px solid var(--border, rgba(255,255,255,.14));
    background: transparent; color: var(--text-dim, inherit); font: inherit; font-size: 0.82rem; cursor: pointer;
}
.slow-chip:hover { border-color: var(--accent); }
.slow-chip.is-active { background: var(--accent); border-color: var(--accent); color: #fff; }

.mods-add { display: flex; gap: 8px; margin-bottom: 8px; }
.mods-add .form-input { flex: 1; min-width: 0; }
.mods-list, .cp-rewards { list-style: none; margin: 10px 0; padding: 0; display: grid; gap: 8px; }
.mods-list li, .cp-rewards li {
    display: flex; align-items: center; justify-content: space-between; gap: 10px;
    padding: 10px 12px; border-radius: 12px; background: rgba(255,255,255,.04);
}
.mods-list small { color: var(--text-dim); margin-left: 6px; }
.mods-list li.mods-empty, .cp-rewards li.mods-empty { justify-content: center; color: var(--text-dim); }
.cp-rewards li.is-off { opacity: .55; }
.cp-rewards .form-hint { display: block; margin: 2px 0 0; }
.cp-actions { display: inline-flex; gap: 6px; flex-shrink: 0; }
.cp-h { margin: 14px 0 6px; font-size: .95rem; }

.watch-points {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
    padding: 8px 12px; border-bottom: 1px solid var(--border, rgba(255,255,255,.08)); font-size: .85rem;
}
.watch-points-bal { display: inline-flex; align-items: center; gap: 6px; }
.watch-points-bal small { color: var(--text-dim); }
.watch-points i, .cp-balance-icon i { color: var(--accent-2, #ffb020); }
.watch-points-name { display: inline-flex; align-items: center; gap: 6px; color: var(--text-dim); }
.cp-emoji { font-size: 1em; line-height: 1; }
.cp-badge { display: inline-block; min-width: 18px; padding: 0 5px; margin-left: 4px; border-radius: 999px; background: var(--accent); color: #fff; font-size: .72rem; text-align: center; }

.cp-balance { display: flex; align-items: center; gap: 14px; padding: 14px; border-radius: 14px; background: rgba(255,255,255,.05); }
.cp-balance-icon { font-size: 1.8rem; }
.cp-balance b { font-size: 1.4rem; }
.cp-balance small { display: block; color: var(--text-dim); margin-top: 2px; }

.cp-icons { display: grid; grid-template-columns: repeat(8, 1fr); gap: 6px; margin-bottom: 8px; }
.cp-icon {
    aspect-ratio: 1; border-radius: 10px; border: 1px solid var(--border, rgba(255,255,255,.14));
    background: transparent; color: inherit; cursor: pointer;
}
.cp-icon:hover { border-color: var(--accent); }
.cp-icon.is-active { background: var(--accent); border-color: var(--accent); color: #fff; }
.cp-earn { display: grid; grid-template-columns: 1fr auto 1fr; align-items: end; gap: 10px; margin-bottom: 10px; }
.cp-earn > span { padding-bottom: 12px; color: var(--text-dim); }
.cp-toggle { display: flex; align-items: center; gap: 8px; margin: 8px 0; cursor: pointer; }

/* ---------- v339: чат ---------- */
/* Появление нового сообщения: свои выезжают справа, чужие слева */
.message.is-entering { animation: messageEnter .26s cubic-bezier(.2,.8,.3,1.15) both; transform-origin: left bottom; }
.message.sent.is-entering { transform-origin: right bottom; animation-name: messageEnterOwn; }
@keyframes messageEnter    { from { opacity: 0; transform: translate(-14px, 10px) scale(.92); } to { opacity: 1; transform: none; } }
@keyframes messageEnterOwn { from { opacity: 0; transform: translate(14px, 14px) scale(.9); }  to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .message.is-entering { animation: none; } }

/* Плашки под полем ввода нет: она у .popover-host перебивала absolute
   (position: relative объявлен позже), и лента упиралась в неё. Теперь
   кнопки лежат прямо на обоях чата. */
.chat-input-container.popover-host { position: absolute; }

/* Отправленные и кнопка отправки — цвет темы (Dantes Pass), если она надета */
.message.sent .message-content,
.send-btn { background: var(--accent-gradient, linear-gradient(135deg, var(--accent) 0%, var(--accent-2) 100%)); }

/* Поиск чатов — на всю ширину колонки */
.chat-search-wide {
    display: flex; align-items: center; gap: 10px;
    width: calc(100% - 20px); margin: 8px 10px;
    padding: 9px 14px; flex-shrink: 0;
    border-radius: var(--radius-sm); border: 1px solid var(--border);
    background: var(--surface-soft); color: var(--text-dim);
    font: inherit; font-size: .88rem; cursor: pointer; text-align: left;
}
.chat-search-wide:hover { border-color: var(--accent); color: var(--accent-2); }
.chat-search-wide[hidden] { display: none; }
.chat-list-actions { display: none !important; }

/* ---------- v340: инвентарь на телефоне и планшете ----------
   Карточки и титулы рисуются только когда попадают в экран, а вместе с
   ними не считаются их градиенты и картинки. Плюс на устройствах с
   пальцем убраны размытие, filter и бесконечная пульсация у карточек. */
.cosmetic-card { content-visibility: auto; contain-intrinsic-size: auto 250px; }
.title-choice-wrap, .special-title.is-locked-title { content-visibility: auto; contain-intrinsic-size: auto 44px; }
@media (pointer: coarse), (max-width: 1100px) {
    .profile-canvas.has-custom-bg .cosmetic-card,
    .profile-canvas.has-custom-bg .plan-card,
    .profile-canvas.has-custom-bg .pack-card,
    .profile-canvas.has-custom-bg .friend-card,
    .profile-canvas.has-custom-bg .subscriber-card,
    .profile-canvas.has-custom-bg .crown-card,
    .profile-canvas.has-custom-bg .perk,
    .profile-canvas.has-custom-bg .premium-setting,
    .profile-canvas.has-custom-bg .add-friend,
    .profile-canvas.has-custom-bg .request-row {
        backdrop-filter: none;
        background-color: rgba(10, 10, 30, 0.82);
    }
    .cosmetic-bg-preview { filter: none; }
    .rarity-pass_premium { animation: none; }
    .cosmetic-card, .special-title { transition: none; }
}

/* ---------- Бравлеры турнира 1 на 1 ---------- */
.brawler-format-rows { display: flex; flex-direction: column; gap: 8px; }
.brawler-format-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.brawler-format-row > b { min-width: 38px; color: var(--accent-2); }
.brawler-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); gap: 8px;
    max-height: 52vh; overflow-y: auto; padding: 2px; margin-bottom: 12px;
}
.brawler-pick {
    position: relative; display: flex; flex-direction: column; align-items: center; gap: 4px;
    padding: 8px 4px; border: 1px solid var(--border-soft); border-radius: 12px;
    background: var(--surface-3); cursor: pointer; text-align: center; font-size: 0.75rem;
}
.brawler-pick[hidden] { display: none; }
.brawler-pick input { position: absolute; opacity: 0; pointer-events: none; }
.brawler-pick img, .brawler-noimg { width: 48px; height: 48px; border-radius: 10px; object-fit: cover; }
.brawler-noimg { display: inline-flex; align-items: center; justify-content: center; background: var(--accent-soft); color: var(--accent-2); }
.brawler-pick:hover { border-color: var(--accent); }
.brawler-pick:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); box-shadow: 0 0 0 1px var(--accent); }
.brawler-tiles { list-style: none; margin: 0 0 8px; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.brawler-tiles li { display: flex; flex-direction: column; align-items: center; gap: 3px; width: 68px; font-size: 0.72rem; text-align: center; }
.brawler-tiles img, .brawler-tiles .brawler-noimg { width: 52px; height: 52px; border-radius: 12px; object-fit: cover; }
.brawler-tiles img.is-broken { visibility: hidden; }
.brawler-stage-ctl { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-left: 8px; }
.stage-format-row { flex-wrap: wrap; }
.brawler-all-row { display: flex; align-items: center; gap: 8px; }

/* Ряд кнопок оценки: сообщение · дизлайк · лайк · закончить — в один ряд, без текста */
.dating-action-row { display: flex; align-items: center; justify-content: center; gap: 14px; flex-wrap: nowrap; }
.dating-action-row .btn { width: 56px; height: 56px; border-radius: 50%; padding: 0; display: flex; align-items: center; justify-content: center; font-size: 1.2rem; flex: none; }
.dating-action-row .dating-btn-like { width: 64px; height: 64px; }
.dating-icon-btn { background: var(--surface-3); color: var(--accent-2); border: 1px solid var(--accent-2); }
.dating-icon-btn:hover { filter: brightness(1.15); }
.dating-message-btn.is-open { background: var(--accent-soft); }
.dating-filter-btn { width: 44px; height: 44px; padding: 0; border-radius: 12px; display: inline-flex; align-items: center; justify-content: center; }


/* Знакомства: вкладки и фильтр в одной строке, анкета + кнопки влезают в экран без прокрутки страницы */
.dating-topbar { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; border-bottom: 1px solid var(--border); }
.dating-topbar .dating-tabs { border-bottom: 0; }
.dating-topbar .dating-filter-btn { flex: none; margin-bottom: 2px; }
.dating-topbar .dating-filter-btn[hidden] { display: none; }
.dating-swipe-area { gap: 10px; }
.dating-swipe-area .dating-queue-hint { display: none; }
.dating-swipe-area .dating-card-shot { aspect-ratio: auto; height: clamp(200px, calc(100vh - 400px), 560px); height: clamp(200px, calc(100dvh - 400px), 560px); }
.dating-swipe-area .dating-card-body { padding: 10px 14px; }
.dating-swipe-area .dating-card-about { -webkit-line-clamp: 2; display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; margin: 0; }
.dating-swipe-area .dating-card-meta { margin-bottom: 4px; }
.dating-swipe-area .dating-card-body h3 { margin-bottom: 2px; }

/* Системная памятка в начале чата матча */
.match-chat-system {
    margin: 0 0 12px; padding: 12px 14px;
    border: 1px dashed color-mix(in srgb, var(--accent) 60%, var(--border));
    border-radius: var(--radius-md, 12px);
    background: color-mix(in srgb, var(--accent) 10%, transparent);
    color: var(--text); font-size: .9rem; line-height: 1.45;
}
.match-chat-system p { margin: 4px 0 0; }
.match-chat-system-head { font-weight: 800; color: var(--accent); display: flex; align-items: center; gap: 7px; }

/* Мини-окно «Подключите Telegram» */
.tg-start p { margin: 0 0 12px; line-height: 1.5; }
.tg-start .form-actions { margin: 12px 0; }

.tstart-text { color: var(--text-muted); line-height: 1.55; margin: 0 0 18px; font-size: 1rem; }

/* ---------- v379: чат пары, мигающий «!», окно правил, кнопка закрытия сетки ---------- */
.match-chat-top { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 10px; }
.match-chat-top .match-chat-system { flex: 1 1 auto; min-width: 0; margin: 0; max-height: 200px; overflow: auto; }
.match-chat-top .support-actions { flex: none; margin: 0; }
.match-chat-top .support-actions[hidden] { display: none; }
.match-chat-must { color: var(--warning); }
@media (max-width: 560px) { .match-chat-top { flex-direction: column; } .match-chat-top .support-actions { align-self: stretch; } .match-chat-top .support-actions .btn { width: 100%; } }

.bracket-alert {
    position: absolute; top: -12px; right: -8px; z-index: 3;
    width: 26px; height: 26px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--danger, #e5484d); color: #fff; font-weight: 900; font-size: 1rem;
    box-shadow: 0 0 0 0 rgba(229, 72, 77, .7);
    animation: bracketAlertBlink 1s ease-in-out infinite;
}
@keyframes bracketAlertBlink {
    0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(229, 72, 77, .6); }
    50% { opacity: .35; box-shadow: 0 0 0 8px rgba(229, 72, 77, 0); }
}
.bracket-col-window { display: block; margin-top: 2px; font-size: 0.74rem; text-transform: none; letter-spacing: 0; color: var(--accent-2); }
.tournament-rules p, .tournament-rules li { margin: 0 0 8px; line-height: 1.45; }
.tournament-rules-list { padding-left: 20px; margin: 0; }

/* Кнопка закрытия сетки на телефонах и планшетах — ниже, чтобы не липла к верхнему краю */
@media (max-width: 1024px) {
    .bracket-sheet-close { top: 38px; }
    .bracket-sheet-head { padding-right: 56px; }
}

/* v379: окно сетки не меняет размер при масштабе — меняются только пары */
.bracket-sheet { height: 96vh; }
@media (max-width: 720px) { .bracket-sheet { height: 94vh; } }
.container-bracket-page .bracket-viewport { height: 74vh; }

.creators-soon { max-width: 560px; margin: 8vh auto; text-align: center; padding: 40px 24px; border-radius: var(--radius-lg, 16px); background: var(--surface-2); border: 1px solid var(--border); }
.creators-soon > i { font-size: 2.6rem; color: var(--accent-2); margin-bottom: 14px; }
.creators-soon p { margin: 10px 0 0; font-size: 1.1rem; line-height: 1.5; color: var(--text-muted); }

/* v379: перенос времени, статистика игрока, мои матчи */
.match-resched-bar { margin: 0 0 10px; padding: 10px 12px; border-radius: 12px; border: 1px solid var(--border); background: var(--surface-3); font-size: .92rem; display: grid; gap: 6px; }
.match-resched-bar .btn { margin-left: 6px; }
.player-tstats { margin-top: 14px; }
.player-tstats-list { list-style: none; padding: 0; margin: 8px 0 0; display: grid; gap: 4px; font-size: .88rem; }
.player-tstats-list li span { color: var(--text-muted); }
.player-tstats-list li.is-win b { color: #4cd964; }
.player-tstats-list li.is-loss b { color: #ff4757; }
.my-matches-list { display: grid; gap: 12px; }
.my-match { display: flex; gap: 14px; align-items: center; flex-wrap: wrap; padding: 14px 16px; border-radius: 14px; border: 1px solid var(--border); background: var(--surface-2); }
.my-match.is-soon { border-color: var(--accent); }
.my-match-main { flex: 1 1 220px; min-width: 0; }
.my-match-title { margin: 0; font-weight: 700; }
.my-match-sub { margin: 2px 0 0; color: var(--text-muted); font-size: .88rem; }
.my-match-time { font-weight: 700; color: var(--accent-2); }
.my-match-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.my-match.is-win .my-match-time { color: #4cd964; }
.my-match.is-loss .my-match-time { color: #ff4757; }
.my-match-group{margin:14px 0 4px;font-size:1rem;color:var(--text-muted)}
.match-dispute-hint { margin: 10px 0; padding: 10px 12px; border-radius: 12px; border: 1px dashed var(--accent); background: var(--surface-3); font-size: .88rem; }
.match-dispute-hint p { margin: 0 0 4px; }
.match-dispute-hint ul { margin: 0; padding-left: 18px; display: grid; gap: 3px; }
.tournament-funnel { margin: 0 0 14px; padding: 12px; border-radius: 12px; background: var(--surface-3); border: 1px solid var(--border); }
.tournament-funnel-title { margin: 0 0 8px; font-size: .95rem; }
.funnel-row { display: grid; grid-template-columns: 1fr auto; gap: 2px 8px; margin-bottom: 8px; font-size: .88rem; }
.funnel-bar { grid-column: 1 / -1; height: 6px; border-radius: 4px; background: var(--accent); display: block; }
.funnel-row small { grid-column: 1 / -1; color: var(--text-muted); }
.player-card-public { margin: 0 0 14px; padding: 14px; border-radius: 14px; border: 1px solid var(--border); background: var(--surface-2); display: grid; gap: 8px; justify-items: start; }
.league-badge { display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px; border-radius: 999px; font-size: .9rem; background: var(--surface-3); border: 1px solid var(--border); }
.league-badge span { color: var(--text-muted); font-size: .8rem; }
.league-bronze i { color: #cd7f32; } .league-silver i { color: #c0c7d1; } .league-gold i { color: #ffc83d; }
.league-platinum i { color: #5ce1e6; } .league-diamond i { color: #6aa8ff; } .league-legend i { color: #ff5ca8; }
.draft-label { display: block; width: 100%; font-size: .7rem; text-transform: uppercase; letter-spacing: .04em; color: var(--text-muted); margin-bottom: 2px; }
.draft-pick.is-ban { text-decoration: line-through; opacity: .75; border-color: #ff4757; }
.match-game-bans { margin-top: 4px; }

/* ---------- Партнёры ---------- */
.partners-tabs { display: flex; gap: 8px; margin: 0 0 14px; }
.partners-tab { flex: 1; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px 16px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface-2); color: var(--text-dim); font-family: var(--font-head); font-weight: 700; cursor: pointer; }
.partners-tab:hover { color: var(--text); border-color: var(--accent); }
.partners-tab[aria-selected="true"] { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.partners-toolbar { margin: 0 0 14px; }
.partners-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px; }
.partner-card { background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-lg, 16px); overflow: hidden; display: flex; flex-direction: column; }
.partner-banner { aspect-ratio: 3 / 1; background: var(--surface-3); }
.partner-banner img { width: 100%; height: 100%; object-fit: cover; display: block; }
.partner-banner-empty { display: grid; place-items: center; height: 100%; color: var(--text-muted); font-size: 2rem; }
.partner-body { padding: 14px 16px 16px; display: grid; gap: 10px; }
.partner-nick { margin: 0; font-size: 1.15rem; }
.partner-socials { display: flex; gap: 8px; flex-wrap: wrap; }
.partner-social { width: 38px; height: 38px; display: grid; place-items: center; border-radius: 50%; background: var(--surface-3); border: 1px solid var(--border); color: var(--text); font-size: 1.1rem; }
.partner-social-tiktok:hover { background: #000; color: #fff; }
.partner-social-youtube:hover { background: #ff0000; color: #fff; }
.partner-social-twitch:hover { background: #9146ff; color: #fff; }
.partner-social-telegram:hover { background: #229ed9; color: #fff; }
.partner-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.partners-empty { grid-column: 1 / -1; text-align: center; padding: 40px 16px; color: var(--text-muted); }
.partners-empty i { font-size: 2rem; margin-bottom: 8px; }
.partner-interview p { margin: 0 0 12px; line-height: 1.55; }
@media (max-width: 600px) { .partners-grid { grid-template-columns: 1fr; } }

.partners-tab-icon { width: 28px; height: 28px; object-fit: contain; flex: none; display: block; }

/* Значки соцсетей: без подчёркивания и в фирменных цветах
   (карточки партнёров и подвал сайта). */
.partner-social, .partner-social:hover,
.social-links a, .social-links a:hover { text-decoration: none; }
.partner-social-tiktok { color: var(--text); }
.partner-social-youtube, .social-links a[aria-label="YouTube"] { color: #ff0000; }
.partner-social-twitch, .social-links a[aria-label="Twitch"] { color: #9146ff; }
.partner-social-telegram, .social-links a[aria-label="Telegram"] { color: #229ed9; }
.social-links a[aria-label="Discord"] { color: #5865f2; }
.partner-social-youtube:hover, .social-links a[aria-label="YouTube"]:hover { background: #ff0000; color: #fff; }
.partner-social-twitch:hover, .social-links a[aria-label="Twitch"]:hover { background: #9146ff; color: #fff; }
.partner-social-telegram:hover, .social-links a[aria-label="Telegram"]:hover { background: #229ed9; color: #fff; }
.social-links a[aria-label="Discord"]:hover { background: #5865f2; color: #fff; }
.partner-social-tiktok:hover { background: var(--text); color: var(--surface-2); }

/* ---------- Страницы под запросы (/brawl-stars и т. п.) ---------- */
.game-landing-title { margin: 0 0 10px; font-size: var(--text-2xl, 1.8rem); }
.game-landing-lead { margin: 0 0 14px; line-height: 1.6; color: var(--text-muted); max-width: 70ch; }
.game-landing-facts { margin: 0 0 16px; padding-left: 20px; display: grid; gap: 6px; }
.game-landing-cta { display: flex; gap: 10px; flex-wrap: wrap; margin: 0 0 8px; }
.game-landing-h2 { margin: 28px 0 12px; text-align: left; }
.game-landing-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.game-landing-card { display: grid; gap: 6px; padding: 14px 16px; border-radius: 14px; border: 1px solid var(--border); background: var(--surface-2); color: var(--text); text-decoration: none; }
.game-landing-card:hover { border-color: var(--accent); }
.game-landing-card span { color: var(--text-muted); font-size: .9rem; }
.game-landing-empty { grid-column: 1 / -1; color: var(--text-muted); }
.game-faq { display: grid; gap: 8px; }
.game-faq-item { padding: 12px 16px; border-radius: 12px; border: 1px solid var(--border); background: var(--surface-2); }
.game-faq-item summary { cursor: pointer; font-weight: 700; }
.game-faq-item p { margin: 8px 0 0; color: var(--text-muted); line-height: 1.55; }
@media (max-width: 600px) { .game-landing-list { grid-template-columns: 1fr; } }

/* v390: модалки целиком в экране (без прокрутки страницы); если контент выше —
   прокручивается тело модалки, а не страница. */
.modal .modal-content { max-height: calc(100vh - 24px); display: flex; flex-direction: column; }
@supports (height: 100dvh) { .modal .modal-content { max-height: calc(100dvh - 24px); } }
.modal .modal-content > .modal-header { flex: 0 0 auto; }
.modal .modal-content > .modal-body, .modal .modal-content > form { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
#matchChatModal .support-thread { min-height: 140px; max-height: calc(100vh - 330px); max-height: calc(100dvh - 330px); }
/* плашки главной выше летучих мышей, чтобы цифры не перекрывались */
.pulse-stats { position: relative; z-index: 9972; }
