<template>
  <div class="idle-player">
    <!-- 调试切换按钮（showDebugSwitch 为 true 时显示） -->
    <!-- <button
      v-if="theme.showDebugSwitch !== false"
      class="debug-toggle"
      @click.stop="onToggleMode"
      title="开发调试：切换待机页显示模式"
    >
      {{ actualMode === 'welcome' ? '切换播放方案' : '切换欢迎页' }}
    </button> -->

    <!-- ================================================
         欢迎模式（默认兜底页）
         ================================================ -->
    <div
      v-if="actualMode === 'welcome'"
      class="mode-welcome"
      :class="`fit-${theme.backgroundFit || 'stretch'}`"
      :style="{ '--welcome-bg-url': welcomeBgUrl }"
      @click="onScreenClick"
    >
      <!-- 欢迎语柔光承托层 -->
      <div v-if="theme.backgroundOverlay !== false" class="welcome-glow"></div>

      <!-- 左上角品牌区 -->
      <div class="brand-area">
        <div class="brand-logo">
          <img
            v-if="theme.logoUrl"
            :src="theme.logoUrl"
            class="brand-logo-img"
            alt=""
          />
          <svg v-else viewBox="0 0 56 56" fill="none" xmlns="http://www.w3.org/2000/svg">
            <circle cx="28" cy="20" r="12" fill="currentColor"/>
            <rect x="14" y="34" width="28" height="18" rx="7" fill="currentColor"/>
            <circle cx="23" cy="18" r="3" fill="white"/>
            <circle cx="33" cy="18" r="3" fill="white"/>
            <rect x="9" y="38" width="6" height="10" rx="3" fill="currentColor" opacity="0.7"/>
            <rect x="41" y="38" width="6" height="10" rx="3" fill="currentColor" opacity="0.7"/>
          </svg>
        </div>
        <div class="brand-text">
          <span class="brand-name">{{ theme.robotName }}</span>
          <span class="brand-subtitle">{{ theme.brandSubtitle }}</span>
        </div>
      </div>

      <!-- 页面主体：居中大欢迎视觉 -->
      <div class="main-central">
        <h1 class="main-title">{{ theme.welcomeTitle }}</h1>
        <p class="main-subtitle">{{ theme.welcomeSubtitle }}</p>
      </div>

      <!-- 底部操作区 -->
      <div class="footer-bar">

        <!-- 左下角：状态 -->
        <div v-if="theme.showStatusBar !== false" class="footer-status">
          <span class="status-dot"></span>
          <span>待机中</span>
          <span class="sep">/</span>
          <span>电量 {{ batteryLevel }}%</span>
          <span class="sep">/</span>
          <span>{{ networkOk ? '网络正常' : '网络异常' }}</span>
        </div>

        <!-- 中间：触摸进入按钮 -->
        <div class="footer-cta" @click.stop>
          <svg class="cta-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
            <path d="M15 15l-2 5L9 9l11 4-5 2zm0 0l5 5"/>
          </svg>
          <span>{{ theme.touchText }}</span>
        </div>

        <!-- 右下角：时间日期 -->
        <div v-if="theme.showTime !== false" class="footer-time">
          <span class="time-str">{{ currentTime }}</span>
          <span class="date-str">{{ currentDate }}</span>
        </div>
      </div>
    </div>

    <!-- ================================================
         播放方案模式（广告 / 宣传 / 通知播放页）
         ================================================ -->
    <div
      v-else-if="actualMode === 'playlist'"
      class="mode-playlist"
      :class="playlistBgClass"
      @click="onScreenClick"
    >
      <!-- 素材层 -->
      <div v-if="currentMedia" class="playlist-media-wrap" :class="{ 'is-transitioning': isTransitioning }">
        <!-- 图片 -->
        <img
          v-if="currentMedia.type === 'image'"
          :src="currentMedia.url"
          :alt="currentMedia.title"
          class="media-img"
          :style="mediaFitStyle"
          @load="onMediaLoad"
          @error="onMediaError"
        />
        <!-- 视频 -->
        <video
          v-else-if="currentMedia.type === 'video'"
          ref="videoEl"
          :src="currentMedia.url"
          class="media-video"
          :style="mediaFitStyle"
          :muted="currentMedia.muted === true"
          autoplay
          playsinline
          preload="auto"
          @canplay="onMediaLoad"
          @error="onMediaError"
          @ended="onVideoEnded"
        />
      </div>

      <!-- 无素材时的兜底 -->
      <div v-else class="playlist-empty">
        <span>暂无播放内容</span>
      </div>

      <!-- 左上角轻量品牌浮层 -->
      <div class="playlist-brand">
        <span class="playlist-brand-name">{{ theme.robotName }}</span>
        <span class="playlist-brand-status">
          <span class="playlist-status-dot"></span>
          待机中
        </span>
      </div>

      <!-- 底部轻量信息浮层 -->
      <div class="playlist-bottom-bar">
        <!-- 左：素材标题（仅当 showTitle === true 时显示） -->
        <div
          class="playlist-media-title"
          v-if="currentMedia && currentMedia.showTitle === true && currentMedia.title"
        >
          <span>{{ currentMedia.title }}</span>
        </div>

        <!-- 中：轮播指示器 + 触摸提示（始终水平居中） -->
        <div class="playlist-center-group">
          <div class="playlist-indicators" v-if="mediaCount > 1">
            <span
              v-for="i in mediaCount"
              :key="i"
              class="indicator"
              :class="{ active: i - 1 === currentIndex }"
            />
          </div>
          <div class="playlist-touch-hint">
            <svg class="hint-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
              <path d="M15 15l-2 5L9 9l11 4-5 2zm0 0l5 5"/>
            </svg>
            <span>触摸屏幕进入服务</span>
          </div>
        </div>

        <!-- 右：当前时间（固定右下角） -->
        <div class="playlist-time">
          <span class="playlist-time-str">{{ currentTime }}</span>
          <span class="playlist-date-str">{{ currentDate }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { computed, ref, watch, onMounted, onUnmounted } from 'vue'
import { useScreenStore } from '@/stores/screen'
import { formatTimeShort, formatDateCN } from '@/utils/time'
import defaultWelcomeBg from '@/assets/images/default-welcome-bg.png'
import * as api from '@/api/screen'

const emit = defineEmits(['click'])

const screenStore = useScreenStore()

const currentIndex = ref(0)
const currentTime = ref(formatTimeShort())
const currentDate = ref(formatDateCN())

// 播放方案相关 ref
const videoEl = ref(null)
const isTransitioning = ref(false)
const isVideoPlaying = ref(false)

// 播报音频相关
const broadcastAudio = ref(null)
// 记录已播放的播报 key，避免同一 taskId+version 每 2 秒重复播放
const lastPlayedBroadcastKey = ref('')
// 播报开始时缓存一份 snapshot，结束时 ack 用（避免 markBroadcastFinishedLocally 清空后读取不到）
const lastBroadcastSnapshot = ref(null)
// 标记播报处理状态，避免 onerror 和 onended 重复触发
const isBroadcastProcessed = ref(false)

const actualMode = computed(() => screenStore.actualIdleMode)

const hasMedia = computed(() => {
  return screenStore.playPlan && Array.isArray(screenStore.playPlan.items) && screenStore.playPlan.items.length > 0
})

const mediaCount = computed(() => {
  return hasMedia.value ? screenStore.playPlan.items.length : 0
})

const currentMedia = computed(() => {
  if (!hasMedia.value) return null
  return screenStore.playPlan.items[currentIndex.value] || null
})

const batteryLevel = computed(() => screenStore.robotStatus.batteryLevel)
const networkOk = computed(() => screenStore.networkOk)
const workStatus = computed(() => screenStore.robotStatus.workStatus)

const workStatusText = computed(() => {
  const map = { idle: '待机中', working: '工作中', charging: '充电中', error: '异常' }
  return map[workStatus.value] || '待机中'
})

// 主题配置兜底默认值
const theme = computed(() => {
  const t = screenStore.screenTheme
  const defaults = {
    robotName: '迎宾巡逻机器人',
    brandSubtitle: '智能接待 · 路线引导 · 信息服务',
    logoUrl: '',
    welcomeTitle: '您好，欢迎光临',
    welcomeSubtitle: '我可以为您提供访客登记、路线引导、通知公告查询与现场帮助服务',
    primaryColor: '#2f8ee5',
    secondaryColor: '#20b7c7',
    backgroundType: 'image',
    backgroundImage: '',
    backgroundFit: 'stretch',
    backgroundOverlay: true,
    showDecorations: false,
    touchText: '触摸屏幕进入服务',
    showServicePanel: false,
    showStatusBar: true,
    showTime: true,
    showDebugSwitch: true,
    serviceItems: [
      { code: '01', title: '访客登记', desc: '预约到访 / 现场登记' },
      { code: '02', title: '路线引导', desc: '大厅、展厅、会议室等' },
      { code: '03', title: '通知公告', desc: '查看最新通知信息' },
      { code: '04', title: '呼叫工作人员', desc: '需要帮助时快速联系' }
    ]
  }

  if (!t) return defaults

  return {
    robotName: t.robotName || defaults.robotName,
    brandSubtitle: t.brandSubtitle || defaults.brandSubtitle,
    logoUrl: t.logoUrl || defaults.logoUrl,
    welcomeTitle: t.welcomeTitle || defaults.welcomeTitle,
    welcomeSubtitle: t.welcomeSubtitle || defaults.welcomeSubtitle,
    primaryColor: t.primaryColor || defaults.primaryColor,
    secondaryColor: t.secondaryColor || defaults.secondaryColor,
    backgroundType: t.backgroundType || defaults.backgroundType,
    backgroundImage: t.backgroundImage || defaults.backgroundImage,
    backgroundFit: t.backgroundFit || defaults.backgroundFit,
    backgroundOverlay: t.backgroundOverlay !== false,
    showDecorations: t.showDecorations !== false,
    touchText: t.touchText || defaults.touchText,
    showServicePanel: t.showServicePanel === true,
    showStatusBar: t.showStatusBar !== false,
    showTime: t.showTime !== false,
    showDebugSwitch: t.showDebugSwitch !== false,
    serviceItems: t.serviceItems || defaults.serviceItems
  }
})

// 背景图 URL
const welcomeBgUrl = computed(() => {
  const bg = theme.value.backgroundImage || defaultWelcomeBg
  return `url("${bg}")`
})

// 播放方案：当前素材适配方式
const currentFitMode = computed(() => {
  if (!currentMedia.value) return 'cover'
  return currentMedia.value.fitMode || screenStore.playPlan?.defaultFitMode || 'cover'
})

// 播放方案：背景 class（contain 模式用深色背景兜底）
const playlistBgClass = computed(() => {
  const mode = currentFitMode.value
  if (mode === 'contain') return 'playlist-bg-contain'
  if (mode === 'stretch') return 'playlist-bg-stretch'
  return 'playlist-bg-cover'
})

// 播放方案：素材适配样式
const mediaFitStyle = computed(() => {
  const mode = currentFitMode.value
  if (mode === 'contain') return { 'object-fit': 'contain' }
  if (mode === 'stretch') return { 'object-fit': 'fill' }
  return { 'object-fit': 'cover' }
})

const onToggleMode = () => {
  screenStore.toggleIdleMode()
}

const onScreenClick = () => {
  emit('click')
}

// 播放方案：切换下一条素材（带淡入淡出）
const goNextMedia = () => {
  isTransitioning.value = true

  const totalItems = screenStore.playPlan?.items?.length || 0

  // 只有方案有多个素材时才检查是否完成一轮
  // 单素材方案：每次切换都视为"完成一轮"
  if (totalItems <= 1) {
    // 单素材方案：标记当前方案已完成一轮
    screenStore.markCurrentPlanCycleComplete()
  } else {
    // 多素材方案：当索引即将回到 0 时标记完成一轮
    const nextIndex = (screenStore.currentMediaIndex + 1) % totalItems
    if (nextIndex === 0) {
      screenStore.markCurrentPlanCycleComplete()
    }
  }

  // 检查是否可以切换到新方案
  const canSwitchToPending =
    screenStore.pendingPlayPlan &&
    screenStore.currentPlanCycleComplete

  if (canSwitchToPending) {
    // 当前方案完成一轮，且有待切换方案，切换到新方案
    setTimeout(() => {
      screenStore.applyPendingPlayPlan()
      currentIndex.value = 0
      isVideoPlaying.value = false
      setTimeout(() => {
        isTransitioning.value = false
      }, 50)
    }, 200)
    return
  }

  // 无待切换方案，或当前方案未完成一轮，切换到下一个素材
  setTimeout(() => {
    screenStore.nextMedia()
    currentIndex.value = screenStore.currentMediaIndex
    isVideoPlaying.value = false
    setTimeout(() => {
      isTransitioning.value = false
    }, 50)
  }, 200)
}

// 播放方案：图片定时切换
let imageTimer = null
let imageTimerMediaUrl = null  // Track which media URL the timer is for

const startImageTimer = (force = false) => {
  const media = currentMedia.value
  if (!media || media.type !== 'image') return

  const duration = media.duration || 8000
  const mediaUrl = media.url

  // Skip if timer already running for this URL (unless forced)
  if (imageTimer && imageTimerMediaUrl === mediaUrl && !force) {
    return
  }

  clearImageTimer()
  imageTimer = setTimeout(() => {
    goNextMedia()
    startImageTimer()
  }, duration)
  imageTimerMediaUrl = mediaUrl
  console.log('[Broadcast] 图片轮播定时器恢复', media.duration)
}

const clearImageTimer = () => {
  if (imageTimer) {
    clearTimeout(imageTimer)
    imageTimer = null
    imageTimerMediaUrl = null
  }
}

// 播放方案：视频播放结束
const onVideoEnded = () => {
  goNextMedia()
  startImageTimer()
}

// 播放方案：素材加载成功
const onMediaLoad = () => {
  // 视频加载后同步全局音量/静音状态；播报中保持视频静音
  if (currentMedia.value?.type === 'video' && videoEl.value) {
    if (screenStore.isBroadcastAudioPlaying) {
      videoEl.value.muted = true
      videoEl.value.volume = 0
      try {
        videoEl.value.pause()
      } catch (err) {
        console.warn('[IdlePlayer] 播报中暂停视频失败:', err)
      }
      return
    }
    const volumeValue = Number(screenStore.volume ?? 80)
    const shouldMute = screenStore.muted || currentMedia.value.muted === true
    videoEl.value.muted = shouldMute
    videoEl.value.volume = shouldMute
      ? 0
      : Math.max(0, Math.min(1, volumeValue / 100))
  }
}

// 播放方案：素材加载失败，跳下一条
const onMediaError = () => {
  console.warn('[IdlePlayer] Media load error, skipping:', currentMedia.value?.url)
  goNextMedia()
  startImageTimer()
}

// 播放方案：监听 currentMedia 变化，重启图片定时器
watch(() => currentMedia.value, (newVal) => {
  if (!newVal) {
    clearImageTimer()
    return
  }
  if (newVal.type !== 'image') {
    clearImageTimer()
    return
  }
  // Only start timer if this is a different media URL
  if (newVal.url !== imageTimerMediaUrl) {
    startImageTimer()
  }
})

// 播放方案：监听 currentMediaIndex，重置状态
watch(() => screenStore.currentMediaIndex, (newIdx) => {
  currentIndex.value = newIdx
  isVideoPlaying.value = false
})

// 播放方案：监听待切换方案，在当前素材播放结束后切换
watch(() => screenStore.pendingPlayPlan, (pendingPlan) => {
  if (pendingPlan) {
    console.log('[IdlePlayer] 检测到待切换的播放方案，将在本素材播放结束后切换')
  }
})

// 播放方案：监听播放方案是否还有效（用于处理方案被禁用的情况）
watch(() => screenStore.hasPlayPlan, (hasPlan, oldHasPlan) => {
  if (oldHasPlan && !hasPlan) {
    // 播放方案被禁用或清空，回退到欢迎模式（hasPlayPlan 为 false 时自动回退）
    console.log('[IdlePlayer] 播放方案已无效，回退到欢迎模式')
  }
})

const updateClock = () => {
  currentTime.value = formatTimeShort()
  currentDate.value = formatDateCN()
}

let clockTimer = null

onMounted(() => {
  clockTimer = setInterval(updateClock, 1000)
  updateClock()
  if (actualMode.value === 'playlist') {
    startImageTimer()
  }
})

// 播放方案：mode 切换时管理定时器
watch(actualMode, (newMode) => {
  if (newMode === 'playlist') {
    currentIndex.value = screenStore.currentMediaIndex
    startImageTimer()
  } else {
    clearImageTimer()
  }
})

// =============================================
// 播报插播：播放音频 + 暂停/恢复素材
// =============================================

/**
 * 开始播放播报音频
 */
const playBroadcastAudio = (audioUrl) => {
  if (!audioUrl) return

  // 重置处理标志
  isBroadcastProcessed.value = false

  // 停止之前的音频
  stopBroadcastAudio()

  // 创建新的 Audio 实例
  broadcastAudio.value = new Audio()
  broadcastAudio.value.src = audioUrl
  const volumeValue = Number(screenStore.volume ?? 80)
  broadcastAudio.value.volume = screenStore.muted
    ? 0
    : Math.max(0, Math.min(1, volumeValue / 100))

  // 播放结束
  broadcastAudio.value.onended = () => {
    console.log('[IdlePlayer] 播报音频播放结束')
    onBroadcastEnded()
  }

  // 播放出错
  broadcastAudio.value.onerror = (e) => {
    console.warn('[IdlePlayer] 播报音频播放失败:', e)
    onBroadcastError()
  }

  // 开始播放
  broadcastAudio.value.play().catch(err => {
    console.warn('[IdlePlayer] 播报音频播放被阻止:', err)
    // 浏览器阻止自动播放时，恢复素材
    onBroadcastError()
  })
  console.log('[Broadcast] 播放播报音频:', screenStore.getBroadcastKey(screenStore.currentBroadcast), audioUrl)
}

/**
 * 停止播报音频
 */
const stopBroadcastAudio = () => {
  if (broadcastAudio.value) {
    broadcastAudio.value.onended = null
    broadcastAudio.value.onerror = null
    broadcastAudio.value.pause()
    broadcastAudio.value.src = ''
    broadcastAudio.value = null
  }
}

/**
 * 播报音频播放结束
 */
const onBroadcastEnded = () => {
  // 防止 onerror 和 onended 同时触发导致的重复处理
  if (isBroadcastProcessed.value) {
    console.log('[Broadcast] 播报已处理完毕，忽略重复的 onended')
    return
  }
  isBroadcastProcessed.value = true

  console.log('[Broadcast] onBroadcastEnded 触发，准备恢复素材', {
    actualMode: actualMode.value,
    mediaType: currentMedia.value?.type,
    mediaUrl: currentMedia.value?.url,
    videoExists: !!videoEl.value
  })
  screenStore.setBroadcastAudioPlaying(false)
  // 先恢复素材播放，再标记播报完成
  resumeMediaForBroadcast()
  // 再本地标记播报完成并隐藏播报条
  screenStore.markBroadcastFinishedLocally()
  // 最后异步 ack，不阻塞恢复播放
  api.ackBroadcast({
    taskId: lastBroadcastSnapshot.value?.taskId,
    contentId: lastBroadcastSnapshot.value?.contentId,
    resultStatus: 'success',
    resultMsg: '播放完成',
    playTime: new Date().toISOString()
  }).catch(() => {})
}

/**
 * 播报音频播放失败
 */
const onBroadcastError = () => {
  // 防止 onerror 和 onended 同时触发导致的重复处理
  if (isBroadcastProcessed.value) {
    console.log('[Broadcast] 播报已处理完毕，忽略重复的 onerror')
    return
  }
  isBroadcastProcessed.value = true

  console.warn('[Broadcast] onBroadcastError 触发，准备恢复素材', {
    actualMode: actualMode.value,
    mediaType: currentMedia.value?.type,
    mediaUrl: currentMedia.value?.url,
    videoExists: !!videoEl.value
  })
  screenStore.setBroadcastAudioPlaying(false)
  // 播报失败也要先恢复素材
  resumeMediaForBroadcast()
  screenStore.markBroadcastFinishedLocally()
  api.ackBroadcast({
    taskId: lastBroadcastSnapshot.value?.taskId,
    contentId: lastBroadcastSnapshot.value?.contentId,
    resultStatus: 'failed',
    resultMsg: '播放失败',
    playTime: new Date().toISOString()
  }).catch(() => {})
}

/**
 * 播报开始时，暂停当前素材
 */
const pauseMediaForBroadcast = () => {
  // 暂停图片轮播
  clearImageTimer()
  // 暂停视频，并强制静音，避免视频声音与播报 MP3 同时输出
  if (videoEl.value) {
    try {
      videoEl.value.pause()
    } catch (err) {
      console.warn('[IdlePlayer] 暂停视频失败:', err)
    }
    videoEl.value.muted = true
    videoEl.value.volume = 0
  }
}

/**
 * 播报结束后，恢复素材播放
 */
const resumeMediaForBroadcast = () => {
  console.log('[Broadcast] resumeMediaForBroadcast 执行', {
    actualMode: actualMode.value,
    mediaType: currentMedia.value?.type,
    mediaUrl: currentMedia.value?.url,
    videoPaused: videoEl.value?.paused,
    videoMuted: videoEl.value?.muted,
    videoVolume: videoEl.value?.volume
  })
  // 只有在播放方案模式下才恢复
  if (actualMode.value !== 'playlist') return
  const media = currentMedia.value
  if (!media) return
  if (media.type === 'image') {
    clearImageTimer()
    startImageTimer()
    console.log('[Broadcast] 图片轮播已恢复')
    return
  }
  if (media.type === 'video' && videoEl.value) {
    const volumeValue = Number(screenStore.volume ?? 80)
    const shouldMute = screenStore.muted || media.muted === true
    videoEl.value.muted = shouldMute
    videoEl.value.volume = shouldMute
      ? 0
      : Math.max(0, Math.min(1, volumeValue / 100))
    // 确保视频元素加载状态可播放
    const tryPlay = () => {
      videoEl.value.play()
        .then(() => {
          console.log('[Broadcast] 视频已恢复播放')
        })
        .catch(err => {
          console.warn('[Broadcast] 视频恢复播放失败，尝试重新 load 后播放:', err)
          try {
            videoEl.value.load()
            setTimeout(() => {
              videoEl.value.play().catch(e => {
                console.warn('[Broadcast] 视频二次恢复播放失败:', e)
              })
            }, 120)
          } catch (e) {
            console.warn('[Broadcast] 视频 load 恢复失败:', e)
          }
        })
    }
    tryPlay()
  }
}

/**
 * 监听播报状态变化
 */
// 当前播报的 key，用于监听 taskId/version/audioUrl 变化触发新播报
const activeBroadcastKey = computed(() => {
  if (!screenStore.isBroadcasting) return ''
  return screenStore.getBroadcastKey(screenStore.currentBroadcast)
})

watch(activeBroadcastKey, (key, oldKey) => {
  if (!key) {
    // 素材恢复统一由 onBroadcastEnded / onBroadcastError 负责
    return
  }
  const broadcast = screenStore.currentBroadcast
  if (!broadcast || !broadcast.audioUrl) return
  // 避免重复播放同一播报
  if (key === lastPlayedBroadcastKey.value) {
    return
  }
  lastPlayedBroadcastKey.value = key
  lastBroadcastSnapshot.value = { ...broadcast }
  pauseMediaForBroadcast()
  screenStore.setBroadcastAudioPlaying(true)
  playBroadcastAudio(broadcast.audioUrl)
})

onUnmounted(() => {
  if (clockTimer) clearInterval(clockTimer)
  clearImageTimer()
  stopBroadcastAudio()
})
</script>

<style scoped>
.idle-player {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: #f0f6fc;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}

/* ============================================
   调试切换按钮（极弱化）
   ============================================ */
.debug-toggle {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 100;
  padding: 3px 9px;
  font-size: 11px;
  color: rgba(0, 0, 0, 0.2);
  background: rgba(0, 0, 0, 0.03);
  border: 1px dashed rgba(0, 0, 0, 0.08);
  border-radius: 10px;
  cursor: pointer;
  transition: background 0.2s, color 0.2s;
  font-family: inherit;
  letter-spacing: 0.2px;
  white-space: nowrap;
}

.debug-toggle:hover {
  background: rgba(0, 0, 0, 0.06);
  color: rgba(0, 0, 0, 0.35);
}

/* ============================================
   欢迎模式
   ============================================ */
.mode-welcome {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  position: relative;
  background-image:
    linear-gradient(rgba(246, 251, 255, 0.10), rgba(246, 251, 255, 0.10)),
    var(--welcome-bg-url);
  background-position: center;
  background-repeat: no-repeat;
  background-color: #e2edf8;
}

.fit-stretch { background-size: 100% 100%; }
.fit-cover   { background-size: cover; }
.fit-contain { background-size: contain; background-color: #1a2a3a; }

.mode-welcome::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0.04) 0%,
    transparent 18%,
    transparent 65%,
    rgba(255, 255, 255, 0.35) 100%
  );
  pointer-events: none;
  z-index: 1;
}

