<template>
  <view class="page">
    <view class="topbar">
      <view class="topbar-inner">
        <view class="back-btn" @click="confirmExit"><text class="back-arrow">‹</text></view>
        <view class="topbar-center">
          <view class="topbar-pos-row">
            <text class="topbar-position">{{ position || 'AI面试' }}</text>
            <text class="topbar-status">面试中</text>
          </view>
          <view class="progress-track" v-if="interviewId">
            <view class="progress-fill" :style="{ width: progressPercent + '%' }"></view>
          </view>
          <text class="topbar-timer">⏱ {{ formatTime }}</text>
        </view>
        <view class="topbar-right">
          <text class="avatar-toggle" @click="avatarMode = !avatarMode">
            {{ avatarMode ? '💬' : '👤' }}
          </text>
        </view>
      </view>
    </view>

    <!-- Avatar mode -->
    <view class="avatar-section" v-if="avatarMode">
      <digital-human
        ref="dhRef"
        :text="aiSpeechText"
        :audio-url="aiAudioUrl"
        :amplitude-data="aiAmplitudeData"
        :position="position"
        :auto-play="true"
        @speaking-start="onAvatarSpeaking"
        @speaking-end="onAvatarSilent"
      />
    </view>

    <!-- Chat area (both modes) -->
    <scroll-view class="chat-area" scroll-y :scroll-into-view="scrollToId" :scroll-with-animation="true" :class="{ 'chat-compact': avatarMode }">
      <view v-for="(msg, idx) in messages" :key="idx" :id="'msg-' + idx" class="msg-row" :class="msg.role">
        <view v-if="msg.role === 'ai'" class="msg-avatar ai-avatar">🤖</view>
        <view class="msg-body">
          <view class="msg-label">{{ msg.role === 'ai' ? '面试官' : '我' }}</view>
          <view class="msg-bubble" :class="msg.role">
            <text>{{ msg.content }}</text>
          </view>
        </view>
        <view v-if="msg.role === 'user'" class="msg-avatar user-avatar">👤</view>
      </view>

      <view class="msg-row ai" v-if="aiLoading">
        <view class="typing">
          <view class="typing-dot"></view>
          <view class="typing-dot"></view>
          <view class="typing-dot"></view>
        </view>
      </view>

      <view id="msg-bottom" style="height: 16rpx;"></view>
    </scroll-view>

    <view class="input-bar" v-if="!isComplete">
      <view class="mic-wrap">
        <view class="mic-btn" :class="{ recording: isRecording }" @click="toggleRecord">
          <text class="mic-icon">{{ isRecording ? '🔴' : '🎤' }}</text>
          <text class="mic-label" v-if="isRecording">{{ recordingDuration }}s</text>
        </view>
        <text class="mic-hint" v-if="isRecording">点击结束</text>
      </view>
      <view class="input-box">
        <textarea class="input-area" v-model="inputText" placeholder="点击🎤开始录音或输入回答..." :auto-height="true" :maxlength="2000" :disabled="aiLoading || isRecording" @confirm="sendAnswer" />
      </view>
      <view class="send-btn" :class="{ disabled: !inputText.trim() || isRecording || aiLoading }" @click="sendAnswer">
        <text class="send-icon">➤</text>
      </view>
    </view>

    <!-- 岗位选择弹窗 -->
    <view class="modal-overlay" v-if="showPositionPicker" @click="showPositionPicker = false">
      <view class="modal-content" @click.stop>
        <text class="modal-title">选择面试岗位</text>
        <view class="pos-list">
          <view class="pos-option" v-for="(pos, idx) in positions" :key="idx" @click="selectPosition(pos)">
            <text class="pos-name">{{ pos.name }}</text>
            <text class="pos-arrow">›</text>
          </view>
          <view class="pos-option" v-if="positions.length === 0 && !positionsLoading">
            <text class="pos-name disabled">暂无可用岗位</text>
          </view>
          <view class="pos-option" v-if="positionsLoading">
            <text class="pos-name disabled">加载中...</text>
          </view>
        </view>
        <text class="modal-close" @click="showPositionPicker = false">取消</text>
      </view>
    </view>

    <view class="disclaimer-bar" v-if="!isComplete">AI 生成内容仅供参考，请核实重要信息</view>

    <view class="complete-bar" v-else>
      <button class="cta-btn" @click="goResult">查看面试报告</button>
      <button class="buy-btn" v-if="completedReason === 'noCredits'" @click="goGravityBuy">引力值不足，立即补充 ›</button>
    </view>

    <!-- 引力值不足弹窗 -->
    <view class="modal-overlay" v-if="showGravityBuyModal" @click="showGravityBuyModal = false">
      <view class="modal-content" @click.stop>
        <text class="modal-title">引力值不足</text>
        <text class="modal-hint">您的引力值不足，请补充后继续面试（每次面试消耗 5 引力值）</text>
        <view class="purchase-options">
          <view class="purchase-option" @click="goGravityBuyAndClose">
            <text class="purchase-name">购买引力值</text>
            <text class="purchase-price">前往充值</text>
            <text class="purchase-desc">小程序内直接购买，微信支付安全便捷</text>
          </view>
        </view>
        <text class="modal-close" @click="showGravityBuyModal = false">取消</text>
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount, nextTick } from 'vue'
// #ifdef MP-WEIXIN
import { onLoad, onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app'
// #endif
// #ifndef MP-WEIXIN
import { onLoad } from '@dcloudio/uni-app'
// #endif
import { api, API_ENDPOINTS } from '../../config'
import { checkAuth } from '../../utils/auth'
import DigitalHuman from '../../components/digital-human.vue'
// #ifdef MP-WEIXIN
onShareAppMessage(() => ({ title: '职引 - AI模拟面试 | 数字人面试官实战练习', path: '/pages/interview/interview' }))
onShareTimeline(() => ({ title: '职引 - AI模拟面试 | 数字人面试官实战练习' }))
// #endif
const messages = ref([{ role: 'ai', content: '你好！我是 AI 面试官，请选择岗位开始模拟面试！' }])
const inputText = ref('')
const aiLoading = ref(false)
const interviewId = ref('')
const answeredCount = ref(0)
const isComplete = ref(false)
const completedReason = ref('')
const scrollToId = ref('')
const position = ref('')
const avatarMode = ref(true)
const showPositionPicker = ref(false)
const showGravityBuyModal = ref(false)
const positions = ref([])
const positionsLoading = ref(false)
const aiSpeechText = ref('')
const aiAudioUrl = ref('')
const aiAmplitudeData = ref([])
const isSpeaking = ref(false)
const dhRef = ref(null)
const isRecording = ref(false)
const recordingDuration = ref(0)
let manager = null
let recordTimer = null


function initRecorder() {
  // #ifdef MP-WEIXIN
  if (manager) return
  try {
    const plugin = requirePlugin('WechatSI')
    manager = plugin.getRecordRecognitionManager()
    manager.onStart = () => {
      console.log('[WechatSI] start')
      isRecording.value = true
      inputText.value = ''
      recordingDuration.value = 0
      recordTimer = setInterval(() => { recordingDuration.value++ }, 1000)
    }
    manager.onRecognize = (res) => {
      if (res?.result?.trim()) inputText.value = res.result.trim()
    }
    manager.onStop = (res) => {
      isRecording.value = false
      recordingDuration.value = 0
      if (recordTimer) { clearInterval(recordTimer); recordTimer = null }
      const text = res?.result?.trim()
      if (text && text.length >= 2) {
        inputText.value = text
        sendAnswer()
      } else if (text && text.length === 1) {
        uni.showToast({ title: '语音过短，请重试', icon: 'none' })
      } else if (!text) {
        uni.showToast({ title: '未检测到语音，请重试', icon: 'none' })
      }
    }
    manager.onError = (res) => {
      console.error('[WechatSI] error:', JSON.stringify(res))
      isRecording.value = false
      recordingDuration.value = 0
      if (recordTimer) { clearInterval(recordTimer); recordTimer = null }
      const msg = res?.errMsg?.includes('permission') ? '请允许录音权限' : '语音识别失败，请重试'
      uni.showToast({ title: msg, icon: 'none' })
      manager = null
    }
  } catch (e) {
    console.error('WechatSI plugin init failed:', e)
    manager = null
  }
  // #endif
}

let timerSeconds = 0
let timerInterval = null
let MAX_QUESTIONS = 10
const progressPercent = computed(() => Math.min((answeredCount.value / MAX_QUESTIONS) * 100, 100))
const formatTime = computed(() => {
  const m = Math.floor(timerSeconds / 60); const s = timerSeconds % 60
  return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`
})
const token = () => uni.getStorageSync('token') || ''

onLoad((options) => {
  if (options?.position) {
    const pos = decodeURIComponent(options.position)
    position.value = pos
    messages.value = [{ role: 'ai', content: `你好！我是你的专属 ${pos} 面试官。准备好后发送任意消息，我会立即开始面试并给出第一个问题。` }]
  }
})

/** 加载热门岗位列表 */
const loadPositions = async () => {
  positionsLoading.value = true
  try {
    const res = await uni.request({ url: api('/positions/hot'), method: 'GET' })
    if (res.statusCode >= 200 && res.statusCode < 300 && Array.isArray(res.data)) {
      positions.value = res.data
    } else if (res.data?.data && Array.isArray(res.data.data)) {
      positions.value = res.data.data
    }
  } catch (e) { console.error('加载岗位列表失败', e) }
  finally { positionsLoading.value = false }
}

/** 用户选择岗位后开始面试 */
const selectPosition = (pos) => {
  position.value = pos.name
  showPositionPicker.value = false
  messages.value = [{ role: 'ai', content: `你好！我是你的专属 ${pos.name} 面试官。准备好后发送任意消息，我会立即开始面试并给出第一个问题。` }]
}

onMounted(() => {
  initRecorder()
  timerInterval = setInterval(() => timerSeconds++, 1000)
  if (!position.value) {
    loadPositions()
    showPositionPicker.value = true
  }
})

onBeforeUnmount(() => {
  clearInterval(timerInterval)
})

const checkLogin = () => {
  if (!token()) {
    uni.showModal({
      title: '请先登录', content: '登录后即可开始 AI 模拟面试', confirmText: '去登录',
      success: (r) => { if (r.confirm) uni.navigateTo({ url: '/pages/login/login' }) },
    })
    return false
  }
  return true
}

const startInterview = async () => {
  if (!checkLogin()) return
  aiLoading.value = true
  try {
    const res = await uni.request({
      url: api('/interview/create'), method: 'POST',
      header: { 'Authorization': `Bearer ${token()}`, 'Content-Type': 'application/json' },
      data: { position: position.value },
    })
    if (res.statusCode >= 200 && res.statusCode < 300 && res.data) {
      interviewId.value = res.data.id
      answeredCount.value = res.data.questionCount || 0
      if (res.data.totalQuestions) MAX_QUESTIONS = res.data.totalQuestions
      // 将后端返回的 AI 消息追加入对话，不替换已有消息（保留用户已发的准备消息）
      if (res.data.messages?.length) {
        const aiMsgs = res.data.messages.filter(m => m.role === 'ai')
        if (aiMsgs.length > 0) messages.value.push(...aiMsgs)
      }
      // Speak first question in avatar mode
      if (avatarMode.value && res.data.messages?.length) {
        const last = res.data.messages[res.data.messages.length - 1]
        if (last?.role === 'ai') await speakAiText(last.content)
      }
    } else if (res.statusCode === 403) {
      const errMsg = res.data?.message || '面试次数已用完'
      messages.value.push({ role: 'ai', content: errMsg + ' 👉 购买后可继续面试' })
      isComplete.value = true
      completedReason.value = 'noCredits'
    } else if (checkAuth(res)) {
      return // token 过期，已清除并跳转登录
    } else {
      const errMsg = typeof res.data === 'string' ? res.data : (res.data?.message || '')
      const msg = errMsg || `创建面试失败（${res.statusCode}）`
      messages.value.push({ role: 'ai', content: msg })
    }
  } catch {
    messages.value.push({ role: 'ai', content: '创建面试失败，请重试' })
  } finally {
    aiLoading.value = false
    scrollToBottom()
  }
}

const sendAnswer = async () => {
  if (!inputText.value.trim() || aiLoading.value || isRecording.value || isComplete.value) return
  if (!token()) { checkLogin(); return }
  const answer = inputText.value.trim()

  // 首次发送：不把用户消息当答案提交，而是先创建面试获取第一个问题
  if (!interviewId.value) {
    messages.value.push({ role: 'user', content: answer })
    inputText.value = ''
    scrollToBottom()
    await startInterview()
    // startInterview 成功后已经把第一个问题追加到 messages 了
    return
  }

  messages.value.push({ role: 'user', content: answer })
  inputText.value = ''
  scrollToBottom()
  aiLoading.value = true

  try {
    const res = await uni.request({
      url: api(`/interview/${interviewId.value}/answer`), method: 'POST',
      header: { 'Authorization': `Bearer ${token()}`, 'Content-Type': 'application/json' },
      data: avatarMode.value ? { answer, avatar: true } : { answer },
    })
    if (res.statusCode >= 200 && res.statusCode < 300 && res.data?.messages) {
      const aiMsg = res.data.messages.find(m => m.role === 'ai')
      // Only push AI messages from response to avoid duplicating the user message already added above
      const newAiMessages = res.data.messages.filter(m => m.role === 'ai')
      if (newAiMessages.length > 0) messages.value.push(...newAiMessages)
      if (avatarMode.value && aiMsg) {
        await speakAiText(aiMsg.content, res.data.ttsHash, res.data.ttsAmplitude)
      }
      answeredCount.value = res.data.questionCount || answeredCount.value + 1
      if (res.data.totalQuestions) MAX_QUESTIONS = res.data.totalQuestions
    } else if (res.statusCode === 403) {
      const errMsg = res.data?.message || '面试次数已用完'
      messages.value.push({ role: 'ai', content: errMsg + ' 👉 购买后可继续面试' })
      isComplete.value = true
      completedReason.value = 'noCredits'
    } else if (checkAuth(res)) {
      return
    } else {
      messages.value.push({ role: 'ai', content: res.data?.message || '回答提交失败' })
    }
  } catch {
    messages.value.push({ role: 'ai', content: '回答提交失败，请重试' })
  } finally {
    aiLoading.value = false
    scrollToBottom()
  }
}

async function speakAiText(text, ttsHash, ttsAmplitude) {
  aiSpeechText.value = text
  aiAmplitudeData.value = ttsAmplitude || []
  if (ttsHash) {
    aiAudioUrl.value = api(API_ENDPOINTS.TTS.AUDIO(ttsHash))
  } else {
    try {
      const synthRes = await uni.request({
        url: api('/tts/synthesize'), method: 'POST',
        header: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token()}` },
        data: { text },
      })
      if (synthRes.statusCode === 200 && synthRes.data?.hash) {
        aiAudioUrl.value = api(API_ENDPOINTS.TTS.AUDIO(synthRes.data.hash))
        aiAmplitudeData.value = synthRes.data?.amplitudeData || []
      } else {
        checkAuth(synthRes)
      }
    } catch {}
  }
}

