* { box-sizing: border-box; }

:root {
  /* Стартовое значение до первого вызова fitPanelToCharacter() (js/layout.js) — тот
     сразу переопределяет через inline style, подгоняя под фиксированный размер
     персонажа (--scale ниже). min(58vh,520px) остаётся как разумный дефолт на случай,
     если JS почему-то ещё не отработал (например, на самый первый кадр рендера). */
  --panel-h: min(58vh, 520px);

  /* Масштаб персонажей — простая КОНСТАНТА, не зависит от размера экрана/окна (раньше
     зависела от высоты #room, из-за чего персонаж выглядел совсем по-разному на разных
     мониторах — см. js/layout.js). Персонаж везде одного реального пиксельного размера;
     под НЕГО подстраивается высота чата (--panel-h, см. fitPanelToCharacter() в
     js/layout.js), а #room{min-height} ниже гарантирует, что комнате всегда хватит
     места показать персонажа этого размера целиком, не обрезая через overflow:hidden. */
  --scale: 0.44;

  /* Реальная высота #announcementBanner, когда он показан (0px, когда нет) — см.
     updateAnnouncementHeightVar() в js/announcement.js. #gameScreen и мобильные
     fixed-элементы ниже читают её, чтобы баннер СДВИГАЛ их вниз, а не закрывал
     собой (баннер сам position:fixed, вне обычного потока — иначе никак). */
  --announcement-h: 0px;
}

body {
  margin: 0;
  font-family: Arial, sans-serif;
  background: white;
}

/* #gameScreen — колонка на всю высоту экрана: #topZone (языки/профиль/админка + чат/онлайн +
   строка ввода) занимает свою естественную высоту, #room — весь остаток (flex:1, см. ниже).
   Раньше все эти блоки были position:fixed с ручным calc()-подсчётом отступов друг под
   другом (через vh) — на зуме браузера это расходилось (vh и фиксированные px реагируют
   на зум по-разному), из-за чего комната то обрезала персонажа, то расходилась с чатом.
   Flexbox сам корректно отдаёт "остаток" комнате при любом зуме/размере окна — это и
   есть JS/display:none в HTML переключает на 'flex' после логина (см. js/socket.js). */
#gameScreen {
  flex-direction: column;
  /* Сдвинуто вниз + укорочено ровно на высоту баннера (см. --announcement-h в :root
     выше) — когда баннера нет, calc(100vh - 0px)=100vh и margin-top:0px, то есть
     ничего не меняется относительно старого поведения. */
  height: calc(100vh - var(--announcement-h, 0px));
  margin-top: var(--announcement-h, 0px);
}

/* Баннер-объявление (см. js/announcement.js) — намеренно position:fixed, НЕ
   участвует в потоке #topZone/#room (см. комментарий у #announcementBanner
   в index.html: на мобильном #topBar сам fixed с подогнанными отступами,
   вставлять туда ещё один элемент в поток было бы рискованно). Просто
   перекрывает самый верх экрана поверх всего (z-index выше любого другого
   фиксированного слоя в игре), пока не закрыт крестиком или не истёк срок. */
#announcementBanner {
  display: none;
  align-items: center;
  gap: 10px;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20000;
  padding: 10px 16px;
  background: #4a3f1a;
  color: #fde9b0;
  font-size: 14px;
  line-height: 1.4;
  box-shadow: 0 2px 8px rgba(0,0,0,0.25);
}
#announcementText {
  flex: 1;
  word-break: break-word;
}
#announcementCloseBtn {
  flex-shrink: 0;
  background: transparent;
  border: none;
  color: inherit;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  padding: 4px 6px;
  opacity: 0.8;
}
#announcementCloseBtn:hover {
  opacity: 1;
}

/* Раньше flex-shrink:0 — на невысоких окнах (короткий 13" ноутбук, урезанный по
   высоте браузер) topZone требовал себе ПОЛНУЮ высоту (topBar+чат+строка ввода),
   а #room (min-height:0 ниже) сжимался почти до нуля вместе с персонажем в нём —
   на некоторых экранах персонаж становился почти невидимым. Теперь topZone тоже
   может сжиматься — но не сам целиком (topBar и #chatInput внутри него по
   отдельности flex-shrink:0, см. их правила), а именно #topPanel (чат/онлайн)
   отдаёт место первым — у него уже есть внутренний скролл (#chatMessages,
   #onlineSection), терять контент при сжатии ему нечего.
   min-height здесь — не 0, а сумма реальных полов детей (40 topBar + 140 topPanel +
   ~65 chatInput с отступами, см. их правила) — БЕЗ него на экстремально низком окне
   (после того как #room{min-height} подняли под фиксированный размер персонажа, см.
   #room ниже и js/layout.js) браузер мог ужать #topZone flexbox'ом НИЖЕ суммы
   собственных минимумов его детей — те просто визуально вылезали за пределы своего
   сжатого родителя и перекрывали #room снизу, вместо аккуратного скролла страницы. */
#topZone {
  min-height: 260px;
  display: flex;
  flex-direction: column;
}

/* ===== ПЕРЕКЛЮЧАТЕЛЬ ЯЗЫКА ===== */
.lang-switcher {
  display: flex;
  gap: 4px;
  background: rgba(255, 255, 255, 0.9);
  padding: 4px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

/* На экране входа переключатель — плавающий, в углу поверх формы.
   В игре (.lang-switcher-game) он теперь просто обычный элемент внутри #topBar,
   позиционировать отдельно не нужно. */
.lang-switcher-auth {
  position: fixed;
  top: 8px;
  right: 8px;
  z-index: 2000;
}

/* Базовый .lang-switcher-select (белый текст на тёмном) рассчитан на игровой топбар
   (см. admin_styles.css) — здесь, поверх светлой плашки экрана входа, нужен обратный
   контраст: тёмный текст на белом, как раньше было у кнопок-переключателей. */
.lang-switcher-auth .lang-switcher-select {
  border: 1px solid #ddd;
  background: white;
  color: #555;
  font-weight: 700;
}

.lang-switcher-auth .lang-switcher-select:hover {
  border-color: #667eea;
  color: #667eea;
}

/* ===== ЛОГИН ===== */
#loginScreen {
  position: fixed;
  inset: 0;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

#loginBox {
  background: white;
  padding: 40px;
  border-radius: 12px;
  box-shadow: 0 10px 40px rgba(0,0,0,0.3);
  text-align: center;
}

#loginBox h2 {
  margin-top: 0;
  color: #333;
}

#loginBox input {
  padding: 12px;
  width: 250px;
  border: 2px solid #ddd;
  border-radius: 6px;
  font-size: 16px;
  margin: 10px 0;
}

#loginBox button {
  padding: 12px 30px;
  background: #667eea;
  color: white;
  border: none;
  border-radius: 6px;
  font-size: 16px;
  cursor: pointer;
  margin-top: 10px;
}

#loginBox button:hover {
  background: #5568d3;
}

#loginError {
  color: red;
  margin-top: 10px;
  display: none;
}

/* ===== ВЕРХНЯЯ ПАНЕЛЬ ===== */
/* top/height сдвинуты на 40px — под #topBar (языки/профиль/админка), который
   виден всем залогиненным и всегда занимает эту полосу сверху (см. admin_styles.css). */
#topPanel {
  /* flex (не жёсткий height) — на нехватку вертикального места (короткое окно)
     панель теперь сама сжимается первой, отдавая место #room/персонажу, вместо
     того чтобы требовать полные var(--panel-h) и сжимать комнату до почти нуля
     (см. #topZone/#room выше). min-height — чат/онлайн всё ещё читаемы и
     прокручиваются (#chatMessages/#onlineSection: overflow-y:auto), не пропадают совсем. */
  flex: 1 1 var(--panel-h);
  min-height: 140px;
  display: grid;
  grid-template-columns: 1fr 250px;
  background: #f9f9f9;
  border-bottom: 2px solid #ddd;
}

/* Чат */
#chatSection {
  display: flex;
  flex-direction: column;
  padding: 10px;
  overflow: hidden;
}

#roomBrowserBtn,
#referralsBtn,
#wallFeedBtn,
#achievementsBtn,
#leaderboardBtn,
#battlePassBtn,
#minigamesBtn,
#faqBtn,
#rulesBtn,
#supportBtn,
#logoutBtn {
  padding: 8px 14px;
  border: 1px solid #ddd;
  border-radius: 6px;
  background: white;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s;
}

#roomBrowserBtn:hover,
#referralsBtn:hover,
#wallFeedBtn:hover,
#achievementsBtn:hover,
#leaderboardBtn:hover,
#battlePassBtn:hover,
#minigamesBtn:hover,
#faqBtn:hover,
#rulesBtn:hover,
#supportBtn:hover {
  background: #f5f6ff;
}

/* Прижата к правому краю вместе с остальными кнопками .topbar-right-group (см.
   admin_styles.css) — с лёгким красноватым акцентом, чтобы визуально читаться
   как "выход/опасное" действие. */
#logoutBtn {
  color: #d32f2f;
  border-color: #f0c2c2;
}

#logoutBtn:hover {
  background: #fdf1f1;
}

#chatTabs {
  display: flex;
  gap: 5px;
  margin-bottom: 10px;
  border-bottom: 1px solid #ddd;
  flex-wrap: wrap;
  flex-shrink: 0;
}

/* ===== ЛИЧНЫЕ ЧАТЫ — ВЫПАДАЮЩИЙ СПИСОК (не по вкладке на человека) ===== */
.private-chats-dropdown {
  position: relative;
}

.private-chats-toggle {
  position: relative;
  display: flex;
  align-items: center;
  gap: 4px;
}

.private-chats-arrow {
  font-size: 10px;
  opacity: 0.6;
}

.private-chats-list {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  min-width: 180px;
  max-height: 260px;
  overflow-y: auto;
  background: white;
  border: 1px solid #ddd;
  border-radius: 6px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
  animation: privateChatsListSlideIn 0.15s ease-out; /* "выезжает" — на каждый показ (display:none->block перезапускает анимацию) */
  z-index: 20;
}

@keyframes privateChatsListSlideIn {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: translateY(0); }
}

.private-chat-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  cursor: pointer;
  border-bottom: 1px solid #f0f0f0;
}

.private-chat-row:last-child {
  border-bottom: none;
}

.private-chat-row:hover {
  background: #f7f8fc;
}

.private-chat-row.active {
  background: #eef0ff;
  font-weight: 600;
}

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

.private-chat-row-unread-dot {
  display: inline-block; /* тоже используется внутри .chatTab (не flex) — без этого span не примет width/height/radius */
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #e74c3c;
  flex-shrink: 0;
  margin: 0 2px;
  vertical-align: middle;
}

.private-chat-row-close {
  flex-shrink: 0;
  color: #999;
  font-size: 12px;
  padding: 2px 4px;
}

.private-chat-row-close:hover {
  color: #e74c3c;
}

.chatTab {
  padding: 8px 12px;
  cursor: pointer;
  border: none;
  background: white;
  border-bottom: 2px solid transparent;
  border-radius: 4px 4px 0 0;
}

.chatTab:hover {
  background: #f0f0f0;
}

