<template>
  <view class="page-container">
    <!-- Animated Branded Background -->
    <view class="bg-layer">
      <view class="game-glow glow-1"></view>
      <view class="game-glow glow-2"></view>
      <view class="game-glow glow-3"></view>
    </view>

    <!-- Top Navigation & Ticker -->
    <view class="top-nav">
      <view class="win-ticker" v-if="winRecords.length > 0">
        <text class="ticker-icon">📣</text>
        <swiper vertical autoplay circular interval="3000" class="ticker-swiper">
          <swiper-item v-for="rec in winRecords" :key="rec.id">
            <view class="ticker-item">
              恭喜 <text class="ticker-user">玩家</text> 抽中 <text class="ticker-prize">{{ rec.title }}</text>
            </view>
          </swiper-item>
        </swiper>
      </view>
      <view class="rules-btn" @click="showRules = true">
        <text class="rules-icon">?</text>
        玩法说明
      </view>
    </view>

    <scroll-view class="page-content" scroll-y :enhanced="true" :show-scrollbar="false">
      <!-- Loading State -->
      <view class="loading-portal" v-if="loading && !issues.length">
        <view class="loading-animation"></view>
        <text class="loading-text">正在连接游戏大厅...</text>
      </view>

      <!-- Empty State -->
      <view class="empty-portal animate-fade-in" v-else-if="!loading && issues.length === 0">
        <view class="empty-art-wrapper">
          <view class="empty-orb"></view>
          <text class="empty-emoji">🎮</text>
        </view>
        <text class="empty-title">当前无活动上线</text>
        <text class="empty-desc">别担心，去仓库看看其他好货吧</text>
        <button class="return-home-btn" @click="goHome">返回大厅</button>
      </view>

      <block v-else>
        <!-- Banner -->
        <view class="banner-section animate-slide-up" v-if="detail.banner" @click="onPreviewBanner">
          <image class="banner-image" :src="detail.banner" mode="widthFix" />
          <view class="banner-overlay"></view>
        </view>

        <!-- Dynamic Game Arena -->
        <block v-if="gameId">
          <!-- Stats Header -->
          <view class="arena-stats">
            <view class="stat-gem animate-bounce-in">
              <view class="gem-icon">💎</view>
              <view class="gem-content">
                <text class="gem-label">消除得分</text>
                <text class="gem-value">{{ totalPairs }}</text>
              </view>
            </view>
            <view class="stat-gem animate-bounce-in" style="animation-delay: 0.1s">
              <view class="gem-icon">📦</view>
              <view class="gem-content">
                <text class="gem-label">牌堆容量</text>
                <text class="gem-value">{{ deckCount }}</text>
              </view>
            </view>
            <view class="stat-gem animate-bounce-in" style="animation-delay: 0.2s">
              <view class="gem-icon">⏳</view>
              <view class="gem-content">
                <text class="gem-label">当前轮次</text>
                <text class="gem-value">{{ currentRound }}</text>
              </view>
            </view>
          </view>

          <!-- Apple Effect Overlay -->
          <view class="special-overlay" v-if="showAppleEffect">
            <view class="apple-card animate-zoom-in">
              <view class="apple-glow"></view>
              <text class="apple-emoji">🍎</text>
              <text class="apple-title">苹果加成！</text>
              <text class="apple-subtitle">检测到运气爆发，额外补牌中...</text>
            </view>
          </view>

          <!-- The Game Board -->
          <view class="board-arena glass-panel animate-zoom-in">
            <view class="board-grid">
              <view v-for="(slot, idx) in board" :key="idx" 
                    class="card-unit"
                    :class="{ 
                      'is-pairing': slot && pairingIds.includes(slot.id),
                      'is-disappearing': slot && disappearingIds.includes(slot.id),
                      'is-drawing': slot && newCardIds.includes(slot.id),
                      'is-rare': slot && slot.type === 'A'
                    }">
                <view v-if="slot" class="card-face">
                  <view class="card-shine" v-if="slot.type === 'A'"></view>
                  <view class="match-badge" v-if="pairingIds.includes(slot.id)">MATCH!</view>
                  <image v-if="slot.image" class="card-thumb" :src="slot.image" mode="aspectFit" />
                  <text class="card-tag" v-else>{{ slot.name || slot.type }}</text>
                </view>
                <view v-else class="card-void">
                  <view class="void-circle"></view>
                </view>
              </view>
            </view>
          </view>
        </block>

        <!-- Issue Selection (Hall State) -->
        <view class="entry-hall glass-panel animate-slide-up" v-else>
          <view class="arena-header">
            <view class="hall-title">
              <text class="title-main">选择竞技场</text>
              <text class="title-sub">Select Your Arena</text>
            </view>
            <view class="issue-count">活跃中 {{ issues.length }}</view>
          </view>

          <!-- Horizontal Card Selector -->
          <scroll-view scroll-x class="issue-scroll" :show-scrollbar="false">
            <view class="issue-cards">
              <view v-for="(it, idx) in issues" :key="it.id" 
                    class="issue-card" 
                    :class="{ active: selectedIssueIndex === idx }"
                    @click="onSelectIssue(idx)">
                <view class="card-background-glow"></view>
                <text class="issue-no">NO.{{ it.no || (idx + 1) }}</text>
                <text class="issue-name">{{ it.title }}</text>
                <view class="issue-tag" :class="'status-' + it.status">{{ it.status_text }}</view>
                <view class="active-indicator" v-if="selectedIssueIndex === idx">
                  <view class="dot"></view>
                  SELECTED
                </view>
              </view>
            </view>
          </scroll-view>

          <!-- Info Tabs -->
          <view class="hall-tabs">
            <view class="hall-tab" :class="{ active: tabActive === 'pool' }" @click="tabActive = 'pool'">
              奖励预览
              <view class="tab-bar-glow" v-if="tabActive === 'pool'"></view>
            </view>
            <view class="hall-tab" :class="{ active: tabActive === 'records' }" @click="tabActive = 'records'">
              中奖动态
              <view class="tab-bar-glow" v-if="tabActive === 'records'"></view>
            </view>
          </view>

          <!-- Content Lists -->
          <view class="tab-container">
            <!-- Pool Preview -->
            <view v-if="tabActive === 'pool'" class="rewards-mosaic">
              <view v-for="(rw, idx) in (rewardsMap[currentIssueId] || [])" :key="rw.id" class="mosaic-item animate-stagger" :style="{ '--delay': idx * 0.05 + 's' }">
                <view class="mosaic-inner">
                  <view class="mosaic-img-box">
                    <image :src="rw.image" class="mosaic-img" mode="aspectFill" />
                    <view class="mosaic-boss" v-if="rw.boss">BOSS</view>
                    <view class="mosaic-prob">{{ rw.percent }}%</view>
                  </view>
                  <text class="mosaic-title">{{ rw.title }}</text>
                </view>
              </view>
            </view>

            <!-- Win Records -->
            <view v-if="tabActive === 'records'" class="dynamic-records">
              <view v-for="(it, idx) in winRecords" :key="it.id" class="win-row animate-stagger" :style="{ '--delay': idx * 0.05 + 's' }">
                <view class="win-avatar-box">
                  <image class="win-avatar" src="/static/images/common/default-avatar.png" mode="aspectFill" />
                </view>
                <view class="win-info">
                  <view class="win-top">
                    <text class="win-user">玩家</text>
                    <text class="win-time">刚刚</text>
                  </view>
                  <text class="win-item-name">获得 {{ it.title }} x{{ it.count }}</text>
                </view>
                <image class="win-thumb" :src="it.image" mode="aspectFill" />
              </view>
              <view class="empty-win" v-if="!winRecords.length">
                <text class="empty-win-icon">🏜️</text>
                <text class="empty-win-text">虚位以待，快来挑战</text>
              </view>
            </view>
          </view>
        </view>
      </block>
      
      <!-- Safe Bottom Padding -->
      <view style="height: 140rpx"></view>
    </scroll-view>

    <!-- Floating Action Hub -->
    <view class="action-hub" v-if="activityId && issues.length">
      <view class="action-glow"></view>
      
      <!-- Entry Mode -->
      <button v-if="!gameId" class="hub-btn neon-btn pulsate" @click="handleStartGame" :loading="loading">
        <text class="btn-text">立即进入竞技场</text>
        <view class="btn-energy-line"></view>
      </button>

      <!-- Gaming Mode -->
      <view v-else-if="!gameOver" class="gaming-controls">
        <view class="auto-toggle-box" @click="isAutoMode = !isAutoMode">
          <view class="toggle-track" :class="{ active: isAutoMode }">
            <view class="toggle-thumb"></view>
          </view>
          <text class="toggle-label">{{ isAutoMode ? '自动模式 ON' : '手动模式 OFF' }}</text>
        </view>
        
        <button class="hub-btn primary-btn" @click="handlePlayRound" :loading="loading" :disabled="isAnimating">
          <text v-if="isAnimating" class="matching-pulse">🧠 {{ isAutoMode ? '自动匹配中...' : '计算配对中...' }}</text>
          <text v-else>执行下一轮消除</text>
        </button>
      </view>

      <view class="game-over-hub" v-else>
        <button class="hub-btn secondary-btn" @click="resetGame">退出游戏</button>
        <button class="hub-btn gold-btn" @click="resetGame">再次发起挑战</button>
      </view>
    </view>

    <!-- Rule Modal -->
    <view class="modal-layer" v-if="showRules" @tap="showRules = false">
      <view class="premium-modal animate-bounce-in" @tap.stop>
        <view class="modal-header">
          <text class="modal-title">匹配挑战规则</text>
          <view class="close-x" @tap="showRules = false">×</view>
        </view>
        <scroll-view class="modal-scroll" scroll-y>
          <view class="rule-item">
            <text class="rule-no">01</text>
            <view class="rule-content">每局游戏开始时，将从牌堆中抽取卡牌填充至 3x3 棋盘。</view>
          </view>
          <view class="rule-item">
            <text class="rule-no">02</text>
            <view class="rule-content">当棋盘中出现 3 张相同卡牌时，将自动进行“对对碰”消除并获得奖励。</view>
          </view>
          <view class="rule-item">
            <text class="rule-no">03</text>
            <view class="rule-content">🍎 如果初始手牌中包含苹果卡，将触发暴击效果，额外抽取更多手牌！</view>
          </view>
          <view class="rule-item">
            <text class="rule-no">04</text>
            <view class="rule-content">消除后会自动补位，直到牌堆耗尽或无法继续消除，游戏结束。</view>
          </view>
        </scroll-view>
        <button class="modal-confirm" @tap="showRules = false">我明白了</button>
      </view>
    </view>

    <!-- Result Modal -->
    <view class="modal-layer" v-if="showResult" @tap="showResult = false">
      <view class="settlement-card glass-panel animate-zoom-in" @tap.stop>
        <view class="settlement-crown">👑</view>
        <text class="settlement-title">挑战圆满结束</text>
        <view class="settlement-stats">
          <view class="set-stat">
            <text class="set-val">{{ totalPairs }}</text>
            <text class="set-lab">消除对数</text>
          </view>
        </view>
        <text class="settlement-tip">恭喜！所有获得奖励已存入您的账户库</text>
        <button class="set-btn" @click="resetGame">领取战利品</button>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref, computed, nextTick } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { 
  getActivityDetail, 
  getActivityIssues, 
  getActivityIssueRewards, 
  getActivityWinRecords,
  startMatchingGame,
  playMatchingGame,
  getMatchingGameState,
  getMatchingCardTypes
} from '../../../api/appUser'

