<script setup lang="ts">
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import FightViewer from '../components/FightViewer.vue'
import { useNostr } from '../composables/useNostr'
import { useFightPolling } from '../composables/useFightPolling'
import { useHumanChallenge } from '../composables/useHumanChallenge'
import { cacheFight, getCachedFight } from '../composables/useFightCache'
import { createFightScene, type FightSceneController } from '../game/FightScene'
import {
  fanfareRound,
  sfxCrowdCheer, sfxApplause, sfxDrumRoll,
  announceFinishHim, announceFlawlessVictory, announceDeepIntro,
  setMusicIntensity, stopAllAudio, ensureAudioContext, setMasterMute,
} from '../game/audio'

const route = useRoute()
const router = useRouter()
const { bot: myBot, isLoggedIn } = useNostr()
const fightId = ref(route.params.fightId as string)
const isRequeueing = ref(false)
const replayDone = ref(false)
const autoBattle = ref(false)
const autoBattleCount = ref(0)

// Human fight detection
const isHumanFight = computed(() => !!myBot.value?.isHuman || myBot.value?.archetype === 'human')

// Composables
const polling = useFightPolling(fightId)
const {
  isLive, isLoading, liveRounds, fightError, fight, liveFightData,
  spectatorCount, currentChallengeInfo, pendingSSEEvents,
  loadFight, startPolling, stopPolling, connectSSE, disconnectSSE, cleanup: cleanupPolling,
} = polling

const myBotId = computed(() => {
  if (!isLoggedIn.value || !myBot.value) return null
  const f = fight.value || liveFightData.value
  if (!f) return null
  if (myBot.value.id === f.botA?.id) return f.botA.id
  if (myBot.value.id === f.botB?.id) return f.botB.id
  return null
})

const challenge = useHumanChallenge(fightId, myBotId)
const {
  humanChallenge, humanAnswer, humanTimer, humanSubmitted, humanChoices,
  roundCooldown, pendingChallengeData,
  applyChallenge, submitChoice, startHumanPolling, stopHumanPolling,
  startCooldown, clearChallenge, resetState: resetChallengeState, handleSSEChallenge,
} = challenge

// Live scene state
const liveCanvas = ref<HTMLCanvasElement>()
const liveLogEl = ref<HTMLElement>()
let liveScene: FightSceneController | null = null
const liveLogItems = ref<{ type: string; round: number; text: string; color: string }[]>([])
const liveHpA = ref(100)
const liveHpB = ref(100)
const liveCurrentRound = ref(0)
const liveSceneReady = ref(false)
const liveSoundOn = ref(true)
const liveAnnouncement = ref('')
const liveAnnouncementColor = ref('#ffffff')
const liveAnnouncementVisible = ref(false)
const humanFightDone = ref(false)
const humanFightResult = ref<{ winnerId: string; winnerName: string; isPerfect: boolean } | null>(null)

// Emoji reactions
const liveFloatingEmojis = ref<{ id: number; emoji: string; x: number }[]>([])
let liveEmojiCounter = 0
const EMOJI_MAP: Record<string, string> = {
  fist: '\u{1F44A}', fire: '\u{1F525}', skull: '\u{1F480}', '100': '\u{1F4AF}', clown: '\u{1F921}',
}
function spawnLiveReactionEmoji(key: string) {
  const emoji = EMOJI_MAP[key] || key
  const id = liveEmojiCounter++
  const x = 15 + Math.random() * 70
  liveFloatingEmojis.value.push({ id, emoji, x })
  setTimeout(() => {
    liveFloatingEmojis.value = liveFloatingEmojis.value.filter(e => e.id !== id)
  }, 2000)
}

const showOverlay = computed(() => replayDone.value && !isRequeueing.value && !autoBattle.value)

let _pageDestroyed = false
function sleep(ms: number): Promise<void> {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      if (_pageDestroyed) reject(new Error('unmounted'))
      else resolve()
    }, ms)
  })
}
function scrollLiveLog() { nextTick(() => { liveLogEl.value?.scrollTo({ top: liveLogEl.value.scrollHeight, behavior: 'smooth' }) }) }

const challengeLabel = (type: string) => {
  const labels: Record<string, string> = {
    speed_blitz: 'SPEED BLITZ', riddle: 'RIDDLE ME THIS', code_golf: 'CODE GOLF',
    roast_battle: 'ROAST BATTLE', hallucination_check: 'HALLUCINATION CHECK',
    token_economy: 'TOKEN ECONOMY', creative_writing: 'CREATIVE WRITING',
    math_blitz: 'MATH BLITZ', trap_card: 'TRAP CARD',
    food_fight: 'FOOD FIGHT', wrestling_match: 'WRESTLING MATCH',
    music_battle: 'MUSIC BATTLE', magic_duel: 'MAGIC DUEL',
    sports_showdown: 'SPORTS SHOWDOWN', nature_clash: 'NATURE CLASH',
    space_war: 'SPACE WAR', hack_battle: 'HACK BATTLE',
    meme_war: 'MEME WAR', animal_kingdom: 'ANIMAL KINGDOM',
    demolition: 'DEMOLITION DERBY', vehicle_mayhem: 'VEHICLE MAYHEM',
    medieval_combat: 'MEDIEVAL COMBAT',
  }
  return labels[type] || type.replace(/_/g, ' ').toUpperCase()
}

const tierClass = (t: number) => `tier-${t}`

// --- Live scene management ---
async function initLiveScene() {
  const data = liveFightData.value
  if (!data?.botA || !data?.botB || !liveCanvas.value) return

  if (liveScene) { liveScene.destroy(); liveScene = null }

  const container = liveCanvas.value.parentElement
  if (container) {
    for (let i = 0; i < 10 && (!container.clientWidth || !container.clientHeight); i++) {
      await new Promise(r => requestAnimationFrame(r))
    }
    const oldCanvas = liveCanvas.value
    const newCanvas = document.createElement('canvas')
    newCanvas.className = oldCanvas.className
    newCanvas.width = container.clientWidth || 800
    newCanvas.height = container.clientHeight || 500
    oldCanvas.replaceWith(newCanvas)
    liveCanvas.value = newCanvas
  }

  try {
    liveScene = await createFightScene({
      canvas: liveCanvas.value,
      botA: { name: data.botA.name, seed: data.botA.avatarSeed || data.botA.name, tier: data.botA.tier, archetype: data.botA.archetype, customization: data.botA.customization ?? undefined, wins: data.botA.wins, losses: data.botA.losses },
      botB: { name: data.botB.name, seed: data.botB.avatarSeed || data.botB.name, tier: data.botB.tier, archetype: data.botB.archetype, customization: data.botB.customization ?? undefined, wins: data.botB.wins, losses: data.botB.losses },
      arena: data.arena,
    })
  } catch (err) {
    console.error('[FightPage] createFightScene failed:', err)
    liveScene = null
  }

  liveSceneReady.value = true

  if (liveScene) {
    if (liveSoundOn.value) {
      await ensureAudioContext()
      liveScene.startMusic()
    }
    announceDeepIntro()
    await liveScene.playEntrance()
  }

  liveLogItems.value.push(
    { type: 'system', round: 0, text: `ARENA: ${data.arenaInfo?.name || 'THE RING'}`, color: 'neon-purple' },
    { type: 'system', round: 0, text: `${data.botA.name} vs ${data.botB.name}`, color: 'text-secondary' },
    { type: 'divider', round: 0, text: '', color: '' },
  )
  scrollLiveLog()
}