/* Кнопка-переключатель списка "Онлайн" — скрыта по умолчанию (на десктопе список и
   так всегда виден сайдбаром рядом с чатом, см. #topPanel grid-template-columns
   выше), появляется только в мобильном оверлее чата (см. @media pointer:coarse
   ниже), где #onlineSection больше не показан как отдельная колонка. */
#onlineToggleBtn {
  display: none;
  align-items: center;
  gap: 4px;
  margin-left: auto;
  padding: 6px 10px;
  border: none;
  border-radius: 4px;
  background: #f0f0f0;
  font-size: 14px;
  cursor: pointer;
}

.chatTab.active {
  border-bottom-color: #667eea;
  background: white;
  font-weight: bold;
}

.chatTab .close {
  margin-left: 8px;
  color: #999;
  font-weight: bold;
}

.chatTab .close:hover {
  color: #ff0000;
}

#chatMessages {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  background: white;
  border: 1px solid #ddd;
  border-radius: 6px;
  padding: 10px;
  min-height: 0;
}

#chatMessages::-webkit-scrollbar {
  width: 8px;
}

#chatMessages::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 4px;
}

#chatMessages::-webkit-scrollbar-thumb {
  background: #888;
  border-radius: 4px;
}

#chatMessages::-webkit-scrollbar-thumb:hover {
  background: #555;
}

.message {
  margin-bottom: 8px;
  padding: 6px;
  border-radius: 4px;
  overflow-wrap: break-word;
}

.message .text {
  overflow-wrap: break-word;
}

.message.system {
  color: #888;
  font-style: italic;
  text-align: center;
}

/* Своё сообщение — та же подсветка фоном что в личке (own) и в общем чате
   (own-general), раньше в общем чате вместо фона был жирный текст самого
   сообщения — выглядело как будто "кричишь", а не просто "это моё сообщение". */
.message.own,
.message.own-general {
  background: #e3f2fd;
}

.message .username {
  font-weight: bold;
  margin-right: 5px;
}

/* "@ник" в тексте сообщения чата комнаты (см. renderMessageTextWithMentions
   в js/chat.js) — тому, кого упомянули, ещё и реальное уведомление со звуком
   прилетает (processMentions в server.js), это просто визуальная метка в самом
   чате, чтобы упоминание сразу бросалось в глаза всем, кто читает переписку. */
.chat-mention {
  background: #fff3cd;
  color: #8a6d00;
  padding: 0 3px;
  border-radius: 4px;
  font-weight: 600;
}

.message .time {
  font-size: 10px;
  color: #888;
  margin-left: 5px;
}

/* Онлайн */
#onlineSection {
  border-left: 1px solid #ddd;
  padding: 10px;
  background: white;
  overflow-y: auto;
}

#onlineSection::-webkit-scrollbar {
  width: 8px;
}

#onlineSection::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 4px;
}

#onlineSection::-webkit-scrollbar-thumb {
  background: #888;
  border-radius: 4px;
}

#onlineSection::-webkit-scrollbar-thumb:hover {
  background: #555;
}

#onlineSection h3 {
  margin: 0 0 10px 0;
  font-size: 14px;
}

/* Скрыта на десктопе — там #onlineSection просто сайдбар без своего оверлея, закрывать
   нечего. Появляется только в мобильном оверлее (@media pointer:coarse ниже), где она
   нужна, т.к. #onlineSection на мобильном перекрывает собой #onlineToggleBtn. */
#onlineCloseBtn {
  display: none;
  margin-left: auto;
  border: none;
  background: none;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  color: #888;
  padding: 4px;
}

.user {
  padding: 5px;
  border-bottom: 1px solid #eee;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 13px;
}

.user:hover {
  background: #e8e8e8;
}

.user.me {
  background: #e3f2fd;
}

/* Подсветка роли в списке "Онлайн": фиолетовый — создатель игры, красный — владелец
   текущей комнаты, оранжевый — её модератор (см. userRoleHighlightClass в socket.js). */
.user.user-role-creator .user-name-wrap {
  color: #8e44ad;
  font-weight: 700;
}

.user.user-role-room-owner .user-name-wrap {
  color: #e74c3c;
  font-weight: 700;
}

.user.user-role-room-moderator .user-name-wrap {
  color: #e67e22;
  font-weight: 700;
}

.user-name-wrap {
  display: flex;
  align-items: center;
  gap: 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.user-actions {
  display: flex;
  gap: 6px;
  flex-shrink: 0;
  margin-left: 6px;
}

.user-action-icon {
  font-size: 12px;
  cursor: pointer;
  opacity: 0.7;
  transition: opacity 0.15s, transform 0.15s;
}

.user-action-icon:hover {
  opacity: 1;
  transform: scale(1.2);
}

.user-rating {
  font-size: 11px;
  color: #b8860b;
  font-weight: 700;
  white-space: nowrap;
  margin-left: 6px;
}

/* Медаль ранга (топ-3 по рейтингу) — золото/серебро/бронза, слева от имени.
   Используется и в списке "Онлайн", и над персонажем в комнате (.rank-medal-name). */
.rank-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  font-size: 10px;
  font-weight: 800;
  line-height: 1;
  flex-shrink: 0;
}

.rank-badge.rank-1 { background: #FFD700; color: #5c4b00; }
.rank-badge.rank-2 { background: #C0C0C0; color: #3a3a3a; }
.rank-badge.rank-3 { background: #CD7F32; color: #3a1d00; }

.rank-medal-name {
  display: inline-flex;
  vertical-align: middle;
  margin-right: 4px;
}

.rank-medal-name:empty {
  margin-right: 0;
}

/* Над персонажем имя крупное (.playerName, font-size: 38px) — медаль там должна
   быть под стать имени, а не оставаться маленькой, как в списке "Онлайн". */
.playerName .rank-badge {
  width: 34px;
  height: 34px;
  font-size: 20px;
}

.playerName .rank-medal-name {
  margin-right: 8px;
}

/* Бейдж VIP-статуса (см. /api/vip/purchase) — тот же принцип, что .rank-badge
   выше: маленький в списке "Онлайн", крупнее над персонажем в комнате. */
.vip-tag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 4px;
  height: 15px;
  border-radius: 4px;
  font-size: 9px;
  font-weight: 800;
  line-height: 1;
  flex-shrink: 0;
  background: linear-gradient(135deg, #FFD700, #FFA500);
  color: #5c4b00;
}

.vip-badge-name {
  display: inline-flex;
  vertical-align: middle;
  margin-right: 4px;
}

.vip-badge-name:empty {
  margin-right: 0;
}

.playerName .vip-tag {
  height: 22px;
  padding: 0 8px;
  font-size: 14px;
  border-radius: 6px;
}

.playerName .vip-badge-name {
  margin-right: 8px;
}

/* ===== КОМНАТА ===== */
#room {
  position: relative; /* система координат для scrollArrow/returnBtn/roomContent ниже */
  /* flex-shrink:0 (через "1 0 auto") — комната не отдаёт место #topPanel при нехватке
     высоты окна (это #topPanel сжимается первым, см. fitPanelToCharacter() в
     js/layout.js), только растёт (flex-grow), когда места в избытке. min-height —
     запасной пол на случай самого первого кадра до того, как отработает JS; реально
     нужную высоту (~391px при текущем --scale, т.е. персонаж влезает целиком без
     обрезания через overflow:hidden ниже) на каждом ресайзе/старте уже гарантирует
     сама fitPanelToCharacter(), сжимая чат — так что на практике до этого пола
     дело почти не доходит. */
  flex: 1 0 auto;
  min-height: 400px;
  background: white;
  overflow: hidden;
  user-select: none; /* двойной клик по комнате не должен выделять текст/картинки под курсором */
}

#roomContent {
  position: absolute;
  width: 100%;
  height: 100%;
  transition: transform 0.3s ease;
}

#playersContainer {
  position: relative;
  width: 100%;
  height: 100%;
}

/* Стрелки прокрутки — размер вдвое меньше прежнего и менее контрастный/яркий фон
   (0.6→0.35 непрозрачности, белый текст приглушён до 0.8), чтобы не бросались в глаза. */
.scrollArrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 30px;
  height: 40px;
  background: rgba(0,0,0,0.35);
  color: rgba(255,255,255,0.8);
  border: none;
  border-radius: 4px;
  font-size: 12px;
  cursor: pointer;
  z-index: 10;
  transition: background 0.2s;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 3px;
}

.scrollArrow:hover {
  background: rgba(0,0,0,0.5);
}

#leftArrow {
  left: 10px;
}

#rightArrow {
  right: 10px;
}

.arrowIcon {
  font-size: 12px;
  line-height: 1;
}

.arrowCount {
  font-size: 8px;
  margin-top: 3px;
}

/* Кнопка возврата к персонажу */
#returnBtn {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 12px 24px;
  background: rgba(0,0,0,0.7);
  color: white;
  border: none;
  border-radius: 8px;
  font-size: 16px;
  cursor: pointer;
  z-index: 15;
  display: none;
  transition: background 0.2s;
}

#returnBtn:hover {
  background: rgba(0,0,0,0.9);
}

/* Силуэт города на фоне (кастомный рисунок pic/custom/city.png) — тайлится по
   горизонтали (repeat-x) вместе с прокруткой комнаты, лежит позади персонажей
   (z-index ниже .player) и не должен ловить клики (иначе перехватывал бы двойной
   клик "вернуться к себе"). bottom РАВЕН высоте #floor (дороги) ниже — город
   начинается ровно НАД дорогой, а не под ней (иначе дорога рисуется поверх и
   перекрывает нижнюю часть города, т.к. #floor имеет более высокий z-index).
   Ширина тайла и высота посчитаны из реального соотношения сторон картинки (7800x1348)
   и подобраны так, чтобы город смотрелся пропорционально рядом с персонажем при его
   текущем фиксированном --scale (см. style.css :root и js/layout.js). Фиксированные
   px, а не завязка на --scale — если размер персонажа поменяют, эти числа стоит
   пересверить глазами, а не полагаться на автоматический пересчёт.
   Комната концептуально бесконечна в обе стороны от спавна (см. ROOM_X_LIMIT в
   server.js) — ширина тут просто заведомо больше этой защитной границы (не завязана
   на неё математически, background-repeat тайлится одинаково дёшево при любом
   размере блока), чтобы дорога/город никогда не заканчивались раньше, чем мог
   реально дойти персонаж. */
#citySkyline {
  position: absolute;
  bottom: 50px; /* = высота #floor ниже — держать в синхроне при её изменении */
  left: -220000px;
  width: 440000px;
  height: 136px;
  background-image: url("/pic/custom/city.png");
  background-repeat: repeat-x;
  background-position: bottom left;
  background-size: 787px 136px;
  pointer-events: none;
  z-index: 1;
}

/* Дорога (кастомный рисунок pic/custom/doroga.png) под ногами персонажа — тайлится
   так же, как город выше, лежит ПОВЕРХ него (z-index:2 > 1), но всё ещё позади
   .player (z-index:10). Персонаж приподнят на её высоту через .player{bottom} ниже,
   чтобы стоять именно НА дороге, а не проваливаться в неё по колено. Ширина тайла
   посчитана из реального соотношения сторон картинки (775x140). */