function onAvatarSpeaking() {
  isSpeaking.value = true
}

function onAvatarSilent() {
  isSpeaking.value = false
}

const goResult = () => uni.navigateTo({ url: `/pages/report/report?interviewId=${interviewId.value}` })

// 购买引力值
const goGravityBuy = () => {
  showGravityBuyModal.value = true
}
const goGravityBuyAndClose = () => {
  showGravityBuyModal.value = false
  uni.navigateTo({ url: '/pages/member/member' })
}
const scrollToBottom = () => {
  nextTick(() => { scrollToId.value = ''; setTimeout(() => { scrollToId.value = 'msg-bottom' }, 100) })
}

const confirmExit = () => {
  uni.showModal({
    title: '退出面试', content: interviewId.value ? '确定退出吗？当前进度将不会保存。' : '确定退出？',
    success: (r) => { if (r.confirm) uni.navigateBack() },
  })
}

function toggleRecord() {
  if (aiLoading.value || isComplete.value) return
  // #ifdef MP-WEIXIN
  if (!isRecording.value) {
    if (!manager) initRecorder()
    if (!manager) {
      uni.showToast({ title: '语音功能初始化失败', icon: 'none' })
      return
    }
    manager.start({ lang: 'zh_CN', duration: 60000 })
    uni.vibrateShort({ type: 'medium' })
    return
  }
  if (!manager) { isRecording.value = false; return }
  if (recordTimer) { clearInterval(recordTimer); recordTimer = null }
  recordingDuration.value = 0
  manager.stop()
  // #endif
  // #ifndef MP-WEIXIN
  uni.showToast({ title: '语音输入仅支持小程序', icon: 'none' })
  // #endif
}
</script>