// --- SSE event wiring ---
function wireSSE() {
  connectSSE({
    onReaction(data) {
      if (typeof data.emoji === 'string' && data.counts) {
        spawnLiveReactionEmoji(data.emoji)
      }
    },
    onRoundStart(data) {
      liveLogItems.value.push({
        type: 'challenge',
        round: data.round,
        text: `${data.challenge.label}: ${data.challenge.prompt}`,
        color: 'neon-green',
      })
      scrollLiveLog()
    },
    async onHumanChallenge(sseData) {
      if (myBot.value) {
        try {
          const res = await fetch(`/api/fights/${fightId.value}/challenge/${myBot.value.id}`)
          if (res.ok) {
            const fullData = await res.json()
            if (fullData.pending) {
              handleSSEChallenge(fullData)
              return
            }
          }
        } catch { /* fall through */ }
      }
      handleSSEChallenge(sseData)
    },
    onRoundEnd(data) {
      handleRoundEnd(data).catch(() => {})
    },
    onFightEnd(data) {
      handleFightEnd(data).catch(() => {})
    },
  })
}

async function showLiveOverlay(text: string, color: string, duration: number) {
  liveAnnouncement.value = text
  liveAnnouncementColor.value = color
  liveAnnouncementVisible.value = true
  await sleep(duration)
  liveAnnouncementVisible.value = false
  await sleep(60)
}

async function handleRoundEnd(data: any) {
  const fd = liveFightData.value
  if (!fd || !fd.botA || !fd.botB) {
    pendingSSEEvents.value.push({ type: 'round_end', data })
    return
  }

  const round = data.round
  const result = data.result
  const hp = data.hp

  liveCurrentRound.value = round
  clearChallenge()

  // Update HP (server 0-200, display 0-100)
  liveHpA.value = Math.round((hp.a / 200) * 100)
  liveHpB.value = Math.round((hp.b / 200) * 100)
  setMusicIntensity(1 - Math.min(liveHpA.value, liveHpB.value) / 100)

  const aWon = result.winnerId === fd.botA.id
  const bWon = result.winnerId === fd.botB.id
  const isCritical = Math.abs((result.botAScore || 0) - (result.botBScore || 0)) > 4

  const cLabel = currentChallengeInfo.value?.label || challengeLabel(currentChallengeInfo.value?.type || '')

  liveLogItems.value.push(
    { type: 'header', round, text: `ROUND ${round}: ${cLabel}`, color: 'neon-purple' },
  )
  if (result.botAResponse) {
    liveLogItems.value.push({ type: 'responseA', round, text: `${fd.botA.name}: ${result.botAResponse.slice(0, 120)}`, color: 'neon-cyan' })
  }
  if (result.botBResponse) {
    liveLogItems.value.push({ type: 'responseB', round, text: `${fd.botB.name}: ${result.botBResponse.slice(0, 120)}`, color: 'neon-pink' })
  }
  if (result.narration) {
    liveLogItems.value.push({ type: 'narration', round, text: `>> ${result.narration}`, color: 'neon-yellow' })
  }
  const winnerName = aWon ? fd.botA.name : bWon ? fd.botB.name : 'DRAW'
  liveLogItems.value.push(
    { type: 'result', round, text: `${winnerName} ${aWon || bWon ? 'wins round!' : '- no winner'} (${result.botAScore} vs ${result.botBScore})`, color: aWon ? 'neon-cyan' : bWon ? 'neon-pink' : 'text-muted' },
    { type: 'divider', round, text: '', color: '' },
  )
  scrollLiveLog()

  if (liveScene) {
    fanfareRound(round)
    if (result.botAResponse) liveScene.showSpeechBubble('a', result.botAResponse.slice(0, 60), 3)
    if (result.botBResponse) {
      setTimeout(() => {
        if (liveScene && result.botBResponse) liveScene.showSpeechBubble('b', result.botBResponse.slice(0, 60), 2.5)
      }, 300)
    }

    try {
      await liveScene.playRound({
        round,
        challengeType: currentChallengeInfo.value?.type || '',
        winnerId: result.winnerId,
        botAId: fd.botA.id,
        botBId: fd.botB.id,
        narration: result.narration || '',
        isCritical,
        botAScore: result.botAScore || 0,
        botBScore: result.botBScore || 0,
      })
    } catch (err) {
      console.warn('[FightPage] playRound animation failed:', err)
    }

    if (aWon || bWon) {
      await liveScene.playTaunt(aWon ? 'a' : 'b')
    }
  }

  currentChallengeInfo.value = null
  startCooldown(3)
}

async function handleFightEnd(data: any) {
  const fd = liveFightData.value
  if (!fd || !fd.botA || !fd.botB) {
    pendingSSEEvents.value.push({ type: 'fight_end', data })
    return
  }

  clearChallenge()
  roundCooldown.value = 0

  if (data.winnerId) {
    if (data.winnerId === fd.botA.id) liveHpB.value = 0
    else liveHpA.value = 0
  }

  if (liveScene && data.winnerId) {
    const winningSide = (data.winnerId === fd.botA.id ? 'a' : 'b') as 'a' | 'b'

    sfxDrumRoll()
    await sleep(500)
    announceFinishHim()
    await showLiveOverlay('FINISH IT!', '#ff2d2d', 900)

    if (data.isPerfect) {
      await liveScene.playPerfect(winningSide, data.winnerName)
      announceFlawlessVictory()
    } else {
      await liveScene.playKO(winningSide, data.winnerName)
    }

    sfxApplause()
    sfxCrowdCheer()
    await showLiveOverlay(`${data.winnerName} WINS!`, '#00f0ff', 2000)
    if (data.mode === 'ranked' && data.potSats) {
      await showLiveOverlay(`WON ${data.potSats} SATS!`, '#00f0ff', 1500)
    }
    liveScene.stopMusic()
  }

  if (isHumanFight.value) {
    humanFightDone.value = true
    humanFightResult.value = { winnerId: data.winnerId, winnerName: data.winnerName, isPerfect: data.isPerfect }
    const myWon = myBot.value && data.winnerId === myBot.value.id
    liveLogItems.value.push(
      { type: 'divider', round: 0, text: '', color: '' },
      { type: 'system', round: 0, text: myWon ? 'YOU WIN!' : 'YOU LOSE!', color: myWon ? 'neon-cyan' : 'neon-pink' },
    )
    if (data.mode === 'ranked' && data.potSats && myWon) {
      liveLogItems.value.push(
        { type: 'system', round: 0, text: `YOU WON ${data.potSats} SATS!`, color: 'neon-cyan' },
      )
    }
    scrollLiveLog()
    disconnectSSE()
    stopHumanPolling()
    stopPolling()
    return
  }

  if (liveScene) { liveScene.destroy(); liveScene = null }
  liveSceneReady.value = false

  // Retry loading until rounds are populated (server may still be persisting)
  for (let attempt = 0; attempt < 5; attempt++) {
    await loadFight()
    if (fight.value?.rounds?.length) break
    await new Promise(r => setTimeout(r, 800))
  }
  isLive.value = false
  disconnectSSE()
  stopHumanPolling()
  stopPolling()
}