#floor {
  position: absolute;
  bottom: 0;
  left: -220000px;
  width: 440000px;
  height: 50px;
  background-image: url("/pic/custom/doroga.png");
  background-repeat: repeat-x;
  background-position: bottom left;
  background-size: 277px 50px;
  pointer-events: none;
  z-index: 2;
}

/* ===== МОДЕЛЬ ===== */
.playerModel {
  position: relative;
  width: 332px;
  height: 520px;
}

/* Общий слой для крыльев обнимающейся пары (см. moveWingsToHugLayer/
   checkHandHoldPairs в js/player.js) — воспроизводит те же left/bottom/transform,
   что и .player, поэтому крылья из .playerModel можно переносить сюда как есть.
   z-index:1 — заведомо ниже z-index:10 у любого .player (позади ВСЕХ персонажей,
   а не только своего тела), но ВЫШЕ фона (#citySkyline/#floor — у них z-index не
   задан вовсе, т.е. auto; без явного z-index здесь спор с ними решался бы порядком
   в DOM, и крылья иногда оказывались бы позади города — см. чат). */
.hug-wings-wrapper {
  position: absolute;
  z-index: 1;
  bottom: 25px; /* держать в синхроне с .player{bottom} ниже — воспроизводит её позицию */
  /* Те же width/height, что у .playerModel — все дети внутри position:absolute
     (сами .wing-mount), без явного размера обёртка схлопнулась бы до 0×0, и
     transform-origin:bottom center считал бы центр от НУЛЕВОЙ ширины (левый
     край) вместо центра тела — крылья визуально "улетали" в сторону при
     масштабировании (см. чат). */
  width: 332px;
  height: 520px;
  transform: scale(var(--scale));
  transform-origin: bottom center;
  pointer-events: none;
}

/* Подсветка под ногами топ-3 игроков комнаты по рейтингу (золото/серебро/бронза) —
   первый ребёнок .playerModel, поэтому по умолчанию (без z-index, порядок DOM) рисуется
   ПОД телом/одеждой, но НАД полом/фоном (те снаружи .player, который уже z-index:10).
   Класс rank-N вешает/снимает updatePlayerRankBadges() (js/socket.js) вместе с самой
   медалью у имени — та же логика computeTopRanks(), один источник правды. */
.player-rank-glow {
  position: absolute;
  left: 50%;
  bottom: -22px;
  transform: translateX(-50%);
  width: 260px;
  height: 62px;
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  filter: blur(4px);
  animation: rank-glow-pulse 1.8s ease-in-out infinite;
}

/* Внешний ореол через box-shadow — светит вокруг персонажа, а не только там, где
   элипс не закрыт ногами/одеждой (иначе на светлой одежде подсветку почти не видно,
   см. чат — на тёмном платье золото было заметно, на светлых штанах серебро терялось). */
@keyframes rank-glow-pulse {
  0%, 100% { transform: translateX(-50%) scale(1); opacity: 0.9; }
  50% { transform: translateX(-50%) scale(1.15); opacity: 1; }
}

.player-rank-glow.rank-1 {
  opacity: 1;
  background: radial-gradient(ellipse at center, rgba(255, 225, 60, 0.95) 0%, rgba(255, 195, 0, 0.6) 40%, rgba(255, 170, 0, 0) 75%);
  box-shadow: 0 0 45px 18px rgba(255, 200, 0, 0.55);
}

.player-rank-glow.rank-2 {
  opacity: 1;
  background: radial-gradient(ellipse at center, rgba(190, 110, 255, 0.95) 0%, rgba(160, 70, 230, 0.6) 40%, rgba(140, 50, 210, 0) 75%);
  box-shadow: 0 0 45px 18px rgba(160, 70, 230, 0.55);
}

.player-rank-glow.rank-3 {
  opacity: 1;
  background: radial-gradient(ellipse at center, rgba(70, 150, 255, 0.95) 0%, rgba(30, 110, 240, 0.6) 40%, rgba(20, 90, 220, 0) 75%);
  box-shadow: 0 0 45px 18px rgba(30, 110, 240, 0.55);
}

/* SVG-персонаж: моргание глазами + цвет кожи/глаз через CSS-переменные */
.avatar-body-mount {
  position: absolute;
  left: -34.05px;
  bottom: -51.08px;
  width: 400.1px;
  pointer-events: none;
}

.avatar-body-mount svg.avatar-body {
  display: block;
  width: 100%;
  height: auto;
}