.welcome-glow {
  position: absolute;
  top: 40%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 860px;
  height: 440px;
  background: radial-gradient(
    ellipse at center,
    rgba(255, 255, 255, 0.50) 0%,
    rgba(255, 255, 255, 0.22) 35%,
    rgba(255, 255, 255, 0.05) 55%,
    transparent 72%
  );
  pointer-events: none;
  z-index: 2;
  filter: blur(2px);
}

.brand-area {
  position: relative;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 38px 60px 0;
  flex-shrink: 0;
  animation: fadeInDown 0.5s ease-out;
}

.brand-logo {
  width: 62px;
  height: 62px;
  color: var(--primary);
  flex-shrink: 0;
  filter: drop-shadow(0 3px 10px rgba(47, 142, 229, 0.28));
  position: relative;
}

.brand-logo-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.brand-logo svg { width: 100%; height: 100%; }

.brand-text {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.brand-name {
  font-size: 32px;
  font-weight: 800;
  color: var(--text-primary);
  letter-spacing: 3px;
}

.brand-subtitle {
  font-size: 19px;
  color: var(--text-muted);
  letter-spacing: 1px;
}

.main-central {
  position: relative;
  z-index: 10;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding: 0 60px;
  gap: 36px;
  animation: fadeInUp 0.7s ease-out 0.1s backwards;
}

.main-title {
  font-size: 104px;
  font-weight: 900;
  color: var(--text-primary);
  margin: 0;
  line-height: 1.02;
  letter-spacing: 7px;
  text-align: center;
  text-shadow:
    0 4px 30px rgba(47, 142, 229, 0.14),
    0 8px 60px rgba(47, 142, 229, 0.08);
}

.main-subtitle {
  font-size: 36px;
  color: var(--text-secondary);
  margin: 0;
  line-height: 1.55;
  max-width: 860px;
  text-align: center;
  font-weight: 400;
  letter-spacing: 0.8px;
}

.footer-bar {
  position: relative;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 60px 40px;
  flex-shrink: 0;
  height: 124px;
  animation: fadeInUp 0.6s ease-out 0.25s backwards;
}

.footer-status {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: 1;
}

.status-dot {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: #10b981;
  flex-shrink: 0;
  box-shadow: 0 0 10px rgba(16, 185, 129, 0.6);
  animation: pulse-dot 2.5s ease-in-out infinite;
}

@keyframes pulse-dot {
  0%, 100% { opacity: 1; box-shadow: 0 0 10px rgba(16, 185, 129, 0.6); }
  50% { opacity: 0.7; box-shadow: 0 0 18px rgba(16, 185, 129, 0.85); }
}

.footer-status .sep { color: var(--text-light); margin: 0 6px; }
.footer-status span { font-size: 22px; font-weight: 600; color: var(--text-secondary); }

.footer-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 0 56px;
  height: 92px;
  min-width: 460px;
  background: linear-gradient(135deg, #3b96f0 0%, #2170d0 50%, #1a5db8 100%);
  color: #fff;
  border-radius: 46px;
  box-shadow:
    0 10px 40px rgba(47, 142, 229, 0.45),
    0 4px 16px rgba(26, 93, 184, 0.3),
    0 0 0 1px rgba(255, 255, 255, 0.12) inset;
  cursor: pointer;
  flex-shrink: 0;
  transition: transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.28s ease;
  animation: breathe 4.5s ease-in-out infinite;
  user-select: none;
}

.footer-cta:hover {
  transform: scale(1.05);
  box-shadow:
    0 14px 56px rgba(47, 142, 229, 0.55),
    0 6px 20px rgba(26, 93, 184, 0.35),
    0 0 0 1px rgba(255, 255, 255, 0.18) inset;
}

.footer-cta:active {
  transform: scale(0.97);
  box-shadow:
    0 6px 24px rgba(47, 142, 229, 0.35),
    0 2px 10px rgba(26, 93, 184, 0.25),
    0 0 0 1px rgba(255, 255, 255, 0.08) inset;
}

.cta-icon { width: 30px; height: 30px; flex-shrink: 0; }
.footer-cta span { font-size: 30px; font-weight: 800; white-space: nowrap; letter-spacing: 3px; }

.footer-time {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 7px;
  flex: 1;
}

.time-str {
  font-size: 76px;
  font-weight: 800;
  color: var(--text-primary);
  letter-spacing: 4px;
  line-height: 1;
}

.date-str { font-size: 24px; color: var(--text-muted); letter-spacing: 1.5px; }

/* ============================================
   播放方案模式（广告屏风格）
   ============================================ */
.mode-playlist {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  position: relative;
  background: #0e1a28;
}

.playlist-bg-cover { background: #0e1a28; }
.playlist-bg-contain { background: #111820; }
.playlist-bg-stretch { background: #0e1a28; }

/* 素材层 */
.playlist-media-wrap {
  position: absolute;
  inset: 0;
  transition: opacity 0.2s ease;
}

.playlist-media-wrap.is-transitioning {
  opacity: 0;
}

 .media-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.media-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* 无素材兜底 */
.playlist-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, 0.3);
  font-size: 20px;
  letter-spacing: 2px;
}

/* 左上角品牌浮层 */
.playlist-brand {
  position: absolute;
  top: 26px;
  left: 26px;
  z-index: 10;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px 20px;
  background: rgba(0, 0, 0, 0.34);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 16px;
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

.playlist-brand-name {
  font-size: 25px;
  font-weight: 800;
  color: rgba(255, 255, 255, 0.95);
  letter-spacing: 2px;
  white-space: nowrap;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.5);
}

.playlist-brand-status {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 16px;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.72);
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.42);
}