async function toggleLiveSound() {
  liveSoundOn.value = !liveSoundOn.value
  await ensureAudioContext()
  setMasterMute(!liveSoundOn.value)
}

// Watch route param changes
watch(() => route.params.fightId, async (newId) => {
  if (!newId || newId === fightId.value) return
  cleanupPolling()
  stopHumanPolling()
  stopAllAudio()
  if (liveScene) { liveScene.destroy(); liveScene = null }
  liveSceneReady.value = false

  fightId.value = newId as string
  fight.value = null
  isLoading.value = true
  isLive.value = false
  liveRounds.value = 0
  fightError.value = ''
  replayDone.value = false
  autoBattle.value = false
  autoBattleCount.value = 0
  liveFightData.value = null
  liveLogItems.value = []
  liveHpA.value = 100
  liveHpB.value = 100
  liveCurrentRound.value = 0
  humanFightDone.value = false
  humanFightResult.value = null
  resetChallengeState()

  const status = await loadFight()
  isLoading.value = false
  if (status === null || status !== 'finished') {
    isLive.value = true
  }
  if (isLive.value) {
    startPolling({ onFinished: () => stopHumanPolling(), onTimeout: () => stopHumanPolling() })
    wireSSE()
    if (isHumanFight.value) {
      startHumanPolling()
      await nextTick()
      await nextTick()
      if (liveFightData.value) await initLiveScene()
    } else {
      if (!liveFightData.value) await loadFight()
      await nextTick()
      await nextTick()
      if (liveFightData.value) await initLiveScene()
    }
  }
})

// Watch for liveFightData becoming available
watch(liveFightData, async (val) => {
  if (val && !liveSceneReady.value && !liveScene) {
    await nextTick()
    await nextTick()
    await initLiveScene()
    // For human fights, start challenge polling after scene is ready
    if (isHumanFight.value) {
      startHumanPolling()
    }
    const queued = pendingSSEEvents.value.splice(0)
    for (const evt of queued) {
      if (evt.type === 'round_end') await handleRoundEnd(evt.data)
      else if (evt.type === 'fight_end') await handleFightEnd(evt.data)
    }
  }
})

// --- Mount / Unmount ---
onMounted(async () => {
  let status = await loadFight()

  // If fetch failed (offline), try IndexedDB cache
  if (status === null && fight.value === null) {
    const cached = await getCachedFight(fightId.value)
    if (cached) {
      fight.value = cached
      status = 'finished'
    }
  }

  // Cache finished fights for offline replay
  if (status === 'finished' && fight.value) {
    cacheFight(fight.value).catch(() => {})
  }

  isLoading.value = false

  if (status === null || status !== 'finished') {
    isLive.value = true
  }

  if (isLive.value) {
    startPolling({ onFinished: () => stopHumanPolling(), onTimeout: () => stopHumanPolling() })
    if (isHumanFight.value) {
      wireSSE()
      // Init scene first, then start challenge polling — ensures entrance
      // plays before the first question appears (characters invisible otherwise)
      if (liveFightData.value) {
        await nextTick()
        await nextTick()
        await initLiveScene()
      }
      // Only start polling after scene is ready (or watcher will start it when liveFightData arrives)
      if (liveSceneReady.value) {
        startHumanPolling()
      }
    }
  }
})

onUnmounted(() => {
  _pageDestroyed = true
  cleanupPolling()
  stopHumanPolling()
  stopAllAudio()
  if (liveScene) { liveScene.destroy(); liveScene = null }
  autoBattle.value = false
})

// --- Fight again / matchmake ---
async function fightAgain(botId: string) {
  if (isRequeueing.value) return
  isRequeueing.value = true
  replayDone.value = false
  resetChallengeState()
  humanFightDone.value = false
  humanFightResult.value = null
  if (liveScene) { liveScene.destroy(); liveScene = null }
  liveSceneReady.value = false
  liveFightData.value = null
  liveLogItems.value = []
  liveHpA.value = 100
  liveHpB.value = 100
  liveCurrentRound.value = 0
  disconnectSSE()

  try {
    const res = await fetch(`/api/queue/join/${botId}`, { method: 'POST' })
    if (res.ok) {
      const data = await res.json()
      fightId.value = data.fightId
      fight.value = null
      isLive.value = true
      liveRounds.value = 0
      fightError.value = ''
      window.history.replaceState({}, '', `/arena/${data.fightId}`)
      startPolling({ onFinished: () => stopHumanPolling(), onTimeout: () => stopHumanPolling() })
      if (isHumanFight.value) {
        startHumanPolling()
        wireSSE()
        for (let i = 0; i < 20; i++) {
          await loadFight()
          if (liveFightData.value) break
          await sleep(300)
        }
        await nextTick()
        await nextTick()
        if (liveFightData.value) await initLiveScene()
      }
    } else {
      fightError.value = `Failed to start fight (${res.status})`
    }
  } catch (err) {
    fightError.value = 'Network error starting fight'
    console.warn('[FightPage] fightAgain failed:', err)
  }
  isRequeueing.value = false
}

async function matchmake(botId: string) {
  if (isRequeueing.value) return
  isRequeueing.value = true
  replayDone.value = false
  try {
    const res = await fetch(`/api/fights/matchmake/${botId}`, { method: 'POST' })
    if (res.ok) {
      const data = await res.json()
      fightId.value = data.fightId
      fight.value = null
      isLive.value = true
      liveRounds.value = 0
      fightError.value = ''
      window.history.replaceState({}, '', `/arena/${data.fightId}`)
      startPolling({ onFinished: () => stopHumanPolling(), onTimeout: () => stopHumanPolling() })
    } else {
      fightError.value = `Matchmaking failed (${res.status})`
    }
  } catch (err) {
    fightError.value = 'Network error during matchmaking'
    console.warn('[FightPage] matchmake failed:', err)
  }
  isRequeueing.value = false
}

function onReplayDone() {
  replayDone.value = true
  if (autoBattle.value && myBotId.value && !isHumanFight.value) {
    autoBattleCount.value++
    fightAgain(myBotId.value)
  }
}