.avatar-body .skin      { fill: var(--skin-color, #E8B48C); }
.avatar-body .iris      { fill: var(--eye-color, #3B7DD8); }
.avatar-body .sclera    { fill: #ffffff; }
.avatar-body .pupil     { fill: #1c1c1c; }
.avatar-body .highlight { fill: #ffffff; }
.avatar-body .eyebrow   { fill: none; stroke: var(--eyebrow-color, #6b4a35); stroke-width: 5; stroke-linecap: round; }
.avatar-body .lash      { stroke: #4a3226; stroke-width: 3; stroke-linecap: round; }
.avatar-body .cheek     { fill: var(--cheek-color, #f28b82); opacity: 0.45; }
.avatar-body .mouth     { fill: none; stroke: #b8654a; stroke-width: 4; stroke-linecap: round; }
.avatar-body .mouth-cavity { fill: #7a3838; }
.avatar-body .mouth-teeth  { fill: #ffffff; }
.avatar-body .eyelid    { fill: none; stroke: #8a6a52; stroke-width: 2.5; stroke-linecap: round; opacity: 0.6; }
.avatar-body .eyeshadow { fill: var(--eyeshadow-color, #c07fe0); opacity: 0.5; }
.avatar-body .neckline  { fill: none; stroke: #b8865f; stroke-width: 3; opacity: 0.4; stroke-linecap: round; }
.avatar-body .skin-shadow    { fill: #b8865f; opacity: 0.35; }
.avatar-body .skin-highlight { fill: #ffe8cf; opacity: 0.45; }

.avatar-body .eyes-closed { display: none; }
.avatar-body.blink .eyes-open { display: none; }
.avatar-body.blink .eyes-closed { display: block; }

/* Рот — 4 варианта нарисованы заранее внутри SVG, переключаются через
   setAvatarMouth() (js/avatar.js) простым show/hide нужной группы. */
.avatar-body .mouth-variant { display: none; }
.avatar-body .mouth-variant.mouth-smile { display: block; }

/* Перекрашиваемая одежда из PNG (нарисована в оттенках серого) — тот же холст 300x470/900x1410,
   поэтому позиционируется идентично .avatar-body-mount и ложится на тело пиксель-в-пиксель. */
.clothing-mount {
  position: absolute;
  left: -34.05px;
  bottom: -51.08px;
  width: 400.1px;
  pointer-events: none;
}

/* Крылья — правое и левое это два ОТДЕЛЬНЫХ рисунка (зеркальная пара). Размер
   бокса (width/left) и точка крепления к спине (transform-origin) выставляются
   ИНЛАЙНОМ из JS (см. applyWingsLayout/WINGS_LAYOUT_STANDARD/WIDE в js/avatar.js),
   а не тут статикой — у разных крыльев разный формат холста (старый 1410x2310
   у большинства вещей, новый 2820x2310 "wide" у широких вроде "Крылья 4"), и
   инлайн-стиль каждый раз подбирается под конкретную загруженную картинку.
   Раз рисунки — зеркальная пара, у взмаха ПРОТИВОПОЛОЖНЫЕ по знаку углы поворота
   (иначе кончики расходятся вразнобой, а не взмахивают навстречу друг другу).
   Лёгкое scaleY-сжатие в нижней точке взмаха усиливает ощущение "хлопка",
   а не просто наклона. */
/* alternate + всего 2 кадра = один непрерывный ход туда-обратно за полный
   цикл (браузер сам проигрывает 0%→100%, потом реверсом 100%→0% по той же
   кривой) — без промежуточных ключевых кадров скорость нигде не обнуляется
   посреди цикла, поэтому нет "рывков"; ease-in-out просто плавно тормозит
   в двух крайних точках взмаха, как и должно быть у естественного покачивания. */
.wing-mount.right { animation: wing-flap-right 1.6s ease-in-out infinite alternate; }
.wing-mount.left  { animation: wing-flap-left  1.6s ease-in-out infinite alternate; }
@keyframes wing-flap-right {
  0%   { transform: rotate(-9deg); }
  100% { transform: rotate(9deg); }
}
@keyframes wing-flap-left {
  0%   { transform: rotate(9deg); }
  100% { transform: rotate(-9deg); }
}

/* Дрон — облетает голову по кругу справа. ВАЖНО: раньше позиционировался
   пикселями от .playerModel — а у него разные размеры в комнате и в
   примерочной (конфликтующие правила: 520px/729px высоты + свой scale() в
   примерочной), поэтому дрон "плавал" в разных местах. Теперь бокс
   .drone-orbit-mount — точно та же коробка, что у .avatar-body-mount
   (left/bottom/width) — она everywhere одинаковая, на ней и тело, и вся
   одежда уже надёжно выровнены. Высота выставлена явно (400.1 × 770/470,
   тот же коэффициент, что у ширины/высоты viewBox тела) — сам бокс не
   рисует ничего, только даёт систему координат для процентного пивота.
   Точка облёта — 24%/25% внутри этого бокса (слева и чуть выше середины
   головы). Радиус совсем крошечный (6px) — почти незаметное покачивание
   на месте, а не облёт по-настоящему. Вложенные слои: внешний крутится
   360deg (даёт лёгкое кружение — картинка смещена от центра на радиус
   ORBIT_R), внутренний крутится в ОБРАТНУЮ сторону с той же скоростью —
   компенсирует вращение внешнего, чтобы сам дрон оставался "прямым",
   а не кувыркался. */
.drone-orbit-mount {
  position: absolute;
  left: -34.05px;
  bottom: -51.08px;
  width: 400.1px;
  height: 655.64px;
  pointer-events: none;
}
.drone-pivot {
  position: absolute;
  top: -1%;
  left: 112%;
  width: 0;
  height: 0;
}
.drone-orbit-spin {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  transform-origin: 0 0;
  animation: drone-orbit 6s linear infinite;
}
.drone-counter-spin {
  position: absolute;
  top: 0;
  left: 0;
  transform-origin: 0 0;
  transform: translate(25px, 0);
  animation: drone-counter-orbit 6s linear infinite;
}
.drone-img {
  display: block;
  width: 480px;
  height: auto;
  animation: drone-wobble 1.4s ease-in-out infinite alternate;
}
@keyframes drone-orbit {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
@keyframes drone-counter-orbit {
  from { transform: translate(25px, 0) rotate(0deg); }
  to   { transform: translate(25px, 0) rotate(-360deg); }
}
@keyframes drone-wobble {
  from { transform: translate(-50%, -50%) rotate(-7deg); }
  to   { transform: translate(-50%, -50%) rotate(7deg); }
}

/* Сердечки при "взятии за руки" разнополых персонажей (см. checkHandHoldPairs/spawnHugHearts
   в js/player.js) — контейнер ставится на середину между персонажами через left/top в
   реальных экранных px (position:fixed, поверх всего, как и дрон/чат), сами сердечки —
   его дети, взлетают вверх и растворяются каждое по своей небольшой задержке. */
.hugHeartsContainer {
  position: fixed;
  width: 0;
  height: 0;
  pointer-events: none;
  z-index: 9998;
}

.hugHeart {
  --hug-drift: 0px;
  position: absolute;
  bottom: 0;
  left: 0;
  font-size: 28px;
  opacity: 0;
  transform: translate(-50%, 0) scale(0.6);
  animation: hug-heart-rise 2s ease-out forwards;
}

@keyframes hug-heart-rise {
  0% { opacity: 0; transform: translate(-50%, 0) scale(0.6); }
  15% { opacity: 1; transform: translate(calc(-50% + var(--hug-drift) * 0.2), -20px) scale(1); }
  100% { opacity: 0; transform: translate(calc(-50% + var(--hug-drift)), -140px) scale(1.1); }
}

.raster-item {
  position: relative;
  width: 100%;
}

/* Раскраска считается в JS через <canvas> (см. avatar.js paintRasterClothingCanvas) —
   так надёжнее CSS mask-image, у которой маска по умолчанию строится по яркости
   пикселя, а не по прозрачности, и перепады серого (тени/блики) "протравливали" цвет. */
.raster-item-canvas {
  display: block;
  width: 100%;
  height: auto;
}

/* Вещи с фиксированным (не перекрашиваемым) цветом — просто картинка на весь мешок одежды,
   без canvas-раскраски. Не путать с легаси-классом .layer ниже — у него другие,
   более старые размеры/позиционирование, оставшиеся от прошлой системы персонажа. */
.clothing-static-img {
  display: block;
  width: 100%;
  height: auto;
  pointer-events: none;
}

.layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 332px;
  height: 729px;
  pointer-events: none;
}

.clothes { display: none; }

/* ===== ПЕРСОНАЖИ ===== */
.player {
  /* --scale наследуется с :root — простая константа, одинаковая на любом экране
     (см. :root выше и fitPanelToCharacter() в js/layout.js). */
  position: absolute;
  bottom: 25px; /* по просьбе — стоит примерно на СЕРЕДИНЕ дороги (#floor, height:50px
                   ниже), а не на самом верхнем её краю (было bottom:50px = вровень
                   с высотой дороги). Это сырой px, не масштабируется через --scale,
                   так что подошвы всегда на одной и той же точке дороги независимо
                   от размера персонажа. .hug-wings-wrapper выше держит то же число,
                   чтобы крылья в объятиях не съезжали относительно тела. */
  transform: scale(var(--scale));
  transform-origin: bottom center;
  z-index: 10;
}

/* Приватная сцена ЛС (см. enterPrivateScene в js/player.js) — прячет всех, кроме
   меня и собеседника, пока открыта вкладка личной переписки с ним. */
.player-scene-hidden {
  display: none;
}

/* Декорации комнаты (см. renderRoomDecoration в js/rooms.js) — тот же принцип
   масштаба, что и у .player, но свободны по обеим осям (left И bottom), а не
   зафиксированы на дороге, и чисто декоративны — не кликабельны в v1. */
.room-decoration {
  position: absolute;
  /* SVG-декорации (pic/custom/decor/*.svg) задают только viewBox, без width/height —
     без явного ограничения <img> раздувается до дефолтного intrinsic-размера
     браузера (обычно ~300px), из-за чего предмет получался в разы крупнее
     персонажа. max-width/max-height вместе с width/height:auto вписывают любую
     картинку (портретную, широкую, узкую) в общий бокс, сохраняя пропорции. */
  max-width: 160px;
  max-height: 220px;
  width: auto;
  height: auto;
  transform: scale(var(--scale));
  transform-origin: bottom left;
  pointer-events: none;
  z-index: 5;
}

/* Добавляется на #myPlayer только на момент отпускания после свободного подъёма
   по экрану (см. setupPlayerDrag в js/player.js, пока персонаж временно position:fixed
   в <body>) — персонаж "падает" обратно на землю быстро, но плавно (ease-in-out), а не
   мгновенно телепортируется вниз. Транзиция именно на top (не transform) — в этом режиме
   позиция кодируется через top/left, а transform используется только для scale. Снимается
   при следующем захвате, чтобы само перетаскивание оставалось мгновенным (1:1 с мышью). */
.player.falling {
  transition: top 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

#myPlayer {
  cursor: grab;
  z-index: 15;
  /* Без этого браузер на тач-устройстве пытается ещё и прокрутить/зумить страницу
     пальцем поверх начатого драга персонажа (см. touch-обработчики в js/player.js) —
     конфликт жестов. Только на своём персонаже, других это не касается. */
  touch-action: none;
}

.playerName {
  position: absolute;
  top: -130px; /* прямо над головой (тело виден в локальных, не экранных px — .player целиком масштабируется через --scale) с отступом */
  left: 50%;
  transform: translateX(-50%);
  background: none;
  color: #000;
  padding: 0;
  border: none;
  box-shadow: none;
  font-size: 38px;
  font-weight: 700;
  white-space: nowrap;
  pointer-events: none;
}

/* Временный пузырь над персонажем с текстом сообщения — исчезает через 5 сек
   (js/chat.js: showChatBubble), не показывается для ЛС, только для чата комнаты. */
.chatBubble {
  position: absolute;
  top: -260px;
  left: 50%;
  transform: translateX(-50%);
  min-width: 120px;
  max-width: 520px;
  background: white;
  color: #222;
  padding: 14px 20px;
  border-radius: 22px;
  font-size: 34px;
  font-weight: 600;
  line-height: 1.3;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);
  white-space: pre-wrap;
  word-break: break-word;
  text-align: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s;
  z-index: 25;
}

.chatBubble.visible {
  opacity: 1;
}

.chatBubble::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 14px solid transparent;
  border-top-color: white;
}

/* ===== ПАНЕЛЬ ВВОДА ===== */
#chatInput {
  position: relative; /* система координат для #replyPreviewBar (bottom:100% от этой панели) */
  flex-shrink: 0;
  display: flex;
  gap: 10px;
  margin: 8px 10px;
  background: white;
  padding: 10px;
  border: 1px solid #ddd;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

/* На узких экранах 3 кнопки по min-width:120px (см. правило #sendBtn.../ниже) вместе с
   полем ввода гарантированно не помещаются в одну строку — раньше здесь вообще не было
   мобильного правила, и панель просто визуально переполнялась/обрезалась. Переносим
   поле ввода на свою строку (flex-basis:100%), кнопки — равными по ширине ниже. */
@media (max-width: 768px) {
  #chatInput {
    flex-wrap: wrap;
  }
  /* Составной селектор — не просто #messageInputWrap: у него ниже по файлу (строка
     ~1036) есть безусловное правило flex:1 с ТОЙ ЖЕ специфичностью, которое побеждало
     бы это (более раннее по каскаду) правило, если бы не более высокая специфичность
     здесь. */
  #chatInput #messageInputWrap {
    flex: 1 1 100%;
  }
  #chatInput #sendBtn,
  #chatInput #shopBtn,
  #chatInput #friendsBtn {
    flex: 1;
    min-width: 0;
    padding: 10px 6px;
    font-size: 13px;
  }
}

/* ===== ОТВЕТ НА СООБЩЕНИЕ ===== */
#replyPreviewBar {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 100%;
  margin-bottom: 6px;
  display: flex;
  align-items: center;
  gap: 8px;
  background: white;
  border: 1px solid #ddd;
  border-left: 3px solid #667eea;
  border-radius: 6px;
  padding: 8px 10px;
  box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
}

#replyPreviewText {
  flex: 1;
  font-size: 13px;
  color: #555;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

#replyCancelBtn {
  border: none;
  background: none;
  cursor: pointer;
  font-size: 14px;
  color: #999;
  flex-shrink: 0;
}

#replyCancelBtn:hover {
  color: #d9534f;
}

/* Круглые кнопки записи/отправки голосового — стоп/отправить/отмена, вместо
   обычных прямоугольных кнопок с текстом (единый стиль с мессенджерами). */
.voice-round-btn {
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  border: none;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  transition: transform 0.1s, background 0.15s;
}

.voice-round-btn:hover {
  transform: scale(1.08);
}

/* 30px заметно меньше рекомендованного ~44px минимального тач-таргета — увеличиваем
   только на реальном тач-устройстве, чтобы не менять привычный десктопный вид. */
@media (pointer: coarse) {
  .voice-round-btn {
    width: 44px;
    height: 44px;
    font-size: 18px;
  }
}

.voice-stop-btn {
  background: #d9534f;
  color: white;
}

.voice-stop-btn:hover {
  background: #c9302c;
}

.voice-send-btn {
  background: #667eea;
  color: white;
  font-size: 15px;
  padding-left: 2px; /* оптически центрирует стрелку "➤" */
}

.voice-send-btn:hover {
  background: #5568d3;
}

.voice-cancel-btn {
  background: #f0f0f0;
  color: #888;
}

.voice-cancel-btn:hover {
  background: #e6e6e6;
  color: #d9534f;
}

.chat-reply-quote {
  display: block;
  font-size: 12px;
  color: #667eea;
  border-left: 2px solid #667eea;
  padding-left: 6px;
  margin-bottom: 3px;
  opacity: 0.85;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.message-reply-btn, .message-delete-btn, .message-report-btn {
  border: none;
  background: none;
  cursor: pointer;
  font-size: 12px;
  color: #999;
  opacity: 0;
  transition: opacity 0.15s;
  margin-left: 4px;
}

.message:hover .message-reply-btn, .message:hover .message-delete-btn, .message:hover .message-report-btn {
  opacity: 1;
}

.message-reply-btn:hover {
  color: #667eea;
}

.message-delete-btn:hover {
  color: #d9534f;
}

.message-report-btn:hover {
  color: #e6a817;
}

/* :hover просто не существует на тач-устройствах — без этого кнопки ответить/
   удалить/пожаловаться (opacity:0 по умолчанию, видны только по :hover) были бы
   НЕВИДИМЫ всегда на телефоне/планшете, хоть технически и оставались бы кликабельны
   "вслепую". pointer:coarse — поведенческая, не косметическая штука (отличает
   реальный тач от просто узкого/зумленного десктопа), поэтому именно на нём, а не
   на max-width, см. этот же приём для #topPanel выше. */
@media (pointer: coarse) {
  .message-reply-btn, .message-delete-btn, .message-report-btn {
    opacity: 1;
  }
}

/* ===== ИГРОВОЕ КОНТЕКСТНОЕ МЕНЮ (правый клик) ===== */
#gameContextMenu {
  position: fixed;
  z-index: 3000;
  min-width: 160px;
  background: white;
  border: 1px solid #ddd;
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
  padding: 4px;
  display: flex;
  flex-direction: column;
}

.context-menu-item {
  border: none;
  background: none;
  text-align: left;
  padding: 8px 12px;
  font-size: 13px;
  color: #333;
  border-radius: 5px;
  cursor: pointer;
}

.context-menu-item:hover {
  background: #f0f1ff;
  color: #667eea;
}

.context-menu-item.danger:hover {
  background: #fdeeee;
  color: #d9534f;
}

.context-menu-separator {
  height: 1px;
  background: #eee;
  margin: 4px 2px;
}

/* Поле ввода сообщения со значками микрофона/смайлика прямо внутри него
   (справа), а не отдельными кнопками рядом — как в мессенджерах. */
#messageInputWrap {
  position: relative;
  flex: 1;
  display: flex;
}

#messageInputWrap #messageInput {
  flex: 1;
  /* 3 значка (эмодзи/голос/фото ЛС, см. #emojiPickerWrap/#voiceRecordBtn/#pmPhotoBtn
     выше) — фото скрыто в чате комнаты, но отступ общий, проще одно значение. */
  padding-right: 92px;
}

/* ===== ГОЛОСОВЫЕ СООБЩЕНИЯ ===== */
#voiceRecordBtn {
  position: absolute;
  top: 50%;
  right: 34px;
  transform: translateY(-50%);
  border: none;
  background: none;
  padding: 4px;
  font-size: 18px;
  line-height: 1;
  color: #888;
  cursor: pointer;
}

#voiceRecordBtn:hover {
  color: #667eea;
}

/* Без явного width/height кнопка сжимается до content-box (~26px) — заметно меньше
   рекомендованного ~44px тач-таргета. Увеличиваем только padding (иконка визуально
   остаётся тем же 18px эмодзи), только на реальном тач-устройстве. #emojiPickerBtn
   сюда НЕ включаем — у него ниже по файлу (строка ~1198) есть более позднее
   безусловное правило с той же специфичностью (#emojiPickerBtn{padding:4px}),
   которое побеждало бы это — переопределяем его отдельно, уже ПОСЛЕ той строки. */
@media (pointer: coarse) {
  #voiceRecordBtn {
    padding: 13px;
  }
}

#voiceRecordBtn.recording {
  color: #d9534f;
}

/* Тот же слот-паттерн, что у #voiceRecordBtn/#emojiPickerBtn — следующая позиция
   правее (см. right: 6px/34px там). Только ЛС — см. switchChatTab в chat.js. */
#pmPhotoBtn {
  position: absolute;
  top: 50%;
  right: 62px;
  transform: translateY(-50%);
  border: none;
  background: none;
  padding: 4px;
  font-size: 18px;
  line-height: 1;
  color: #888;
  cursor: pointer;
}

#pmPhotoBtn:hover {
  color: #667eea;
}

@media (pointer: coarse) {
  #pmPhotoBtn {
    padding: 13px;
  }
}

#voiceRecordingBar, #voicePreviewBar {
  flex: 1;
  display: flex;
  align-items: center;
  gap: 10px;
}

#voicePreviewBar audio {
  flex: 1;
  height: 32px;
}

.voice-rec-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #d9534f;
  flex-shrink: 0;
  animation: voice-rec-pulse 1s ease-in-out infinite;
}

@keyframes voice-rec-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}