// Activity State
const activityId = ref('')
const detail = ref({})
const issues = ref([])
const rewardsMap = ref({})
const currentIssueId = ref('')
const selectedIssueIndex = ref(0)
const tabActive = ref('pool')
const winRecords = ref([])
const loading = ref(true) // Start as true to prevent empty-state flash
const hasInited = ref(false)
const cardMetaMap = ref({})

// Game State
const gameId = ref('')
const deckCount = ref(0)
const totalPairs = ref(0)
const currentRound = ref(0)
const gameOver = ref(false)
const isAnimating = ref(false)
const pairingIds = ref([])
const disappearingIds = ref([])
const newCardIds = ref([])
const isAutoMode = ref(false)
const showResult = ref(false)
const showAppleEffect = ref(false)
const showRules = ref(false)
const board = ref(Array(9).fill(null)) // Use a persistent array of 9 for the grid

// Activity Logic
async function fetchDetail(id) {
  try {
    const data = await getActivityDetail(id)
    detail.value = data || {}
  } catch (e) {}
}

async function fetchIssues(id) {
  loading.value = true
  try {
    const data = await getActivityIssues(id)
    issues.value = normalizeIssues(data)
    const latestId = pickLatestIssueId(issues.value)
    setSelectedById(latestId)
    await fetchRewardsForIssues(id)
  } catch (e) {
    console.error('fetchIssues error:', e)
  } finally {
    loading.value = false
  }
}

