/**
 * Star Wars Hearthstone - Client
 * PvP over LAN (Radmin VPN), 2-4 players
 */

(function () {
  'use strict';

  let socket = null;
  let gameState = null;
  let cardDb = {};
  let yourIndex = -1;
  let forgePreviewRequestId = 0;
  let forgePreviewPendingIds = null;
  let attackMode = { active: false, attackerPlayer: -1, attackerBoard: -1 };
  let spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
  let heroAbilityMode = { active: false };
  let stealCardsMode = { active: false, handIndex: -1, targetPlayerIndex: null, targetDeck: [], selectedIndices: [] };
  let battlecryTargetMode = { active: false, battlecryId: '', cardId: '', minionId: '', targetPlayerIndex: null, targetBoardIndex: null };
  const seenMinions = new Set();
  let lastHandLength = 0;
  let prevGameState = null;
  let combatTimeout = null;
  const DEFAULT_PORT = 3542;
  
  // Touch support variables
  let touchState = {
    startX: 0,
    startY: 0,
    startTime: 0,
    target: null,
    isSwipe: false,
    minSwipeDistance: 50,
    maxSwipeTime: 500,
    longPressTimer: null,
    longPressDelay: 500
  };

  const $ = (id) => document.getElementById(id);
  const $all = (sel) => document.querySelectorAll(sel);
  
  // Helper to detect if device is touch-enabled
  const isTouchDevice = () => {
    return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
  };
  
  // Helper to get touch coordinates
  const getTouchCoords = (e) => {
    if (e.touches && e.touches.length > 0) {
      return { x: e.touches[0].clientX, y: e.touches[0].clientY };
    }
    return { x: e.clientX, y: e.clientY };
  };
  
  // Helper to find element at coordinates
  const elementFromPoint = (x, y) => {
    const el = document.elementFromPoint(x, y);
    if (!el) return null;
    return el.closest('.card-wrap, .drop-target, .hero-target, .spell-target, .hero-ability-target');
  };

  function spawnEffect(type, x, y) {
    const layer = $('effects-layer');
    if (!layer) return;
    const el = document.createElement('div');
    el.className = 'effect effect-' + type;
    el.style.left = (typeof x === 'number' ? x : 0) + 'px';
    el.style.top = (typeof y === 'number' ? y : 0) + 'px';
    layer.appendChild(el);
    setTimeout(function () { el.remove(); }, 800);
  }

  function showScreen(id) {
    $all('.screen').forEach((s) => s.classList.add('hidden'));
    const el = $(id);
    if (el) el.classList.remove('hidden');
  }

  function showError(msg) {
    const el = $('lobby-error');
    if (!el) return;
    el.textContent = msg;
    el.classList.remove('hidden');
  }

  function clearError() {
    const el = $('lobby-error');
    if (el) el.classList.add('hidden');
  }

  function setLobbyPanel(name) {
    $all('#lobby .panel').forEach((p) => {
      p.classList.remove('active', 'hidden');
      if (p.id !== name + '-panel') p.classList.add('hidden');
      else p.classList.add('active');
    });
  }

  function renderPlayerList(listId, players) {
    const ul = $(listId);
    if (!ul) return;
    ul.innerHTML = (players || []).map((p) => `<li>${escapeHtml(p.name)}</li>`).join('');
  }

  function escapeHtml(s) {
    const div = document.createElement('div');
    div.textContent = s;
    return div.innerHTML;
  }

  // Обработчик списка комнат - определяем глобально ДО подключения к серверу
  window.handleRoomsList = function(roomsList) {
    const roomsListEl = $('rooms-list');
    if (!roomsListEl) {
      console.warn('rooms-list element not found');
      return;
    }
    
    console.log('handleRoomsList called with:', roomsList);
    
    if (!roomsList || roomsList.length === 0) {
      roomsListEl.innerHTML = '<p class="hint" style="text-align: center; padding: 2rem; color: #94a3b8;">Нет доступных игр</p>';
      return;
    }
    
    roomsListEl.innerHTML = roomsList.map((room) => {
      const status = room.gameStarted ? 'Игра идёт' : 'Ожидание игроков';
      const statusColor = room.gameStarted ? 'var(--amber)' : 'var(--cyan)';
      const playersText = room.players && room.players.length > 0 ? room.players.join(', ') : 'Нет игроков';
      const canJoin = !room.gameStarted && room.playerCount < room.maxPlayers;
      const actionIcon = room.gameStarted ? '<i data-lucide="eye" style="width: 14px; height: 14px; vertical-align: middle; margin-right: 0.3rem;"></i>' : (canJoin ? '<i data-lucide="play" style="width: 14px; height: 14px; vertical-align: middle; margin-right: 0.3rem;"></i>' : '');
      const actionText = room.gameStarted ? 'Наблюдать' : (canJoin ? 'Подключиться' : 'Полная');
      const actionClass = room.gameStarted ? 'btn-ghost' : (canJoin ? 'btn-primary' : 'btn-ghost');
      const actionDisabled = !room.gameStarted && !canJoin;
      
      return `<div class="room-item" style="padding: 1rem; margin-bottom: 0.75rem; background: rgba(0,0,0,0.3); border: 2px solid rgba(212,168,75,0.2); border-radius: 8px;">
        <div style="display: flex; justify-content: space-between; align-items: start; margin-bottom: 0.5rem;">
          <div>
            <div style="font-weight: 700; color: var(--cyan); font-size: 1.1rem; letter-spacing: 0.1em;">${escapeHtml(room.code)}</div>
            <div style="font-size: 0.85rem; color: ${statusColor}; margin-top: 0.25rem;">${status}</div>
          </div>
          <div style="text-align: right; font-size: 0.85rem; color: #94a3b8;">
            <div>Игроки: ${room.playerCount}/${room.maxPlayers}</div>
            ${room.spectators > 0 ? `<div>Наблюдателей: ${room.spectators}</div>` : ''}
            ${room.hasAI ? '<div style="color: var(--amber); display: inline-flex; align-items: center; gap: 0.3rem;"><i data-lucide="bot" style="width: 14px; height: 14px;"></i>ИИ</div>' : ''}
          </div>
        </div>
        <div style="font-size: 0.8rem; color: #94a3b8; margin-bottom: 0.5rem;">${escapeHtml(playersText)}</div>
        <button type="button" class="btn ${actionClass}" data-room-code="${room.code}" ${actionDisabled ? 'disabled' : ''} style="width: 100%;">${actionIcon}${actionText}</button>
      </div>`;
    }).join('');
    
    // Обработчики подключения к комнатам
    $all('.room-item button').forEach(btn => {
      btn.addEventListener('click', function() {
        const code = this.dataset.roomCode;
        const name = ($('browse-name')?.value || '').trim() || 'Игрок';
        if (!code) return;
        
        if (!socket || !socket.connected) {
          const url = window.location.origin;
          connect(url);
          socket.once('connect', () => {
            socket.emit('joinRoom', { code, name });
          });
        } else {
          socket.emit('joinRoom', { code, name });
        }
      });
    });
    
    // Обновляем иконки Lucide после создания кнопок
    if (typeof lucide !== 'undefined') {
      setTimeout(() => {
        try {
          lucide.createIcons();
        } catch (e) {
          console.warn('Error updating Lucide icons:', e);
        }
      }, 100);
    }
  };

  function connect(url) {
    if (socket) {
      socket.disconnect();
      socket.removeAllListeners();
    }
    socket = io(url, { transports: ['websocket', 'polling'], reconnection: false });
    socket.on('connect', () => {
      clearError();
      // Отправляем имя пользователя на сервер, если авторизованы
      if (currentUser && currentUser.username) {
        socket.emit('setUsername', currentUser.username);
      }
    });
    socket.on('connect_error', (e) => {
      const errorMsg = e.message || 'Не удалось подключиться к серверу';
      showError(errorMsg + '. Проверьте, что сервер запущен и используйте расширенные настройки для указания IP вручную.');
    });
    socket.on('error', (msg) => showError(msg));
    socket.on('roomCreated', (data) => {
      const codeEl = $('room-code-display');
      if (codeEl) {
        codeEl.textContent = data.code;
        codeEl.onclick = function () {
          navigator.clipboard.writeText(data.code).then(() => {
            const old = codeEl.textContent;
            codeEl.textContent = 'Скопировано!';
            setTimeout(() => { codeEl.textContent = old; }, 1500);
          }).catch(() => {});
        };
      }
      const connectInfoEl = $('room-connect-info');
      if (connectInfoEl && data.serverIP && data.serverPort) {
        const isLocal = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
        const serverAddr = isLocal ? 'localhost:' + data.serverPort : data.serverIP + ':' + data.serverPort;
        const fullInfo = serverAddr + ' → код: ' + data.code;
        connectInfoEl.textContent = fullInfo;
        connectInfoEl.onclick = function () {
          navigator.clipboard.writeText(fullInfo).then(() => {
            const old = connectInfoEl.textContent;
            connectInfoEl.textContent = 'Скопировано!';
            setTimeout(() => { connectInfoEl.textContent = old; }, 1500);
          }).catch(() => {});
        };
      }
      setLobbyPanel('room');
      renderPlayerList('player-list', data.lobby);
      const portEl = $('display-port');
      if (portEl) portEl.textContent = data.serverPort || window.location.port || DEFAULT_PORT;
    });
    socket.on('roomJoined', (data) => {
      setLobbyPanel('connect');
      renderPlayerList('connect-player-list', data.lobby);
      const statusEl = $('connect-status');
      if (statusEl) statusEl.textContent = 'Подключено к комнате. Ожидание начала игры...';
    });
    socket.on('lobbyUpdate', (lobby) => {
      renderPlayerList('player-list', lobby);
      renderPlayerList('connect-player-list', lobby);
    });
    socket.on('roomsList', (roomsList) => {
      console.log('Received roomsList:', roomsList);
      if (typeof window.handleRoomsList === 'function') {
        window.handleRoomsList(roomsList);
      } else {
        console.warn('handleRoomsList function not found, using fallback');
        // Fallback: отображаем список напрямую
        const roomsListEl = $('rooms-list');
        if (roomsListEl) {
          if (!roomsList || roomsList.length === 0) {
            roomsListEl.innerHTML = '<p class="hint" style="text-align: center; padding: 2rem; color: #94a3b8;">Нет доступных игр</p>';
          } else {
            // Простое отображение для отладки
            roomsListEl.innerHTML = '<p class="hint" style="text-align: center; padding: 2rem; color: #94a3b8;">Найдено игр: ' + roomsList.length + '. Функция handleRoomsList еще не загружена.</p>';
          }
        }
      }
    });
    
    socket.on('joinedAsSpectator', (data) => {
      if (data.gameState) {
        gameState = data.gameState;
        gameState.isSpectator = true;
        gameState.yourIndex = -1;
        showScreen('game');
        renderGame(gameState);
      }
    });
    
    socket.on('backToLobby', (data) => {
      showScreen('lobby');
      clearError();
      if (data && data.lobby) {
        setLobbyPanel('room');
        renderPlayerList('player-list', data.lobby);
      } else {
        setLobbyPanel('host');
      }
      const hp = $('host-panel');
      if (hp) hp.classList.add('active');
    });
    socket.on('turnTime', function (data) {
      var el = $('turn-timer');
      if (!el) return;
      var m = Math.floor(data.left / 60);
      var s = data.left % 60;
      el.textContent = m + ':' + (s < 10 ? '0' : '') + s;
      el.classList.toggle('timer-warn', data.left > 0 && data.left <= 15);
      el.classList.toggle('timer-ended', data.ended);
      if (data.warn && typeof window.Sounds !== 'undefined') window.Sounds.timerWarning();
      if (data.ended && typeof window.Sounds !== 'undefined') window.Sounds.timerEnd();
    });
    socket.on('forgePreviewResult', (data) => {
      if (!data) return;
      if (data.requestId != null && data.requestId !== forgePreviewRequestId) return;
      const preview = $('forge-preview');
      const wrap = $('forge-preview-card-wrap');
      const confirmBtn = $('btn-forge-confirm');
      if (!preview) return;
      if (data.error || !data.resultCardId) {
        preview.classList.add('hidden');
        if (wrap) wrap.innerHTML = '';
        if (confirmBtn) confirmBtn.disabled = true;
        forgePreviewPendingIds = null;
        return;
      }
      const meta = (gameState?.cardDb || cardDb)[data.resultCardId];
      if (!meta) {
        preview.classList.add('hidden');
        forgePreviewPendingIds = null;
        return;
      }
      const you = gameState?.isSpectator ? null : (gameState?.players?.[gameState?.yourIndex] || null);
      const canCraft = !gameState?.isSpectator && you && (you.mana || 0) >= 2;
      if (wrap) {
        const art = typeof getCardArt === 'function' ? getCardArt(meta) : '';
        wrap.innerHTML = '<div class="card-wrap forge-preview-card" style="width:110px;height:154px;"><div class="card faction-' + (meta.faction || 'neutral') + '">' +
          '<div class="card-art">' + art + '</div>' +
          '<div class="card-info"><div class="card-name" style="font-size:0.75rem">' + escapeHtml(meta.name || '') + '</div>' +
          '<div class="card-stats"><span class="atk">' + (meta.attack || 0) + '</span><span class="hp">' + (meta.health || 0) + '</span></div></div></div></div>';
      }
      if (confirmBtn) confirmBtn.disabled = !canCraft;
      preview.classList.remove('hidden');
    });
    
    socket.on('chatMessage', (data) => {
      const chatMessagesEl = $('chat-messages');
      if (chatMessagesEl && data) {
        const time = new Date().toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' });
        const messageEl = document.createElement('div');
        messageEl.className = 'chat-message user';
        messageEl.innerHTML = '<span class="chat-username">' + escapeHtml(data.playerName || 'Игрок') + ':</span> ' + 
                              escapeHtml(data.message || '') + 
                              ' <span class="chat-time">' + escapeHtml(time) + '</span>';
        chatMessagesEl.appendChild(messageEl);
        chatMessagesEl.scrollTop = chatMessagesEl.scrollHeight;
      }
    });
    
    socket.on('gameState', (state) => {
      if (combatTimeout) {
        clearTimeout(combatTimeout);
        combatTimeout = null;
      }
      const wasLobby = $('game')?.classList.contains('hidden') === true;
      if (wasLobby) {
        seenMinions.clear();
        lastHandLength = 0;
        prevGameState = null;
      }
      prevGameState = gameState && state.phase !== 'ended' ? { ...gameState, players: gameState.players.map((p) => ({ ...p, board: (p.board || []).map((m) => ({ ...m })) })) } : null;
      showScreen('game');
      
      // Инициализация чата при первом запуске игры
      if (wasLobby) {
        const chatMessagesEl = $('chat-messages');
        if (chatMessagesEl) {
          chatMessagesEl.innerHTML = '';
          const welcomeMsg = document.createElement('div');
          welcomeMsg.className = 'chat-message system';
          welcomeMsg.textContent = 'Игра началась!';
          chatMessagesEl.appendChild(welcomeMsg);
        }
      }
      
      gameState = state;
      cardDb = state.cardDb || {};
      yourIndex = state.yourIndex ?? 0;
      
      // Режим наблюдателя
      if (state.isSpectator) {
        yourIndex = -1;
        const spectatorBadge = $('spectator-badge');
        if (!spectatorBadge) {
        const badge = document.createElement('div');
        badge.id = 'spectator-badge';
        badge.style.cssText = 'position: fixed; top: 1rem; right: 1rem; background: rgba(212,168,75,0.9); color: #000; padding: 0.5rem 1rem; border-radius: 8px; font-weight: 700; z-index: 200; display: flex; align-items: center; gap: 0.5rem;';
          badge.innerHTML = '<i data-lucide="eye" style="width: 18px; height: 18px;"></i><span>НАБЛЮДАТЕЛЬ</span>';
          document.body.appendChild(badge);
          if (typeof lucide !== 'undefined') {
            setTimeout(() => {
              try {
                lucide.createIcons();
              } catch (e) {
                console.warn('Error updating Lucide icons:', e);
              }
            }, 50);
          }
        }
      } else {
        const spectatorBadge = $('spectator-badge');
        if (spectatorBadge) spectatorBadge.remove();
      }
      
      if (state.phase === 'ended') {
        showGameOver(state);
        renderGameEnded(state);
        return;
      }
      renderGame(state);
    });
    
    socket.on('stealCardsRequest', (data) => {
      if (!gameState) return;
      // Находим handIndex заклинания "Грабеж" в текущей руке
      const you = gameState.isSpectator ? null : (gameState.players[gameState.yourIndex] || null);
      if (!you || !you.hand || gameState.isSpectator) return;
      
      // Ищем заклинание "Грабеж" в руке
      let handIndex = -1;
      for (let i = 0; i < you.hand.length; i++) {
        const card = cardDb[you.hand[i]];
        if (card && card.spellEffect === 'steal_cards') {
          handIndex = i;
          break;
        }
      }
      
      if (handIndex < 0) return;
      
      stealCardsMode.active = true;
      stealCardsMode.handIndex = handIndex;
      stealCardsMode.targetPlayerIndex = data.targetPlayerIndex;
      stealCardsMode.targetDeck = [];
      stealCardsMode.selectedIndices = [];
      
      // Получаем доску противника из gameState
      const targetPlayer = gameState.players[data.targetPlayerIndex];
      if (targetPlayer && targetPlayer.board) {
        stealCardsMode.targetDeck = targetPlayer.board.map(m => m.cardId);
      }
      
      showStealCardsModal(gameState, data);
    });
    
    socket.on('battlecryTargetRequest', (data) => {
      if (data.battlecryId === 'return_hand_enemy') {
        // Показываем модальное окно для выбора противника и его миньона
        showBattlecryTargetModal(gameState, data);
      }
    });
    
    return socket;
  }
  
  function showBattlecryTargetModal(state, data) {
    battlecryTargetMode = { active: true, battlecryId: data.battlecryId, cardId: data.cardId, minionId: data.minionId };
    
    // Активируем режим выбора цели
    spellMode = { active: true, handIndex: -1, cardId: data.cardId, spellTarget: 'enemy_minion', battlecryMode: true, minionId: data.minionId };
    $('spell-mode')?.classList.remove('hidden');
    const spellModeText = $('spell-mode')?.querySelector('p');
    if (spellModeText) {
      spellModeText.textContent = 'Выберите миньона противника для возврата в руку';
    }
    renderGame(state);
  }

  function renderGameEnded(state) {
    const badge = $('turn-badge');
    if (badge) badge.textContent = 'Игра окончена';
    const endBtn = $('btn-end-turn');
    if (endBtn) endBtn.disabled = true;
    const resetBtn = $('btn-reset-lobby');
    if (resetBtn) {
      resetBtn.classList.toggle('hidden', state.yourIndex !== 0);
    }
    bindGameEvents(state);
    
    // Обновляем иконки Lucide после рендеринга
    if (typeof lucide !== 'undefined') {
      setTimeout(() => {
        try {
          lucide.createIcons();
        } catch (e) {
          console.warn('Error updating Lucide icons:', e);
        }
      }, 100);
    }
  }

  function showGameOver(state) {
    const winner = state.winner;
    const modal = $('modal-overlay');
    const title = $('modal-title');
    const body = $('modal-body');
    const newGameBtn = $('btn-new-game');
    if (!modal || !title || !body) return;
    if (winner && winner.id === socket?.id) {
      title.textContent = 'Победа!';
      title.style.color = 'var(--amber)';
      body.textContent = 'Светлая сторона Силы с тобой.';
      if (typeof window.Sounds !== 'undefined') window.Sounds.victory();
    } else if (winner) {
      title.textContent = 'Поражение';
      title.style.color = 'var(--red)';
      body.textContent = 'Победу одержал ' + (winner.name || 'противник') + '.';
      if (typeof window.Sounds !== 'undefined') window.Sounds.defeat();
    } else {
      title.textContent = 'Игра окончена';
      title.style.color = 'var(--cyan)';
      body.textContent = 'Победитель не определён.';
    }
    // Показываем кнопку "Новая игра" только хосту (не наблюдателю)
    if (newGameBtn && !state.isSpectator && state.yourIndex === 0) {
      newGameBtn.style.display = 'block';
    } else if (newGameBtn) {
      newGameBtn.style.display = 'none';
    }
    modal.classList.remove('hidden');
  }

  function showTurnNotification(state) {
    const notification = $('turn-notification');
    const notificationText = $('turn-notification-text');
    if (!notification || !notificationText) return;
    
    const currentPlayer = state.players[state.currentPlayerIndex];
    const isYourTurn = !state.isSpectator && state.currentPlayerIndex === state.yourIndex;
    const playerName = currentPlayer?.name || `Игрок ${state.currentPlayerIndex + 1}`;
    
    if (isYourTurn) {
      notificationText.textContent = 'ВАШ ХОД';
      notificationText.parentElement.classList.add('your-turn');
    } else {
      notificationText.textContent = `ХОД: ${playerName.toUpperCase()}`;
      notificationText.parentElement.classList.remove('your-turn');
    }
    
    // Показываем нотификацию на 2 секунды
    notification.classList.add('show');
    setTimeout(() => {
      notification.classList.remove('show');
    }, 2000);
  }

  function renderBoards(state) {
    const you = state.isSpectator ? null : (state.players[yourIndex] || null);
    const opponentsArea = $('opponents-area');
    const yourBoard = $('your-board');
    if (opponentsArea) {
      opponentsArea.innerHTML = state.players
        .map((p, i) => {
          if (!state.isSpectator && i === yourIndex) return '';
          const isCurrent = state.currentPlayerIndex === i;
          const isDead = p.health <= 0 || p.isDead;
          const name = p.name || 'Игрок ' + (i + 1);
          const isAI = p.isAI || false;
          const minions = (p.board || []).map((m, j) => renderBoardMinion(m, i, j, state, true, false));
          const heroBar = renderHeroTarget(i, state);
          const heroDrop = renderHeroDropZone(i, state);
          const canSteal = !state.isSpectator && state.currentPlayerIndex === state.yourIndex && spellMode.active && spellMode.cardId && cardDb[spellMode.cardId]?.spellEffect === 'steal_cards';
          return `
            <div class="opponent-block ${isCurrent ? 'current-turn' : ''} ${canSteal ? 'steal-target' : ''} ${isDead ? 'defeated' : ''}" data-opponent-index="${i}" data-player-index="${i}">
              <div class="opponent-name ${isDead ? 'defeated-name' : ''}">
                ${isAI ? '<i data-lucide="bot" style="width: 16px; height: 16px; vertical-align: middle; margin-right: 0.3rem; color: var(--cyan);"></i>' : ''}
                ${escapeHtml(name)}${isDead ? ' <span class="defeated-badge"><i data-lucide="skull" style="width: 14px; height: 14px; vertical-align: middle;"></i></span>' : ''}
              </div>
              <div class="opponent-stats ${isDead ? 'defeated-stats' : ''}">
                <span class="opponent-health"><i data-lucide="heart" style="width: 14px; height: 14px; vertical-align: middle; margin-right: 0.2rem; color: #e63946;"></i>${p.health ?? 30}</span>
                ${(p.armor || 0) > 0 ? `<span class="opponent-armor"><i data-lucide="shield" style="width: 14px; height: 14px; vertical-align: middle; margin-right: 0.2rem; color: #5eb3e8;"></i>${p.armor}</span>` : ''}
                <span><i data-lucide="zap" style="width: 14px; height: 14px; vertical-align: middle; margin-right: 0.2rem; color: #00d4ff;"></i>${p.mana ?? 0}/${p.maxMana ?? 0}</span>
                ${p.deck && p.deck.length > 0 ? `<span><i data-lucide="book-open" style="width: 14px; height: 14px; vertical-align: middle; margin-right: 0.2rem; color: var(--gold);"></i>${p.deck.length}</span>` : ''}
              </div>
              <div class="opponent-board">${heroDrop}${heroBar}${minions.join('')}</div>
            </div>`;
        })
        .filter(Boolean)
        .join('');
    }
    if (yourBoard) {
      if (state.isSpectator) {
        yourBoard.innerHTML = '<div style="padding: 1rem; text-align: center; color: #94a3b8; font-size: 0.85rem;">Режим наблюдателя — вы не играете</div>';
      } else if (you) {
        yourBoard.innerHTML = (you.board || []).map((m, j) => {
          const isNew = !seenMinions.has(m.id);
          if (isNew) seenMinions.add(m.id);
          return renderBoardMinion(m, yourIndex, j, state, false, isNew);
        }).join('');
      }
    }
  }

  function showDamageEffect(element, damage, isHero) {
    if (!element) return;
    const damageEl = document.createElement('div');
    damageEl.className = 'damage-indicator';
    damageEl.textContent = '-' + damage;
    damageEl.style.position = 'absolute';
    const rect = element.getBoundingClientRect();
    damageEl.style.left = (rect.left + rect.width / 2) + 'px';
    damageEl.style.top = (rect.top + rect.height / 2) + 'px';
    damageEl.style.pointerEvents = 'none';
    damageEl.style.zIndex = '1000';
    document.body.appendChild(damageEl);
    setTimeout(() => {
      damageEl.style.animation = 'damageFloat 1.5s ease-out forwards';
      setTimeout(() => damageEl.remove(), 1000);
    }, 10);
  }

  function showAttackAnnouncement(state, logEntry) {
    const announcementEl = $('attack-announcement');
    if (!announcementEl || !logEntry) return;
    
    // Обработка специальных событий
    if (logEntry.type === 'skipTurn') {
      const playerName = state.players[logEntry.playerIndex]?.name || `Игрок ${logEntry.playerIndex + 1}`;
      announcementEl.textContent = `⏭ ${playerName} пропускает ход`;
      announcementEl.classList.remove('hidden');
      setTimeout(() => {
        announcementEl.classList.add('hidden');
      }, 2000);
      return;
    }
    
    if (logEntry.type === 'playerDefeated') {
      const playerName = state.players[logEntry.playerIndex]?.name || `Игрок ${logEntry.playerIndex + 1}`;
      announcementEl.textContent = `💀 ${playerName} выбыл из игры`;
      announcementEl.classList.remove('hidden');
      setTimeout(() => {
        announcementEl.classList.add('hidden');
      }, 2500);
      return;
    }
    
    const who = (i) => state.players[i]?.name || ('Игрок ' + (i + 1));
    let text = '';
    
    if (logEntry.type === 'attack' && logEntry.attackerMinionId && logEntry.targetMinionId) {
      const attackerPlayer = state.players.find(p => p.board?.some(m => m.id === logEntry.attackerMinionId));
      const targetPlayer = state.players.find(p => p.board?.some(m => m.id === logEntry.targetMinionId));
      if (attackerPlayer && targetPlayer) {
        const attackerIdx = state.players.indexOf(attackerPlayer);
        const targetIdx = state.players.indexOf(targetPlayer);
        const attackerMinion = attackerPlayer.board.find(m => m.id === logEntry.attackerMinionId);
        const targetMinion = targetPlayer.board.find(m => m.id === logEntry.targetMinionId);
        const attackerCard = cardDb[attackerMinion?.cardId];
        const targetCard = cardDb[targetMinion?.cardId];
        const attackerName = attackerCard?.name || 'Миньон';
        const targetName = targetCard?.name || 'Миньон';
        const damage = logEntry.damage || attackerMinion?.attack || 0;
        text = who(attackerIdx) + ' → ' + attackerName + ' <i data-lucide="swords" style="width: 14px; height: 14px; vertical-align: middle; display: inline-block;"></i> атакует ' + targetName + ' (' + damage + ' урона) → ' + who(targetIdx);
      }
    } else if (logEntry.type === 'attackHero' && logEntry.fromPlayer !== undefined && logEntry.toPlayer !== undefined) {
      const attackerPlayer = state.players[logEntry.fromPlayer];
      const targetPlayer = state.players[logEntry.toPlayer];
      if (attackerPlayer && targetPlayer) {
        if (logEntry.attackerMinionId) {
          const attackerMinion = attackerPlayer.board?.find(m => m.id === logEntry.attackerMinionId);
          const attackerCard = cardDb[attackerMinion?.cardId];
          const attackerName = attackerCard?.name || 'Миньон';
          const damage = logEntry.damage || attackerMinion?.attack || 0;
          text = who(logEntry.fromPlayer) + ' → ' + attackerName + ' <i data-lucide="swords" style="width: 14px; height: 14px; vertical-align: middle; display: inline-block;"></i> атакует героя ' + who(logEntry.toPlayer) + ' (' + damage + ' урона)!';
        } else {
          const damage = logEntry.damage || 0;
          text = who(logEntry.fromPlayer) + ' <i data-lucide="swords" style="width: 14px; height: 14px; vertical-align: middle; display: inline-block;"></i> атакует героя ' + who(logEntry.toPlayer) + ' (' + damage + ' урона)!';
        }
      }
    } else if (logEntry.type === 'spell' && logEntry.fromPlayer !== undefined && logEntry.toPlayer !== undefined) {
      const spellCard = cardDb[logEntry.spell];
      const spellName = spellCard?.name || 'Заклинание';
      if (logEntry.toIdx !== undefined && logEntry.toIdx >= 0) {
        const targetPlayer = state.players[logEntry.toPlayer];
        const targetMinion = targetPlayer?.board?.[logEntry.toIdx];
        const targetCard = cardDb[targetMinion?.cardId];
        const targetName = targetCard?.name || 'Миньон';
        const damage = logEntry.damage || '';
        const damageText = damage ? ' (' + damage + ' урона)' : '';
        text = who(logEntry.fromPlayer) + ' → ' + spellName + ' ✨ по ' + targetName + damageText + ' → ' + who(logEntry.toPlayer);
      } else {
        const damage = logEntry.damage || '';
        const damageText = damage ? ' (' + damage + ' урона)' : '';
        text = who(logEntry.fromPlayer) + ' → ' + spellName + ' ✨ по герою ' + who(logEntry.toPlayer) + damageText + '!';
      }
    } else if (logEntry.type === 'heroAbility' && logEntry.fromPlayer !== undefined && logEntry.toPlayer !== undefined) {
      if (logEntry.toIdx !== undefined && logEntry.toIdx >= 0) {
        const targetPlayer = state.players[logEntry.toPlayer];
        const targetMinion = targetPlayer?.board?.[logEntry.toIdx];
        const targetCard = cardDb[targetMinion?.cardId];
        const targetName = targetCard?.name || 'Миньон';
        const damage = logEntry.damage || 1;
        text = who(logEntry.fromPlayer) + ' → Геройская способность ⚡ по ' + targetName + ' (' + damage + ' урона) → ' + who(logEntry.toPlayer);
      } else {
        const damage = logEntry.damage || 1;
        text = who(logEntry.fromPlayer) + ' → Геройская способность ⚡ по герою ' + who(logEntry.toPlayer) + ' (' + damage + ' урона)!';
      }
    } else if (logEntry.type === 'battlecry' && logEntry.damage && logEntry.fromPlayer !== undefined && logEntry.toPlayer !== undefined) {
      const attackerPlayer = state.players[logEntry.fromPlayer];
      const targetPlayer = state.players[logEntry.toPlayer];
      if (attackerPlayer && targetPlayer) {
        if (logEntry.toIdx !== undefined && logEntry.toIdx >= 0) {
          const targetMinion = targetPlayer?.board?.[logEntry.toIdx];
          const targetCard = cardDb[targetMinion?.cardId];
          const targetName = targetCard?.name || 'Миньон';
          text = who(logEntry.fromPlayer) + ' → Battlecry 💥 по ' + targetName + ' (' + logEntry.damage + ' урона) → ' + who(logEntry.toPlayer);
        } else {
          text = who(logEntry.fromPlayer) + ' → Battlecry 💥 по герою ' + who(logEntry.toPlayer) + ' (' + logEntry.damage + ' урона)!';
        }
      }
    }
    
    if (text) {
      announcementEl.innerHTML = text;
      // Инициализируем иконки Lucide после установки HTML
      if (typeof lucide !== 'undefined') {
        setTimeout(() => {
          try {
            lucide.createIcons();
          } catch (e) {
            console.warn('Error updating Lucide icons in attack announcement:', e);
          }
        }, 10);
      }
      announcementEl.classList.remove('hidden');
      setTimeout(() => {
        announcementEl.classList.add('hidden');
      }, 2000); // Сократил с 3500 до 2000 мс
    }
  }

  function runCombatAnimation(state) {
    const lastLog = state.log && state.log.length ? state.log[state.log.length - 1] : null;
    if (!lastLog) return false;
    
    if (lastLog.type === 'attack' && lastLog.attackerMinionId && lastLog.targetMinionId) {
      const attackerWrap = document.querySelector(`[data-minion-id="${lastLog.attackerMinionId}"]`);
      const targetWrap = document.querySelector(`[data-minion-id="${lastLog.targetMinionId}"]`);
      if (!attackerWrap || !targetWrap) return false;
      
      // Вычисляем позиции для точного перемещения карты
      const attackerRect = attackerWrap.getBoundingClientRect();
      const targetRect = targetWrap.getBoundingClientRect();
      
      // Вычисляем смещение
      const dx = targetRect.left + targetRect.width / 2 - (attackerRect.left + attackerRect.width / 2);
      const dy = targetRect.top + targetRect.height / 2 - (attackerRect.top + attackerRect.height / 2);
      
      // Сохраняем начальную позицию
      const startX = attackerRect.left;
      const startY = attackerRect.top;
      const startWidth = attackerRect.width;
      const startHeight = attackerRect.height;
      
      // Устанавливаем fixed positioning для наложения
      attackerWrap.style.position = 'fixed';
      attackerWrap.style.left = startX + 'px';
      attackerWrap.style.top = startY + 'px';
      attackerWrap.style.width = startWidth + 'px';
      attackerWrap.style.height = startHeight + 'px';
      attackerWrap.style.zIndex = '1000';
      attackerWrap.style.transition = 'none';
      
      // Добавляем класс для анимации
      attackerWrap.classList.add('combat-lunge-overlay');
      targetWrap.classList.add('combat-hit');
      
      // Устанавливаем CSS переменные для перемещения
      attackerWrap.style.setProperty('--attack-dx', dx + 'px');
      attackerWrap.style.setProperty('--attack-dy', dy + 'px');
      
      if (lastLog.damage) showDamageEffect(targetWrap, lastLog.damage, false);
      if (typeof window.Sounds !== 'undefined') window.Sounds.attack();
      
      // Анимация удара
      setTimeout(() => {
        targetWrap.classList.add('combat-hit-impact');
      }, 200);
      
      // Возврат карты и очистка
      setTimeout(() => {
        // Если атакующий не умер, возвращаем карту на место
        if (!lastLog.attackerDied) {
          attackerWrap.classList.remove('combat-lunge-overlay');
          attackerWrap.style.position = '';
          attackerWrap.style.left = '';
          attackerWrap.style.top = '';
          attackerWrap.style.width = '';
          attackerWrap.style.height = '';
          attackerWrap.style.zIndex = '';
          attackerWrap.style.setProperty('--attack-dx', '');
          attackerWrap.style.setProperty('--attack-dy', '');
          attackerWrap.style.transition = '';
        } else {
          // Если атакующий умер, сразу применяем анимацию смерти
          attackerWrap.classList.remove('combat-lunge-overlay');
          attackerWrap.style.position = '';
          attackerWrap.style.left = '';
          attackerWrap.style.top = '';
          attackerWrap.style.width = '';
          attackerWrap.style.height = '';
          attackerWrap.style.zIndex = '';
          attackerWrap.style.setProperty('--attack-dx', '');
          attackerWrap.style.setProperty('--attack-dy', '');
          attackerWrap.style.transition = '';
          attackerWrap.classList.add('combat-death');
          showDamageEffect(attackerWrap, '💀', false);
        }
        
        if (lastLog.targetDied) {
          targetWrap.classList.add('combat-death');
          showDamageEffect(targetWrap, '💀', false);
        }
        
        targetWrap.classList.remove('combat-hit-impact');
      }, 500);
      
      combatTimeout = setTimeout(function () {
        combatTimeout = null;
        renderBoards(state);
        bindGameEvents(state);
      }, 600);
      return true;
    } else if (lastLog.type === 'attackHero' && lastLog.toPlayer !== undefined && lastLog.attackerMinionId) {
      const attackerWrap = document.querySelector(`[data-minion-id="${lastLog.attackerMinionId}"]`);
      const targetPlayer = state.players[lastLog.toPlayer];
      if (attackerWrap && targetPlayer) {
        const heroEl = document.querySelector(`[data-player-index="${lastLog.toPlayer}"].hero-target, .opponent-block[data-opponent-index="${lastLog.toPlayer}"] .drop-target-hero`);
        if (heroEl) {
          // Вычисляем позиции для атаки по герою
          const attackerRect = attackerWrap.getBoundingClientRect();
          const heroRect = heroEl.getBoundingClientRect();
          
          const dx = heroRect.left + heroRect.width / 2 - (attackerRect.left + attackerRect.width / 2);
          const dy = heroRect.top + heroRect.height / 2 - (attackerRect.top + attackerRect.height / 2);
          
          const startX = attackerRect.left;
          const startY = attackerRect.top;
          const startWidth = attackerRect.width;
          const startHeight = attackerRect.height;
          
          // Устанавливаем fixed positioning
          attackerWrap.style.position = 'fixed';
          attackerWrap.style.left = startX + 'px';
          attackerWrap.style.top = startY + 'px';
          attackerWrap.style.width = startWidth + 'px';
          attackerWrap.style.height = startHeight + 'px';
          attackerWrap.style.zIndex = '1000';
          attackerWrap.style.transition = 'none';
          
          attackerWrap.classList.add('combat-lunge-overlay');
          attackerWrap.style.setProperty('--attack-dx', dx + 'px');
          attackerWrap.style.setProperty('--attack-dy', dy + 'px');
          
          heroEl.classList.add('hero-damage-flash', 'combat-hit-impact');
          if (lastLog.damage) showDamageEffect(heroEl, lastLog.damage, true);
          if (typeof window.Sounds !== 'undefined') window.Sounds.attack();
          
          setTimeout(() => {
            attackerWrap.classList.remove('combat-lunge-overlay');
            attackerWrap.style.position = '';
            attackerWrap.style.left = '';
            attackerWrap.style.top = '';
            attackerWrap.style.width = '';
            attackerWrap.style.height = '';
            attackerWrap.style.zIndex = '';
            attackerWrap.style.setProperty('--attack-dx', '');
            attackerWrap.style.setProperty('--attack-dy', '');
            attackerWrap.style.transition = '';
            
            heroEl.classList.remove('hero-damage-flash', 'combat-hit-impact');
          }, 500);
        }
      }
      return true;
    } else if ((lastLog.type === 'battlecry' || lastLog.type === 'spell' || lastLog.type === 'heroAbility') && lastLog.damage && lastLog.toPlayer !== undefined) {
      const targetPlayer = state.players[lastLog.toPlayer];
      if (targetPlayer) {
        if (lastLog.toIdx !== undefined && lastLog.toIdx >= 0 && targetPlayer.board && targetPlayer.board[lastLog.toIdx]) {
          const minionEl = document.querySelector(`[data-player-index="${lastLog.toPlayer}"][data-board-index="${lastLog.toIdx}"]`);
          if (minionEl) {
            minionEl.classList.add('spell-hit');
            showDamageEffect(minionEl, lastLog.damage, false);
            setTimeout(() => minionEl.classList.remove('spell-hit'), 500);
          }
        } else {
          const heroEl = document.querySelector(`[data-player-index="${lastLog.toPlayer}"].hero-target, .opponent-block[data-opponent-index="${lastLog.toPlayer}"] .drop-target-hero`);
          if (heroEl) {
            heroEl.classList.add('hero-damage-flash');
            showDamageEffect(heroEl, lastLog.damage, true);
            setTimeout(() => heroEl.classList.remove('hero-damage-flash'), 500);
          }
        }
      }
      return true;
    }
    return false;
  }

  function renderGame(state) {
    const you = state.isSpectator ? null : (state.players[yourIndex] || null);

    $('your-mana').textContent = state.isSpectator ? '—' : (you?.mana ?? 0);
    $('your-max-mana').textContent = state.isSpectator ? '—' : (you?.maxMana ?? 10);
    const healthEl = $('your-health');
    if (healthEl) {
      const newHealth = state.isSpectator ? '—' : (you?.health ?? 30);
      const oldHealthText = healthEl.textContent;
      const oldHealth = state.isSpectator ? '—' : (parseInt(oldHealthText) || 30);
      healthEl.textContent = newHealth;
      // Добавляем визуальный эффект при изменении HP
      if (!state.isSpectator && typeof newHealth === 'number' && typeof oldHealth === 'number' && newHealth !== oldHealth) {
        healthEl.classList.add('health-changed');
        setTimeout(() => healthEl.classList.remove('health-changed'), 500);
      }
    }
    // Отображение брони
    const armorEl = $('your-armor');
    const armorDisplayEl = $('armor-display');
    if (armorEl && armorDisplayEl) {
      const armor = state.isSpectator ? 0 : (state.yourArmor || you?.armor || 0);
      armorEl.textContent = armor;
      if (armor > 0) {
        armorDisplayEl.style.display = 'inline-flex';
      } else {
        armorDisplayEl.style.display = 'none';
      }
    }
    $('your-deck').textContent = state.yourDeckCount ?? you.deck?.length ?? 0;
    const lastLog = state.log && state.log.length ? state.log[state.log.length - 1] : null;
    
    // Добавляем новые логи в чат
    if (state.log && prevGameState) {
      const chatMessagesEl = $('chat-messages');
      if (chatMessagesEl) {
        const prevLogLength = prevGameState.log ? prevGameState.log.length : 0;
        const newLogs = state.log.slice(prevLogLength);
        newLogs.forEach(entry => {
          if (!entry) return;
          const who = (i) => state.players[i]?.name || ('Игрок ' + (i + 1));
          let message = '';
          
          if (entry.type === 'play') {
            const c = cardDb[entry.cardId];
            message = who(entry.playerIndex) + ' разыграл ' + (c?.name || entry.cardId);
          } else if (entry.type === 'turn') {
            message = 'Ход: ' + who(entry.to);
          } else if (entry.type === 'skipTurn') {
            message = who(entry.playerIndex) + ' пропускает ход';
          } else if (entry.type === 'playerDefeated') {
            message = who(entry.playerIndex) + ' выбыл из игры';
          } else if (entry.type === 'attackHero') {
            message = 'Атака по герою!';
          } else if (entry.type === 'attack') {
            message = 'Бой!';
          } else if (entry.type === 'draw') {
            message = who(entry.playerIndex) + ' вытянул карту';
          } else if (entry.type === 'fatigue') {
            message = who(entry.playerIndex) + ' усталость (' + (entry.damage || 0) + ' урона)';
          } else if (entry.type === 'spell') {
            message = who(entry.fromPlayer) + ' заклинание';
          } else if (entry.type === 'heroAbility') {
            message = who(entry.fromPlayer) + ' — геройская способность';
          } else if (entry.type === 'battlecry' || entry.type === 'deathrattle') {
            return; // Пропускаем эти типы
          }
          
          if (message) {
            const time = new Date().toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' });
            const messageEl = document.createElement('div');
            messageEl.className = 'chat-message system';
            messageEl.innerHTML = '<span class="chat-time">' + escapeHtml(time) + '</span> ' + escapeHtml(message);
            chatMessagesEl.appendChild(messageEl);
            chatMessagesEl.scrollTop = chatMessagesEl.scrollHeight;
          }
        });
      }
    }
    if (lastLog?.type === 'attackHero' && typeof window.Sounds !== 'undefined') window.Sounds.attack();

    const isYourTurn = state.currentPlayerIndex === yourIndex && !state.isSpectator;
    const endBtn = $('btn-end-turn');
    if (endBtn) {
      endBtn.disabled = !isYourTurn || state.isSpectator;
      if (state.isSpectator) endBtn.title = 'Режим наблюдателя';
    }
    const heroBtn = $('btn-hero-ability');
    if (heroBtn) {
      var canHero = isYourTurn && !state.isSpectator && (you.mana ?? 0) >= 2 && !state.yourHeroAbilityUsed && !attackMode.active && !spellMode.active && !heroAbilityMode.active;
      heroBtn.disabled = !canHero || state.isSpectator;
      heroBtn.classList.toggle('hidden', !isYourTurn || state.isSpectator);
    }
    const resetBtnEl = $('btn-reset-lobby');
    if (resetBtnEl) resetBtnEl.classList.add('hidden');
    const badge = $('turn-badge');
    if (badge) {
      badge.classList.toggle('your-turn', isYourTurn);
      badge.textContent = isYourTurn ? 'ВАШ ХОД' : 'Ход ' + (state.turn || 1);
    }
    
    // Показываем нотификацию о том, кто ходит
    showTurnNotification(state);

    var skipBoardUpdate = false;
    if (lastLog?.type === 'attack' && lastLog.attackerMinionId && lastLog.targetMinionId && prevGameState && runCombatAnimation(state)) {
      skipBoardUpdate = true;
      showAttackAnnouncement(state, lastLog);
    } else if (lastLog && (lastLog.type === 'attackHero' || lastLog.type === 'spell' || lastLog.type === 'heroAbility' || (lastLog.type === 'battlecry' && lastLog.damage))) {
      showAttackAnnouncement(state, lastLog);
    } else if (lastLog?.type === 'attack' && lastLog.attackerMinionId && lastLog.targetMinionId) {
      showAttackAnnouncement(state, lastLog);
    } else if (lastLog?.type === 'skipTurn' || lastLog?.type === 'playerDefeated') {
      showAttackAnnouncement(state, lastLog);
    }
    if (!skipBoardUpdate) {
      renderBoards(state);
    }

    const hand = state.isSpectator ? [] : (you.hand || []);
    var justDrew = !state.isSpectator && hand.length > lastHandLength && lastHandLength > 0;
    if (justDrew && typeof window.Sounds !== 'undefined') window.Sounds.drawCard();
    lastHandLength = hand.length;

    const handEl = $('your-hand');
    if (handEl) {
      if (state.isSpectator) {
        handEl.innerHTML = '<div style="padding: 2rem; text-align: center; color: #94a3b8; font-size: 0.9rem;">Режим наблюдателя — вы не можете играть</div>';
      } else {
        handEl.innerHTML = hand
          .map((cid, i) => {
            var meta = cardDb[cid];
            var cost = meta?.cost ?? 0;
            var playable = false;
            var notEnoughMana = false;
            if (isYourTurn) {
            if (meta?.type === 'minion') {
              playable = you && you.mana >= cost && (you.board?.length ?? 0) < 7;
              notEnoughMana = you && you.mana < cost;
            } else if (meta?.type === 'spell') {
              playable = you && you.mana >= cost && !attackMode.active && !spellMode.active && !heroAbilityMode.active;
              notEnoughMana = you && you.mana < cost;
            }
            }
            var drawAnim = justDrew && i === hand.length - 1;
            return renderHandCard(cid, i, hand.length, playable, drawAnim, notEnoughMana);
          })
          .join('');
      }
    }

    const deckCount = state.isSpectator ? 0 : (state.yourDeckCount ?? you?.deck?.length ?? 0);
    const canDraw = isYourTurn && !state.isSpectator && !state.yourManualDrawUsed && deckCount > 0 && (you.hand?.length ?? 0) < 10;
    renderDeckFan(deckCount, justDrew, canDraw);
    bindGameEvents(state);
  }

  function renderDeckFan(deckCount, justDrew, canDraw) {
    const fan = $('deck-fan');
    const stack = $('deck-stack');
    const badge = $('deck-count-badge');
    if (!stack) return;
    const n = Math.min(5, Math.max(0, deckCount));
    let html = '';
    for (let i = 0; i < 5; i++) {
      html += i < n ? '<div class="deck-card"></div>' : '';
    }
    stack.innerHTML = html;
    if (badge) badge.textContent = String(deckCount);
    if (fan) {
      fan.classList.toggle('deck-just-drew', !!justDrew);
      fan.classList.toggle('deck-drawable', !!canDraw);
      fan.title = canDraw ? 'Клик — вытянуть карту' : 'Колода';
      if (justDrew) setTimeout(function () { fan.classList.remove('deck-just-drew'); }, 400);
    }
  }

  function abilityTags(meta) {
    var tags = [];
    if (meta.battlecry) tags.push('<span class="ability-tag">Вой:</span>' + escapeHtml(meta.battlecry));
    if (meta.deathrattle) tags.push('<span class="ability-tag">Предсм.:</span>' + escapeHtml(meta.deathrattle));
    if (!tags.length) return '';
    return '<div class="card-abilities">' + tags.join(' ') + '</div>';
  }

  function renderHandCard(cardId, handIndex, handSize, playable, drawFromDeck, notEnoughMana) {
    var meta = cardDb[cardId];
    if (!meta) return '';
    var name = meta.name || cardId;
    var cost = meta.cost ?? 0;
    var atk = meta.attack ?? 0;
    var hp = meta.health ?? 0;
    var art = getCardArt(meta);
    var faction = meta.faction || 'neutral';
    var rotate = handSize <= 1 ? 0 : -10 + (handIndex / Math.max(1, handSize - 1)) * 20;
    var isMinion = meta.type === 'minion';
    var statsHtml = isMinion
      ? '<div class="card-cost-wrap"><span class="card-stat-label">Мана</span><span class="card-cost">' + cost + '</span></div>'
        + '<div class="card-atk-wrap"><span class="card-stat-label">Атака</span><span class="atk">' + atk + '</span></div>'
        + '<div class="card-hp-wrap"><span class="card-stat-label">Здоровье</span><span class="hp">' + hp + '</span></div>'
      : '<div class="card-cost-wrap"><span class="card-stat-label">Мана</span><span class="card-cost">' + cost + '</span></div>';
    var textHtml = meta.text ? '<div class="card-text">' + escapeHtml(meta.text) + '</div>' : '';
    var abilHtml = abilityTags(meta);
    var fictionalClass = meta.fictional ? ' fictional-card' : '';
    var notEnoughManaClass = notEnoughMana ? ' not-enough-mana' : '';
    return '<div class="card-wrap in-hand ' + (playable ? 'playable' : '') + ' ' + (drawFromDeck ? 'draw-from-deck' : '') + fictionalClass + notEnoughManaClass + '" data-hand-index="' + handIndex + '" data-card-id="' + cardId + '" style="--hand-rotate: ' + rotate + 'deg" title="' + escapeHtml(name) + (meta.text ? ': ' + meta.text : '') + (meta.fictional ? ' [ВЫМЫШЛЕННЫЙ]' : '') + (notEnoughMana ? ' (Недостаточно маны)' : '') + '">'
      + '<div class="card faction-' + faction + fictionalClass + '">'
      + '<div class="card-art">' + art + '</div>'
      + '<div class="card-info">'
      + '<div class="card-name">' + escapeHtml(name) + '</div>'
      + textHtml + abilHtml
      + '<div class="card-stats">' + statsHtml + '</div>'
      + '<div class="card-info-row"><span></span><button type="button" class="card-btn-info" data-card-id="' + cardId + '" title="Описание">i</button></div>'
      + '</div></div></div>';
  }

  var swgMap = {
    r2d2: 'r2d2', c3po: 'c3po', yoda: 'yoda', boba: 'bobbafett', vader: 'darthvader',
    stormtrooper: 'stormtrooper', deathstar: 'deathstar', atat: 'atat', xwing: 'xwing',
    tie: 'tie', falcon: 'falcon', leia: 'leia', chewie: 'wookie', ackbar: 'akbar',
    kylo: 'kylo', bb8: 'bb8', phasma: 'phasma', trooper: 'stormtrooper',
    jawas: 'galrep', sandcrawler: 'galrep', tusken: 'galrep', sarlacc: 'galrep',
    bantha: 'galrep', rancor: 'galrep', tauntaun: 'galrep', temple: 'jediorder',
    cantina: 'galrep', void: 'galrep', storm: 'jediorder', malice: 'darthvader',
    zephyr: 'galrep', walker: 'galrep', crystal: 'jediorder', shadow: 'darthvader',
    nebula: 'galrep', elite: 'galrep',
    anakin: 'saberjedi', kanan: 'saberjedi', ezra: 'saberjedi', cal_kestis: 'saberjedi',
    plo_koon: 'saberjedi', ki_adi: 'saberjedi', aayla: 'saberjedi', shaak_ti: 'saberjedi',
    savage: 'sabersith', jar_jar: 'galrep', tarkin: 'galemp', starkiller: 'sabersith',
    moff_gideon: 'galemp', rebel_trooper: 'galrep', rebel_commando: 'galrep', rebel_scout: 'galrep',
    clone_trooper: 'stormtrooper', clone_commando: 'stormtrooper', arc_trooper: 'stormtrooper',
    battle_droid: 'combatdrone', super_battle_droid: 'combatdrone', droideka: 'combatdrone',
    cody: 'stormtrooper', rex: 'stormtrooper', fives: 'stormtrooper', echo: 'stormtrooper',
    father: 'jediorder', son: 'sith', daughter: 'jediorder',
    korriban: 'galemp', tatooine: 'galrep', coruscant: 'galrep', zakkuul: 'galemp',
    kamino: 'galrep', mustafar: 'galemp', naboo: 'galrep', endor: 'galrep', hoth: 'galrep', dagobah: 'jediorder',
    star_destroyer: 'stardestroyer', speeder: 'landspeeder', wedge: 'xwing',
    nebulon: 'xwing', droideka: 'combatdrone', jango: 'bobbafett',
    luke: 'saberjedi', obiwan: 'saberjedi', quigon: 'saberjedi', mace: 'saberjedi',
    dooku: 'sabersith', maul: 'sabersith', snoke: 'sith', palpatine: 'sith',
    han: 'falcon', rey: 'newrep', finn: 'newrep', padme: 'galrep', jabba: 'carbonite',
    lando: 'cantina', ewok: 'jediorder', wicket: 'jediorder', scout: 'stormtrooper',
    guard: 'stormtrooper', probe: 'r2d2',
    ahsoka: 'saberjedi', ventress: 'sabersith', rex: 'stormtrooper', thrawn: 'galemp',
    mando: 'mandalorian', grogu: 'yoda', jyn: 'newrep', cassian: 'galrep',
    k2so: 'r2d2', chirrut: 'jediorder', baze: 'stormtrooper', poe: 'xwing',
    hux: 'stormtrooper', rose: 'galrep',
    lightsaber: 'saberjedi', force: 'saberjedi', blaster: 'tie', hyperspace: 'xwing', fear: 'sith', hope: 'galrep',
    shield: 'jediorder', barrier: 'jediorder', energy: 'jediorder', generator: 'jediorder',
  };
  function getCardArt(meta) {
    // Проверяем наличие кастомных иконок в папке extraicons
    const extraIconMap = {
      'ezra': 'ezra-bridger.png',
      'ezra_bridger': 'ezra-bridger.png',
      'father': 'the-father.png',
      'the_father': 'the-father.png',
      'ahsoka': 'ashoka-tano.png',
      'ashoka_tano': 'ashoka-tano.png',
      'cal': 'CalCestis.png',
      'cal_kestis': 'CalCestis.png',
      'nihilus': 'darthnihilus.png',
      'darth_nihilus': 'darthnihilus.png',
      'plagueis': 'dartplagues.png',
      'darth_plagueis': 'dartplagues.png',
      'plo': 'plokoon.png',
      'plo_koon': 'plokoon.png',
      'revan': 'revan.png'
    };
    
    const extraIcon = extraIconMap[meta.art];
    if (extraIcon) {
      return '<img src="extraicons/' + extraIcon + '" class="card-art-image" alt="' + (meta.name || '') + '" />';
    }
    
    // Используем стандартные SWG иконки
    var swg = swgMap[meta.art];
    if (swg) return '<i class="swg swg-lg swg-' + swg + ' card-art-swg" aria-hidden="true"></i>';
    return '<span class="card-art-fallback">✦</span>';
  }

  function renderBoardMinion(m, playerIndex, boardIndex, state, isOpponent, summonAnim) {
    const meta = cardDb[m.cardId];
    const name = meta?.name || m.cardId;
    const art = meta ? getCardArt(meta) : '✦';
    const faction = meta?.faction || 'neutral';
    const isYourTurn = state.currentPlayerIndex === state.yourIndex;
    const canAttackTwice = meta && meta.canAttackTwice;
    const attacksUsed = m.attacksUsed || 0;
    const canAttack = !isOpponent && m.canAttack && isYourTurn && (!canAttackTwice || attacksUsed < 2);
    const attackable = attackMode.active && attackMode.attackerPlayer === state.yourIndex && attackMode.attackerBoard === boardIndex;
    const targetable = attackMode.active && attackMode.attackerPlayer === state.yourIndex && playerIndex !== state.yourIndex;
    
    // Учитываем бонусы синергий
    const synergyAttack = m.synergyAttackBonus || 0;
    const synergyHealth = m.synergyHealthBonus || 0;
    const displayAttack = (m.attack || 0) + synergyAttack;
    const displayHealth = (m.health || 0) + synergyHealth;
    const hasSynergy = synergyAttack > 0 || synergyHealth > 0;
    
    const cls = ['card-wrap'];
    if (canAttack && !attackMode.active) cls.push('attackable');
    if (attackable) cls.push('attackable');
    if (targetable) cls.push('targetable');
    if (isOpponent && isYourTurn) cls.push('drop-target');
    if (hasSynergy) cls.push('has-synergy');
    var spellTarget = false;
    if (spellMode.active && spellMode.spellTarget) {
      var st = spellMode.spellTarget;
      if (isOpponent && (st === 'any' || st === 'enemy_minion' || st === 'any_minion')) spellTarget = true;
      if (!isOpponent && (st === 'friendly_minion' || st === 'any_minion')) spellTarget = true;
    }
    var heroTarget = heroAbilityMode.active && isOpponent;
    if (heroTarget) cls.push('hero-ability-target');
    if (spellTarget) cls.push('spell-target');
    if (m.frozen) cls.push('frozen');
    if (meta && meta.fictional) cls.push('fictional-card');
    const draggable = !isOpponent && canAttack && !m.frozen ? ' draggable="true"' : '';
    const cardCls = 'card faction-' + faction + (summonAnim ? ' summon-anim' : '') + (m.frozen ? ' frozen-card' : '') + (meta && meta.fictional ? ' fictional-card' : '');
    const dropAttrs = (isOpponent && isYourTurn) || spellTarget || heroTarget ? ` data-drop-player="${playerIndex}" data-drop-board="${boardIndex}"` : '';
    const dragTitle = !isOpponent && canAttack && !m.frozen ? ' title="Перетащи на врага для атаки"' : (m.frozen ? ' title="Заморожен (не может атаковать)"' : '');
    var abilHtml = meta ? abilityTags(meta) : '';
    var textHtml = meta && meta.text ? '<div class="card-text">' + escapeHtml(meta.text) + '</div>' : '';
    var frozenIcon = m.frozen ? '<div class="frozen-icon">❄</div>' : '';
    return '<div class="' + cls.join(' ') + '" data-player-index="' + playerIndex + '" data-board-index="' + boardIndex + '" data-minion-id="' + m.id + '" data-attacker-board-index="' + (!isOpponent && canAttack && !m.frozen ? boardIndex : '') + '"' + draggable + dropAttrs + dragTitle + '>'
      + '<div class="' + cardCls + '">'
      + frozenIcon
      + '<div class="card-art">' + art + '</div>'
      + '<div class="card-info">'
      + '<div class="card-name">' + escapeHtml(name) + '</div>'
      + textHtml + abilHtml
      + '<div class="card-stats">'
      + '<div class="card-atk-wrap"><span class="card-stat-label">Атака</span><span class="atk">' + displayAttack + (synergyAttack > 0 ? '<span class="synergy-bonus">+' + synergyAttack + '</span>' : '') + '</span></div>'
      + '<div class="card-hp-wrap"><span class="card-stat-label">Здоровье</span><span class="hp">' + displayHealth + (synergyHealth > 0 ? '<span class="synergy-bonus">+' + synergyHealth + '</span>' : '') + '</span></div>'
      + '</div>'
      + '<div class="card-info-row"><span></span><button type="button" class="card-btn-info" data-card-id="' + escapeHtml(m.cardId) + '" title="Описание">i</button></div>'
      + '</div></div></div>';
  }

  function renderHeroDropZone(playerIndex, state) {
    const isYourTurn = state.currentPlayerIndex === state.yourIndex;
    if (!isYourTurn || playerIndex === state.yourIndex) return '';
    if (attackMode.active && !spellMode.active && !heroAbilityMode.active) return '';
    var spellHero = spellMode.active && spellMode.spellTarget === 'any';
    var heroAb = heroAbilityMode.active;
    const p = state.players[playerIndex];
    const name = p?.name || 'Игрок ' + (playerIndex + 1);
    var heroCls = 'drop-target drop-target-hero' + (spellHero ? ' spell-target' : '') + (heroAb ? ' hero-ability-target' : '');
    var title = spellHero ? 'Цель заклинания' : (heroAb ? 'Цель геройской способности' : 'Перетащи сюда миньона для атаки по лидеру');
    return '<div class="' + heroCls + '" data-drop-player="' + playerIndex + '" data-drop-board="-1" title="' + title + '">'
      + '<span class="drop-hero-icon"><i data-lucide="heart" style="width: 18px; height: 18px; color: #e63946;"></i></span>'
      + '<span class="drop-hero-name">' + escapeHtml(name) + '</span>'
      + '</div>';
  }

  function renderHeroTarget(playerIndex, state) {
    if (!attackMode.active || attackMode.attackerPlayer !== state.yourIndex || playerIndex === state.yourIndex) return '';
    const p = state.players[playerIndex];
    const name = p?.name || 'Игрок ' + (playerIndex + 1);
    return `
      <div class="card-wrap targetable hero-target drop-target" data-player-index="${playerIndex}" data-board-index="-1" data-drop-player="${playerIndex}" data-drop-board="-1">
        <div class="card faction-neutral">
          <div class="card-art"><i data-lucide="heart" style="width: 48px; height: 48px; color: #e63946;"></i></div>
          <div class="card-info">
            <div class="card-name">${escapeHtml(name)} (лидер)</div>
            <div class="card-stats"><span class="hp">${p?.health ?? 30}</span></div>
          </div>
        </div>
      </div>`;
  }

  function bindGameEvents(state) {
    const you = state.players[state.yourIndex];
    const isYourTurn = state.currentPlayerIndex === state.yourIndex;
    const sidebar = $('forge-sidebar');
    const isForgeOpen = sidebar && !sidebar.classList.contains('hidden');
    
    // Chat handlers
    const chatContainer = $('chat-container');
    const chatToggle = $('btn-chat-toggle');
    const chatHeader = $('chat-header');
    const chatInput = $('chat-input');
    const chatSendBtn = $('btn-chat-send');
    
    if (chatToggle) {
      chatToggle.onclick = function() {
        if (chatContainer) {
          chatContainer.classList.toggle('collapsed');
          chatToggle.textContent = chatContainer.classList.contains('collapsed') ? '▲' : '▼';
        }
      };
    }
    
    if (chatHeader) {
      chatHeader.onclick = function() {
        if (chatContainer) {
          chatContainer.classList.toggle('collapsed');
          if (chatToggle) {
            chatToggle.textContent = chatContainer.classList.contains('collapsed') ? '▲' : '▼';
          }
        }
      };
    }
    
    function sendChatMessage() {
      if (!chatInput || !socket) return;
      const message = chatInput.value.trim();
      if (message.length === 0) return;
      
      socket.emit('chatMessage', { message: message });
      chatInput.value = '';
    }
    
    if (chatSendBtn) {
      chatSendBtn.onclick = sendChatMessage;
    }
    
    if (chatInput) {
      chatInput.onkeypress = function(e) {
        if (e.key === 'Enter') {
          sendChatMessage();
        }
      };
    }

    $all('.card-wrap.in-hand').forEach((wrap) => {
      wrap.classList.toggle('disabled', !isYourTurn);
      const handIndex = parseInt(wrap.dataset.handIndex, 10);
      const meta = cardDb[wrap.dataset.cardId];
      const isMinion = meta && meta.type === 'minion';
      const canPlay = isYourTurn && !state.isSpectator && !attackMode.active && !heroAbilityMode.active && meta && you && you.mana >= (meta.cost || 0);
      
      // Если кузница открыта и карта - миньон, делаем её перетаскиваемой для кузницы
      if (isForgeOpen && isMinion && !state.isSpectator) {
        wrap.draggable = true;
        wrap.ondragstart = function (e) {
          e.dataTransfer.setData('text/plain', 'hand:' + handIndex);
          e.dataTransfer.setData('source', 'hand');
          wrap.classList.add('dragging');
        };
        wrap.ondragend = function () {
          wrap.classList.remove('dragging');
        };
      } else if (isMinion && canPlay && !state.isSpectator && you && (you.board?.length ?? 0) < 7) {
        wrap.draggable = true;
        wrap.ondragstart = function (e) {
          if (!canPlay) return;
          e.dataTransfer.setData('text/plain', 'hand:' + handIndex);
          e.dataTransfer.effectAllowed = 'move';
          wrap.classList.add('dragging');
        };
        wrap.ondragend = function () {
          wrap.classList.remove('dragging');
          $all('.drop-target').forEach(function (t) { t.classList.remove('drop-over'); });
        };
      } else {
        wrap.draggable = false;
        wrap.ondragstart = null;
        wrap.ondragend = null;
      }
      
      wrap.onclick = function (e) {
        if (e.target.closest('.card-btn-info')) return;
        if (!isYourTurn || attackMode.active || heroAbilityMode.active) return;
        if (!meta) return;
        if (you.mana < (meta.cost || 0)) return;
        if (meta.type === 'minion') {
          if ((you.board?.length ?? 0) >= 7) return;
          if (typeof window.Sounds !== 'undefined') window.Sounds.playCard();
          var r = wrap.getBoundingClientRect();
          spawnEffect('play', r.left + r.width / 2, r.top + r.height / 2);
          wrap.querySelector('.card')?.classList.add('play-anim');
          socket.emit('playCard', { handIndex: handIndex, boardPos: you.board.length });
          setTimeout(function () { wrap.querySelector('.card')?.classList.remove('play-anim'); }, 500);
          return;
        }
        if (meta.type === 'spell') {
          if (state.isSpectator || spellMode.active || heroAbilityMode.active || stealCardsMode.active) return;
          var needTarget = meta.spellTarget && meta.spellTarget !== 'none';
          
          // Специальная обработка для Грабежа
          if (meta.spellEffect === 'steal_cards') {
            if (meta.spellTarget === 'enemy_player') {
              // Открываем модальное окно для выбора противника
              spellMode = { active: true, handIndex: handIndex, cardId: wrap.dataset.cardId, spellTarget: meta.spellTarget };
              $('spell-mode')?.classList.remove('hidden');
              renderGame(state);
              return;
            }
          }
          
          // Если это Грабеж, но spellTarget не enemy_player, все равно активируем режим выбора цели
          if (meta.spellEffect === 'steal_cards' && !meta.spellTarget) {
            spellMode = { active: true, handIndex: handIndex, cardId: wrap.dataset.cardId, spellTarget: 'enemy_player' };
            $('spell-mode')?.classList.remove('hidden');
            renderGame(state);
            return;
          }
          
          if (!needTarget) {
            if (typeof window.Sounds !== 'undefined') window.Sounds.playCard();
            socket.emit('playSpell', { handIndex: handIndex });
            return;
          }
          spellMode = { active: true, handIndex: handIndex, cardId: wrap.dataset.cardId, spellTarget: meta.spellTarget };
          const spellModeText = $('spell-mode')?.querySelector('p');
          if (spellModeText && meta.spellEffect === 'steal_cards') {
            spellModeText.textContent = 'Выберите противника для грабежа (кликните на блок противника)';
          } else if (spellModeText) {
            spellModeText.textContent = 'Выберите цель для заклинания';
          }
          $('spell-mode')?.classList.remove('hidden');
          renderGame(state);
          return;
        }
      };
      
      // Touch support for mobile
      if (isTouchDevice()) {
        wrap.ontouchstart = function (e) {
          if (e.target.closest('.card-btn-info')) {
            // Handle info button separately
            const btn = e.target.closest('.card-btn-info');
            if (btn) {
              const cid = btn.dataset.cardId;
              if (cid) {
                const meta = cardDb[cid];
                if (meta) {
                  const nameEl = $('card-info-name');
                  const metaEl = $('card-info-meta');
                  const textEl = $('card-info-text');
                  const abilEl = $('card-info-abilities');
                  const bioEl = $('card-info-bio');
                  if (nameEl) nameEl.textContent = meta.name || cid;
                  if (metaEl) {
                    if (meta.type === 'spell') metaEl.textContent = 'Заклинание · Мана: ' + (meta.cost ?? 0);
                    else metaEl.textContent = 'Минайон · Мана: ' + (meta.cost ?? 0) + ', Атака: ' + (meta.attack ?? 0) + ', Здоровье: ' + (meta.health ?? 0);
                  }
                  if (textEl) { textEl.textContent = meta.text || ''; textEl.classList.toggle('hidden', !meta.text); }
                  if (abilEl) {
                    var parts = [];
                    if (meta.battlecry) parts.push('<strong>Вой:</strong> ' + escapeHtml(meta.battlecry));
                    if (meta.deathrattle) parts.push('<strong>Предсмертный хрип:</strong> ' + escapeHtml(meta.deathrattle));
                    abilEl.innerHTML = parts.length ? parts.join('<br>') : '';
                    abilEl.classList.toggle('hidden', !parts.length);
                  }
                  if (bioEl) { bioEl.textContent = meta.bio || ''; bioEl.classList.toggle('hidden', !meta.bio); }
                  $('card-info-overlay')?.classList.remove('hidden');
                }
              }
            }
            return;
          }
          
          if (!isYourTurn || attackMode.active || heroAbilityMode.active) return;
          if (!meta) return;
          
          const touch = e.touches[0];
          touchState.startX = touch.clientX;
          touchState.startY = touch.clientY;
          touchState.startTime = Date.now();
          touchState.target = wrap;
          touchState.isSwipe = false;
          wrap.classList.add('touch-active');
          
          // Long press for card info
          touchState.longPressTimer = setTimeout(function() {
            if (touchState.target === wrap && meta) {
              const nameEl = $('card-info-name');
              const metaEl = $('card-info-meta');
              const textEl = $('card-info-text');
              const abilEl = $('card-info-abilities');
              const bioEl = $('card-info-bio');
              if (nameEl) nameEl.textContent = meta.name || wrap.dataset.cardId;
              if (metaEl) {
                if (meta.type === 'spell') metaEl.textContent = 'Заклинание · Мана: ' + (meta.cost ?? 0);
                else metaEl.textContent = 'Минайон · Мана: ' + (meta.cost ?? 0) + ', Атака: ' + (meta.attack ?? 0) + ', Здоровье: ' + (meta.health ?? 0);
              }
              if (textEl) { textEl.textContent = meta.text || ''; textEl.classList.toggle('hidden', !meta.text); }
              if (abilEl) {
                var parts = [];
                if (meta.battlecry) parts.push('<strong>Вой:</strong> ' + escapeHtml(meta.battlecry));
                if (meta.deathrattle) parts.push('<strong>Предсмертный хрип:</strong> ' + escapeHtml(meta.deathrattle));
                abilEl.innerHTML = parts.length ? parts.join('<br>') : '';
                abilEl.classList.toggle('hidden', !parts.length);
              }
              if (bioEl) { bioEl.textContent = meta.bio || ''; bioEl.classList.toggle('hidden', !meta.bio); }
              $('card-info-overlay')?.classList.remove('hidden');
              wrap.classList.add('long-pressed');
            }
          }, touchState.longPressDelay);
        };
        
        wrap.ontouchmove = function (e) {
          if (!touchState.target || touchState.target !== wrap) return;
          
          // Cancel long press if moved
          if (touchState.longPressTimer) {
            clearTimeout(touchState.longPressTimer);
            touchState.longPressTimer = null;
          }
          
          const touch = e.touches[0];
          const dx = touch.clientX - touchState.startX;
          const dy = touch.clientY - touchState.startY;
          const distance = Math.sqrt(dx * dx + dy * dy);
          
          if (distance > touchState.minSwipeDistance) {
            touchState.isSwipe = true;
            wrap.classList.add('swiping');
            wrap.classList.remove('long-pressed');
          }
        };
        
        wrap.ontouchend = function (e) {
          if (!touchState.target || touchState.target !== wrap) return;
          
          // Cancel long press timer
          if (touchState.longPressTimer) {
            clearTimeout(touchState.longPressTimer);
            touchState.longPressTimer = null;
          }
          
          wrap.classList.remove('touch-active', 'swiping', 'long-pressed');
          
          const touch = e.changedTouches[0];
          const dx = touch.clientX - touchState.startX;
          const dy = touch.clientY - touchState.startY;
          const distance = Math.sqrt(dx * dx + dy * dy);
          const time = Date.now() - touchState.startTime;
          
          // If it was a swipe or long press, don't trigger card play
          if (touchState.isSwipe || distance > touchState.minSwipeDistance || time > touchState.longPressDelay) {
            touchState.target = null;
            return;
          }
          
          // Tap - trigger card play
          if (time < touchState.maxSwipeTime && distance < 10 && you.mana >= (meta?.cost || 0)) {
            if (meta?.type === 'minion' && (you.board?.length ?? 0) < 7) {
              if (typeof window.Sounds !== 'undefined') window.Sounds.playCard();
              var r = wrap.getBoundingClientRect();
              spawnEffect('play', r.left + r.width / 2, r.top + r.height / 2);
              wrap.querySelector('.card')?.classList.add('play-anim');
              socket.emit('playCard', { handIndex: handIndex, boardPos: you.board.length });
              setTimeout(function () { wrap.querySelector('.card')?.classList.remove('play-anim'); }, 500);
            } else if (meta?.type === 'spell') {
              if (spellMode.active || heroAbilityMode.active) return;
              var needTarget = meta.spellTarget && meta.spellTarget !== 'none';
              if (!needTarget) {
                if (typeof window.Sounds !== 'undefined') window.Sounds.playCard();
                socket.emit('playSpell', { handIndex: handIndex });
              } else {
                spellMode = { active: true, handIndex: handIndex, cardId: wrap.dataset.cardId, spellTarget: meta.spellTarget };
                $('spell-mode')?.classList.remove('hidden');
                renderGame(state);
              }
            }
          }
          
          touchState.target = null;
        };
        
        wrap.ontouchcancel = function () {
          if (touchState.longPressTimer) {
            clearTimeout(touchState.longPressTimer);
            touchState.longPressTimer = null;
          }
          wrap.classList.remove('touch-active', 'swiping', 'long-pressed');
          touchState.target = null;
        };
      }
    });

    $all('.card-btn-info').forEach(function (btn) {
      btn.onclick = function (e) {
        e.stopPropagation();
        var cid = btn.dataset.cardId;
        if (!cid) return;
        var meta = cardDb[cid];
        if (!meta) return;
        var nameEl = $('card-info-name');
        var metaEl = $('card-info-meta');
        var textEl = $('card-info-text');
        var abilEl = $('card-info-abilities');
        var bioEl = $('card-info-bio');
        if (nameEl) nameEl.textContent = meta.name || cid;
        if (metaEl) {
          if (meta.type === 'spell') metaEl.textContent = 'Заклинание · Мана: ' + (meta.cost ?? 0);
          else metaEl.textContent = 'Минайон · Мана: ' + (meta.cost ?? 0) + ', Атака: ' + (meta.attack ?? 0) + ', Здоровье: ' + (meta.health ?? 0);
        }
        if (textEl) { textEl.textContent = meta.text || ''; textEl.classList.toggle('hidden', !meta.text); }
        if (abilEl) {
          var parts = [];
          if (meta.battlecry) parts.push('<strong>Вой:</strong> ' + escapeHtml(meta.battlecry));
          if (meta.deathrattle) parts.push('<strong>Предсмертный хрип:</strong> ' + escapeHtml(meta.deathrattle));
          abilEl.innerHTML = parts.length ? parts.join('<br>') : '';
          abilEl.classList.toggle('hidden', !parts.length);
        }
        if (bioEl) { bioEl.textContent = meta.bio || ''; bioEl.classList.toggle('hidden', !meta.bio); }
        $('card-info-overlay')?.classList.remove('hidden');
      };
    });
    var closeInfo = $('btn-card-info-close');
    if (closeInfo) closeInfo.onclick = function () { $('card-info-overlay')?.classList.add('hidden'); };

    $all('.card-wrap.attackable:not(.targetable)').forEach((wrap) => {
      wrap.onclick = () => {
        if (!isYourTurn || attackMode.active || spellMode.active || heroAbilityMode.active) return;
        const playerIndex = parseInt(wrap.dataset.playerIndex, 10);
        const boardIndex = parseInt(wrap.dataset.boardIndex, 10);
        if (playerIndex !== state.yourIndex) return;
        attackMode = { active: true, attackerPlayer: playerIndex, attackerBoard: boardIndex };
        $('attack-mode')?.classList.remove('hidden');
        renderGame(state);
      };
      
      // Touch support for attack
      if (isTouchDevice()) {
        wrap.ontouchstart = function (e) {
          if (!isYourTurn || attackMode.active || spellMode.active || heroAbilityMode.active) return;
          const playerIndex = parseInt(wrap.dataset.playerIndex, 10);
          const boardIndex = parseInt(wrap.dataset.boardIndex, 10);
          if (playerIndex !== state.yourIndex) return;
          
          const touch = e.touches[0];
          touchState.startX = touch.clientX;
          touchState.startY = touch.clientY;
          touchState.startTime = Date.now();
          touchState.target = wrap;
        };
        
        wrap.ontouchend = function (e) {
          if (!touchState.target || touchState.target !== wrap) return;
          const touch = e.changedTouches[0];
          const dx = touch.clientX - touchState.startX;
          const dy = touch.clientY - touchState.startY;
          const distance = Math.sqrt(dx * dx + dy * dy);
          const time = Date.now() - touchState.startTime;
          
          if (time < touchState.maxSwipeTime && distance < 20) {
            const playerIndex = parseInt(wrap.dataset.playerIndex, 10);
            const boardIndex = parseInt(wrap.dataset.boardIndex, 10);
            if (playerIndex === state.yourIndex) {
              attackMode = { active: true, attackerPlayer: playerIndex, attackerBoard: boardIndex };
              $('attack-mode')?.classList.remove('hidden');
              renderGame(state);
            }
          }
          
          touchState.target = null;
        };
      }
    });

    $all('.card-wrap.targetable, .card-wrap.hero-target').forEach((wrap) => {
      wrap.onclick = () => {
        if (spellMode.active || heroAbilityMode.active) return;
        if (!attackMode.active) return;
        const targetPlayer = parseInt(wrap.dataset.playerIndex ?? wrap.dataset.dropPlayer, 10);
        const targetBoard = parseInt(wrap.dataset.boardIndex ?? wrap.dataset.dropBoard, 10);
        if (typeof window.Sounds !== 'undefined') window.Sounds.attack();
        socket.emit('attack', {
          attackerPlayerIndex: state.yourIndex,
          attackerBoardIndex: attackMode.attackerBoard,
          targetPlayerIndex: targetPlayer,
          targetBoardIndex: targetBoard,
        });
        attackMode = { active: false, attackerPlayer: -1, attackerBoard: -1 };
        $('attack-mode')?.classList.add('hidden');
      };
      
      // Touch support for target selection
      if (isTouchDevice()) {
        wrap.ontouchstart = function (e) {
          if (spellMode.active || heroAbilityMode.active) return;
          if (!attackMode.active) return;
          e.preventDefault();
          const targetPlayer = parseInt(wrap.dataset.playerIndex ?? wrap.dataset.dropPlayer, 10);
          const targetBoard = parseInt(wrap.dataset.boardIndex ?? wrap.dataset.dropBoard, 10);
          if (typeof window.Sounds !== 'undefined') window.Sounds.attack();
          socket.emit('attack', {
            attackerPlayerIndex: state.yourIndex,
            attackerBoardIndex: attackMode.attackerBoard,
            targetPlayerIndex: targetPlayer,
            targetBoardIndex: targetBoard,
          });
          attackMode = { active: false, attackerPlayer: -1, attackerBoard: -1 };
          $('attack-mode')?.classList.add('hidden');
        };
      }
    });

    $all('.spell-target, .drop-target-hero.spell-target').forEach(function (el) {
      el.onclick = function (e) {
        if (!spellMode.active && !battlecryTargetMode.active) return;
        e.stopPropagation();
        var tp = parseInt(el.dataset.dropPlayer ?? el.dataset.playerIndex, 10);
        var tb = parseInt(el.dataset.dropBoard ?? el.dataset.boardIndex, 10);
        
        // Обработка для battlecry (Ezra Bridger)
        if (battlecryTargetMode.active && battlecryTargetMode.battlecryId === 'return_hand_enemy') {
          if (tp !== state.yourIndex && tp >= 0 && tb >= 0) {
            const targetPlayer = state.players[tp];
            if (targetPlayer && targetPlayer.board && targetPlayer.board[tb]) {
              socket.emit('battlecryTarget', {
                battlecryId: 'return_hand_enemy',
                targetPlayerIndex: tp,
                targetBoardIndex: tb
              });
              battlecryTargetMode = { active: false, battlecryId: '', cardId: '', minionId: '', targetPlayerIndex: null, targetBoardIndex: null };
              spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
              $('spell-mode')?.classList.add('hidden');
              renderGame(state);
              return;
            }
          }
          return;
        }
        
        // Специальная обработка для Грабежа - отправляем playSpell на сервер
        const spellCard = cardDb[spellMode.cardId];
        if (spellCard && spellCard.spellEffect === 'steal_cards' && (spellCard.spellTarget === 'enemy_player' || spellCard.spellTarget === 'enemy_board')) {
          // Выбираем противника (tp должен быть индексом противника, tb игнорируем для enemy_player)
          if (tp !== state.yourIndex && tp >= 0) {
            const targetPlayer = state.players[tp];
            if (targetPlayer && targetPlayer.board && targetPlayer.board.length > 0) {
              // Отправляем playSpell на сервер, чтобы сервер знал о выборе противника
              socket.emit('playSpell', { handIndex: spellMode.handIndex, targetPlayerIndex: tp, targetBoardIndex: null });
              // Сервер отправит stealCardsRequest, который откроет модальное окно
              spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
              $('spell-mode')?.classList.add('hidden');
              return;
            }
          }
          return;
        }
        
        if (typeof window.Sounds !== 'undefined') window.Sounds.playCard();
        socket.emit('playSpell', { handIndex: spellMode.handIndex, targetPlayerIndex: tp, targetBoardIndex: tb });
        spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
        $('spell-mode')?.classList.add('hidden');
        renderGame(state);
      };
      
      // Touch support for spell targets
      if (isTouchDevice()) {
        el.ontouchstart = function (e) {
          if (!spellMode.active) return;
          e.preventDefault();
          e.stopPropagation();
          var tp = parseInt(el.dataset.dropPlayer ?? el.dataset.playerIndex, 10);
          var tb = parseInt(el.dataset.dropBoard ?? el.dataset.boardIndex, 10);
          
          // Специальная обработка для Грабежа - отправляем playSpell на сервер
          const spellCard = cardDb[spellMode.cardId];
          if (spellCard && spellCard.spellEffect === 'steal_cards' && (spellCard.spellTarget === 'enemy_player' || spellCard.spellTarget === 'enemy_board')) {
            if (tp !== state.yourIndex && tp >= 0) {
              const targetPlayer = state.players[tp];
              if (targetPlayer && targetPlayer.board && targetPlayer.board.length > 0) {
                // Отправляем playSpell на сервер, чтобы сервер знал о выборе противника
                socket.emit('playSpell', { handIndex: spellMode.handIndex, targetPlayerIndex: tp, targetBoardIndex: null });
                // Сервер отправит stealCardsRequest, который откроет модальное окно
                spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
                $('spell-mode')?.classList.add('hidden');
                return;
              }
            }
            return;
          }
          
          if (typeof window.Sounds !== 'undefined') window.Sounds.playCard();
          socket.emit('playSpell', { handIndex: spellMode.handIndex, targetPlayerIndex: tp, targetBoardIndex: tb });
          spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
          $('spell-mode')?.classList.add('hidden');
          renderGame(state);
        };
      }
    });

    $all('.hero-ability-target, .drop-target-hero.hero-ability-target').forEach(function (el) {
      el.onclick = function (e) {
        if (!heroAbilityMode.active) return;
        e.stopPropagation();
        var tp = parseInt(el.dataset.dropPlayer ?? el.dataset.playerIndex, 10);
        var tb = parseInt(el.dataset.dropBoard ?? el.dataset.boardIndex, 10);
        if (typeof window.Sounds !== 'undefined') window.Sounds.attack();
        socket.emit('heroAbility', { targetPlayerIndex: tp, targetBoardIndex: tb });
        heroAbilityMode = { active: false };
        $('hero-ability-mode')?.classList.add('hidden');
        renderGame(state);
      };
      
      // Touch support for hero ability targets
      if (isTouchDevice()) {
        el.ontouchstart = function (e) {
          if (!heroAbilityMode.active) return;
          e.preventDefault();
          e.stopPropagation();
          var tp = parseInt(el.dataset.dropPlayer ?? el.dataset.playerIndex, 10);
          var tb = parseInt(el.dataset.dropBoard ?? el.dataset.boardIndex, 10);
          if (typeof window.Sounds !== 'undefined') window.Sounds.attack();
          socket.emit('heroAbility', { targetPlayerIndex: tp, targetBoardIndex: tb });
          heroAbilityMode = { active: false };
          $('hero-ability-mode')?.classList.add('hidden');
          renderGame(state);
        };
      }
    });
    
    // Обработка выбора противника для Грабежа
    $all('.opponent-block.steal-target').forEach(function (el) {
      el.onclick = function (e) {
        if (!spellMode.active) return;
        const spellCard = cardDb[spellMode.cardId];
        if (!spellCard || spellCard.spellEffect !== 'steal_cards' || (spellCard.spellTarget !== 'enemy_player' && spellCard.spellTarget !== 'enemy_board')) return;
        e.stopPropagation();
        var tp = parseInt(el.dataset.playerIndex ?? el.dataset.opponentIndex, 10);
        if (tp === state.yourIndex || tp < 0) return;
        const targetPlayer = state.players[tp];
        if (targetPlayer && targetPlayer.board && targetPlayer.board.length > 0) {
          // Отправляем playSpell на сервер, чтобы сервер знал о выборе противника
          socket.emit('playSpell', { handIndex: spellMode.handIndex, targetPlayerIndex: tp, targetBoardIndex: null });
          // Сервер отправит stealCardsRequest, который откроет модальное окно
          spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
          $('spell-mode')?.classList.add('hidden');
        }
      };
      
      // Touch support
      if (isTouchDevice()) {
        el.ontouchstart = function (e) {
          if (!spellMode.active) return;
          const spellCard = cardDb[spellMode.cardId];
          if (!spellCard || spellCard.spellEffect !== 'steal_cards' || (spellCard.spellTarget !== 'enemy_player' && spellCard.spellTarget !== 'enemy_board')) return;
          e.preventDefault();
          e.stopPropagation();
          var tp = parseInt(el.dataset.playerIndex ?? el.dataset.opponentIndex, 10);
          if (tp === state.yourIndex || tp < 0) return;
          const targetPlayer = state.players[tp];
          if (targetPlayer && targetPlayer.board && targetPlayer.board.length > 0) {
            // Отправляем playSpell на сервер, чтобы сервер знал о выборе противника
            socket.emit('playSpell', { handIndex: spellMode.handIndex, targetPlayerIndex: tp, targetBoardIndex: null });
            // Сервер отправит stealCardsRequest, который откроет модальное окно
            spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
            $('spell-mode')?.classList.add('hidden');
          }
        };
      }
    });

    var heroAbilityBtn = $('btn-hero-ability');
    if (heroAbilityBtn) heroAbilityBtn.onclick = function () {
      if (state.isSpectator || heroAbilityBtn.disabled || heroAbilityMode.active) return;
      heroAbilityMode = { active: true };
      $('hero-ability-mode')?.classList.remove('hidden');
      renderGame(state);
    };
    
    var forgeBtn = $('btn-forge');
    if (forgeBtn && isYourTurn && !state.isSpectator && you && you.mana >= 2) {
      forgeBtn.disabled = false;
      forgeBtn.onclick = function () {
        if (state.isSpectator || attackMode.active || spellMode.active || heroAbilityMode.active) return;
        const sidebar = $('forge-sidebar');
        if (sidebar) {
          sidebar.classList.remove('hidden');
          forgeSelected = []; // Сбрасываем выбор при открытии
          renderForgeHand(state);
          renderForgeSelected();
          updateForgePreview();
        }
      };
    } else if (forgeBtn) {
      forgeBtn.disabled = true;
    }

    var cancelSpellBtn = $('btn-cancel-spell');
    if (cancelSpellBtn) cancelSpellBtn.onclick = function () {
      spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
      attackMode = { active: false, attackerPlayer: -1, attackerBoard: -1 };
      heroAbilityMode = { active: false };
      stealCardsMode = { active: false, handIndex: -1, targetPlayerIndex: null, targetDeck: [], selectedIndices: [] };
      $('spell-mode')?.classList.add('hidden');
      $('attack-mode')?.classList.add('hidden');
      $('hero-ability-mode')?.classList.add('hidden');
      $('steal-cards-overlay')?.classList.add('hidden');
      renderGame(state);
    };

    var cancelHeroBtn = $('btn-cancel-hero');
    if (cancelHeroBtn) cancelHeroBtn.onclick = function () {
      heroAbilityMode = { active: false };
      $('hero-ability-mode')?.classList.add('hidden');
      renderGame(state);
    };

    const cancelBtn = $('btn-cancel-attack');
    if (cancelBtn) {
      cancelBtn.onclick = function () {
        attackMode = { active: false, attackerPlayer: -1, attackerBoard: -1 };
        spellMode = { active: false, handIndex: -1, cardId: '', spellTarget: '' };
        heroAbilityMode = { active: false };
        stealCardsMode = { active: false, handIndex: -1, targetPlayerIndex: null, targetDeck: [], selectedIndices: [] };
        $('attack-mode')?.classList.add('hidden');
        $('spell-mode')?.classList.add('hidden');
        $('hero-ability-mode')?.classList.add('hidden');
        $('steal-cards-overlay')?.classList.add('hidden');
        renderGame(state);
      };
    }

    const endBtn = $('btn-end-turn');
    if (endBtn) {
      endBtn.onclick = isYourTurn
        ? () => {
            if (typeof window.Sounds !== 'undefined') window.Sounds.endTurn();
            socket.emit('endTurn');
          }
        : null;
    }

    const resetBtn = $('btn-reset-lobby');
    if (resetBtn) {
      resetBtn.onclick = state.yourIndex === 0 ? () => socket.emit('resetToLobby') : null;
    }

    var deckEl = $('deck-fan');
    if (deckEl && deckEl.classList.contains('deck-drawable')) {
      deckEl.onclick = function () {
        var r = deckEl.getBoundingClientRect();
        spawnEffect('draw', r.left + r.width / 2, r.top + r.height / 2);
        socket.emit('drawCard');
      };
      deckEl.style.cursor = 'pointer';
      
      // Touch support for deck
      if (isTouchDevice()) {
        deckEl.ontouchstart = function (e) {
          e.preventDefault();
          var r = deckEl.getBoundingClientRect();
          spawnEffect('draw', r.left + r.width / 2, r.top + r.height / 2);
          socket.emit('drawCard');
        };
      }
    } else if (deckEl) {
      deckEl.onclick = null;
      deckEl.style.cursor = 'default';
      if (isTouchDevice()) {
        deckEl.ontouchstart = null;
      }
    }

    $all('.card-wrap.attackable[draggable="true"]').forEach(function (wrap) {
      wrap.ondragstart = function (e) {
        var idx = wrap.dataset.attackerBoardIndex;
        if (idx === undefined) return;
        e.dataTransfer.setData('text/plain', idx);
        e.dataTransfer.effectAllowed = 'move';
        wrap.classList.add('dragging');
      };
      wrap.ondragend = function () {
        wrap.classList.remove('dragging');
        $all('.drop-target').forEach(function (t) { t.classList.remove('drop-over'); });
      };
    });

    $all('.drop-target').forEach(function (target) {
      target.ondragover = function (e) {
        e.preventDefault();
        e.dataTransfer.dropEffect = 'move';
        target.classList.add('drop-over');
      };
      target.ondragleave = function () {
        target.classList.remove('drop-over');
      };
      target.ondrop = function (e) {
        e.preventDefault();
        target.classList.remove('drop-over');
        var data = e.dataTransfer.getData('text/plain');
        if (data === '') return;
        
        if (data.startsWith('hand:')) {
          var handIndex = parseInt(data.split(':')[1], 10);
          if (isNaN(handIndex)) return;
          var meta = cardDb[you.hand?.[handIndex]];
          if (!meta || meta.type !== 'minion') return;
          if (you.mana < (meta.cost || 0)) return;
          if ((you.board?.length ?? 0) >= 7) return;
          if (typeof window.Sounds !== 'undefined') window.Sounds.playCard();
          var rect = target.getBoundingClientRect();
          spawnEffect('play', rect.left + rect.width / 2, rect.top + rect.height / 2);
          socket.emit('playCard', { handIndex: handIndex, boardPos: you.board.length });
          return;
        }
        
        var attackerBoard = parseInt(data, 10);
        var targetPlayer = parseInt(target.dataset.dropPlayer, 10);
        var targetBoard = target.dataset.dropBoard !== undefined ? parseInt(target.dataset.dropBoard, 10) : -1;
        if (isNaN(attackerBoard) || isNaN(targetPlayer)) return;
        if (typeof window.Sounds !== 'undefined') window.Sounds.attack();
        var rect = target.getBoundingClientRect();
        spawnEffect('attack', rect.left + rect.width / 2, rect.top + rect.height / 2);
        socket.emit('attack', {
          attackerPlayerIndex: state.yourIndex,
          attackerBoardIndex: attackerBoard,
          targetPlayerIndex: targetPlayer,
          targetBoardIndex: isNaN(targetBoard) ? -1 : targetBoard,
        });
        attackMode = { active: false, attackerPlayer: -1, attackerBoard: -1 };
        $('attack-mode')?.classList.add('hidden');
      };
    });
    
    var yourBoardEl = $('your-board');
    if (yourBoardEl && isYourTurn && !attackMode.active && !spellMode.active && !heroAbilityMode.active) {
      yourBoardEl.classList.add('drop-target');
      yourBoardEl.ondragover = function (e) {
        e.preventDefault();
        e.dataTransfer.dropEffect = 'move';
        yourBoardEl.classList.add('drop-over');
      };
      yourBoardEl.ondragleave = function () {
        yourBoardEl.classList.remove('drop-over');
      };
      yourBoardEl.ondrop = function (e) {
        e.preventDefault();
        yourBoardEl.classList.remove('drop-over');
        var data = e.dataTransfer.getData('text/plain');
        if (!data.startsWith('hand:')) return;
        var handIndex = parseInt(data.split(':')[1], 10);
        if (isNaN(handIndex)) return;
        var meta = cardDb[you.hand?.[handIndex]];
        if (!meta || meta.type !== 'minion') return;
        if (you.mana < (meta.cost || 0)) return;
        if ((you.board?.length ?? 0) >= 7) return;
        if (typeof window.Sounds !== 'undefined') window.Sounds.playCard();
        var rect = yourBoardEl.getBoundingClientRect();
        spawnEffect('play', rect.left + rect.width / 2, rect.top + rect.height / 2);
        socket.emit('playCard', { handIndex: handIndex, boardPos: you.board.length });
      };
    } else if (yourBoardEl) {
      yourBoardEl.classList.remove('drop-target');
      yourBoardEl.ondragover = null;
      yourBoardEl.ondragleave = null;
      yourBoardEl.ondrop = null;
    }
    
    // Обновляем кузницу, если она открыта
    if (isForgeOpen) {
      renderForgeHand(state);
      renderForgeSelected();
      updateForgePreview();
    }
  }

  function initLobby() {
    const hostTab = document.querySelector('.tab[data-tab="host"]');
    const joinTab = document.querySelector('.tab[data-tab="join"]');
    const browseTab = document.querySelector('.tab[data-tab="browse"]');
    hostTab?.addEventListener('click', () => {
      $all('.tab').forEach((t) => t.classList.remove('active'));
      hostTab.classList.add('active');
      $('host-panel')?.classList.add('active');
      $('join-panel')?.classList.remove('active');
      $('browse-panel')?.classList.remove('active');
      clearError();
    });
    joinTab?.addEventListener('click', () => {
      $all('.tab').forEach((t) => t.classList.remove('active'));
      joinTab.classList.add('active');
      $('join-panel')?.classList.add('active');
      $('host-panel')?.classList.remove('active');
      $('browse-panel')?.classList.remove('active');
      clearError();
    });
    browseTab?.addEventListener('click', () => {
      $all('.tab').forEach((t) => t.classList.remove('active'));
      browseTab.classList.add('active');
      $('browse-panel')?.classList.add('active');
      $('host-panel')?.classList.remove('active');
      $('join-panel')?.classList.remove('active');
      clearError();
      
      // Показываем сообщение о загрузке
      const roomsListEl = $('rooms-list');
      if (roomsListEl) {
        roomsListEl.innerHTML = '<p class="hint" style="text-align: center; padding: 2rem; color: #94a3b8;">Загрузка списка игр...</p>';
      }
      
      // Подключаемся к серверу если еще не подключены
      if (!socket || !socket.connected) {
        const url = window.location.origin;
        connect(url);
        socket.once('connect', () => {
          socket.emit('getRoomsList');
        });
      } else {
        socket.emit('getRoomsList');
      }
    });

    const btnHost = $('btn-host');
    if (btnHost) {
      // Удаляем старые обработчики, если есть
      const newBtn = btnHost.cloneNode(true);
      btnHost.parentNode.replaceChild(newBtn, btnHost);
      
      newBtn.addEventListener('click', function(e) {
        e.preventDefault();
        e.stopPropagation();
        console.log('Кнопка "Создать комнату" нажата');
        clearError();
        const name = ($('host-name')?.value || '').trim() || 'Игрок 1';
        console.log('Имя игрока:', name);
        const currentHost = window.location.hostname;
        let url = window.location.origin;
        if (currentHost !== 'localhost' && currentHost !== '127.0.0.1') {
          url = window.location.origin;
        }
        
        if (!socket || !socket.connected) {
          console.log('Подключение к серверу:', url);
          connect(url);
          socket.once('connect', () => {
            console.log('Подключено, создаём комнату');
            const aiMode = $('ai-mode')?.checked || false;
          socket.emit('createRoom', { name, aiMode });
          });
          socket.once('connect_error', (e) => {
            console.error('Ошибка подключения:', e);
            showError('Не удалось подключиться к серверу. Проверьте, что сервер запущен.');
          });
        } else {
          console.log('Уже подключен, создаём комнату');
          // Уже подключен, сразу отправляем
          const aiMode = $('ai-mode')?.checked || false;
          socket.emit('createRoom', { name, aiMode });
        }
      });
      
      // Также добавляем обработчик через onclick для надёжности
      newBtn.onclick = function(e) {
        e.preventDefault();
        e.stopPropagation();
        console.log('Кнопка "Создать комнату" нажата (onclick)');
        const name = ($('host-name')?.value || '').trim() || 'Игрок 1';
        const currentHost = window.location.hostname;
        let url = window.location.origin;
        if (currentHost !== 'localhost' && currentHost !== '127.0.0.1') {
          url = window.location.origin;
        }
        
        if (!socket || !socket.connected) {
          connect(url);
          socket.once('connect', () => {
            const aiMode = $('ai-mode')?.checked || false;
          socket.emit('createRoom', { name, aiMode });
          });
          socket.once('connect_error', (e) => {
            showError('Не удалось подключиться к серверу. Проверьте, что сервер запущен.');
          });
        } else {
          const aiMode = $('ai-mode')?.checked || false;
          socket.emit('createRoom', { name, aiMode });
        }
      };
    } else {
      console.error('Кнопка btn-host не найдена! Проверьте, что элемент существует в DOM.');
    }

    $('btn-join')?.addEventListener('click', () => {
      clearError();
      const addr = ($('join-addr')?.value || '').trim();
      let url;
      if (addr && addr !== 'Оставьте пустым для авто') {
        const parts = addr.split(':');
        const host = parts[0] || 'localhost';
        const port = parts[1] || DEFAULT_PORT;
        url = `http://${host}:${port}`;
      } else {
        url = window.location.origin;
      }
      connect(url);
      socket.once('connect', () => {
        setLobbyPanel('connect');
        $('connect-panel')?.classList.add('active');
      });
      socket.once('connect_error', () => {
        const detailsEl = document.querySelector('#join-panel details');
        if (detailsEl && !detailsEl.open) {
          detailsEl.open = true;
          showError('Не удалось подключиться автоматически. Проверьте расширенные настройки и введите IP сервера вручную.');
        }
      });
    });

    var joinCodeHandler = function () {
      clearError();
      const code = ($('join-code')?.value || '').trim().toUpperCase();
      if (!code || code.length !== 5) {
        showError('Введите код комнаты (5 символов)');
        return;
      }
      const name = ($('join-name')?.value || '').trim() || 'Игрок 2';
      if (!socket || !socket.connected) {
        const addr = ($('join-addr')?.value || '').trim();
        let url;
        if (addr && addr !== 'Оставьте пустым для авто') {
          const parts = addr.split(':');
          const host = parts[0] || 'localhost';
          const port = parts[1] || DEFAULT_PORT;
          url = `http://${host}:${port}`;
        } else {
          url = window.location.origin;
        }
        connect(url);
        socket.once('connect', () => {
          socket.emit('joinRoom', { code, name });
        });
      } else {
        socket.emit('joinRoom', { code, name });
      }
    };
    $('btn-join-code')?.addEventListener('click', joinCodeHandler);
    $('join-code')?.addEventListener('keypress', function (e) {
      if (e.key === 'Enter') joinCodeHandler();
    });

    $('btn-start')?.addEventListener('click', () => {
      clearError();
      var faction = $('room-faction')?.value || '';
      socket?.emit('startGame', { faction: faction || undefined });
    });

    $('btn-leave')?.addEventListener('click', () => {
      socket?.emit('leaveLobby');
      setLobbyPanel('host');
      $('host-panel')?.classList.add('active');
      showScreen('lobby');
    });

    $('btn-leave-join')?.addEventListener('click', () => {
      socket?.emit('leaveLobby');
      socket?.disconnect();
      setLobbyPanel('join');
      $('join-panel')?.classList.add('active');
      showScreen('lobby');
    });

    $('btn-modal-close')?.addEventListener('click', () => {
      $('modal-overlay')?.classList.add('hidden');
      const newGameBtn = $('btn-new-game');
      if (newGameBtn) newGameBtn.style.display = 'none';
    });
    
    $('btn-new-game')?.addEventListener('click', () => {
      if (socket && socket.connected) {
        socket.emit('resetToLobby');
        $('modal-overlay')?.classList.add('hidden');
        const newGameBtn = $('btn-new-game');
        if (newGameBtn) newGameBtn.style.display = 'none';
      }
    });
    
    $('btn-refresh-rooms')?.addEventListener('click', () => {
      if (socket && socket.connected) {
        socket.emit('getRoomsList');
      } else {
        const url = window.location.origin;
        connect(url);
        socket.once('connect', () => {
          socket.emit('getRoomsList');
        });
      }
    });
    
    $('btn-instructions')?.addEventListener('click', () => {
      $('instructions-overlay')?.classList.remove('hidden');
    });
    $('btn-instructions-lobby')?.addEventListener('click', () => {
      $('instructions-overlay')?.classList.remove('hidden');
    });
    $('btn-instructions-close')?.addEventListener('click', () => {
      $('instructions-overlay')?.classList.add('hidden');
    });
    
    $('btn-cards-gallery')?.addEventListener('click', () => {
      $('cards-gallery-overlay')?.classList.remove('hidden');
      renderCardsGallery();
    });
    $('btn-cards-gallery-game')?.addEventListener('click', () => {
      $('cards-gallery-overlay')?.classList.remove('hidden');
      renderCardsGallery();
    });
    $('btn-gallery-close')?.addEventListener('click', () => {
      $('cards-gallery-overlay')?.classList.add('hidden');
    });
    $('cards-gallery-overlay')?.addEventListener('click', (e) => {
      if (e.target.id === 'cards-gallery-overlay') {
        $('cards-gallery-overlay')?.classList.add('hidden');
      }
    });
    
    $('gallery-faction-filter')?.addEventListener('change', renderCardsGallery);
    $('gallery-type-filter')?.addEventListener('change', renderCardsGallery);
    $('gallery-search')?.addEventListener('input', renderCardsGallery);
    
    let galleryCardDb = null;
    function renderCardsGallery() {
      const grid = $('cards-gallery-grid');
      if (!grid) return;
      
      if (!galleryCardDb) {
        fetch('/api/cards')
          .then(res => res.json())
          .then(data => {
            galleryCardDb = data;
            renderCardsGallery();
          })
          .catch(() => {
            grid.innerHTML = '<p style="color: #94a3b8; text-align: center; padding: 2rem;">Не удалось загрузить карты</p>';
          });
        return;
      }
      
      const factionFilter = ($('gallery-faction-filter')?.value || '').toLowerCase();
      const typeFilter = ($('gallery-type-filter')?.value || '').toLowerCase();
      const searchText = ($('gallery-search')?.value || '').toLowerCase();
      
      const allCards = Object.keys(galleryCardDb || {}).map(id => ({ id, ...galleryCardDb[id] }));
      const filtered = allCards.filter(card => {
        if (factionFilter && card.faction !== factionFilter) return false;
        if (typeFilter && card.type !== typeFilter) return false;
        if (searchText && !card.name.toLowerCase().includes(searchText)) return false;
        return true;
      });
      
      grid.innerHTML = filtered.map(card => {
        const isFictional = card.fictional || false;
        const cost = card.cost || 0;
        const attack = card.attack !== undefined ? card.attack : '';
        const health = card.health !== undefined ? card.health : '';
        const stats = card.type === 'minion' ? `<div class="card-stats"><span class="atk">${attack}</span><span class="hp">${health}</span></div>` : '';
        const costDisplay = card.type === 'spell' ? `<div class="card-cost-wrap"><span class="card-cost">${cost}</span></div>` : '';
        const art = getCardArt ? getCardArt(card) : '✦';
        
        return `<div class="card-wrap gallery-card ${isFictional ? 'fictional' : ''}" data-card-id="${card.id}" style="width: 140px; height: 196px;">
          <div class="card faction-${card.faction || 'neutral'}">
            <div class="card-art">${art}</div>
            <div class="card-info">
              <div class="card-name" style="font-size: 0.75rem;">${escapeHtml(card.name)}</div>
              ${card.text ? `<div class="card-text" style="font-size: 0.65rem;">${escapeHtml(card.text)}</div>` : ''}
              ${stats}
              ${costDisplay}
            </div>
          </div>
        </div>`;
      }).join('');
      
      $all('.gallery-card').forEach(cardEl => {
        cardEl.onclick = function() {
          const cardId = cardEl.dataset.cardId;
          const card = galleryCardDb[cardId];
          if (!card) return;
          const nameEl = $('card-info-name');
          const metaEl = $('card-info-meta');
          const textEl = $('card-info-text');
          const abilEl = $('card-info-abilities');
          const bioEl = $('card-info-bio');
          if (nameEl) nameEl.textContent = card.name;
          if (metaEl) {
            const parts = [];
            if (card.type === 'minion') {
              parts.push(`Стоимость: ${card.cost || 0}`);
              parts.push(`Атака: ${card.attack !== undefined ? card.attack : 0}`);
              parts.push(`Здоровье: ${card.health !== undefined ? card.health : 0}`);
            } else {
              parts.push(`Стоимость: ${card.cost || 0}`);
            }
            if (card.faction) {
              const factionNames = { rebellion: 'Сопротивление', empire: 'Империя', pirates: 'Пираты', mandalorians: 'Мандалорцы', neutral: 'Нейтральная' };
              parts.push(`Фракция: ${factionNames[card.faction] || card.faction}`);
            }
            if (card.legendary) parts.push('Легендарная');
            if (card.fictional) parts.push('⚡ ВЫМЫШЛЕННЫЙ ПЕРСОНАЖ');
            metaEl.textContent = parts.join(' | ');
          }
          if (textEl) textEl.textContent = card.text || '';
          if (abilEl) {
            let abil = '';
            if (card.battlecry) abil += `Battlecry: ${card.battlecry} `;
            if (card.deathrattle) abil += `Deathrattle: ${card.deathrattle} `;
            abilEl.textContent = abil || 'Нет способностей';
          }
          if (bioEl) bioEl.textContent = card.bio || 'Нет описания';
          $('card-info-overlay')?.classList.remove('hidden');
          $('cards-gallery-overlay')?.classList.add('hidden');
        };
      });
    }
    
    $('btn-settings')?.addEventListener('click', () => {
      $('settings-overlay')?.classList.remove('hidden');
    });
    $('btn-settings-lobby')?.addEventListener('click', () => {
      $('settings-overlay')?.classList.remove('hidden');
    });
    $('btn-settings-close')?.addEventListener('click', () => {
      $('settings-overlay')?.classList.add('hidden');
    });
    
    $('settings-overlay')?.addEventListener('click', (e) => {
      if (e.target.id === 'settings-overlay') {
        $('settings-overlay')?.classList.add('hidden');
      }
    });
    
    $('btn-forge-close')?.addEventListener('click', () => {
      const sidebar = $('forge-sidebar');
      if (sidebar) {
        sidebar.classList.add('hidden');
        forgeSelected = [];
        forgePreviewPendingIds = null;
        const preview = $('forge-preview');
        if (preview) preview.classList.add('hidden');
        renderForgeSelected();
        updateForgePreview();
      }
    });
    
    $('btn-forge-clear')?.addEventListener('click', () => {
      forgeSelected = [];
      forgePreviewPendingIds = null;
      renderForgeSelected();
      updateForgePreview();
      if (gameState) renderForgeHand(gameState);
    });
    
    $('btn-steal-close')?.addEventListener('click', () => {
      $('steal-cards-overlay')?.classList.add('hidden');
      stealCardsMode.active = false;
      stealCardsMode.handIndex = -1;
      stealCardsMode.targetPlayerIndex = null;
      stealCardsMode.targetDeck = [];
      stealCardsMode.selectedIndices = [];
    });
    
    $('steal-cards-overlay')?.addEventListener('click', (e) => {
      if (e.target.id === 'steal-cards-overlay') {
        $('steal-cards-overlay')?.classList.add('hidden');
        stealCardsMode.active = false;
        stealCardsMode.handIndex = -1;
        stealCardsMode.targetPlayerIndex = null;
        stealCardsMode.targetDeck = [];
        stealCardsMode.selectedIndices = [];
      }
    });
    
    function showStealCardsModal(state, data) {
      const deckList = $('steal-deck-list');
      const selectedEl = $('steal-selected');
      const confirmBtn = $('btn-steal-confirm');
      const hintEl = $('steal-cards-hint');
      const targetSelect = $('steal-target-select');
      
      if (!deckList || !selectedEl || !confirmBtn) {
        console.error('Steal cards modal elements not found');
        return;
      }
      
      const currentState = gameState || state;
      if (!currentState || !currentState.players) {
        console.error('Invalid game state for steal cards modal');
        return;
      }
      
      // Если противник уже выбран, показываем его доску (карты на столе)
      if (stealCardsMode.targetPlayerIndex !== null) {
        // Обновляем доску из актуального gameState
        const targetPlayer = currentState.players[stealCardsMode.targetPlayerIndex];
        if (targetPlayer && targetPlayer.board) {
          stealCardsMode.targetDeck = targetPlayer.board.map(m => m.cardId);
        } else {
          console.warn('Target player not found or board is empty:', stealCardsMode.targetPlayerIndex);
        }
        
        if (stealCardsMode.targetDeck.length === 0) {
          // Доска пуста, закрываем модальное окно
          $('steal-cards-overlay')?.classList.add('hidden');
          stealCardsMode.active = false;
          return;
        }
        
        targetSelect.classList.add('hidden');
        deckList.classList.remove('hidden');
        
        if (hintEl) {
          hintEl.textContent = `Выберите до 2 карт с доски ${targetPlayer?.name || `Игрока ${stealCardsMode.targetPlayerIndex + 1}`} (${stealCardsMode.targetDeck.length} карт на столе)`;
        }
        
        deckList.innerHTML = targetPlayer.board.map((minion, idx) => {
          const cardId = minion.cardId;
          const cardDbToUse = currentState?.cardDb || cardDb;
          const meta = cardDbToUse[cardId];
          if (!meta) {
            console.warn('Card not found in cardDb:', cardId, 'Available keys:', Object.keys(cardDbToUse).slice(0, 10));
            return `<div class="card-wrap steal-deck-card" data-card-id="${cardId}" data-deck-index="${idx}" style="width: 100px; height: 140px; cursor: pointer; border: 2px solid red; position: relative; z-index: 10;">
              <div style="padding: 0.5rem; text-align: center; font-size: 0.7rem; color: #ff6b6b;">Карта ${cardId}</div>
            </div>`;
          }
          const isSelected = stealCardsMode.selectedIndices.includes(idx);
          const cost = meta.cost || 0;
          const attack = meta.attack !== undefined ? meta.attack : '';
          const health = meta.health !== undefined ? meta.health : '';
          const stats = meta.type === 'minion' ? `<div class="card-stats"><span class="atk">${attack}</span><span class="hp">${health}</span></div>` : '';
          const costDisplay = `<div class="card-cost-wrap"><span class="card-cost">${cost}</span></div>`;
          const art = typeof getCardArt === 'function' ? getCardArt(meta) : '✦';
          
          return `<div class="card-wrap steal-deck-card ${isSelected ? 'selected' : ''}" data-card-id="${cardId}" data-board-index="${idx}" style="width: 100px; height: 140px; cursor: pointer; position: relative; z-index: 10;">
            <div class="card faction-${meta.faction || 'neutral'}">
              <div class="card-art">${art}</div>
              <div class="card-info">
                <div class="card-name" style="font-size: 0.7rem;">${escapeHtml(meta.name || cardId)}</div>
                ${stats}
                ${costDisplay}
              </div>
            </div>
          </div>`;
        }).join('');
        
        $all('.steal-deck-card').forEach(card => {
          const handleCardClick = function(e) {
            e.preventDefault();
            e.stopPropagation();
            const idx = parseInt(card.dataset.boardIndex, 10);
            if (isNaN(idx)) {
              console.warn('Invalid board index:', card.dataset.boardIndex);
              return;
            }
            const selectedIdx = stealCardsMode.selectedIndices.indexOf(idx);
            if (selectedIdx >= 0) {
              stealCardsMode.selectedIndices.splice(selectedIdx, 1);
            } else if (stealCardsMode.selectedIndices.length < 2) {
              stealCardsMode.selectedIndices.push(idx);
            }
            const currentState = gameState || state;
            showStealCardsModal(currentState, data || {
              targetPlayerIndex: stealCardsMode.targetPlayerIndex,
              targetPlayerName: currentState?.players?.[stealCardsMode.targetPlayerIndex]?.name || `Игрок ${stealCardsMode.targetPlayerIndex + 1}`,
              targetBoardSize: currentState?.players?.[stealCardsMode.targetPlayerIndex]?.board?.length || 0,
              maxCards: Math.min(2, currentState?.players?.[stealCardsMode.targetPlayerIndex]?.board?.length || 0)
            });
          };
          card.onclick = handleCardClick;
          card.style.pointerEvents = 'auto';
          if (isTouchDevice()) {
            card.ontouchstart = function(e) {
              e.preventDefault();
              handleCardClick(e);
            };
          }
        });
        
        selectedEl.innerHTML = stealCardsMode.selectedIndices.length ? stealCardsMode.selectedIndices.map(idx => {
          const cardId = stealCardsMode.targetDeck[idx];
          const meta = cardDb[cardId];
          if (!meta) return '';
          return `<div class="card-wrap" style="width: 80px; height: 112px;"><div class="card faction-${meta.faction || 'neutral'}"><div class="card-art">${getCardArt(meta)}</div><div class="card-info"><div class="card-name" style="font-size: 0.6rem;">${escapeHtml(meta.name)}</div></div></div></div>`;
        }).join('') : '<div class="steal-selected-empty">Выберите до 2 карт</div>';
        
        confirmBtn.disabled = stealCardsMode.selectedIndices.length === 0;
        confirmBtn.onclick = function() {
          if (confirmBtn.disabled || stealCardsMode.selectedIndices.length === 0) return;
          if (typeof window.Sounds !== 'undefined') window.Sounds.playCard();
          socket.emit('stealCards', {
            handIndex: stealCardsMode.handIndex,
            targetPlayerIndex: stealCardsMode.targetPlayerIndex,
            cardIndices: stealCardsMode.selectedIndices
          });
          stealCardsMode.active = false;
          stealCardsMode.handIndex = -1;
          stealCardsMode.targetPlayerIndex = null;
          stealCardsMode.targetDeck = [];
          stealCardsMode.selectedIndices = [];
          $('steal-cards-overlay')?.classList.add('hidden');
        };
      } else {
        // Показываем выбор противника (если еще не выбран)
        targetSelect.classList.remove('hidden');
        deckList.classList.add('hidden');
        
        if (hintEl) {
          hintEl.textContent = 'Выберите противника для грабежа';
        }
        
        const enemies = currentState.players.filter((p, i) => i !== currentState.yourIndex && p.health > 0 && p.deck && p.deck.length > 0);
        if (enemies.length === 0) {
          if (hintEl) hintEl.textContent = 'Нет доступных противников для грабежа';
          targetSelect.innerHTML = '';
          return;
        }
        targetSelect.innerHTML = enemies.map((enemy, idx) => {
          const enemyIdx = currentState.players.indexOf(enemy);
          return `<div class="steal-target-option" data-player-index="${enemyIdx}" style="padding: 1rem; margin: 0.5rem 0; background: rgba(0,0,0,0.3); border: 2px solid rgba(0,180,255,0.3); border-radius: 8px; cursor: pointer; transition: all 0.2s;">
            <div style="font-weight: 700; color: var(--cyan);">${escapeHtml(enemy.name || `Игрок ${enemyIdx + 1}`)}</div>
            <div style="font-size: 0.85rem; color: #94a3b8; margin-top: 0.25rem;">Колода: ${enemy.deck.length} карт</div>
          </div>`;
        }).join('');
        
        $all('.steal-target-option').forEach(option => {
          const handleOptionClick = function(e) {
            e.preventDefault();
            e.stopPropagation();
            const playerIdx = parseInt(option.dataset.playerIndex, 10);
            if (isNaN(playerIdx)) return;
            const currentState = gameState || state;
            if (!currentState || !currentState.players) {
              console.error('Invalid state when selecting target player');
              return;
            }
            const targetPlayer = currentState.players[playerIdx];
            if (targetPlayer && targetPlayer.board && targetPlayer.board.length > 0) {
              stealCardsMode.targetPlayerIndex = playerIdx;
              stealCardsMode.targetDeck = targetPlayer.board ? targetPlayer.board.map(m => m.cardId) : [];
              console.log('Selected target player:', playerIdx, 'Board size:', stealCardsMode.targetDeck.length);
              showStealCardsModal(currentState, {
                targetPlayerIndex: playerIdx,
                targetPlayerName: targetPlayer.name || `Игрок ${playerIdx + 1}`,
                targetBoardSize: targetPlayer.board.length,
                maxCards: Math.min(2, targetPlayer.board.length)
              });
            } else {
              console.warn('Target player has no board or is invalid:', playerIdx, targetPlayer);
            }
          };
          option.onclick = handleOptionClick;
          option.style.pointerEvents = 'auto';
          option.style.cursor = 'pointer';
          if (isTouchDevice()) {
            option.ontouchstart = function(e) {
              e.preventDefault();
              handleOptionClick(e);
            };
          }
        });
      }
      
      $('steal-cards-overlay')?.classList.remove('hidden');
    }
    
    let forgeSelected = [];
    
    function renderForgeSelected() {
      const selectedEl = $('forge-selected');
      const countEl = $('forge-selected-count');
      if (!selectedEl) return;
      
      if (countEl) {
        countEl.textContent = forgeSelected.length;
      }
      
      if (forgeSelected.length === 0) {
        selectedEl.innerHTML = '<div class="forge-selected-empty">Кликните на карты из руки</div>';
      } else {
        selectedEl.innerHTML = forgeSelected.map((cardId, idx) => {
          const meta = cardDb[cardId];
          if (!meta) return '';
          return `<div class="card-wrap forge-selected-card" data-card-id="${cardId}" data-forge-index="${idx}" style="width: 90px; height: 126px; position: relative;">
            <div class="card faction-${meta.faction || 'neutral'}">
              <div class="card-art">${getCardArt(meta)}</div>
              <div class="card-info">
                <div class="card-name" style="font-size: 0.7rem;">${escapeHtml(meta.name)}</div>
                ${meta.type === 'minion' ? `<div class="card-stats"><span class="atk">${meta.attack || 0}</span><span class="hp">${meta.health || 0}</span></div>` : ''}
              </div>
            </div>
          </div>`;
        }).filter(Boolean).join('');
        
        // Добавляем обработчики удаления
        $all('.forge-selected-card').forEach(card => {
          card.onclick = function(e) {
            e.stopPropagation();
            const cardId = card.dataset.cardId;
            removeCardFromForge(cardId);
          };
        });
      }
    }
    
    function updateForgePreview() {
      const preview = $('forge-preview');
      const wrap = $('forge-preview-card-wrap');
      const confirmBtn = $('btn-forge-confirm');
      if (!preview) return;
      if (forgeSelected.length < 2 || forgeSelected.length > 3) {
        preview.classList.add('hidden');
        if (wrap) wrap.innerHTML = '';
        if (confirmBtn) confirmBtn.disabled = true;
        forgePreviewPendingIds = null;
        return;
      }
      forgePreviewRequestId = Date.now();
      forgePreviewPendingIds = [...forgeSelected];
      if (wrap) wrap.innerHTML = '<p class="forge-preview-loading">Загрузка…</p>';
      if (confirmBtn) confirmBtn.disabled = true;
      preview.classList.remove('hidden');
      socket.emit('forgePreview', { cardIds: forgePreviewPendingIds, requestId: forgePreviewRequestId });
    }

    function addCardToForge(cardId, source) {
      if (!cardId) return;
      if (source !== 'hand') return; // только из руки
      if (forgeSelected.includes(cardId)) {
        removeCardFromForge(cardId);
        return;
      }
      if (forgeSelected.length >= 3) {
        // Показываем сообщение, что максимум 3 карты
        const selectedEl = $('forge-selected');
        if (selectedEl) {
          selectedEl.style.animation = 'shake 0.5s';
          setTimeout(() => selectedEl.style.animation = '', 500);
        }
        return;
      }
      
      const meta = cardDb[cardId];
      if (!meta || meta.type !== 'minion') return; // Только миньоны
      
      forgeSelected.push(cardId);
      renderForgeSelected();
      updateForgePreview();
      if (gameState) renderForgeHand(gameState);
    }

    function removeCardFromForge(cardId) {
      const idx = forgeSelected.indexOf(cardId);
      if (idx >= 0) {
        forgeSelected.splice(idx, 1);
        renderForgeSelected();
        updateForgePreview();
        if (gameState) renderForgeHand(gameState);
      }
    }
    
    function renderForgeHand(state) {
      const you = state.players[state.yourIndex];
      const handList = $('forge-hand-list');
      if (!handList) return;
      
      const hand = you.hand || state.yourHand || [];
      
      if (!hand || hand.length === 0) {
        handList.innerHTML = '<div style="color: #94a3b8; text-align: center; padding: 2rem; font-size: 0.9rem;">Рука пуста</div>';
        return;
      }
      
      // Фильтруем только миньонов
      const minionCards = hand.filter(cardId => {
        const meta = cardDb[cardId];
        return meta && meta.type === 'minion';
      });
      
      if (minionCards.length === 0) {
        handList.innerHTML = '<div style="color: #94a3b8; text-align: center; padding: 2rem; font-size: 0.9rem;">Нет миньонов в руке</div>';
        return;
      }
      
      handList.innerHTML = minionCards.map((cardId) => {
        const meta = cardDb[cardId];
        if (!meta) return '';
        const isSelected = forgeSelected.includes(cardId);
        return `<div class="card-wrap ${isSelected ? 'selected' : ''}" data-card-id="${cardId}" style="width: 100px; height: 140px; cursor: pointer;">
          <div class="card faction-${meta.faction || 'neutral'}">
            <div class="card-art">${getCardArt(meta)}</div>
            <div class="card-info">
              <div class="card-name" style="font-size: 0.7rem;">${escapeHtml(meta.name)}</div>
              <div class="card-stats">
                <span class="atk">${meta.attack || 0}</span>
                <span class="hp">${meta.health || 0}</span>
              </div>
            </div>
          </div>
        </div>`;
      }).filter(Boolean).join('');
      
      // Обработчики клика для карт из руки
      $all('#forge-hand-list .card-wrap').forEach(card => {
        card.onclick = function(e) {
          e.stopPropagation();
          const cardId = card.dataset.cardId;
          if (cardId) {
            addCardToForge(cardId, 'hand');
          }
        };
      });
    }
    
    const confirmBtn = $('btn-forge-confirm');
    if (confirmBtn) {
      confirmBtn.onclick = function() {
        if (confirmBtn.disabled || !forgePreviewPendingIds || forgePreviewPendingIds.length < 2) return;
        const you = gameState?.players?.[gameState?.yourIndex];
        if (!you || (you.mana || 0) < 2) return;
        socket.emit('forgeCard', { cardIds: forgePreviewPendingIds });
        if (typeof window.Sounds !== 'undefined' && window.Sounds.forge) window.Sounds.forge();
        forgeSelected = [];
        forgePreviewPendingIds = null;
        const preview = $('forge-preview');
        if (preview) preview.classList.add('hidden');
        renderForgeSelected();
        updateForgePreview();
        if (gameState) renderForgeHand(gameState);
        const sidebar = $('forge-sidebar');
        if (sidebar) sidebar.classList.add('hidden');
      };
    }
    const cancelPreviewBtn = $('btn-forge-cancel-preview');
    if (cancelPreviewBtn) {
      cancelPreviewBtn.onclick = function() {
        const preview = $('forge-preview');
        if (preview) preview.classList.add('hidden');
        forgePreviewPendingIds = null;
        const wrap = $('forge-preview-card-wrap');
        if (wrap) wrap.innerHTML = '';
        const cb = $('btn-forge-confirm');
        if (cb) cb.disabled = true;
      };
    }
    
    $('music-toggle')?.addEventListener('click', () => {
      if (window.Music) {
        window.Music.toggle();
      }
    });
    
    $('music-volume-slider')?.addEventListener('input', (e) => {
      const volume = parseFloat(e.target.value) / 100;
      if (window.Music) {
        window.Music.setVolume(volume);
      }
    });
  }

  // Авторизация
  let currentUser = null;
  
  async function checkAuth() {
    try {
      const response = await fetch('/api/user', { credentials: 'include' });
      if (response.ok) {
        const data = await response.json();
        currentUser = data.user;
        updateUserUI();
        hideAuthModal();
        return true;
      } else {
        // Не авторизован - показываем модальное окно авторизации
        currentUser = null;
        showAuthModal();
        return false;
      }
    } catch (error) {
      console.error('Ошибка проверки авторизации:', error);
      // При ошибке также показываем модальное окно
      currentUser = null;
      showAuthModal();
      return false;
    }
  }
  
  function updateUserUI() {
    const userInfo = $('user-info');
    const userName = $('user-name');
    if (currentUser && userInfo && userName) {
      userInfo.style.display = 'flex';
      userName.textContent = currentUser.username;
      if (currentUser.gamesPlayed !== undefined) {
        userName.textContent += ` (${currentUser.gamesWon || 0}/${currentUser.gamesPlayed || 0})`;
      }
    }
  }
  
  function showAuthModal() {
    const authOverlay = $('auth-overlay');
    if (authOverlay) {
      authOverlay.classList.remove('hidden');
    }
  }
  
  function hideAuthModal() {
    // Закрываем модальное окно только если пользователь авторизован
    if (!currentUser) {
      return; // Не закрываем, если пользователь не авторизован
    }
    const authOverlay = $('auth-overlay');
    if (authOverlay) {
      authOverlay.classList.add('hidden');
    }
  }
  
  function initAuth() {
    // Предотвращаем закрытие модального окна кликом вне его, если пользователь не авторизован
    const authOverlay = $('auth-overlay');
    if (authOverlay) {
      authOverlay.addEventListener('click', (e) => {
        // Закрываем только если клик был по самому overlay (не по модальному окну внутри)
        if (e.target === authOverlay && currentUser) {
          hideAuthModal();
        } else if (e.target === authOverlay && !currentUser) {
          // Если пользователь не авторизован, не закрываем модальное окно
          e.stopPropagation();
        }
      });
      // Предотвращаем закрытие при клике на само модальное окно
      const authModal = authOverlay.querySelector('.auth-modal');
      if (authModal) {
        authModal.addEventListener('click', (e) => {
          e.stopPropagation();
        });
      }
    }
    
    // Переключение между вкладками авторизации
    $all('.auth-tab').forEach(tab => {
      tab.addEventListener('click', () => {
        $all('.auth-tab').forEach(t => t.classList.remove('active'));
        $all('.auth-panel').forEach(p => p.classList.add('hidden'));
        tab.classList.add('active');
        const panelId = 'auth-' + tab.dataset.authTab + '-panel';
        const panel = $(panelId);
        if (panel) {
          panel.classList.remove('hidden');
          panel.classList.add('active');
        }
      });
    });
    
    // Форма входа
    const loginForm = $('login-form');
    if (loginForm) {
      loginForm.addEventListener('submit', async (e) => {
        e.preventDefault();
        const username = $('login-username')?.value.trim();
        const password = $('login-password')?.value;
        const errorEl = $('login-error');
        
        if (!username || !password) {
          if (errorEl) {
            errorEl.textContent = 'Заполните все поля';
            errorEl.classList.remove('hidden');
          }
          return;
        }
        
        try {
          const response = await fetch('/api/login', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            credentials: 'include',
            body: JSON.stringify({ username, password })
          });
          
          const data = await response.json();
          
          if (response.ok && data.success) {
            currentUser = data.user;
            updateUserUI();
            hideAuthModal();
            if (errorEl) errorEl.classList.add('hidden');
          } else {
            if (errorEl) {
              errorEl.textContent = data.error || 'Ошибка входа';
              errorEl.classList.remove('hidden');
            }
          }
        } catch (error) {
          console.error('Ошибка входа:', error);
          if (errorEl) {
            errorEl.textContent = 'Ошибка соединения с сервером';
            errorEl.classList.remove('hidden');
          }
        }
      });
    }
    
    // Форма регистрации
    const registerForm = $('register-form');
    if (registerForm) {
      registerForm.addEventListener('submit', async (e) => {
        e.preventDefault();
        const username = $('register-username')?.value.trim();
        const password = $('register-password')?.value;
        const email = $('register-email')?.value.trim();
        const errorEl = $('register-error');
        
        if (!username || !password) {
          if (errorEl) {
            errorEl.textContent = 'Заполните обязательные поля';
            errorEl.classList.remove('hidden');
          }
          return;
        }
        
        try {
          const response = await fetch('/api/register', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            credentials: 'include',
            body: JSON.stringify({ username, password, email })
          });
          
          const data = await response.json();
          
          if (response.ok && data.success) {
            currentUser = data.user;
            updateUserUI();
            hideAuthModal();
            if (errorEl) errorEl.classList.add('hidden');
            // Отправляем имя пользователя на сервер через socket
            if (socket && socket.connected && currentUser.username) {
              socket.emit('setUsername', currentUser.username);
            }
          } else {
            if (errorEl) {
              errorEl.textContent = data.error || 'Ошибка регистрации';
              errorEl.classList.remove('hidden');
            }
          }
        } catch (error) {
          console.error('Ошибка регистрации:', error);
          if (errorEl) {
            errorEl.textContent = 'Ошибка соединения с сервером';
            errorEl.classList.remove('hidden');
          }
        }
      });
    }
    
    // Кнопка закрытия авторизации - скрываем, так как авторизация обязательна
    const authClose = $('auth-close');
    if (authClose) {
      authClose.style.display = 'none';
    }
    
    // Кнопка выхода
    const btnLogout = $('btn-logout');
    if (btnLogout) {
      btnLogout.addEventListener('click', async () => {
        try {
          await fetch('/api/logout', { method: 'POST', credentials: 'include' });
          currentUser = null;
          const userInfo = $('user-info');
          if (userInfo) userInfo.style.display = 'none';
          // После выхода показываем модальное окно авторизации
          showAuthModal();
        } catch (error) {
          console.error('Ошибка выхода:', error);
          // Даже при ошибке показываем модальное окно
          currentUser = null;
          showAuthModal();
        }
      });
    }
    
    // Leaderboard
    const btnLeaderboard = $('btn-leaderboard');
    if (btnLeaderboard) {
      btnLeaderboard.addEventListener('click', async () => {
        const overlay = $('leaderboard-overlay');
        const content = $('leaderboard-content');
        if (overlay) overlay.classList.remove('hidden');
        if (content) content.innerHTML = '<p class="hint" style="text-align: center; padding: 2rem;">Загрузка...</p>';
        
        try {
          const response = await fetch('/api/leaderboard', { credentials: 'include' });
          const data = await response.json();
          
          if (response.ok && data.leaderboard) {
            if (data.leaderboard.length === 0) {
              content.innerHTML = '<p class="hint" style="text-align: center; padding: 2rem;">Рейтинг пуст</p>';
            } else {
              content.innerHTML = `
                <table class="leaderboard-table">
                  <thead>
                    <tr>
                      <th class="rank">#</th>
                      <th class="username">Игрок</th>
                      <th class="stats">Игр</th>
                      <th class="stats">Побед</th>
                      <th class="stats">% Побед</th>
                      <th class="stats">Урон</th>
                      <th class="stats">Хил</th>
                    </tr>
                  </thead>
                  <tbody>
                    ${data.leaderboard.map((player, idx) => `
                      <tr>
                        <td class="rank">${idx + 1}</td>
                        <td class="username">${escapeHtml(player.username)}</td>
                        <td class="stats">${player.gamesPlayed}</td>
                        <td class="stats">${player.gamesWon}</td>
                        <td class="stats">${player.winRate}%</td>
                        <td class="stats">${player.totalDamage}</td>
                        <td class="stats">${player.totalHealing}</td>
                      </tr>
                    `).join('')}
                  </tbody>
                </table>
              `;
            }
          } else {
            content.innerHTML = '<p class="hint" style="text-align: center; padding: 2rem; color: var(--red);">Ошибка загрузки рейтинга</p>';
          }
        } catch (error) {
          console.error('Ошибка загрузки leaderboard:', error);
          if (content) {
            content.innerHTML = '<p class="hint" style="text-align: center; padding: 2rem; color: var(--red);">Ошибка соединения</p>';
          }
        }
        
        if (typeof lucide !== 'undefined') {
          setTimeout(() => {
            try {
              lucide.createIcons();
            } catch (e) {
              console.warn('Error updating Lucide icons:', e);
            }
          }, 100);
        }
      });
    }
    
    const leaderboardClose = $('leaderboard-close');
    if (leaderboardClose) {
      leaderboardClose.addEventListener('click', () => {
        const overlay = $('leaderboard-overlay');
        if (overlay) overlay.classList.add('hidden');
      });
    }
  }

  function init() {
    initLobby();
    initAuth();
    // Проверяем авторизацию - модальное окно покажется автоматически, если не авторизован
    checkAuth().catch(() => {
      // При ошибке модальное окно уже показано в checkAuth()
    });
    showScreen('lobby');
    socket = null;
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => {
      init();
      if (window.Music) {
        window.Music.init();
      }
      // Инициализация Lucide Icons после загрузки DOM
      if (typeof lucide !== 'undefined') {
        lucide.createIcons();
        // Обновляем иконки при изменении DOM с debounce, чтобы избежать бесконечного цикла
        if (!window.lucideObserver) {
          let iconUpdateTimer = null;
          window.lucideObserver = new MutationObserver(() => {
            // Отменяем предыдущий таймер
            if (iconUpdateTimer) clearTimeout(iconUpdateTimer);
            // Устанавливаем новый таймер с задержкой
            iconUpdateTimer = setTimeout(() => {
              try {
                lucide.createIcons();
              } catch (e) {
                console.warn('Error updating Lucide icons:', e);
              }
            }, 200);
          });
          window.lucideObserver.observe(document.body, { childList: true, subtree: true });
        }
      }
    });
  } else {
    init();
    if (typeof lucide !== 'undefined') {
      setTimeout(() => {
        try {
          lucide.createIcons();
        } catch (e) {
          console.warn('Error updating Lucide icons:', e);
        }
      }, 100);
    }
    if (window.Music) {
      window.Music.init();
    }
  }
})();