#voiceRecordingTimer {
  font-variant-numeric: tabular-nums;
  color: #d9534f;
  font-weight: 600;
}

.voice-message audio {
  height: 34px;
  max-width: 220px;
  vertical-align: middle;
}

#chatCooldownNotice {
  align-self: center;
  white-space: nowrap;
  font-size: 12px;
  color: #d9534f;
  font-weight: 600;
  flex-shrink: 0;
}

/* Исчезающее фото в ЛС — см. js/chat.js (viewPrivatePhoto/'private-photo-expired'). */
.pm-photo-wrap {
  display: inline-block;
  position: relative;
}

.pm-photo-hidden {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 14px;
  border-radius: 10px;
  background: #3730a3;
  color: #fff;
  cursor: pointer;
  font-size: 13px;
}

.pm-photo-hidden:hover {
  background: #4338ca;
}

.pm-photo-img {
  display: block;
  max-width: 220px;
  max-height: 220px;
  border-radius: 10px;
  object-fit: contain;
}

.pm-photo-countdown {
  position: absolute;
  top: 4px;
  right: 4px;
  padding: 2px 6px;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.pm-photo-expired {
  display: inline-block;
  padding: 10px 14px;
  border-radius: 10px;
  background: #f0f0f0;
  color: #888;
  font-size: 13px;
  font-style: italic;
}

#chatInput input {
  flex: 1;
  padding: 12px;
  border: 1px solid #ddd;
  border-radius: 6px;
  font-size: 14px;
}

/* ===== СМАЙЛИКИ ===== */
#emojiPickerWrap {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
}

#emojiPickerBtn {
  border: none;
  background: none;
  padding: 4px;
  font-size: 18px;
  line-height: 1;
  color: #888;
  cursor: pointer;
}

#emojiPickerBtn:hover {
  color: #667eea;
}

@media (pointer: coarse) {
  #emojiPickerBtn {
    padding: 13px;
  }
}

#emojiPickerPanel {
  position: absolute;
  bottom: calc(100% + 8px);
  right: 0;
  width: 280px;
  height: 300px;
  background: white;
  border: 1px solid #ddd;
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  z-index: 1000;
}

.emoji-tabs {
  display: flex;
  border-bottom: 1px solid #eee;
  flex-shrink: 0;
}

.emoji-tab-btn {
  flex: 1;
  padding: 8px 0;
  border: none;
  background: none;
  font-size: 16px;
  cursor: pointer;
  border-bottom: 2px solid transparent;
}

.emoji-tab-btn:hover {
  background: #f5f5f5;
}

.emoji-tab-btn.active {
  border-bottom-color: #667eea;
  background: #f5f6ff;
}

.emoji-grid {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 6px;
}

.emoji-grid::-webkit-scrollbar {
  width: 8px;
}

.emoji-grid::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 4px;
}

.emoji-grid::-webkit-scrollbar-thumb {
  background: #ccc;
  border-radius: 4px;
}

.emoji-grid::-webkit-scrollbar-thumb:hover {
  background: #aaa;
}

.emoji-grid-page {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
}

.emoji-btn {
  border: none;
  background: none;
  font-size: 20px;
  line-height: 1;
  padding: 6px 0;
  cursor: pointer;
  border-radius: 4px;
}

.emoji-btn:hover {
  background: #f0f0f0;
}

@media (max-width: 768px) {
  #emojiPickerPanel {
    width: 240px;
    right: -8px;
  }
}

#sendBtn,
#shopBtn,
#profileBtn,
#friendsBtn {
  padding: 12px 24px;
  color: white;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 500;
  transition: background 0.2s;
  white-space: nowrap;
  min-width: 120px;
}

#sendBtn {
  background: #667eea;
}

#sendBtn:hover {
  background: #5568d3;
}

#shopBtn {
  background: #4CAF50;
}

#shopBtn:hover {
  background: #45a049;
}

#profileBtn {
  background: #764ba2;
}

#profileBtn:hover {
  background: #653d8c;
}

#friendsBtn {
  background: #e6a817;
}

#friendsBtn:hover {
  background: #cc9412;
}

/* ===== МАГАЗИН ===== */
#shopOverlay {
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.4);
  display: none;
  z-index: 1000;
}

#shopWindow {
  width: 900px;
  height: 500px;
  background: linear-gradient(#8fd3f4, #eaf8ff);
  border-radius: 12px;
  position: absolute;
  inset: 0;
  margin: auto;
  display: flex;
  flex-direction: column;
}

#shopHeader {
  padding: 10px;
  font-weight: bold;
  display: flex;
  justify-content: space-between;
}

#shopBody {
  flex: 1;
  display: grid;
  grid-template-columns: 200px 1fr 260px;
}

#categories {
  padding: 10px;
}

#items {
  padding: 20px;
  display: grid;
  grid-template-columns: repeat(2, 160px);
  gap: 20px;
  align-content: start;
}

.item {
  background: white;
  border-radius: 14px;
  height: 180px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.item img {
  max-width: 100%;
  max-height: 100%;
}

.item.active {
  box-shadow: inset 0 0 0 3px gold;
}

#preview {
  position: relative;
}

#previewPlayer {
  position: absolute;
  bottom: 100px;
  left: 50%;
  transform: translateX(-50%) scale(0.35);
  transform-origin: bottom center;
}

/* ===== ЭКРАН АВТОРИЗАЦИИ ===== */
#authScreen {
  position: fixed;
  inset: 0;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  display: flex;
  align-items: center;
  /* Прогрессивное улучшение: обычный center — если контент (особенно длинная
     форма регистрации) выше экрана, современные браузеры с safe center сами
     переключаются на выравнивание сверху вместо того, чтобы обрезать верх
     недоступной для скролла частью — на старых браузерах просто останется center. */
  align-items: safe center;
  justify-content: center;
  overflow-y: auto;
  padding: 30px 0;
  box-sizing: border-box;
  z-index: 1000;
}

/* Декоративные персонажи по бокам экрана входа — те же SVG-аватарки, что и в
   игре (js/avatar.js), просто без одежды. Скрываются на узких экранах, чтобы
   не мешать самой форме входа. */
.auth-mascot {
  position: absolute;
  bottom: 0;
  width: 220px;
  pointer-events: none;
  z-index: 1;
  filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.25));
}

.auth-mascot svg.avatar-body {
  width: 100%;
  height: auto;
  display: block;
}

.auth-mascot-left {
  left: 40px;
}

.auth-mascot-right {
  right: 40px;
}

@media (max-width: 1150px) {
  .auth-mascot {
    display: none;
  }
}

#authBox {
  background: white;
  padding: 40px;
  border-radius: 12px;
  box-shadow: 0 10px 40px rgba(0,0,0,0.3);
  width: 520px;
  max-width: 92vw;
  box-sizing: border-box;
  position: relative;
  z-index: 2;
  transition: width 0.2s;
}

/* Форма регистрации даёт полям и выбору внешности по колонке, а не одну под
   другой — шире, чем форма входа, чтобы обе колонки нормально помещались. */
#authBox.auth-box-wide {
  width: 700px;
}

/* ========== ДВЕ КОЛОНКИ В ФОРМЕ РЕГИСТРАЦИИ ========== */
/* Слева — все текстовые поля (логин/email/пароли/капча), справа — выбор пола
   персонажа и его внешности. Раньше всё шло одной колонкой и форма сильно
   растягивалась вниз, упираясь в высоту экрана. */
.register-columns {
  display: flex;
  gap: 28px;
  align-items: flex-start;
}

.register-col {
  flex: 1;
  min-width: 0;
}

@media (max-width: 640px) {
  #authBox.auth-box-wide {
    width: 520px;
  }

  .register-columns {
    flex-direction: column;
    gap: 0;
  }
}

@media (max-width: 480px) {
  #authBox {
    padding: 24px 18px;
  }
}

.auth-logo {
  display: block;
  height: 56px;
  margin: 0 auto 12px;
}

#authBox h2 {
  margin-top: 0;
  color: #333;
  text-align: center;
}

.auth-stats {
  text-align: center;
  font-size: 13px;
  color: #888;
  margin: -8px 0 18px;
}

/* ========== ПРАВИЛА ИСПОЛЬЗОВАНИЯ (форма регистрации) ========== */

.rules-box {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 12px 14px;
  max-height: 160px;
  overflow-y: auto;
  margin-bottom: 10px;
  background: #fafafa;
}

.rules-box h4 {
  margin: 0 0 8px;
  font-size: 14px;
  color: #333;
}