const isLoadingNext = ref(false)
async function watchAnotherFight() {
  if (isLoadingNext.value) return
  isLoadingNext.value = true
  try {
    const res = await fetch('/api/fights')
    if (res.ok) {
      const fights = await res.json()
      const finished = fights.filter((f: { status: string; id: string }) => f.status === 'finished' && f.id !== fightId.value)
      if (finished.length > 0) {
        const pick = finished[Math.floor(Math.random() * finished.length)]
        router.push(`/arena/${pick.id}`)
        return
      }
    }
    router.push('/arena')
  } catch {
    router.push('/arena')
  } finally {
    isLoadingNext.value = false
  }
}

function startAutoBattle() {
  if (!myBotId.value || isHumanFight.value) return
  autoBattle.value = true
  autoBattleCount.value = 0
  fightAgain(myBotId.value)
}

function stopAutoBattle() {
  autoBattle.value = false
}
</script>

<template>
  <div class="h-full flex flex-col px-2 sm:px-3 py-2 sm:py-3 overflow-hidden">
    <div v-if="isLoading" class="flex-1 flex items-center justify-center">
      <p class="font-display text-text-muted animate-pulse tracking-wider">LOADING FIGHT...</p>
    </div>

    <!-- LIVE HUMAN FIGHT: full arena view with input -->
    <div v-else-if="isLive && isHumanFight" class="flex-1 flex flex-col lg:flex-row gap-1 sm:gap-2 min-h-0 overflow-hidden">

      <!-- Battle Log + Human Input — mobile: bottom 50%, desktop: left 38% -->
      <div class="flex flex-col min-h-0 border border-border rounded-lg bg-black/90 overflow-hidden
                  h-[50%] lg:h-auto lg:w-[38%] order-2 lg:order-1">
        <div class="bg-surface-raised border-b border-border px-3 py-1 lg:py-1.5 flex items-center gap-2 flex-shrink-0">
          <span class="w-2 h-2 lg:w-2.5 lg:h-2.5 rounded-full bg-ko" />
          <span class="w-2 h-2 lg:w-2.5 lg:h-2.5 rounded-full bg-neon-yellow" />
          <span class="w-2 h-2 lg:w-2.5 lg:h-2.5 rounded-full bg-neon-green" />
          <span class="font-pixel text-[10px] text-text-muted ml-2 tracking-wider">BATTLE LOG</span>
          <span v-if="spectatorCount > 0" class="ml-auto font-pixel text-[10px] text-neon-cyan tracking-wider flex items-center gap-1">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-3 h-3">
              <path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/>
            </svg>
            {{ spectatorCount }}
          </span>
        </div>
        <div ref="liveLogEl" class="flex-1 overflow-y-auto p-2 sm:p-4 font-mono text-xs sm:text-sm space-y-1.5 leading-relaxed">
          <div v-for="(item, idx) in liveLogItems" :key="idx">
            <div v-if="item.type === 'divider'" class="py-1.5"><div class="border-t border-white/5" /></div>
            <p v-else-if="item.type === 'header'" class="text-neon-purple font-bold text-base tracking-wide pt-3 pb-1 uppercase">{{ item.text }}</p>
            <div v-else-if="item.type === 'challenge'" class="bg-neon-green/[0.06] border border-neon-green/20 rounded-md px-3 py-1.5 my-1">
              <p class="text-neon-green text-xs font-mono leading-snug">{{ item.text }}</p>
            </div>
            <div v-else-if="item.type === 'responseA'" class="bg-neon-cyan/[0.04] border-l-2 border-neon-cyan/30 rounded-r-md px-3 py-1.5 my-1">
              <p class="text-neon-cyan text-sm leading-snug">{{ item.text }}</p>
            </div>
            <div v-else-if="item.type === 'responseB'" class="bg-neon-pink/[0.04] border-l-2 border-neon-pink/30 rounded-r-md px-3 py-1.5 my-1">
              <p class="text-neon-pink text-sm leading-snug">{{ item.text }}</p>
            </div>
            <div v-else-if="item.type === 'narration'" class="bg-neon-yellow/[0.06] border border-neon-yellow/20 rounded-md px-3 py-1.5 my-1">
              <p class="text-neon-yellow font-bold text-sm">{{ item.text }}</p>
            </div>
            <p v-else-if="item.type === 'result'" :class="['font-bold text-sm pl-2 py-0.5', item.color === 'neon-cyan' ? 'text-neon-cyan' : item.color === 'neon-pink' ? 'text-neon-pink' : 'text-text-secondary']">{{ item.text }}</p>
            <p v-else-if="item.type === 'system'" :class="['text-sm', item.color === 'neon-purple' ? 'text-neon-purple font-bold tracking-wider' : 'text-text-muted']">{{ item.text }}</p>
          </div>
          <div v-if="liveLogItems.length === 0" class="text-neon-purple italic pt-8 text-center text-sm">Waiting for fight to begin...</div>
        </div>

        <!-- Human Input / Post-fight buttons at bottom of battle log -->
        <div class="px-3 py-2 border-t border-border bg-surface-raised/80 flex-shrink-0">
          <div v-if="humanFightDone" class="flex flex-col gap-2 py-1">
            <button
              v-if="myBot"
              :disabled="isRequeueing"
              class="w-full py-2.5 bg-neon-cyan/10 border-2 border-neon-cyan/50 text-neon-cyan
                     font-display font-black text-xs tracking-widest rounded-lg
                     hover:bg-neon-cyan/20 hover:border-neon-cyan transition-all
                     disabled:opacity-50 disabled:cursor-wait flex items-center justify-center gap-2"
              @click="fightAgain(myBot!.id)"
            >
              <span v-if="isRequeueing" class="w-4 h-4 border-2 border-neon-cyan/30 border-t-neon-cyan rounded-full animate-spin" />
              {{ isRequeueing ? 'MATCHING...' : 'FIGHT AGAIN' }}
            </button>
            <button
              class="w-full py-2 border border-white/10 text-text-muted
                     font-display text-xs tracking-widest rounded-lg
                     hover:bg-white/5 hover:text-text-primary transition-all"
              @click="$router.push('/join')"
            >
              BACK TO LOBBY
            </button>
          </div>
          <div v-else-if="roundCooldown > 0" class="text-center py-4">
            <p class="font-display text-neon-yellow text-lg tracking-widest animate-pulse">
              NEXT ROUND IN {{ roundCooldown }}...
            </p>
          </div>
          <div v-else-if="humanChallenge && !humanSubmitted">
            <div class="flex items-center justify-between mb-2">
              <div class="flex items-center gap-2 min-w-0 flex-1">
                <span class="font-display font-black text-xs tracking-wider text-neon-cyan shrink-0">
                  R{{ humanChallenge.roundNumber }}
                </span>
                <span class="font-display font-bold text-xs tracking-wider text-neon-purple uppercase truncate">
                  {{ humanChallenge.label }}
                </span>
              </div>
              <span
                class="font-display font-black text-lg tracking-wider tabular-nums shrink-0 ml-2"
                :class="humanTimer <= 1 ? 'text-ko animate-pulse scale-125' : humanTimer <= 2 ? 'text-ko animate-pulse' : 'text-neon-yellow'"
              >
                {{ humanTimer }}s
              </span>
            </div>
            <p class="font-mono text-sm text-text-primary leading-relaxed mb-3">
              {{ humanChallenge.prompt }}
            </p>
            <!-- Multiple choice buttons -->
            <div class="flex flex-col gap-2">
              <button
                v-for="(choice, i) in humanChoices"
                :key="i"
                class="w-full text-left px-4 py-3 border-2 rounded-lg font-mono text-sm leading-normal
                       active:scale-[0.97] transition-all"
                :class="[
                  i === 0 ? 'border-neon-cyan/40 text-neon-cyan bg-neon-cyan/5 hover:bg-neon-cyan/15 active:bg-neon-cyan/20' :
                  i === 1 ? 'border-neon-pink/40 text-neon-pink bg-neon-pink/5 hover:bg-neon-pink/15 active:bg-neon-pink/20' :
                            'border-neon-purple/40 text-neon-purple bg-neon-purple/5 hover:bg-neon-purple/15 active:bg-neon-purple/20'
                ]"
                @click="submitChoice(choice)"
              >
                {{ choice }}
              </button>
            </div>
          </div>
          <div v-else-if="humanSubmitted" class="text-center py-3">
            <p class="font-display text-text-muted text-sm tracking-wider animate-pulse">SCORING ROUND...</p>
          </div>
          <div v-else class="flex items-center justify-between py-2">
            <p class="font-mono text-text-muted text-sm">Waiting for challenge...</p>
            <button
              class="w-7 h-7 flex items-center justify-center border border-border/50 text-text-muted
                     hover:text-neon-cyan hover:border-neon-cyan/50 transition-all"
              :title="liveSoundOn ? 'Mute' : 'Unmute'"
              @click="toggleLiveSound"
            >
              <svg v-if="liveSoundOn" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-3.5 h-3.5">
                <path d="M11 5L6 9H2v6h4l5 4V5z"/><path d="M19.07 4.93a10 10 0 010 14.14M15.54 8.46a5 5 0 010 7.07"/>
              </svg>
              <svg v-else xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-3.5 h-3.5">
                <path d="M11 5L6 9H2v6h4l5 4V5z"/><line x1="23" y1="9" x2="17" y2="15"/><line x1="17" y1="9" x2="23" y2="15"/>
              </svg>
            </button>
          </div>
        </div>
      </div>

      <!-- Game Canvas — mobile: top 50%, desktop: right 62% -->
      <div class="h-[50%] lg:h-auto lg:flex-1 lg:w-[62%] flex flex-col min-h-0 border border-border rounded-lg bg-black overflow-hidden order-1 lg:order-2">

        <!-- Health bars -->
        <div v-if="liveFightData?.botA" class="px-2 sm:px-3 py-1 sm:py-2 bg-surface-raised/80 border-b border-border flex-shrink-0">
          <!-- Mobile: compact single-row names + HP -->
          <div class="sm:hidden">
            <div class="flex items-center gap-1">
              <p class="font-marker text-[10px] tracking-wider truncate text-neon-cyan flex-1 min-w-0">{{ liveFightData.botA.name }}</p>
              <span class="font-mono font-bold text-[10px] w-5 text-right tabular-nums" :class="liveHpA > 50 ? 'text-neon-cyan' : liveHpA > 20 ? 'text-neon-yellow' : 'text-ko'">{{ liveHpA }}</span>
              <div class="w-6 h-2.5 bg-black/50 rounded-sm overflow-hidden border border-neon-cyan/30">
                <div class="h-full bg-neon-cyan transition-all duration-500" :style="{ width: `${liveHpA}%` }" />
              </div>
              <span class="font-funky text-neon-purple text-[10px] px-0.5 flex-shrink-0">VS</span>
              <div class="w-6 h-2.5 bg-black/50 rounded-sm overflow-hidden border border-neon-pink/30">
                <div class="h-full bg-neon-pink transition-all duration-500 ml-auto" :style="{ width: `${liveHpB}%` }" />
              </div>
              <span class="font-mono font-bold text-[10px] w-5 text-left tabular-nums" :class="liveHpB > 50 ? 'text-neon-pink' : liveHpB > 20 ? 'text-neon-yellow' : 'text-ko'">{{ liveHpB }}</span>
              <p class="font-marker text-[10px] tracking-wider truncate text-right text-neon-pink flex-1 min-w-0">{{ liveFightData.botB?.name }}</p>
            </div>
          </div>
          <!-- Desktop: single-row layout -->
          <div class="hidden sm:block">
            <div class="flex items-center gap-2">
              <p class="font-marker text-sm tracking-wider truncate text-neon-cyan flex-shrink-0 max-w-[20%]">{{ liveFightData.botA.name }}</p>
              <div class="flex-1 h-5 bg-black/50 rounded-sm overflow-hidden border border-neon-cyan/30">
                <div class="h-full bg-gradient-to-r from-neon-cyan to-neon-purple transition-all duration-500" :style="{ width: `${liveHpA}%` }" />
              </div>
              <span class="font-mono font-bold text-sm w-8 text-right tabular-nums" :class="liveHpA > 50 ? 'text-neon-cyan' : liveHpA > 20 ? 'text-neon-yellow' : 'text-ko'">{{ liveHpA }}</span>
              <span class="font-funky text-neon-purple text-xl px-1">VS</span>
              <span class="font-mono font-bold text-sm w-8 text-left tabular-nums" :class="liveHpB > 50 ? 'text-neon-pink' : liveHpB > 20 ? 'text-neon-yellow' : 'text-ko'">{{ liveHpB }}</span>
              <div class="flex-1 h-5 bg-black/50 rounded-sm overflow-hidden border border-neon-pink/30">
                <div class="h-full bg-gradient-to-l from-neon-pink to-neon-purple transition-all duration-500 ml-auto" :style="{ width: `${liveHpB}%` }" />
              </div>
              <p class="font-marker text-sm tracking-wider truncate text-right text-neon-pink flex-shrink-0 max-w-[20%]">{{ liveFightData.botB?.name }}</p>
            </div>
            <div class="flex items-center justify-between mt-0.5">
              <span class="font-pixel text-[9px]" :class="tierClass(liveFightData.botA.tier || 0)">{{ Math.round(liveFightData.botA.eloRating || 0) }}</span>
              <span class="font-pixel text-[9px] text-text-muted">
                {{ liveFightData.arenaInfo?.name }} | R{{ liveCurrentRound }}
                <span v-if="liveFightData.mode === 'ranked'" class="text-neon-cyan"> | ⚡{{ liveFightData.potSats || 42 }} SATS</span>
                <span v-if="spectatorCount > 0" class="text-neon-cyan"> | {{ spectatorCount }} watching</span>
              </span>
              <span class="font-pixel text-[9px]" :class="tierClass(liveFightData.botB?.tier || 0)">{{ Math.round(liveFightData.botB?.eloRating || 0) }}</span>
            </div>
          </div>
        </div>

        <!-- Canvas area -->
        <div class="flex-1 relative min-h-0">
          <canvas ref="liveCanvas" class="w-full h-full block" />

          <!-- Floating reaction emojis -->
          <div
            v-for="fe in liveFloatingEmojis"
            :key="fe.id"
            class="absolute pointer-events-none z-25 emoji-float"
            :style="{ left: `${fe.x}%`, bottom: '10%' }"
          >
            <span class="text-2xl sm:text-3xl">{{ fe.emoji }}</span>
          </div>

          <!-- Floating announcement -->
          <Transition name="announce">
            <div v-if="liveAnnouncementVisible"
                 class="absolute inset-0 flex items-center justify-center pointer-events-none z-20">
              <p class="font-funky text-2xl sm:text-5xl lg:text-7xl tracking-widest uppercase announce-text"
                 :style="{ color: liveAnnouncementColor, textShadow: `0 0 20px ${liveAnnouncementColor}, 0 0 40px ${liveAnnouncementColor}` }">
                {{ liveAnnouncement }}
              </p>
            </div>
          </Transition>

          <!-- Loading scene overlay -->
          <div v-if="!liveSceneReady" class="absolute inset-0 flex items-center justify-center bg-black/80 z-10">
            <div class="text-center">
              <div class="w-12 h-12 border-4 border-neon-pink/30 border-t-neon-pink rounded-full animate-spin mx-auto mb-3" />
              <p class="font-display text-neon-pink tracking-widest animate-pulse">LOADING ARENA...</p>
            </div>
          </div>

        </div>

      </div>
    </div>

    <!-- LIVE BOT FIGHT: spectator view with live scene -->
    <div v-else-if="isLive && !isHumanFight" class="flex-1 flex flex-col lg:flex-row gap-1 sm:gap-2 min-h-0 overflow-hidden">

      <!-- Battle Log — mobile: bottom 40%, desktop: left 35% -->
      <div class="flex flex-col min-h-0 border border-border rounded-lg bg-black/90 overflow-hidden
                  h-[40%] lg:h-auto lg:w-[35%] order-2 lg:order-1">
        <div class="bg-surface-raised border-b border-border px-3 py-1 lg:py-1.5 flex items-center gap-2 flex-shrink-0">
          <span class="w-2 h-2 lg:w-2.5 lg:h-2.5 rounded-full bg-ko" />
          <span class="w-2 h-2 lg:w-2.5 lg:h-2.5 rounded-full bg-neon-yellow" />
          <span class="w-2 h-2 lg:w-2.5 lg:h-2.5 rounded-full bg-neon-green" />
          <span class="font-pixel text-[10px] text-text-muted ml-2 tracking-wider">BATTLE LOG</span>
          <span v-if="spectatorCount > 0" class="ml-auto font-pixel text-[10px] text-neon-cyan tracking-wider flex items-center gap-1">
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-3 h-3">
              <path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zM12 17c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/>
            </svg>
            {{ spectatorCount }}
          </span>
        </div>
        <div ref="liveLogEl" class="flex-1 overflow-y-auto p-2 sm:p-4 font-mono text-xs sm:text-sm space-y-1.5 leading-relaxed">
          <div v-for="(item, idx) in liveLogItems" :key="idx">
            <div v-if="item.type === 'divider'" class="py-1.5"><div class="border-t border-white/5" /></div>
            <p v-else-if="item.type === 'header'" class="text-neon-purple font-bold text-base tracking-wide pt-3 pb-1 uppercase">{{ item.text }}</p>
            <div v-else-if="item.type === 'challenge'" class="bg-neon-green/[0.06] border border-neon-green/20 rounded-md px-3 py-1.5 my-1">
              <p class="text-neon-green text-xs font-mono leading-snug">{{ item.text }}</p>
            </div>
            <div v-else-if="item.type === 'responseA'" class="bg-neon-cyan/[0.04] border-l-2 border-neon-cyan/30 rounded-r-md px-3 py-1.5 my-1">
              <p class="text-neon-cyan text-sm leading-snug">{{ item.text }}</p>
            </div>
            <div v-else-if="item.type === 'responseB'" class="bg-neon-pink/[0.04] border-l-2 border-neon-pink/30 rounded-r-md px-3 py-1.5 my-1">
              <p class="text-neon-pink text-sm leading-snug">{{ item.text }}</p>
            </div>
            <div v-else-if="item.type === 'narration'" class="bg-neon-yellow/[0.06] border border-neon-yellow/20 rounded-md px-3 py-1.5 my-1">
              <p class="text-neon-yellow font-bold text-sm">{{ item.text }}</p>
            </div>
            <p v-else-if="item.type === 'result'" :class="['font-bold text-sm pl-2 py-0.5', item.color === 'neon-cyan' ? 'text-neon-cyan' : item.color === 'neon-pink' ? 'text-neon-pink' : 'text-text-secondary']">{{ item.text }}</p>
            <p v-else-if="item.type === 'system'" :class="['text-sm', item.color === 'neon-purple' ? 'text-neon-purple font-bold tracking-wider' : 'text-text-muted']">{{ item.text }}</p>
          </div>
          <div v-if="liveLogItems.length === 0" class="text-neon-purple italic pt-8 text-center text-sm">Waiting for fight to begin...</div>
        </div>

        <!-- Spectator footer -->
        <div class="px-3 py-2 border-t border-border bg-surface-raised/80 flex-shrink-0">
          <div class="flex items-center justify-between">
            <p class="font-mono text-text-muted text-xs">
              <span v-if="liveCurrentRound > 0">Round {{ liveCurrentRound }}</span>
              <span v-else>Waiting for fight...</span>
            </p>
            <button
              class="w-7 h-7 flex items-center justify-center border border-border/50 text-text-muted
                     hover:text-neon-cyan hover:border-neon-cyan/50 transition-all"
              :title="liveSoundOn ? 'Mute' : 'Unmute'"
              @click="toggleLiveSound"
            >
              <svg v-if="liveSoundOn" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-3.5 h-3.5">
                <path d="M11 5L6 9H2v6h4l5 4V5z"/><path d="M19.07 4.93a10 10 0 010 14.14M15.54 8.46a5 5 0 010 7.07"/>
              </svg>
              <svg v-else xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="w-3.5 h-3.5">
                <path d="M11 5L6 9H2v6h4l5 4V5z"/><line x1="23" y1="9" x2="17" y2="15"/><line x1="17" y1="9" x2="23" y2="15"/>
              </svg>
            </button>
          </div>
          <p v-if="autoBattle" class="font-pixel text-[10px] text-neon-yellow tracking-wider mt-1">
            AUTO BATTLE #{{ autoBattleCount + 1 }}
            <button class="ml-2 text-ko hover:text-text-primary transition-colors" @click="stopAutoBattle">STOP</button>
          </p>
        </div>
      </div>

      <!-- Game Canvas — mobile: top 60%, desktop: right 65% -->
      <div class="h-[60%] lg:h-auto lg:flex-1 lg:w-[65%] flex flex-col min-h-0 border border-border rounded-lg bg-black overflow-hidden order-1 lg:order-2">

        <!-- Health bars -->
        <div v-if="liveFightData?.botA" class="px-2 sm:px-3 py-1 sm:py-2 bg-surface-raised/80 border-b border-border flex-shrink-0">
          <!-- Mobile: compact single-row names + HP -->
          <div class="sm:hidden">
            <div class="flex items-center gap-1">
              <p class="font-marker text-[10px] tracking-wider truncate text-neon-cyan flex-1 min-w-0">{{ liveFightData.botA.name }}</p>
              <span class="font-mono font-bold text-[10px] w-5 text-right tabular-nums" :class="liveHpA > 50 ? 'text-neon-cyan' : liveHpA > 20 ? 'text-neon-yellow' : 'text-ko'">{{ liveHpA }}</span>
              <div class="w-6 h-2.5 bg-black/50 rounded-sm overflow-hidden border border-neon-cyan/30">
                <div class="h-full bg-neon-cyan transition-all duration-500" :style="{ width: `${liveHpA}%` }" />
              </div>
              <span class="font-funky text-neon-purple text-[10px] px-0.5 flex-shrink-0">VS</span>
              <div class="w-6 h-2.5 bg-black/50 rounded-sm overflow-hidden border border-neon-pink/30">
                <div class="h-full bg-neon-pink transition-all duration-500 ml-auto" :style="{ width: `${liveHpB}%` }" />
              </div>
              <span class="font-mono font-bold text-[10px] w-5 text-left tabular-nums" :class="liveHpB > 50 ? 'text-neon-pink' : liveHpB > 20 ? 'text-neon-yellow' : 'text-ko'">{{ liveHpB }}</span>
              <p class="font-marker text-[10px] tracking-wider truncate text-right text-neon-pink flex-1 min-w-0">{{ liveFightData.botB?.name }}</p>
            </div>
          </div>
          <!-- Desktop: single-row layout -->
          <div class="hidden sm:block">
            <div class="flex items-center gap-2">
              <p class="font-marker text-sm tracking-wider truncate text-neon-cyan flex-shrink-0 max-w-[20%]">{{ liveFightData.botA.name }}</p>
              <div class="flex-1 h-5 bg-black/50 rounded-sm overflow-hidden border border-neon-cyan/30">
                <div class="h-full bg-gradient-to-r from-neon-cyan to-neon-purple transition-all duration-500" :style="{ width: `${liveHpA}%` }" />
              </div>
              <span class="font-mono font-bold text-sm w-8 text-right tabular-nums" :class="liveHpA > 50 ? 'text-neon-cyan' : liveHpA > 20 ? 'text-neon-yellow' : 'text-ko'">{{ liveHpA }}</span>
              <span class="font-funky text-neon-purple text-xl px-1">VS</span>
              <span class="font-mono font-bold text-sm w-8 text-left tabular-nums" :class="liveHpB > 50 ? 'text-neon-pink' : liveHpB > 20 ? 'text-neon-yellow' : 'text-ko'">{{ liveHpB }}</span>
              <div class="flex-1 h-5 bg-black/50 rounded-sm overflow-hidden border border-neon-pink/30">
                <div class="h-full bg-gradient-to-l from-neon-pink to-neon-purple transition-all duration-500 ml-auto" :style="{ width: `${liveHpB}%` }" />
              </div>
              <p class="font-marker text-sm tracking-wider truncate text-right text-neon-pink flex-shrink-0 max-w-[20%]">{{ liveFightData.botB?.name }}</p>
            </div>
            <div class="flex items-center justify-between mt-0.5">
              <span class="font-pixel text-[9px]" :class="tierClass(liveFightData.botA.tier || 0)">{{ Math.round(liveFightData.botA.eloRating || 0) }}</span>
              <span class="font-pixel text-[9px] text-text-muted">
                {{ liveFightData.arenaInfo?.name }} | R{{ liveCurrentRound }}
                <span v-if="spectatorCount > 0" class="text-neon-cyan ml-1">| {{ spectatorCount }} watching</span>
              </span>
              <span class="font-pixel text-[9px]" :class="tierClass(liveFightData.botB?.tier || 0)">{{ Math.round(liveFightData.botB?.eloRating || 0) }}</span>
            </div>
          </div>
        </div>

        <!-- Canvas area -->
        <div class="flex-1 relative min-h-0">
          <canvas ref="liveCanvas" class="w-full h-full block" />

          <!-- Floating reaction emojis -->
          <div
            v-for="fe in liveFloatingEmojis"
            :key="fe.id"
            class="absolute pointer-events-none z-25 emoji-float"
            :style="{ left: `${fe.x}%`, bottom: '10%' }"
          >
            <span class="text-2xl sm:text-3xl">{{ fe.emoji }}</span>
          </div>

          <!-- Floating announcement -->
          <Transition name="announce">
            <div v-if="liveAnnouncementVisible"
                 class="absolute inset-0 flex items-center justify-center pointer-events-none z-20">
              <p class="font-funky text-2xl sm:text-5xl lg:text-7xl tracking-widest uppercase announce-text"
                 :style="{ color: liveAnnouncementColor, textShadow: `0 0 20px ${liveAnnouncementColor}, 0 0 40px ${liveAnnouncementColor}` }">
                {{ liveAnnouncement }}
              </p>
            </div>
          </Transition>

          <!-- Loading scene overlay -->
          <div v-if="!liveSceneReady && liveFightData" class="absolute inset-0 flex items-center justify-center bg-black/80 z-10">
            <div class="text-center">
              <div class="w-12 h-12 border-4 border-neon-pink/30 border-t-neon-pink rounded-full animate-spin mx-auto mb-3" />
              <p class="font-display text-neon-pink tracking-widest animate-pulse">LOADING ARENA...</p>
            </div>
          </div>

          <!-- No fight data yet -->
          <div v-if="!liveFightData" class="absolute inset-0 flex flex-col items-center justify-center bg-black z-10 gap-4">
            <div class="w-16 h-16 border-4 border-neon-pink/30 border-t-neon-pink rounded-full animate-spin" />
            <p class="font-display text-neon-pink text-xl tracking-widest animate-pulse glow-pink">FIGHT IN PROGRESS</p>
            <p class="font-mono text-text-muted text-xs">Connecting to live fight...</p>
          </div>
        </div>

      </div>
    </div>

    <div v-else-if="fightError" class="flex-1 flex flex-col items-center justify-center gap-3">
      <p class="font-display text-ko text-sm tracking-wider">{{ fightError }}</p>
      <button
        class="px-6 py-2 border border-neon-cyan/40 text-neon-cyan font-display font-bold text-xs tracking-wider
               hover:bg-neon-cyan/10 transition-all"
        @click="$router.push('/join')"
      >
        BACK TO LOBBY
      </button>
    </div>

    <div v-else-if="!fight" class="flex-1 flex items-center justify-center">
      <p class="font-display text-text-muted">Fight not found.</p>
    </div>

    <template v-else>
      <div class="flex-1 min-h-0 relative">
        <FightViewer :key="fightId" :fight="fight" :autoplay="true" class="h-full" @replay-done="onReplayDone" />

        <!-- Post-fight overlay -->
        <Transition name="fade-up">
          <div v-if="showOverlay"
               class="absolute inset-0 z-50 flex items-end justify-center pointer-events-none pb-16 sm:pb-20">
            <div class="pointer-events-auto flex flex-col items-center gap-2 sm:gap-3
                        bg-black/80 backdrop-blur-sm border border-white/10 rounded-xl
                        px-4 sm:px-8 py-4 sm:py-6 shadow-2xl max-w-md w-full mx-4">

              <template v-if="myBotId">
                <button
                  :disabled="isRequeueing"
                  class="w-full py-3 bg-neon-cyan/10 border-2 border-neon-cyan/50 text-neon-cyan
                         font-display font-black text-sm tracking-widest rounded-lg
                         hover:bg-neon-cyan/20 hover:border-neon-cyan transition-all neon-border-cyan
                         disabled:opacity-50 disabled:cursor-wait flex items-center justify-center gap-2"
                  @click="fightAgain(myBotId!)"
                >
                  <span v-if="isRequeueing" class="w-4 h-4 border-2 border-neon-cyan/30 border-t-neon-cyan rounded-full animate-spin" />
                  {{ isRequeueing ? 'MATCHING...' : 'FIGHT ANOTHER BOT' }}
                </button>
                <button
                  v-if="!isHumanFight"
                  :disabled="isRequeueing"
                  class="w-full py-3 bg-neon-yellow/10 border-2 border-neon-yellow/50 text-neon-yellow
                         font-display font-black text-sm tracking-widest rounded-lg
                         hover:bg-neon-yellow/20 hover:border-neon-yellow transition-all
                         disabled:opacity-50 disabled:cursor-wait"
                  @click="startAutoBattle"
                >
                  AUTO BATTLE
                  <span class="block font-mono text-[9px] tracking-wider text-neon-yellow/60 mt-0.5">
                    CONTINUOUS FIGHTS
                  </span>
                </button>
              </template>

              <template v-else-if="isLoggedIn && myBot">
                <button
                  :disabled="isRequeueing"
                  class="w-full py-3 bg-neon-cyan/10 border-2 border-neon-cyan/50 text-neon-cyan
                         font-display font-black text-sm tracking-widest rounded-lg
                         hover:bg-neon-cyan/20 hover:border-neon-cyan transition-all neon-border-cyan
                         disabled:opacity-50 disabled:cursor-wait flex items-center justify-center gap-2"
                  @click="matchmake(myBot!.id)"
                >
                  <span v-if="isRequeueing" class="w-4 h-4 border-2 border-neon-cyan/30 border-t-neon-cyan rounded-full animate-spin" />
                  {{ isRequeueing ? 'MATCHING...' : 'FIGHT WITH MY BOT' }}
                  <span v-if="!isRequeueing" class="block font-mono text-[9px] tracking-wider text-neon-cyan/60 mt-0.5">
                    {{ myBot!.name.toUpperCase() }}
                  </span>
                </button>
              </template>

              <button
                :disabled="isLoadingNext"
                class="w-full py-3 bg-neon-purple/10 border-2 border-neon-purple/50 text-neon-purple
                       font-display font-black text-sm tracking-widest rounded-lg
                       hover:bg-neon-purple/20 hover:border-neon-purple transition-all
                       disabled:opacity-50 disabled:cursor-wait flex items-center justify-center gap-2"
                @click="watchAnotherFight"
              >
                <span v-if="isLoadingNext" class="w-4 h-4 border-2 border-neon-purple/30 border-t-neon-purple rounded-full animate-spin" />
                {{ isLoadingNext ? 'LOADING...' : 'WATCH ANOTHER FIGHT' }}
              </button>
              <button
                class="w-full py-2 border border-white/10 text-text-muted
                       font-display text-xs tracking-widest rounded-lg
                       hover:bg-white/5 hover:text-text-primary transition-all"
                @click="$router.push('/join')"
              >
                BACK TO LOBBY
              </button>
            </div>
          </div>
        </Transition>

        <!-- Auto-battle indicator -->
        <div v-if="autoBattle && fight"
             class="absolute top-2 right-2 z-50 flex items-center gap-2
                    bg-black/80 border border-neon-yellow/30 rounded-lg px-3 py-1.5">
          <span class="w-2 h-2 rounded-full bg-neon-yellow animate-pulse" />
          <span class="font-pixel text-[10px] text-neon-yellow tracking-wider">
            AUTO #{{ autoBattleCount }}
          </span>
          <button
            class="font-pixel text-[10px] text-ko hover:text-text-primary transition-colors ml-1"
            @click="stopAutoBattle"
          >
            STOP
          </button>
        </div>
      </div>
    </template>
  </div>