function unwrap(list) {
  if (Array.isArray(list)) return list
  const obj = list || {}
  const data = obj.data || {}
  // Deep search for array
  const arr = obj.issues || obj.list || obj.items || data.issues || data.list || data.items || data
  return Array.isArray(arr) ? arr : []
}

function normalizeIssues(list) {
  console.log('[DEBUG] Raw Issues Data:', list)
  const arr = unwrap(list)
  console.log('[DEBUG] Unwrapped Issues:', arr)
  return arr.map((i, idx) => ({
    id: i.id ?? String(idx),
    title: i.title ?? i.name ?? i.issue_no ?? `第${idx+1}期`,
    no: i.no ?? i.index ?? i.issue_no ?? null,
    status: i.status,
    status_text: i.status === 1 ? '进行中' : i.status === 0 ? '未开始' : '已结束'
  }))
}

async function fetchRewardsForIssues(aid) {
  if (!currentIssueId.value) return
  try {
    const data = await getActivityIssueRewards(aid, currentIssueId.value)
    const arr = Array.isArray(data) ? data : (data?.data || [])
    rewardsMap.value[currentIssueId.value] = arr.map((i, idx) => ({
      id: i.product_id ?? i.id ?? String(idx),
      title: i.name ?? i.title ?? '',
      image: i.product_image ?? i.image ?? '',
      weight: Number(i.weight) || 0,
      boss: !!(i.is_boss || i.boss),
      percent: 0 // logic to calculate percentage if total_weight is known
    }))
  } catch (e) {}
}

async function fetchWinRecords(aid) {
  try {
    const data = await getActivityWinRecords(aid, 1, 20)
    const arr = Array.isArray(data) ? data : (data?.data || [])
    winRecords.value = arr.map((i, idx) => ({
      id: i.id ?? String(idx),
      title: i.title ?? i.name ?? '',
      image: i.image ?? '',
      count: i.count ?? 1,
      percent: i.percent
    }))
  } catch (e) {}
}

function pickLatestIssueId(list) {
  return list[list.length - 1]?.id || ''
}

function setSelectedById(id) {
  const idx = issues.value.findIndex(x => x.id === id)
  selectedIssueIndex.value = Math.max(0, idx)
  currentIssueId.value = issues.value[selectedIssueIndex.value]?.id || ''
}

function onIssueChange(e) {
  const idx = e.detail.value[0]
  onSelectIssue(idx)
}

function onSelectIssue(idx) {
  if (isAnimating.value) return
  selectedIssueIndex.value = idx
  currentIssueId.value = issues.value[idx]?.id || ''
  fetchRewardsForIssues(activityId.value)
}

async function handleStartGame() {
  if (!currentIssueId.value) return
  loading.value = true
  try {
    const res = await startMatchingGame(issues.value[selectedIssueIndex.value].id)
    gameId.value = res.game_id
    deckCount.value = res.deck_count
    totalPairs.value = 0
    currentRound.value = 1
    
    // Spec priority: res.board (9-slot) > res.hand (old list)
    board.value = normalizeCards(res.board || res.hand)
    
    // If we fell back to 'hand' (old API), we might need to pad it to 9 slots manually 
    // to match the new 9-slot grid expectation in the template
    if (!res.board && board.value.length < 9) {
       while(board.value.length < 9) board.value.push(null)
    }

    // Reset loop
    isAutoMode.value = false
  } catch (e) {
    uni.showToast({ title: '初始化失败', icon: 'none' })
  } finally {
    loading.value = false
  }
}