.rules-box-intro {
  margin: 0 0 10px;
  font-size: 12px;
  color: #777;
  line-height: 1.4;
}

.rules-box-subtitle {
  margin: 12px 0 4px;
  font-size: 12px;
  font-weight: 700;
  color: #555;
}

.rules-box-subtitle:first-of-type {
  margin-top: 0;
}

.rules-list {
  margin: 0;
  padding-left: 18px;
  font-size: 12px;
  color: #555;
  line-height: 1.5;
}

.rules-list li {
  margin-bottom: 6px;
}

.rules-accept-label {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  font-size: 13px;
  color: #444;
  margin-bottom: 14px;
  cursor: pointer;
}

.rules-accept-label input {
  margin-top: 2px;
  flex-shrink: 0;
}

.rules-accept-label span {
  flex: 1;
  min-width: 0;
}

#authButtons {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
}

.auth-switch-btn {
  flex: 1;
  padding: 12px;
  border: 2px solid #667eea;
  background: white;
  color: #667eea;
  border-radius: 6px;
  font-size: 16px;
  cursor: pointer;
  transition: all 0.3s;
}

.auth-switch-btn.active {
  background: #667eea;
  color: white;
}

.auth-switch-btn:hover {
  background: #5568d3;
  color: white;
  border-color: #5568d3;
}

.auth-form input {
  width: 100%;
  padding: 12px;
  margin-bottom: 15px;
  border: 2px solid #ddd;
  border-radius: 6px;
  font-size: 14px;
  transition: border-color 0.3s;
}

.auth-form input:focus {
  outline: none;
  border-color: #667eea;
}

/* .auth-form input бьёт по умолчанию width:100%/паддинги/рамку на все инпуты
   формы, включая чекбокс "согласен с правилами" — из-за этого он растягивался
   на всю ширину строки и выталкивал текст правил за пределы окна. Сбрасываем
   именно для чекбоксов, оставляя обычные текстовые поля как есть. */
.auth-form input[type="checkbox"] {
  width: auto;
  padding: 0;
  margin: 0;
  border: none;
  flex-shrink: 0;
}

.auth-form button {
  width: 100%;
  padding: 12px;
  background: #667eea;
  color: white;
  border: none;
  border-radius: 6px;
  font-size: 16px;
  cursor: pointer;
  transition: background 0.3s;
  margin-bottom: 10px;
}

.auth-form button:hover {
  background: #5568d3;
}

.auth-form button:disabled {
  background: #ccc;
  cursor: not-allowed;
}

.gender-select {
  margin-bottom: 15px;
}

.gender-select label {
  display: block;
  margin-bottom: 8px;
  color: #333;
  font-weight: 500;
}

.gender-options {
  display: flex;
  gap: 15px;
}

.gender-option {
  flex: 1;
  padding: 12px;
  border: 2px solid #ddd;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.3s;
  display: flex;
  align-items: center;
  justify-content: center;
}

.gender-option:hover {
  border-color: #667eea;
  background: #f0f0ff;
}

.gender-option input[type="radio"] {
  margin-right: 8px;
  margin-bottom: 0;
}

.gender-option input[type="radio"]:checked + span {
  font-weight: bold;
  color: #667eea;
}

/* ===== ВНЕШНОСТЬ ПРИ РЕГИСТРАЦИИ ===== */
.appearance-select {
  margin-bottom: 15px;
}

.appearance-select label {
  display: block;
  margin-bottom: 8px;
  color: #333;
  font-weight: 500;
}

.reg-avatar-preview {
  width: 120px;
  height: 188px;
  margin: 0 auto 12px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.reg-avatar-preview svg.avatar-body {
  width: 100%;
  height: auto;
}

.skin-swatches {
  display: flex;
  gap: 8px;
  margin-bottom: 15px;
  justify-content: center;
}

.skin-swatch {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 2px solid #ddd;
  cursor: pointer;
  padding: 0;
  transition: transform 0.15s, border-color 0.15s;
}

.skin-swatch:hover {
  transform: scale(1.1);
}

.skin-swatch.selected {
  border-color: #667eea;
  box-shadow: 0 0 0 2px #667eea;
}

.eye-color-input {
  width: 60px !important;
  height: 40px;
  padding: 2px !important;
  cursor: pointer;
  margin: 0 auto 15px !important;
  display: block;
}

#codeSection {
  margin-top: 15px;
}

.error-msg {
  color: #d32f2f;
  font-size: 14px;
  margin-top: 10px;
  display: none;
  padding: 8px;
  background: #ffebee;
  border-radius: 4px;
  text-align: center;
}

.success-msg {
  color: #388e3c;
  font-size: 14px;
  margin-top: 10px;
  display: none;
  padding: 8px;
  background: #e8f5e9;
  border-radius: 4px;
  text-align: center;
}

.error-msg.show,
.success-msg.show {
  display: block;
}

/* ========== СТИЛИ ДЛЯ МАГАЗИНА ========== */

/* Оверлей магазина */
#shopOverlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.7);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  backdrop-filter: blur(5px);
}

#shopWindow {
  background: white;
  width: 90%;
  max-width: 1000px;
  height: 80vh;
  border-radius: 20px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 0 10px 50px rgba(0, 0, 0, 0.5);
}

/* Заголовок магазина */
.shop-header {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  padding: 20px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.shop-header h2 {
  margin: 0;
  font-size: 28px;
}

.coins-timer-container {
  display: flex;
  gap: 15px;
  align-items: center;
}

.coin-icon {
  font-size: 20px;
}

.shop-coins {
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(255, 255, 255, 0.2);
  padding: 8px 16px;
  border-radius: 20px;
  font-size: 18px;
  font-weight: bold;
}

.coin-timer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
}

#coinTimer {
  font-size: 14px;
  font-weight: bold;
  color: white;
}

#claimCoinsBtn {
  padding: 6px 12px;
  background: rgba(76, 175, 80, 0.9);
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  font-size: 13px;
  font-weight: bold;
  transition: all 0.3s;
  white-space: nowrap;
}

#claimCoinsBtn:hover:not(:disabled) {
  background: rgba(76, 175, 80, 1);
  transform: scale(1.05);
}

#claimCoinsBtn:disabled {
  background: rgba(255, 255, 255, 0.2);
  cursor: not-allowed;
  opacity: 0.5;
}

.close-shop-btn {
  background: rgba(255, 255, 255, 0.2);
  border: none;
  color: white;
  font-size: 24px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  cursor: pointer;
  transition: background 0.3s;
}

.close-shop-btn:hover {
  background: rgba(255, 255, 255, 0.3);
}

/* Контейнер магазина */
.shop-container {
  display: flex;
  flex: 1;
  overflow: hidden;
}

/* Боковая панель */
.shop-sidebar {
  width: 200px;
  background: #f5f5f5;
  padding: 15px;
  overflow-y: auto;
  border-right: 1px solid #ddd;
}

.shop-category-btn {
  width: 100%;
  padding: 12px 15px;
  margin-bottom: 8px;
  background: white;
  border: 2px solid transparent;
  border-radius: 8px;
  cursor: pointer;
  font-size: 14px;
  text-align: left;
  transition: all 0.3s;
  color: #333;
}

.shop-category-btn:hover {
  background: #e8e8e8;
  transform: translateX(5px);
}

.shop-category-btn.active {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  border-color: #667eea;
  font-weight: bold;
}

/* Контент магазина */
#shopContent {
  flex: 1;
  padding: 20px;
  overflow-y: auto;
}

#shopContent h3 {
  margin: 0 0 20px 0;
  font-size: 24px;
  color: #333;
}

/* Сетка предметов */
.shop-items-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 15px;
}

/* Карточка предмета */
.shop-item-card {
  background: white;
  border: 2px solid #e0e0e0;
  border-radius: 12px;
  overflow: hidden;
  transition: all 0.3s;
  cursor: pointer;
}

.shop-item-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
  border-color: #667eea;
}