.playlist-status-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #10b981;
  flex-shrink: 0;
  animation: pulse-dot 2.5s ease-in-out infinite;
}

/* 底部浮层（绝对定位，不参与 flex 挤压） */
.playlist-bottom-bar {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 10;
  height: 132px;
  pointer-events: none;
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.76) 0%,
    rgba(0, 0, 0, 0.48) 48%,
    rgba(0, 0, 0, 0) 100%
  );
}

/* 左：素材标题（绝对定位左下角） */
.playlist-media-title {
  position: absolute;
  left: 30px;
  bottom: 28px;
  overflow: hidden;
  pointer-events: none;
}

.playlist-media-title span {
  font-size: 20px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.90);
  letter-spacing: 1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: block;
  max-width: 260px;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
}

/* 中：轮播指示器 + 触摸提示（绝对定位，始终水平居中） */
.playlist-center-group {
  position: absolute;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  pointer-events: none;
}

.playlist-indicators {
  display: flex;
  align-items: center;
  gap: 5px;
}

.indicator {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.38);
  transition: all 0.3s ease;
  flex-shrink: 0;
}

.indicator.active {
  width: 24px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.92);
}

/* 触摸提示（可触摸，pointer-events 恢复） */
.playlist-touch-hint {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  height: 80px;
  min-width: 420px;
  padding: 0 46px;
  background: rgba(0, 0, 0, 0.42);
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 40px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 14px 42px rgba(0, 0, 0, 0.38);
  cursor: pointer;
  pointer-events: auto;
}