async function handlePlayRound() {
  if (!gameId.value || isAnimating.value) return
  loading.value = !isAutoMode.value // Don't show full-page loading in auto mode to avoid flicker
  try {
    const res = await playMatchingGame(gameId.value)
    totalPairs.value = res.total_pairs
    gameOver.value = res.game_over
    deckCount.value = (res.round?.deck_count !== undefined) ? res.round.deck_count : (res.deck_count || deckCount.value)
    
    await processRound(res.round)
    
    if (res.game_over) {
      uni.removeStorageSync('matching_game_id')
      // Small pause after all animations to see the final board
      setTimeout(() => { showResult.value = true }, 1500)
    } else if (isAutoMode.value) {
      // Auto-loop
      setTimeout(() => {
        handlePlayRound()
      }, 500)
    }
  } catch (err) {
    isAutoMode.value = false // Stop auto mode on error
    uni.showToast({ title: '执行失败', icon: 'none' })
  } finally {
    loading.value = false
  }
}

// Game Logic
async function initGame(aid) {
  try {
    loading.value = true
    // Parallel fetch basic info + card metadata
    const [detailRes, issuesRes, cardTypesRes] = await Promise.all([
      getActivityDetail(aid),
      getActivityIssues(aid),
      getMatchingCardTypes()
    ])
    
    detail.value = detailRes || {}
    issues.value = normalizeIssues(issuesRes)
    
    // Build card metadata map
    const types = Array.isArray(cardTypesRes) ? cardTypesRes : (cardTypesRes?.list || cardTypesRes?.data || [])
    const meta = {}
    types.forEach(t => {
      meta[t.code] = {
        name: t.name,
        image: t.image_url || t.image
      }
    })
    cardMetaMap.value = meta
    
    console.log('[DEBUG] Card Meta Map initialized:', Object.keys(meta).length)
    
    if (issues.value.length > 0) {
      const latestId = pickLatestIssueId(issues.value)
      setSelectedById(latestId)
      await fetchRewardsForIssues(aid)
      
      // Auto-start or Restore
      const restored = await checkGameStatus()
      if (!restored && currentIssueId.value) {
        await handleStartGame()
      }
    }
    
    // Non-blocking fetch records
    fetchWinRecords(aid)
  } catch (err) {
    console.error('[DEBUG] Init failed:', err)
  } finally {
    hasInited.value = true
    loading.value = false
  }
}

function normalizeCards(list) {
  const arr = Array.isArray(list) ? list : []
  return arr.map((item, idx) => {
    // Pass through nulls (for empty slots in 9-grid)
    if (item === null) return null
    
    const code = typeof item === 'string' ? item : (item.type ?? item.card_type ?? item.cardType ?? item.code ?? item.name ?? item.title ?? '')
    const meta = cardMetaMap.value[code] || {}
    
    if (typeof item === 'string') {
      return { 
        id: `card-${idx}-${Date.now()}`, 
        type: code, 
        image: meta.image || '',
        name: meta.name || code
      }
    }
    
    const normalized = {
      id: item.id ?? item.card_id ?? `card-${idx}-${Date.now()}`,
      type: code,
      image: item.image ?? item.product_image ?? item.image_url ?? item.thumb ?? item.img ?? meta.image ?? '',
      name: item.name ?? item.title ?? meta.name ?? code
    }
    return normalized
  })
}

async function processRound(round, isFirstRound = false) {
  if (!round) return
  isAnimating.value = true
  currentRound.value = round.round
  
  // 1. Precise Elimination based on `card_ids` in pairs
  // Spec: round.pairs contains { card_ids: ["c1", "c5"] }
  if (round.pairs && round.pairs.length > 0) {
    console.log('[DEBUG] Processing pairs:', round.pairs)
    const toPairIds = []
    
    round.pairs.forEach(p => {
      if (p.card_ids && Array.isArray(p.card_ids)) {
        toPairIds.push(...p.card_ids)
      } else {
        // Fallback for old API (count based logic)
        const type = p.card_type ?? p.type
        let count = p.count || 2
        // Naive fallback: find first N cards of this type
        // This is risky but keeps old logic working if partial update
        board.value.forEach(c => {
           if (c && c.type === type && count > 0 && !toPairIds.includes(c.id)) {
             toPairIds.push(c.id)
             count--
           }
        })
      }
    })
    
    if (toPairIds.length > 0) {
      pairingIds.value = toPairIds
      await sleep(1200)

      disappearingIds.value = [...toPairIds]
      pairingIds.value = []
      await sleep(600)

      // Clear the slots for these exact IDs
      const nextBoard = [...board.value]
      toPairIds.forEach(id => {
        const idx = nextBoard.findIndex(s => s && s.id === id)
        if (idx !== -1) nextBoard[idx] = null
      })
      board.value = nextBoard
      disappearingIds.value = []
    }
  }
  
  // 2. Stable Filling: Sync with Final Board
  // Spec: round.board is the final state. 
  // We compare final board with current board to find what changed (Filling empties).
  if (round.board) {
    const finalBoard = normalizeCards(round.board)
    const currentBoard = [...board.value]
    const addedIds = []
    
    // Apply changes (fill nulls)
    for (let i = 0; i < 9; i++) {
        // If local is null but final is not null -> New Card filled here
        if (currentBoard[i] === null && finalBoard[i] !== null) {
            currentBoard[i] = finalBoard[i]
            addedIds.push(finalBoard[i].id)
        } 
        // Sync override (just in case)
        else if (finalBoard[i] !== null && currentBoard[i]?.id !== finalBoard[i].id) {
             currentBoard[i] = finalBoard[i] 
             // Maybe animate this too if it's a swap? Spec says stable, so mostly filling.
        }
    }
    
    board.value = currentBoard
    
    if (addedIds.length > 0) {
        newCardIds.value = addedIds
        await sleep(1000)
        newCardIds.value = []
    }
  } 

  // Deck count update if available
  // (Usually in root response, but if in round object...)
  // if (round.deck_count !== undefined) deckCount.value = round.deck_count
  
  isAnimating.value = false
}