.item-image {
  width: 100%;
  height: 150px;
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.item-image img {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.item-info {
  padding: 10px;
}

.item-price {
  font-size: 18px;
  font-weight: bold;
  color: #FFA500;
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  gap: 5px;
}

.item-actions {
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.item-btn {
  padding: 8px 12px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
  transition: all 0.3s;
}

.buy-btn {
  background: linear-gradient(135deg, #4CAF50, #45a049);
  color: white;
}

.buy-btn:hover:not(:disabled) {
  background: linear-gradient(135deg, #45a049, #3d8b40);
  transform: scale(1.05);
}

.buy-btn:disabled {
  background: #ccc;
  cursor: not-allowed;
  opacity: 0.6;
}

.equip-btn {
  background: linear-gradient(135deg, #2196F3, #1976D2);
  color: white;
}

.equip-btn:hover:not(:disabled) {
  background: linear-gradient(135deg, #1976D2, #0D47A1);
  transform: scale(1.05);
}

/* Общее правило для disabled-состояния любой кнопки .item-btn (например
   .room-place-decor-btn, когда игрок открыл управление чужой/другой своей
   комнатой, а не той, где физически стоит) — без него кнопка выглядит как
   обычная активная и клик молча ничего не делает, что уже путало пользователя. */
.item-btn:disabled {
  background: #ccc !important;
  color: #888;
  cursor: not-allowed;
  transform: none !important;
}

.unequip-btn {
  background: linear-gradient(135deg, #FF9800, #F57C00);
  color: white;
}

.unequip-btn:hover {
  background: linear-gradient(135deg, #F57C00, #E65100);
  transform: scale(1.05);
}

.sell-btn {
  background: linear-gradient(135deg, #f44336, #d32f2f);
  color: white;
  font-size: 12px;
}

.sell-btn:hover {
  background: linear-gradient(135deg, #d32f2f, #b71c1c);
  transform: scale(1.05);
}

.owned-btn {
  background: #e0e0e0;
  color: #666;
  cursor: not-allowed;
}

/* Сообщение когда нет предметов */
.no-items {
  text-align: center;
  color: #999;
  font-size: 16px;
  padding: 40px;
  grid-column: 1 / -1;
}

/* Скроллбары */
.shop-sidebar::-webkit-scrollbar,
#shopContent::-webkit-scrollbar {
  width: 8px;
}

.shop-sidebar::-webkit-scrollbar-track,
#shopContent::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 4px;
}

.shop-sidebar::-webkit-scrollbar-thumb,
#shopContent::-webkit-scrollbar-thumb {
  background: #888;
  border-radius: 4px;
}

.shop-sidebar::-webkit-scrollbar-thumb:hover,
#shopContent::-webkit-scrollbar-thumb:hover {
  background: #555;
}

/* Кнопка чата — по умолчанию скрыта, показывается только в мобильном @media ниже.
   Должна идти ПЕРЕД этим @media в исходнике — иначе более позднее правило
   display:none (равный приоритет, тот же селектор) перебивает display:flex из-под
   медиа-запроса, и кнопка никогда не показывается даже на мобильном экране. */
/* Больше не плавающий кругляш поверх страницы — обычный flex-ребёнок #topBar (сидит
   в тонкой мобильной полосе рядом с #mobileMenuBtn, см. index.html/@media ниже). */
#chatToggleBtn {
  display: none;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: #667eea;
  color: white;
  font-size: 18px;
  cursor: pointer;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

#chatToggleBtn.active {
  background: #4a5bc4;
}

/* Тот же принцип, что и у #chatToggleBtn выше — скрыта на десктопе всегда, размер/вид
   задаются здесь, а сама видимость (display:flex) включается только в мобильном
   @media ниже. */
#mobileMenuBtn {
  display: none;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  color: white;
  font-size: 20px;
  cursor: pointer;
}

#mobileMenuBtn.active {
  background: rgba(255, 255, 255, 0.28);
}

/* Видимый текст рядом с иконкой (уведомления/звук) — нужен только когда кнопка стоит
   строкой в мобильном ☰-меню (см. @media ниже, #mobileMenu .mobile-menu-label);
   на десктопе, где это компактная иконка в топбаре, скрыт. */
.mobile-menu-label {
  display: none;
}

/* Адаптив */
@media (max-width: 768px) {
  #shopWindow {
    width: 95%;
    height: 90vh;
  }
  
  .shop-sidebar {
    width: 150px;
    padding: 10px;
  }
  
  .shop-category-btn {
    font-size: 12px;
    padding: 10px;
  }
  
  .shop-items-grid {
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 10px;
  }
  
  #coinsDisplay {
    top: 5px;
    right: 5px;
    padding: 8px 15px;
    font-size: 16px;
  }

  #onlineSection {
    max-height: 35vh;
  }
}

/* Оверлей чата (#topPanel становится position:fixed, убирая его из потока #topZone —
   #room тут же занимает освободившееся место; персонаж при этом остаётся тем же
   фиксированным размером — --scale константа, см. :root и fitPanelToCharacter() в
   js/layout.js — просто вокруг него становится больше свободного места) включаем
   ТОЛЬКО на реальных тач-устройствах (pointer:coarse), а не просто по ширине экрана.
   Раньше это было частью обычного `max-width:768px` — но зум браузера тоже уменьшает
   CSS-ширину viewport, и на десктопе, если зумиться сильно (~175%+), можно было
   случайно "перескочить" через эту границу и получить рывок раскладки на ровном
   месте. pointer:coarse (мышь/тачпад — "fine", палец — "coarse") не зависит от зума
   и реагирует только на реальный тип устройства ввода. */
@media (max-width: 768px) and (pointer: coarse) {
  /* #topZone{min-height} (см. базовое правило) рассчитан на десктопный набор
     топбар+чат+ввод, всегда видимых одновременно. На мобильном #topBar теперь САМ
     position:fixed (см. ниже, та же схема, что уже была у #topPanel/#chatInput) — то
     есть НИ ОДИН из детей #topZone больше не участвует в обычном потоке, реальная
     высота #topZone всегда 0 и ему нечего резервировать. */
  #topZone {
    min-height: 0;
  }

  /* Раньше пробовали position:sticky — не сработало: sticky-элемент может "прилипать"
     только в пределах бокса СВОЕГО родителя, а высота #topZone (родителя) была ровно
     равна высоте самого топбара (40px) — ни одного пикселя запаса, чтобы вообще было
     где "прилипать" (стика без запаса — то же самое, что её нет). position:fixed —
     та же, уже проверенная на #topPanel/#mobileMenu/#chatInput схема: не участвует в
     потоке вообще, значит не может никуда "уехать" вместе с переполнившимся контентом
     под ним, вне зависимости от арифметики высот. */
  #topBar {
    position: fixed;
    /* var(--announcement-h) — см. :root выше: 0px, когда баннера-объявления нет
       (то же, что раньше), иначе топбар сдвигается под баннер, а не прячется под ним. */
    top: var(--announcement-h, 0px);
    left: 0;
    right: 0;
    z-index: 800;
  }

  /* Раз топбар теперь fixed (вне потока) — #room начинается от самого верха #gameScreen,
     и без отступа его верхние 40px были бы визуально ПОД топбаром (тот сверху, по
     z-index) — padding-top компенсирует тем же отступом, что и top:40px у
     #topPanel/#mobileMenu.
     Остальное — на десктопе #room нарочно растягивается на весь остаток экрана через
     flex-grow, лишнее место просто становится фоном вокруг персонажа фиксированного
     размера (см. :root/fitPanelToCharacter в js/layout.js). На мобильном в портретной
     ориентации то же самое поведение выглядит иначе: топбар+чат/меню занимают в
     закрытом состоянии считанные 40px, и #room растягивается на ПОЧТИ ВЕСЬ экран
     (700+px на иных телефонах) — персонаж, стоящий у своего нижнего края, визуально
     "проваливается" в самый низ огромной пустой комнаты (см. фото пользователя).
     Ограничиваем высоту разумным потолком и центрируем по вертикали в оставшемся
     месте (margin:auto по основной оси flex-колонки #gameScreen — стандартный приём
     центрирования flex-item). max-height (не жёсткая height) — оставляет
     #room{min-height:400px} рабочим полом и позволяет ужаться ниже потолка, если
     реально не хватает места (короткий landscape — там #room просто ляжет вплотную
     под fixed-топбар без скролла всей страницы, а не утащит топбар за собой, как
     было со sticky). */
  #room {
    /* +40 к базовому 400px (см. общее правило #room выше по файлу) компенсирует
       резервируемую под топбар полосу у #roomContent ниже — без этого персонажу
       (привязан к НИЖНЕМУ краю комнаты) снова не хватило бы места сверху, та же
       проблема обрезания, что чинили через #room{min-height} изначально. */
    min-height: 440px;
    flex-grow: 0;
    max-height: 560px;
    margin: auto 0;
  }

  /* #roomContent — то, что раньше сдвигали через #room{padding-top}: НЕ сработало —
     у абсолютно спозиционированного height:100%-ребёнка (как здесь) проценты по
     высоте считаются от PADDING-бокса родителя целиком (включая сам padding), а не
     от урезанной им области, так что 40px padding-top у #room просто сдвигал верх
     #roomContent вниз, ОСТАВЛЯЯ высоту прежней (100% = полный бокс) — в сумме нижний
     край съезжал на те же 40px ЗА пределы #room, и обрезался тем самым overflow:hidden
     (обрезалась не верхняя, а НИЖНЯЯ часть сцены — персонаж/пол). Явные top+bottom
     вместо height:100% растягивают #roomContent ровно между ними, без этой ловушки. */
  #roomContent {
    top: calc(40px + var(--announcement-h, 0px));
    bottom: 0;
    height: auto;
  }

  #mobileMenuBtn,
  #chatToggleBtn {
    display: flex;
    width: 32px;
    height: 32px;
    flex-shrink: 0;
  }

  #topPanel {
    position: fixed;
    display: none;
    top: calc(40px + var(--announcement-h, 0px));
    left: 0;
    right: 0;
    height: 70vh;
    z-index: 550;
    grid-template-columns: 1fr;
    /* Список "Онлайн" больше не второй колонкой (см. #onlineSection ниже — он теперь
       спрятан и всплывает отдельным оверлеем), так что в гриде остаётся только
       #chatSection. Без явного grid-template-rows:1fr его единственная строка была бы
       auto-размера (по содержимому), и чат НЕ растягивался бы на все 70vh высоты
       #topPanel — оставалась бы пустая полоса снизу вместо расширенного чата. */
    grid-template-rows: 1fr;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
  }

  /* Кнопка появляется только здесь — на десктопе #onlineSection всегда видна сама. */
  #onlineToggleBtn {
    display: flex;
  }

  /* Список "Онлайн" убран из чата по умолчанию (раньше "max-height:35vh" в общем
     мобильном блоке выше по файлу занимал заметную часть экрана чата даже когда
     никто не спрашивал список) и теперь всплывает отдельным полноэкранным (в рамках
     той же области, что и #topPanel) оверлеем по кнопке #onlineToggleBtn. */
  #onlineSection {
    display: none;
    position: fixed;
    top: calc(40px + var(--announcement-h, 0px));
    left: 0;
    right: 0;
    height: 70vh;
    max-height: none;
    z-index: 560;
    border-left: none;
  }

  #topZone.mobile-online-open #onlineSection {
    display: block;
  }

  #onlineSection h3 {
    display: flex;
    align-items: center;
  }

  #onlineCloseBtn {
    display: block;
  }

  /* Переключатель — на общем родителе #topZone (а не на #topPanel самом по себе, как
     было раньше), потому что 💬 теперь должен одновременно открывать И список
     сообщений (#topPanel), И строку ввода (#chatInput) — а они соседи, не вложены
     друг в друга, один класс на общем предке открывает оба разом. */
  #topZone.mobile-chat-open #topPanel {
    display: grid;
  }

  /* Строка ввода сообщения — на десктопе всегда в потоке; на мобильном по умолчанию
     скрыта (без этого между чатом и персонажем остаётся протяжённый всегда-видимый
     кусок с полями ввода/Друзья/Магазин — см. фото пользователя), появляется
     пристыкованной прямо под #topPanel только вместе с чатом. */
  #chatInput {
    display: none;
    position: fixed;
    top: calc(40px + 70vh);
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 550;
    margin: 0;
    border-radius: 0;
    overflow-y: auto;
    /* bottom:0 сам по себе не учитывает системную нижнюю область (жест-полоску/
       домашний индикатор) — на телефонах с ней кнопка "Отправить" оказывалась
       частично под ней/обрезанной снизу. env(...) с фолбэком 0 — на устройствах
       без такой области ничего не меняет. */
    padding-bottom: calc(10px + env(safe-area-inset-bottom, 0px));
    /* Реальная причина того, что "Отправить" выглядела съехавшей/огромной: у этого
       блока явная высота (разница между top и bottom, см. выше), а строки внутри
       переносятся (flex-wrap:wrap, см. общее @media(max-width:768px) правило выше
       по файлу) — без align-content браузер по умолчанию РАСТЯГИВАЕТ (stretch)
       обе строки (поле ввода и кнопку) поровну на всю освободившуюся высоту вместо
       того чтобы оставить им естественный размер. center — естественный размер
       обеих строк, с равным отступом сверху/снизу внутри отведённой области. */
    align-content: center;
  }

  #topZone.mobile-chat-open #chatInput {
    display: flex;
  }

  /* ☰-меню — те же 10 кнопок, что на десктопе живут в #topBar/#chatInput (см.
     applyMobileMenuLayout в js/layout.js — реальные DOM-узлы, не копии), просто
     в виде вертикального списка вместо тесной строки. Переключатель языка (11-й)
     туда не переезжает — остаётся в самой полосе рядом с ☰/💬, см. #topBar ниже. */
  #mobileMenu {
    position: fixed;
    top: calc(40px + var(--announcement-h, 0px));
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 700;
    display: none;
    flex-direction: column;
    overflow-y: auto;
    background: #fff;
  }

  #mobileMenu.open {
    display: flex;
  }

  #mobileMenu.open > * {
    width: 100%;
    box-sizing: border-box;
    margin: 0;
    padding: 14px 16px;
    border: none;
    border-bottom: 1px solid #eee;
    border-radius: 0;
    text-align: left;
    background: #fff;
    color: #222;
    font-size: 15px;
  }

  /* .icon-btn/.lang-switcher-select (admin_styles.css) — рассчитаны на тёмный фон
     #topBar (белый текст на полупрозрачном тёмном), на белом списке иначе нечитаемы. */
  #mobileMenu .icon-btn {
    color: #333;
    justify-content: flex-start;
    gap: 8px;
  }

  /* Подпись рядом с иконкой — на десктопе это просто иконка без текста (title только
     по hover мышью, на тач его не будет вовсе), в списке нужен видимый текст. */
  #mobileMenu .mobile-menu-label {
    display: inline;
    margin-left: 8px;
  }
}