.hint-icon {
  width: 30px;
  height: 30px;
  color: rgba(255, 255, 255, 0.92);
  flex-shrink: 0;
}

.playlist-touch-hint span {
  font-size: 29px;
  font-weight: 800;
  color: rgba(255, 255, 255, 0.92);
  white-space: nowrap;
  letter-spacing: 2px;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.48);
}

/* 右：当前时间（绝对定位右下角） */
.playlist-time {
  position: absolute;
  right: 34px;
  bottom: 30px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
}

.playlist-time-str {
  font-size: 64px;
  font-weight: 800;
  color: #ffffff;
  letter-spacing: 3px;
  line-height: 1;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.50);
}

.playlist-date-str {
  font-size: 24px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.9);
  letter-spacing: 1px;
  line-height: 1;
  text-shadow: 0 2px 8px rgba(0, 0, 0, 0.46);
}

/* ============================================
   动画
   ============================================ */
@keyframes fadeInDown {
  from { opacity: 0; transform: translateY(-16px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(22px); }
  to { opacity: 1; transform: translateY(0); }
}

@keyframes breathe {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.025); }
}

/* ============================================
   响应式适配（8寸 1024x768 横屏）
   ============================================ */
@media (max-width: 980px), (max-height: 720px) {
  .brand-area { padding: 34px 52px 0; }
  .brand-logo { width: 58px; height: 58px; }
  .brand-name { font-size: 30px; }
  .brand-subtitle { font-size: 18px; }
  .main-title { font-size: 98px; }
  .main-subtitle { font-size: 34px; max-width: 820px; }
  .footer-bar { padding: 0 52px 34px; height: 118px; }
  .footer-cta { min-width: 460px; height: 88px; }
  .footer-cta span { font-size: 29px; }
  .time-str { font-size: 72px; }
  .date-str { font-size: 23px; }

  .playlist-brand { top: 24px; left: 24px; padding: 12px 18px; }
  .playlist-brand-name { font-size: 24px; }
  .playlist-brand-status { font-size: 15px; }
  .playlist-status-dot { width: 9px; height: 9px; }

  .playlist-bottom-bar { height: 126px; }
  .playlist-media-title { left: 28px; bottom: 26px; }
  .playlist-media-title span { font-size: 18px; max-width: 240px; }

  .playlist-center-group { bottom: 22px; gap: 10px; }
  .indicator { width: 7px; height: 7px; }
  .indicator.active { width: 22px; }

  .playlist-touch-hint { height: 76px; min-width: 400px; padding: 0 40px; border-radius: 38px; }
  .playlist-touch-hint span { font-size: 27px; }
  .hint-icon { width: 28px; height: 28px; }

  .playlist-time { right: 30px; bottom: 28px; }
  .playlist-time-str { font-size: 60px; }
  .playlist-date-str { font-size: 21px; }
}
</style>