</template>

<style scoped>
.fade-up-enter-active {
  transition: all 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.fade-up-leave-active {
  transition: all 0.2s ease-in;
}
.fade-up-enter-from {
  opacity: 0;
  transform: translateY(20px);
}
.fade-up-leave-to {
  opacity: 0;
  transform: translateY(10px);
}

.announce-enter-active { animation: announce-in 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); }
.announce-leave-active { animation: announce-out 0.25s ease-in; }
@keyframes announce-in { from { opacity: 0; transform: scale(0.1) rotate(-15deg); filter: blur(8px); } to { opacity: 1; transform: scale(1) rotate(0); filter: blur(0); } }
@keyframes announce-out { from { opacity: 1; } to { opacity: 0; transform: scale(1.5) rotate(5deg); filter: blur(4px); } }

.announce-text {
  animation: announce-pulse 0.4s ease-in-out infinite alternate;
  -webkit-text-stroke: 1px rgba(0,0,0,0.3);
}
@keyframes announce-pulse {
  from { transform: scale(1) rotate(-1deg); }
  to { transform: scale(1.08) rotate(1deg); }
}

/* Floating reaction emoji */
.emoji-float {
  animation: emoji-rise 2s ease-out forwards;
}
@keyframes emoji-rise {
  0% { opacity: 1; transform: translateY(0) scale(1); }
  50% { opacity: 0.8; transform: translateY(-60px) scale(1.2); }
  100% { opacity: 0; transform: translateY(-140px) scale(0.6); }
}

/* Safe area padding for notched phones */
.safe-bottom {
  padding-bottom: max(0.75rem, env(safe-area-inset-bottom));
}
</style>