/* ВСЕ контейнеры персонажа должны разрешать overflow */
.player {
  overflow: visible !important;
}

.playerModel {
  overflow: visible !important;
}

/* Базовый слой - персонаж остаётся 332×729 */
.layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 332px;
  height: 729px;
  pointer-events: none;
  object-fit: contain;
}

/* Базовое изображение персонажа */
.layer-base,
.layer:not([class*="-"]) {
  width: 332px !important;
  height: 729px !important;
}

/* Слои которые МОГУТ быть больше */
.layer-hat,
.layer-hair,
.layer-accs,
.layer-up,
.layer-down,
.layer-boots {
  position: absolute !important;
  /* Центрируем относительно персонажа */
  top: 50% !important;
  left: 50% !important;
  transform: translate(-50%, -50%) !important;
  /* Размер по содержимому изображения */
  width: auto !important;
  height: auto !important;
  max-width: none !important;
  max-height: none !important;
  object-fit: contain !important;
}

/* Для превью в магазине */
.shop-preview {
  overflow: visible !important;
}

.shop-preview .preview-character {
  overflow: visible !important;
}

.shop-preview .playerModel {
  overflow: visible !important;
}

#previewCharacter {
  overflow: visible !important;
}

#previewBase {
  width: 400.1px !important;
  height: 655.5px !important;
  bottom: -51.08px !important;
  left: -34.05px !important;
  transform: none !important;
}

#previewHair,
#previewHat,
#previewUp,
#previewDown,
#previewBoots,
#previewAccs {
  width: 400.1px !important;
  bottom: -51.08px !important;
  left: -34.05px !important;
}

/* Игровое поле тоже должно разрешать overflow */
#gameCanvas,
#gameContainer {
  overflow: visible !important;
}

/* Кнопки "Написать"/"Профиль" при клике на игрока — раньше тут была одна .pmButton
   с абсолютным позиционированием на себе, теперь обе кнопки лежат в общей
   .playerActionButtons, а позиционирование/масштаб — на обёртке. */
.playerActionButtons {
  position: absolute;
  top: -210px; /* Ещё выше - было -180px */
  left: 50%;
  transform: translateX(-50%) scale(2.3);
  transform-origin: center;
  display: none;
  gap: 8px;
  z-index: 20;
  transition: all 0.3s;
}

.playerActionButtons.visible {
  display: flex;
  animation: fadeIn 0.3s ease;
}

.playerActionButtons:hover {
  transform: translateX(-50%) scale(2.5); /* Чуть больше при наведении */
}

.pmButton,
.profileButton {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 10px;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: 0 4px 16px rgba(0,0,0,0.4);
  transition: box-shadow 0.3s;
  pointer-events: auto;
}

.playerActionButtons:hover .pmButton,
.playerActionButtons:hover .profileButton {
  box-shadow: 0 6px 20px rgba(0,0,0,0.5);
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(-10px) scale(2.3);
  }
  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0) scale(2.3);
  }
}
/* ===== Уровень персонажа ===== */
.level-bar {
  margin-bottom: 10px;
  padding: 8px 10px;
  background: linear-gradient(135deg, #f3f0ff, #e8f0ff);
  border: 1px solid #d7d2f5;
  border-radius: 10px;
}

.level-bar-head {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 12px;
}

.level-bar-level { font-weight: 800; color: #4a3fa8; }
.level-bar-title { color: #8a6d00; font-weight: 600; }
.level-bar-percent { margin-left: auto; font-weight: 700; color: #4a3fa8; }

.level-bar-track {
  height: 8px;
  margin: 5px 0 3px;
  background: #ddd8f5;
  border-radius: 4px;
  overflow: hidden;
}

.level-bar-fill {
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, #667eea, #764ba2);
  border-radius: 4px;
  transition: width 0.4s ease;
}

.level-bar-xp { font-size: 10px; color: #777; text-align: right; }

/* Бейдж уровня рядом с ником: маленький в списке "Онлайн", крупный над персонажем
   (тот же принцип, что .rank-badge/.vip-tag выше). */
.level-tag {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 5px;
  height: 15px;
  margin-right: 3px;
  border-radius: 4px;
  font-size: 9px;
  font-weight: 800;
  line-height: 1;
  flex-shrink: 0;
  background: linear-gradient(135deg, #667eea, #764ba2);
  color: #fff;
}

.level-badge-name {
  display: inline-flex;
  vertical-align: middle;
  margin-right: 4px;
}

.level-badge-name:empty { margin-right: 0; }

.playerName .level-tag {
  height: 22px;
  padding: 0 8px;
  font-size: 14px;
  border-radius: 6px;
}

.playerName .level-badge-name { margin-right: 8px; }

.level-toast {
  position: fixed;
  bottom: 90px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2000;
  background: linear-gradient(135deg, #667eea, #764ba2);
  color: #fff;
  padding: 10px 18px;
  border-radius: 12px;
  font-weight: 700;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
}

/* Свои декорации в своей комнате можно таскать (см. pointerdown в js/rooms.js) —
   класс включается на #playersContainer только владельцу в его комнате. */
#playersContainer.decor-editable .room-decoration {
  pointer-events: auto;
  cursor: grab;
  touch-action: none;
}

.room-decoration.dragging {
  cursor: grabbing;
  opacity: 0.8;
}

/* Блок "Удаление аккаунта" в своей анкете — визуально отделён от обычных настроек */
.profile-danger-zone {
  border: 1px solid #f5c2c0;
  background: #fff5f5;
}

/* ========== ГЛАВНАЯ СТРАНИЦА (экран входа) ========== */
/* Раньше на фоне была одна форма входа по центру — теперь это полноценная страница:
   слева описание игры, справа форма, ниже преимущества, шаги и ссылки на правила/
   юридические документы. Экран по-прежнему один и тот же #authScreen (прячется при логине). */
#authScreen {
  display: block;
  padding: 0;
  color: #fff;
}

.landing-wrap {
  max-width: 1180px;
  margin: 0 auto;
  padding: 64px 24px 24px;
  box-sizing: border-box;
}

.landing-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 48px;
  align-items: center;
}

.landing-intro { min-width: 0; }

.landing-badge {
  display: inline-block;
  padding: 5px 14px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.35);
  font-size: 13px;
  font-weight: 700;
  margin-bottom: 16px;
}

.landing-title {
  font-family: 'Baloo 2', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 46px;
  line-height: 1.1;
  margin: 0 0 14px;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);
}

.landing-lead {
  font-size: 18px;
  line-height: 1.5;
  margin: 0 0 18px;
  max-width: 560px;
  color: rgba(255, 255, 255, 0.92);
}

.landing-points {
  list-style: none;
  padding: 0;
  margin: 0 0 8px;
  display: grid;
  gap: 8px;
  font-size: 16px;
  font-weight: 600;
}

.landing-points li::before {
  content: '✓';
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  margin-right: 10px;
  border-radius: 50%;
  background: #fff;
  color: #667eea;
  font-size: 13px;
  font-weight: 800;
}

.landing-mascots {
  display: flex;
  gap: 8px;
  align-items: flex-end;
  margin-top: 14px;
}

.landing-mascots .auth-mascot {
  position: static;
  display: block;
  width: 150px;
}

.landing-section { margin-top: 72px; }

.landing-section-title {
  font-family: 'Baloo 2', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 32px;
  text-align: center;
  margin: 0 0 28px;
}

.landing-features {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
}

.landing-card {
  background: #fff;
  color: #333;
  border-radius: 16px;
  padding: 24px 22px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18);
}

.landing-card-icon {
  width: 52px;
  height: 52px;
  border-radius: 14px;
  background: linear-gradient(135deg, #667eea, #764ba2);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26px;
  margin-bottom: 14px;
}

.landing-card h3 { margin: 0 0 6px; font-size: 18px; color: #3d3494; }
.landing-card p { margin: 0; font-size: 14.5px; line-height: 1.55; color: #555; }

.landing-steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
}

.landing-step {
  position: relative;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 16px;
  padding: 22px;
}

.landing-step-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: #fff;
  color: #667eea;
  font-weight: 800;
  font-size: 18px;
  margin-bottom: 10px;
}

.landing-step h3 { margin: 0 0 6px; font-size: 18px; }
.landing-step p { margin: 0; font-size: 14.5px; line-height: 1.55; color: rgba(255, 255, 255, 0.9); }

.landing-footer {
  margin-top: 72px;
  padding: 22px 0 8px;
  border-top: 1px solid rgba(255, 255, 255, 0.3);
  text-align: center;
}

.landing-footer-links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 22px;
  font-size: 14px;
}

.landing-footer-links a { color: #fff; text-decoration: none; opacity: 0.92; }
.landing-footer-links a:hover { text-decoration: underline; opacity: 1; }
.landing-footer-copy { margin-top: 12px; font-size: 13px; opacity: 0.75; }

@media (max-width: 1000px) {
  .landing-hero { grid-template-columns: minmax(0, 1fr); justify-items: center; gap: 32px; }
  .landing-intro { text-align: center; }
  .landing-lead { margin-left: auto; margin-right: auto; }
  .landing-points { justify-content: center; justify-items: start; display: inline-grid; text-align: left; }
  .landing-mascots { justify-content: center; }
  .landing-features, .landing-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 640px) {
  .landing-wrap { padding: 56px 14px 18px; }
  .landing-title { font-size: 32px; }
  .landing-lead { font-size: 16px; }
  .landing-mascots { display: none; }
  .landing-features, .landing-steps { grid-template-columns: minmax(0, 1fr); }
  .landing-section { margin-top: 48px; }
  .landing-section-title { font-size: 26px; }
}

/* Текст внутри карточки входа остаётся тёмным, хотя сам экран теперь с белым текстом */
#authBox { color: #333; }

/* Форма регистрации широкая (700px) — рядом с ней описанию слева не хватает места, поэтому
   на экранах уже ~1250px при регистрации форма встаёт первой, а описание уходит под неё. */
@media (max-width: 1250px) {
  .landing-hero:has(#authBox.auth-box-wide) {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    gap: 32px;
  }
  .landing-hero:has(#authBox.auth-box-wide) #authBox { order: -1; }
  .landing-hero:has(#authBox.auth-box-wide) .landing-intro { text-align: center; }
  .landing-hero:has(#authBox.auth-box-wide) .landing-lead { margin-left: auto; margin-right: auto; }
  .landing-hero:has(#authBox.auth-box-wide) .landing-points { display: inline-grid; text-align: left; }
  .landing-hero:has(#authBox.auth-box-wide) .landing-mascots { justify-content: center; }
}

/* На узких экранах форма входа — первой (большинство приходит войти), описание ниже */
@media (max-width: 1000px) {
  .landing-hero #authBox { order: -1; }
}