<style scoped>
.page { height: 100vh; display: flex; flex-direction: column; background: #F8F9FC; }

.topbar {
  background: linear-gradient(135deg, var(--color-gradient-start), var(--color-gradient-mid));
  padding-top: 20rpx; flex-shrink: 0;
}
.topbar-inner {
  display: flex; align-items: center; padding: 16rpx 24rpx 20rpx; gap: 16rpx;
}
.back-btn {
  width: 60rpx; height: 60rpx; background: rgba(255,255,255,0.15);
  border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.back-arrow { font-size: 36rpx; color: #FFFFFF; font-weight: 300; line-height: 1; }
.topbar-center { flex: 1; display: flex; flex-direction: column; gap: 8rpx; }
.topbar-pos-row { display: flex; align-items: center; gap: 10rpx; }
.topbar-position { font-size: 26rpx; color: #FFFFFF; font-weight: 600; }
.topbar-status { font-size: 18rpx; color: #FFFFFF; background: rgba(255,255,255,0.2); padding: 2rpx 12rpx; border-radius: 20rpx; }
.progress-track { height: 6rpx; background: rgba(255,255,255,0.2); border-radius: 3rpx; overflow: hidden; }
.progress-fill { height: 100%; background: #FFFFFF; border-radius: 3rpx; transition: width 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94); }
.topbar-timer { font-size: 20rpx; color: rgba(255,255,255,0.7); font-variant-numeric: tabular-nums; }
.topbar-right { width: 60rpx; flex-shrink: 0; text-align: center; }
.avatar-toggle { font-size: 36rpx; cursor: pointer; }

/* Avatar section */
.avatar-section {
  background: linear-gradient(180deg, #EEF2FF 0%, #F8F9FC 100%);
  flex-shrink: 0;
}

/* Chat */
.chat-area { flex: 1; padding: 24rpx 20rpx; overflow-y: auto; }
.chat-compact { max-height: 40vh; }
.msg-row { display: flex; margin-bottom: 32rpx; align-items: flex-start; gap: 12rpx; }
.msg-row.ai { justify-content: flex-start; }
.msg-row.user { justify-content: flex-end; }

.msg-avatar { width: 48rpx; height: 48rpx; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 24rpx; flex-shrink: 0; }
.ai-avatar { background: #EEF2FF; }
.user-avatar { background: #FEF3C7; }

.msg-body { max-width: 70%; display: flex; flex-direction: column; gap: 6rpx; }
.msg-row.user .msg-body { align-items: flex-end; }

.msg-label { font-size: 20rpx; color: #9CA3AF; padding: 0 8rpx; }

.msg-bubble { padding: 20rpx 24rpx; line-height: 1.7; font-size: 26rpx; word-break: break-word; }
.msg-bubble.ai {
  background: #FFFFFF; color: var(--color-text);
  border-radius: 0 var(--radius-lg) var(--radius-lg) var(--radius-lg);
  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04);
}
.msg-bubble.user {
  background: linear-gradient(135deg, var(--color-gradient-start), var(--color-gradient-mid));
  color: #FFFFFF;
  border-radius: var(--radius-lg) 0 var(--radius-lg) var(--radius-lg);
}

/* Typing */
.typing {
  background: #FFFFFF; padding: 20rpx 28rpx;
  border-radius: 0 var(--radius-lg) var(--radius-lg) var(--radius-lg);
  display: flex; gap: 8rpx; align-items: center;
  box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04);
}
.typing-dot { width: 12rpx; height: 12rpx; border-radius: 50%; background: #D1D5DB; animation: blink 1.4s infinite; }
.typing-dot:nth-child(2) { animation-delay: 0.2s; }
.typing-dot:nth-child(3) { animation-delay: 0.4s; }
@keyframes blink { 0%,80%,100% { opacity: 0.3 } 40% { opacity: 1 } }

/* Input */
.input-bar {
  background: #FFFFFF; padding: 16rpx 20rpx;
  padding-bottom: calc(16rpx + var(--safe-bottom));
  display: flex; align-items: flex-end; gap: 12rpx;
  box-shadow: 0 -4rpx 20rpx rgba(0,0,0,0.04); flex-shrink: 0;
}
.input-box { flex: 1; background: var(--color-bg); border-radius: var(--radius-md); padding: 12rpx 20rpx; }
.input-area { width: 100%; font-size: 26rpx; color: var(--color-text); max-height: 160rpx; line-height: 1.5; }
.mic-wrap { display: flex; flex-direction: column; align-items: center; gap: 4rpx; flex-shrink: 0; }
.mic-btn {
  width: 80rpx; height: 80rpx; border-radius: 50%; background: #F3F4F6;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  transition: all 0.2s; gap: 2rpx;
}
.mic-btn:active { transform: scale(0.9); }
.mic-btn.recording { background: #FEE2E2; animation: mic-pulse 1s infinite; }
.mic-icon { font-size: 28rpx; line-height: 1; }
.mic-label { font-size: 16rpx; color: #9CA3AF; line-height: 1; }
.mic-btn.recording .mic-label { color: #EF4444; font-weight: 600; }
.mic-hint { font-size: 18rpx; color: #EF4444; font-weight: 500; line-height: 1; white-space: nowrap; }
@keyframes mic-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); }
  50% { box-shadow: 0 0 0 16rpx rgba(239, 68, 68, 0); }
}
.send-btn {
  width: 80rpx; height: 80rpx; background: linear-gradient(135deg, var(--color-gradient-start), var(--color-gradient-mid));
  border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  transition: all 0.2s ease;
}
.send-btn:active { transform: scale(0.9); }
.send-btn.disabled { background: var(--color-border); }
.send-icon { font-size: 32rpx; color: #FFFFFF; transform: translateY(2rpx); }

.complete-bar { background: #FFFFFF; padding: 20rpx 24rpx; padding-bottom: calc(20rpx + var(--safe-bottom)); display: flex; flex-direction: column; gap: 16rpx; }
.cta-btn { width: 100%; height: 88rpx; line-height: 88rpx; background: linear-gradient(135deg, var(--color-gradient-start), var(--color-gradient-mid)); color: #FFFFFF; border-radius: var(--radius-md); font-size: 28rpx; font-weight: 600; border: none; }
.buy-btn { width: 100%; height: 72rpx; line-height: 72rpx; background: #FEF3C7; color: #92400E; border-radius: var(--radius-md); font-size: 26rpx; font-weight: 600; border: 2rpx solid #F59E0B; }
.disclaimer-bar { text-align: center; font-size: 20rpx; color: var(--color-text-tertiary); padding: 8rpx 24rpx; background: #FFFFFF; border-top: 1rpx solid var(--color-border); }

/* 岗位选择弹窗 */
.modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.45); z-index: 999; display: flex; align-items: center; justify-content: center; }
.modal-content { background: #FFF; border-radius: 20rpx; width: 600rpx; max-height: 70vh; display: flex; flex-direction: column; align-items: center; padding: 40rpx 32rpx 32rpx; }
.modal-title { font-size: 30rpx; font-weight: 800; color: var(--color-text); margin-bottom: 24rpx; }
.pos-list { width: 100%; max-height: 440rpx; overflow-y: auto; }
.pos-option { display: flex; align-items: center; justify-content: space-between; padding: 24rpx 16rpx; border-bottom: 1rpx solid #F3F4F6; }
.pos-option:active { background: #F9FAFB; border-radius: 12rpx; }
.pos-name { font-size: 28rpx; color: var(--color-text); }
.pos-name.disabled { color: #9CA3AF; }
.pos-arrow { font-size: 32rpx; color: #9CA3AF; }
.modal-close { margin-top: 24rpx; font-size: 26rpx; color: #9CA3AF; padding: 12rpx 32rpx; }

/* 购买弹窗 */
.modal-hint { font-size: 24rpx; color: #6B7280; text-align: center; margin-bottom: 28rpx; padding: 0 16rpx; }
.purchase-options { width: 100%; display: flex; flex-direction: column; gap: 16rpx; }
.purchase-option { background: #F9FAFB; border-radius: var(--radius-md); padding: 24rpx; border: 2rpx solid #E5E7EB; }
.purchase-option.recommended { background: #FFFBEB; border-color: #F59E0B; }
.purchase-option:active { transform: scale(0.97); }
.purchase-badge { font-size: 18rpx; color: #FFF; background: #F59E0B; padding: 2rpx 12rpx; border-radius: 6rpx; align-self: flex-start; margin-bottom: 8rpx; }
.purchase-name { font-size: 28rpx; font-weight: 700; color: var(--color-text); display: block; }
.purchase-price { font-size: 36rpx; font-weight: 800; color: var(--color-primary); margin-top: 8rpx; }
.purchase-unit { font-size: 22rpx; font-weight: 400; color: #9CA3AF; }
.purchase-desc { font-size: 22rpx; color: #6B7280; margin-top: 6rpx; }
</style>