// Reconnection logic
async function checkGameStatus() {
  const savedGameId = uni.getStorageSync('matching_game_id')
  if (!savedGameId) return false
  
  loading.value = true
  try {
    const res = await getMatchingGameState(savedGameId)
    gameId.value = savedGameId
    
    // Spec: res.board is the fixed 9-slot array directly from storage including nulls
    board.value = normalizeCards(res.board)

    // Ensure it's 9 slots just in case
    while (board.value.length < 9) {
       board.value.push(null)
    }
    
    totalPairs.value = res.total_pairs
    currentRound.value = res.round
    deckCount.value = res.deck_count
    
    uni.showToast({ title: '已恢复游戏进度', icon: 'none' })
    return true
  } catch (e) {
    uni.removeStorageSync('matching_game_id')
    return false
  } finally {
    loading.value = false
  }
}

function resetGame() {
  uni.removeStorageSync('matching_game_id')
  gameId.value = ''
  board.value = Array(9).fill(null)
  totalPairs.value = 0
  currentRound.value = 0
  gameOver.value = false
  showResult.value = false
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))
}

function onPreviewBanner() {
  const url = detail.value.banner
  if (url) uni.previewImage({ urls: [url] })
}

onLoad((opts) => {
  const id = opts.id || ''
  if (id) {
    activityId.value = id
    initGame(id)
  } else {
    uni.showToast({ title: '参数错误', icon: 'none' })
    loading.value = false
  }
})

function goHome() {
  uni.switchTab({ url: '/pages/shop/index' })
}
</script>

<style lang="scss" scoped>
.page-container {
  min-height: 100vh;
  background: #0f0c29;
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* Branded Background */
.bg-layer {
  position: absolute;
  top: 0; left: 0; width: 100%; height: 100%;
  z-index: 0;
}

.game-glow {
  position: absolute;
  border-radius: 50%;
  filter: blur(120rpx);
  opacity: 0.6;
}

.glow-1 { width: 600rpx; height: 600rpx; background: radial-gradient(circle, #ff6b35 0%, transparent 70%); top: -150rpx; left: -100rpx; }
.glow-2 { width: 700rpx; height: 700rpx; background: radial-gradient(circle, #e81cff 0%, transparent 70%); bottom: -200rpx; right: -100rpx; }
.glow-3 { width: 500rpx; height: 500rpx; background: radial-gradient(circle, #fcb045 0%, transparent 70%); top: 35%; right: -150rpx; }

/* Top Nav & Ticker */
.top-nav {
  position: relative;
  z-index: 10;
  padding: $spacing-md $spacing-lg;
  padding-top: calc($spacing-md + env(safe-area-inset-top));
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.win-ticker {
  flex: 1;
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(10px);
  height: 64rpx;
  border-radius: 32rpx;
  display: flex;
  align-items: center;
  padding: 0 $spacing-md;
  margin-right: $spacing-md;
  border: 1rpx solid rgba(255, 255, 255, 0.15);
}

.ticker-icon { font-size: 24rpx; margin-right: 12rpx; }
.ticker-swiper { flex: 1; height: 100%; }
.ticker-item {
  height: 100%;
  display: flex;
  align-items: center;
  font-size: 22rpx;
  color: rgba(255, 255, 255, 0.9);
}
.ticker-prize { color: #ffca28; font-weight: bold; margin-left: 8rpx; }

.rules-btn {
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(10px);
  padding: 12rpx $spacing-md;
  border-radius: $radius-round;
  color: #fff;
  font-size: 22rpx;
  display: flex;
  align-items: center;
  border: 1rpx solid rgba(255, 255, 255, 0.2);
}
.rules-icon {
  width: 28rpx; height: 28rpx; background: rgba(255,255,255,0.2); border-radius: 50%;
  display: flex; align-items: center; justify-content: center; margin-right: 8rpx;
}

.page-content {
  flex: 1;
  position: relative;
  z-index: 1;
}

/* Glass Panels */
.glass-panel {
  background: rgba(255, 255, 255, 0.08);
  backdrop-filter: blur(25px);
  border: 1rpx solid rgba(255, 255, 255, 0.12);
  border-radius: 40rpx;
  box-shadow: 0 20rpx 50rpx rgba(0,0,0,0.3);
}

/* Loading Portal */
.loading-portal {
  padding-top: 200rpx;
  display: flex; flex-direction: column; align-items: center;
}
.loading-animation {
  width: 120rpx; height: 120rpx;
  border: 4rpx solid rgba(255,255,255,0.1);
  border-top-color: #ff6b35;
  border-radius: 50%;
  animation: rotate 1s linear infinite;
  margin-bottom: $spacing-xl;
}
.loading-text { color: rgba(255,255,255,0.6); font-size: $font-sm; letter-spacing: 2rpx; }

/* Empty States */
.empty-portal {
  padding-top: 150rpx;
  display: flex; flex-direction: column; align-items: center;
}
.empty-art-wrapper {
  position: relative; width: 240rpx; height: 240rpx; margin-bottom: 60rpx;
}
.empty-orb {
  position: absolute; top: 0; left: 0; width: 100%; height: 100%;
  background: radial-gradient(circle, rgba(232, 28, 255, 0.2) 0%, transparent 70%);
  animation: pulse 3s infinite;
}
.empty-emoji { font-size: 140rpx; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); filter: drop-shadow(0 0 20rpx #e81cff); }
.empty-title { font-size: 40rpx; color: #fff; font-weight: 800; margin-bottom: 16rpx; }
.empty-desc { font-size: 26rpx; color: rgba(255,255,255,0.5); margin-bottom: 80rpx; }
.return-home-btn {
  width: 320rpx; height: 90rpx; background: linear-gradient(90deg, #FF6B35, #ff9f43);
  color: #fff; border-radius: 45rpx; font-weight: bold; border: none;
}

/* Banner */
.banner-section { margin: $spacing-md $spacing-lg $spacing-xl; border-radius: 32rpx; overflow: hidden; position: relative; }
.banner-image { width: 100%; display: block; }
.banner-overlay { position: absolute; bottom: 0; left: 0; width: 100%; height: 60%; background: linear-gradient(to top, rgba(15,12,41,0.8), transparent); }

/* Arena Stats */
.arena-stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 20rpx; padding: 0 $spacing-lg; margin-bottom: 40rpx;
}
.stat-gem {
  background: rgba(255, 255, 255, 0.05);
  border: 1rpx solid rgba(255,255,255,0.1);
  border-radius: 30rpx;
  padding: 24rpx 16rpx;
  display: flex; flex-direction: column; align-items: center;
  backdrop-filter: blur(10px);
}
.gem-icon { font-size: 36rpx; margin-bottom: 8rpx; }
.gem-label { font-size: 18rpx; color: rgba(255,255,255,0.4); text-transform: uppercase; margin-bottom: 4rpx; }
.gem-value { font-size: 34rpx; font-weight: 900; color: #fff; font-family: 'DIN Alternate', sans-serif; text-shadow: 0 0 10rpx rgba(232, 28, 255, 0.5); }

/* Apple Effect */
.special-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 1000; display: flex; align-items: center; justify-content: center; background: rgba(0,0,0,0.6); backdrop-filter: blur(5px); }
.apple-card { width: 500rpx; height: 600rpx; background: #fff; border-radius: 50rpx; display: flex; flex-direction: column; align-items: center; justify-content: center; position: relative; overflow: hidden; }
.apple-glow { position: absolute; width: 150%; height: 150%; background: radial-gradient(circle, rgba(255, 107, 53, 0.3) 0%, transparent 70%); animation: rotate 4s linear infinite; }
.apple-emoji { font-size: 160rpx; z-index: 1; margin-bottom: 40rpx; }
.apple-title { font-size: 44rpx; font-weight: 900; color: #f44336; z-index: 1; }
.apple-subtitle { font-size: 24rpx; color: #777; z-index: 1; margin-top: 10rpx; }

/* Board Arena */
.board-arena { margin: 0 $spacing-lg; padding: 30rpx; }
.board-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20rpx; }
.card-unit {
  aspect-ratio: 1; background: rgba(0, 0, 0, 0.2); border-radius: 24rpx; position: relative;
  transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
  
  &.is-pairing { transform: scale(1.1); box-shadow: 0 0 50rpx rgba(255, 107, 53, 0.8); z-index: 5; }
  &.is-disappearing { transform: scale(0); opacity: 0; filter: blur(10px); }
  &.is-drawing { animation: cardDraw 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275) backwards; }
  &.is-rare { border: 2rpx solid #ffca28; box-shadow: inset 0 0 20rpx rgba(255, 202, 40, 0.2); }
}

.match-badge {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(-15deg);
  background: #ff6b35; color: #fff; font-size: 24rpx; font-weight: 900;
  padding: 4rpx 12rpx; border-radius: 8rpx; z-index: 10;
  animation: matchPop 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
}
@keyframes matchPop { from { transform: translate(-50%, -50%) scale(0) rotate(0deg); } to { transform: translate(-50%, -50%) scale(1) rotate(-15deg); } }

.card-face {
  width: 100%; height: 100%; border-radius: 24rpx; background: #fff; padding: 12rpx; display: flex; flex-direction: column; align-items: center; justify-content: center; position: relative; overflow: hidden;
}
.card-shine { position: absolute; top: -100%; left: -100%; width: 200%; height: 200%; background: linear-gradient(135deg, transparent 45%, rgba(255,255,255,0.8) 50%, transparent 55%); animation: shine 3s infinite; }
.card-thumb { width: 80%; height: 80%; border-radius: 12rpx; }
.card-tag { font-size: 18rpx; color: #333; font-weight: 800; margin-top: 8rpx; @include text-ellipsis(1); }

.card-void { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; opacity: 0.3; }
.void-circle { width: 40rpx; height: 40rpx; border: 4rpx dashed rgba(255,255,255,0.2); border-radius: 50%; }

/* Entry Hall */
.entry-hall { margin: 0 $spacing-lg; padding: 40rpx 0; }
.arena-header { padding: 0 40rpx; display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 40rpx; }
.hall-title { display: flex; flex-direction: column; }
.title-main { font-size: 38rpx; font-weight: 900; color: #fff; letter-spacing: 2rpx; }
.title-sub { font-size: 18rpx; color: rgba(255,255,255,0.3); font-weight: bold; }
.issue-count { font-size: 20rpx; background: rgba(255,255,255,0.1); color: #ff6b35; padding: 8rpx 20rpx; border-radius: 20rpx; border: 1rpx solid rgba(255, 255, 255, 0.1); }

.issue-scroll { width: 100%; margin-bottom: 40rpx; }
.issue-cards { display: flex; padding: 20rpx 40rpx; gap: 30rpx; }
.issue-card {
  flex-shrink: 0; width: 260rpx; height: 320rpx; border-radius: 36rpx; background: rgba(255,255,255,0.05); border: 1rpx solid rgba(255,255,255,0.1);
  padding: 30rpx; display: flex; flex-direction: column; position: relative; overflow: hidden;
  transition: all 0.3s;
  
  &.active { background: rgba(255,255,255,0.12); border-color: #ff6b35; transform: translateY(-10rpx); box-shadow: 0 20rpx 40rpx rgba(255, 107, 53, 0.2); }
}
.card-background-glow { position: absolute; top: -50rpx; right: -50rpx; width: 150rpx; height: 150rpx; background: radial-gradient(circle, rgba(232, 28, 255, 0.1) 0%, transparent 70%); }
.issue-no { font-size: 20rpx; color: rgba(255,255,255,0.3); font-weight: 900; margin-bottom: 20rpx; }
.issue-name { font-size: 32rpx; color: #fff; font-weight: bold; line-height: 1.4; flex: 1; }
.issue-tag { font-size: 18rpx; padding: 6rpx 16rpx; border-radius: 10rpx; align-self: flex-start; background: rgba(255,255,255,0.1); color: rgba(255,255,255,0.6); }
.issue-tag.status-1 { background: rgba(76, 175, 80, 0.2); color: #81c784; }
.active-indicator { position: absolute; bottom: 24rpx; right: 24rpx; font-size: 16rpx; color: #ff6b35; font-weight: 900; display: flex; align-items: center; gap: 6rpx; }
.active-indicator .dot { width: 8rpx; height: 8rpx; background: #ff6b35; border-radius: 50%; animation: pulse 1s infinite; }

.hall-tabs { display: flex; padding: 0 40rpx; gap: 60rpx; margin-bottom: 30rpx; }
.hall-tab {
  font-size: 28rpx; color: rgba(255,255,255,0.4); font-weight: bold; position: relative; padding-bottom: 15rpx;
  &.active { color: #fff; }
}
.tab-bar-glow { position: absolute; bottom: 0; left: 0; width: 100%; height: 4rpx; background: #ff6b35; border-radius: 2rpx; box-shadow: 0 0 10rpx #ff6b35; }

/* Rewards Mosaic */
.rewards-mosaic { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20rpx; padding: 0 30rpx; }
.mosaic-item { background: rgba(255, 255, 255, 0.03); border-radius: 24rpx; padding: 16rpx; }
.mosaic-inner { display: flex; flex-direction: column; gap: 12rpx; }
.mosaic-img-box { width: 100%; aspect-ratio: 1; background: rgba(0,0,0,0.2); border-radius: 16rpx; position: relative; overflow: hidden; }
.mosaic-img { width: 100%; height: 100%; }
.mosaic-boss { position: absolute; top: 12rpx; right: 12rpx; font-size: 16rpx; background: #ffca28; color: #000; font-weight: 900; padding: 4rpx 10rpx; border-radius: 6rpx; }
.mosaic-prob { position: absolute; bottom: 12rpx; left: 12rpx; font-size: 14rpx; background: rgba(0,0,0,0.6); color: #fff; padding: 4rpx 12rpx; border-radius: 6rpx; backdrop-filter: blur(4rpx); }
.mosaic-title { font-size: 22rpx; color: rgba(255,255,255,0.8); font-weight: bold; @include text-ellipsis(1); }

/* Dynamic Records */
.dynamic-records { display: flex; flex-direction: column; gap: 20rpx; padding: 0 30rpx; }
.win-row { display: flex; align-items: center; background: rgba(255,255,255,0.03); padding: 20rpx; border-radius: 24rpx; }
.win-avatar-box { width: 70rpx; height: 70rpx; border-radius: 50%; border: 2rpx solid rgba(255,255,255,0.1); overflow: hidden; margin-right: 20rpx; }
.win-avatar { width: 100%; height: 100%; }
.win-info { flex: 1; display: flex; flex-direction: column; gap: 4rpx; }
.win-top { display: flex; align-items: baseline; gap: 12rpx; }
.win-user { font-size: 22rpx; color: #fff; font-weight: bold; }
.win-time { font-size: 18rpx; color: rgba(255,255,255,0.3); }
.win-item-name { font-size: 20rpx; color: #ff6b35; font-weight: bold; }
.win-thumb { width: 80rpx; height: 80rpx; border-radius: 12rpx; }

/* Action Hub */
.action-hub {
  position: fixed; bottom: 0; left: 0; width: 100%; z-index: 100;
  padding: 40rpx; padding-bottom: calc(40rpx + env(safe-area-inset-bottom));
  background: linear-gradient(to top, #0f0c29 70%, transparent);
}
.action-glow { position: absolute; bottom: 0; left: 10%; width: 80%; height: 100rpx; background: rgba(255, 107, 53, 0.3); filter: blur(40rpx); opacity: 0.6; }

.gaming-controls {
  display: flex; flex-direction: column; gap: 30rpx; width: 100%;
}
.auto-toggle-box {
  align-self: flex-center; display: flex; align-items: center; gap: 20rpx;
  background: rgba(255, 255, 255, 0.05); padding: 12rpx 30rpx; border-radius: 40rpx;
  border: 1rpx solid rgba(255,255,255,0.1);
}
.toggle-track {
  width: 80rpx; height: 40rpx; background: rgba(255,255,255,0.1); border-radius: 20rpx;
  position: relative; transition: all 0.3s;
  &.active { background: #4caf50; .toggle-thumb { transform: translateX(40rpx); } }
}
.toggle-thumb {
  position: absolute; top: 4rpx; left: 4rpx; width: 32rpx; height: 32rpx;
  background: #fff; border-radius: 50%; transition: all 0.3s;
  box-shadow: 0 0 10rpx rgba(0,0,0,0.3);
}
.toggle-label { font-size: 22rpx; color: #fff; font-weight: 800; }

/* Action Hub Standard Buttons */
.hub-btn {
  width: 100%; height: 110rpx; border-radius: 55rpx; display: flex; align-items: center; justify-content: center;
  font-weight: 900; font-size: 32rpx; letter-spacing: 2rpx; position: relative; overflow: hidden; transition: all 0.2s;
  
  &:active { transform: scale(0.96); }
}

.neon-btn {
  background: linear-gradient(90deg, #FF6B35, #E81CFF);
  color: #fff; box-shadow: 0 15rpx 40rpx rgba(232, 28, 255, 0.4);
}
.btn-energy-line { position: absolute; bottom: 0; left: 0; width: 100%; height: 6rpx; background: rgba(255,255,255,0.3); animation: energyFlow 2s linear infinite; }

.primary-btn { background: #fff; color: #000; box-shadow: 0 10rpx 30rpx rgba(255,255,255,0.2); }
.secondary-btn { background: rgba(255,255,255,0.1); color: #fff; }
.gold-btn { background: $gradient-gold; color: #000; }

.game-over-hub { display: flex; gap: 20rpx; .hub-btn { flex: 1; } }

/* Modals */
.modal-layer { position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 1000; background: rgba(0,0,0,0.85); backdrop-filter: blur(10px); display: flex; align-items: center; justify-content: center; }
.premium-modal { width: 620rpx; max-height: 80vh; background: #1a1a2e; border: 1rpx solid rgba(255,255,255,0.1); border-radius: 50rpx; padding: 50rpx; display: flex; flex-direction: column; }
.modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 40rpx; }
.modal-title { font-size: 36rpx; color: #fff; font-weight: 900; }
.close-x { font-size: 40rpx; color: rgba(255,255,255,0.3); line-height: 1; }

.modal-scroll { flex: 1; overflow: hidden; }
.rule-item { display: flex; gap: 30rpx; margin-bottom: 40rpx; }
.rule-no { font-size: 32rpx; font-weight: 900; color: #ff6b35; font-family: 'DIN Alternate'; }
.rule-content { font-size: 26rpx; color: rgba(255,255,255,0.7); line-height: 1.6; }
.modal-confirm { width: 100%; height: 90rpx; border-radius: 45rpx; background: #fff; color: #000; font-weight: 900; margin-top: 40rpx; }

/* Settlement Card */
.settlement-card { width: 600rpx; padding: 80rpx 50rpx; display: flex; flex-direction: column; align-items: center; text-align: center; }
.settlement-crown { font-size: 120rpx; margin-bottom: 40rpx; filter: drop-shadow(0 0 20rpx #ffea00); }
.settlement-title { font-size: 44rpx; color: #fff; font-weight: 900; margin-bottom: 60rpx; }
.settlement-stats { margin-bottom: 60rpx; }
.set-stat { display: flex; flex-direction: column; align-items: center; }
.set-val { font-size: 100rpx; color: #ff6b35; font-weight: 900; font-family: 'DIN Alternate'; line-height: 1; }
.set-lab { font-size: 22rpx; color: rgba(255,255,255,0.4); margin-top: 10rpx; }
.settlement-tip { font-size: 24rpx; color: rgba(255,255,255,0.5); margin-bottom: 60rpx; }
.set-btn { width: 100%; height: 100rpx; border-radius: 50rpx; background: linear-gradient(90deg, #FF6B35, #E81CFF); color: #fff; font-weight: bold; }

/* Animations */
@keyframes cardDraw { from { transform: translateY(200rpx) scale(0.5); opacity: 0; } to { transform: translateY(0) scale(1.0); opacity: 1; } }
@keyframes energyFlow { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
@keyframes shine { 0% { left: -100%; } 20% { left: 120%; } 100% { left: 120%; } }
@keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
@keyframes pulse { 0% { opacity: 0.6; transform: scale(1); } 50% { opacity: 1; transform: scale(1.05); } 100% { opacity: 0.6; transform: scale(1); } }

.animate-fade-in { animation: fadeIn 0.8s ease-out; }
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

.animate-slide-up { animation: slideUp 0.6s cubic-bezier(0.175, 0.885, 0.32, 1.275) backwards; }
@keyframes slideUp { from { transform: translateY(100rpx); opacity: 0; } to { transform: translateY(0); opacity: 1; } }

.animate-bounce-in { animation: bounceIn 0.8s cubic-bezier(0.175, 0.885, 0.32, 1.275) backwards; }
@keyframes bounceIn { 0% { transform: scale(0.3); opacity: 0; } 50% { transform: scale(1.05); opacity: 1; } 70% { transform: scale(0.9); } 100% { transform: scale(1); } }

.animate-zoom-in { animation: zoomIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) backwards; }
@keyframes zoomIn { from { transform: scale(0.8); opacity: 0; } to { transform: scale(1); opacity: 1; } }

.matching-pulse { animation: mPulse 1.5s infinite; }
@keyframes mPulse { 0% { opacity: 1; } 50% { opacity: 0.6; } 100% { opacity: 1; } }

.pulsate { animation: pulsate 2s infinite ease-in-out; }
@keyframes pulsate {
  0% { transform: scale(1); box-shadow: 0 15rpx 40rpx rgba(232, 28, 255, 0.4); }
  50% { transform: scale(1.02); box-shadow: 0 25rpx 60rpx rgba(232, 28, 255, 0.6); }
  100% { transform: scale(1); box-shadow: 0 15rpx 40rpx rgba(232, 28, 255, 0.4); }
}
</style>
