<template>
  <v-container class="event-markets-container">
    <v-card v-if="detailLoading && !eventDetail" class="loading-card" elevation="0" rounded="lg">
      <div class="loading-placeholder">
        <v-progress-circular indeterminate color="primary" size="48" />
        <p>{{ t('common.loading') }}</p>
      </div>
    </v-card>

    <template v-else-if="detailError">
      <v-card class="error-card" elevation="0" rounded="lg">
        <p class="error-text">{{ detailError }}</p>
      </v-card>
    </template>

    <template v-else-if="eventDetail">
      <v-row align="stretch" class="event-markets-row">
        <!-- 左侧：分时图 + 市场列表 -->
        <v-col cols="12" class="chart-col">
          <!-- 分时图卡片（多市场多条线） -->
          <v-card
            v-if="markets.length > 0"
            class="chart-card polymarket-chart"
            elevation="0"
            rounded="lg"
          >
            <div class="chart-header">
              <h1 class="chart-title">{{ eventDetail?.title || t('eventMarkets.allMarkets') }}</h1>
              <p v-if="eventDetail.series?.length || eventDetail.tags?.length" class="chart-meta">
                {{ categoryText }}
              </p>
              <div class="chart-controls-row">
                <v-btn variant="text" size="small" class="past-btn">{{ t('eventMarkets.past') }}</v-btn>
                <v-btn class="date-pill" size="small" rounded="pill">{{ resolutionDate }}</v-btn>
              </div>
              <p class="chart-legend-hint">{{ t('eventMarkets.marketsCount', { n: markets.length }) }}</p>
            </div>
            <div class="chart-wrapper">
              <div v-if="chartLoading" class="chart-loading-overlay">
                <v-progress-circular indeterminate color="primary" size="32" />
              </div>
              <div ref="chartContainerRef" class="chart-container"></div>
            </div>
            <div class="chart-footer">
              <div class="chart-footer-left">
                <span class="chart-volume">{{ eventVolume || t('eventMarkets.volumeZero') }}</span>
                <span v-if="marketExpiresAt" class="chart-expires">| {{ marketExpiresAt }}</span>
              </div>
              <div class="chart-time-ranges">
                <v-btn
                  v-for="r in timeRanges"
                  :key="r.value"
                  :class="['time-range-btn', { active: selectedTimeRange === r.value }]"
                  variant="text"
                  size="small"
                  @click="selectTimeRange(r.value)"
                >
                  {{ r.label }}
                </v-btn>
              </div>
            </div>
          </v-card>

          <!-- 规则说明（描述 + 裁决来源） -->
          <v-card
            v-if="eventDetail?.description || eventDetail?.resolutionSource"
            class="rules-card"
            elevation="0"
            rounded="lg"
          >
            <div class="rules-pane">
              <div v-if="eventDetail?.description" class="rules-section">
                <h3 class="rules-title">{{ t('activity.rulesDescription') }}</h3>
                <div class="rules-text">{{ eventDetail.description }}</div>
              </div>
              <div v-if="eventDetail?.resolutionSource" class="rules-section">
                <h3 class="rules-title">{{ t('activity.rulesSource') }}</h3>
                <a
                  v-if="isResolutionSourceUrl"
                  :href="eventDetail.resolutionSource"
                  target="_blank"
                  rel="noopener noreferrer"
                  class="rules-link"
                >
                  {{ eventDetail.resolutionSource }}
                  <v-icon size="14">mdi-open-in-new</v-icon>
                </a>
                <div v-else class="rules-text">{{ eventDetail.resolutionSource }}</div>
              </div>
            </div>
          </v-card>

          <!-- 市场列表 -->
          <v-card class="markets-list-card" elevation="0" rounded="lg">
            <div class="markets-list">
              <div
                v-for="(market, index) in markets"
                :key="market.ID ?? index"
                class="market-row"
                :class="{ selected: selectedMarketIndex === index }"
                @click="goToTradeDetail(market)"
              >
                <div class="market-row-main">
                  <span class="market-question">{{ market.question || t('eventMarkets.marketPlaceholder') }}</span>
                  <span class="market-chance">{{ marketChance(market) }}%</span>
                </div>
                <div class="market-row-vol">{{ formatVolume(market.volume) }}</div>
                <div class="market-row-actions" @click.stop>
                  <v-btn
                    class="buy-yes-btn"
                    variant="flat"
                    size="small"
                    rounded="sm"
                    @click="openTrade(market, index, 'yes')"
                  >
                    {{ yesLabel(market) }} {{ yesPrice(market) }}
                  </v-btn>
                  <v-btn
                    class="buy-no-btn"
                    variant="flat"
                    size="small"
                    rounded="sm"
                    @click="openTrade(market, index, 'no')"
                  >
                    {{ noLabel(market) }} {{ noPrice(market) }}
                  </v-btn>
                </div>
              </div>
            </div>
          </v-card>
        </v-col>

        <!-- 右侧：购买组件（桌面端显示；移动端用底部栏+弹窗） -->
        <v-col v-if="!isMobile" cols="12" class="trade-col">
          <div v-if="markets.length > 0" class="trade-sidebar">
            <TradeComponent
              :market="tradeMarketPayload"
              :initial-option="tradeInitialOption"
              @submit="onTradeSubmit"
            />
          </div>
        </v-col>
      </v-row>

      <!-- 移动端：单 market 时显示固定底部 Yes/No 栏 + 三点菜单（Merge/Split） -->
      <template v-if="isMobile && markets.length === 1">
        <div class="mobile-trade-bar-spacer" aria-hidden="true"></div>
        <div class="mobile-trade-bar">
          <v-btn
            class="mobile-bar-btn mobile-bar-yes"
            variant="flat"
            rounded="sm"
            @click="openSheetWithOption('yes')"
          >
            {{ barMarket ? yesLabel(barMarket) : t('eventMarkets.yes') }} {{ barMarket ? yesPrice(barMarket) : t('eventMarkets.priceZero') }}
          </v-btn>
          <v-btn
            class="mobile-bar-btn mobile-bar-no"
            variant="flat"
            rounded="sm"
            @click="openSheetWithOption('no')"
          >
            {{ barMarket ? noLabel(barMarket) : t('eventMarkets.no') }} {{ barMarket ? noPrice(barMarket) : t('eventMarkets.priceZero') }}
          </v-btn>
          <v-menu
            v-model="mobileMenuOpen"
            :close-on-content-click="true"
            location="top"
            transition="scale-transition"
          >
            <template #activator="{ props: menuProps }">
              <v-btn
                v-bind="menuProps"
                class="mobile-bar-more-btn"
                variant="flat"
                icon
                rounded="pill"
                :aria-label="t('eventMarkets.moreActions')"
              >
                <v-icon size="20">mdi-dots-horizontal</v-icon>
              </v-btn>
            </template>
            <v-list density="compact">
              <v-list-item @click="openMergeFromBar">
                <v-list-item-title>{{ t('trade.merge') }}</v-list-item-title>
              </v-list-item>
              <v-list-item @click="openSplitFromBar">
                <v-list-item-title>{{ t('trade.split') }}</v-list-item-title>
              </v-list-item>
            </v-list>
          </v-menu>
        </div>
      </template>
      <!-- 移动端交易弹窗：单 market 与多 market 均需（多 market 时通过列表 Buy Yes/No 打开） -->
      <template v-if="isMobile && markets.length > 0">
        <v-bottom-sheet v-model="tradeSheetOpen" content-class="event-markets-trade-sheet">
          <TradeComponent
            v-if="tradeSheetRenderContent"
            ref="tradeComponentRef"
            :key="`trade-${selectedMarketIndex}-${tradeInitialOption}`"
            :market="tradeMarketPayload"
            :initial-option="tradeInitialOption"
            embedded-in-sheet
            @submit="onTradeSubmit"
            @order-success="onOrderSuccess"
          />
        </v-bottom-sheet>
      </template>
    </template>
  </v-container>
</template>

<script setup lang="ts">
defineOptions({ name: 'EventMarkets' })
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useDisplay } from 'vuetify'
import { createChart, LineSeries, LineType, LastPriceAnimationMode, type IChartApi, type ISeriesApi } from 'lightweight-charts'
import { toLwcData } from '../composables/useLightweightChart'
import TradeComponent from '../components/TradeComponent.vue'
import {
  findPmEvent,
  getMarketId,
  getClobTokenId,
  type FindPmEventParams,
  type PmEventListItem,
  type PmEventMarketItem,
} from '../api/event'
import { getPmPriceHistoryPublic, priceHistoryToChartData, getTimeRangeSeconds } from '../api/priceHistory'
import { getMockEventById } from '../api/mockData'
import { USE_MOCK_EVENT } from '../config/mock'
import { useI18n } from 'vue-i18n'
import { useUserStore } from '../stores/user'
import { useToastStore } from '../stores/toast'
import { useLocaleStore } from '../stores/locale'

const route = useRoute()
const { t } = useI18n()
const router = useRouter()
const userStore = useUserStore()
const localeStore = useLocaleStore()
const { mobile } = useDisplay()
const isMobile = computed(() => mobile.value)

const eventDetail = ref<PmEventListItem | null>(null)
const detailLoading = ref(false)
const detailError = ref<string | null>(null)

const selectedMarketIndex = ref(0)
/** 点击 Buy Yes/No 时传给购买组件的初始方向，不点击则为 undefined 使用组件默认 */
const tradeInitialOption = ref<'yes' | 'no' | undefined>(undefined)
/** 移动端交易弹窗开关 */
const tradeSheetOpen = ref(false)
/** 控制底部栏内 TradeComponent 的渲染，延迟挂载以避免 slot 竞态警告 */
const tradeSheetRenderContent = ref(false)
/** 从三点菜单点击 Merge/Split 时待打开的弹窗，等 TradeComponent 挂载后执行 */
const pendingMergeSplitDialog = ref<'merge' | 'split' | null>(null)
/** 移动端底部栏三点菜单开关 */
const mobileMenuOpen = ref(false)
/** TradeComponent 引用，用于从底部栏触发 Merge/Split */
const tradeComponentRef = ref<InstanceType<typeof TradeComponent> | null>(null)
const markets = computed(() => {
  const list = eventDetail.value?.markets ?? []
  return list.length > 0 ? list : []
})
const selectedMarket = computed(() => markets.value[selectedMarketIndex.value] ?? null)
/** 移动端底部栏显示的市场（选中项或首个），仅在 markets.length > 0 时使用 */
const barMarket = computed(() => selectedMarket.value ?? markets.value[0])
/** 传给购买组件的市场数据（当前选中的市场） */
const tradeMarketPayload = computed(() => {
  const m = selectedMarket.value
  if (!m) return undefined
  const yesRaw = m.outcomePrices?.[0]
  const noRaw = m.outcomePrices?.[1]
  const yesPrice = yesRaw != null && Number.isFinite(Number(yesRaw)) ? Number(yesRaw) : 0.5
  const noPrice = noRaw != null && Number.isFinite(Number(noRaw)) ? Number(noRaw) : 0.5
  return {
    marketId: getMarketId(m),
    yesPrice,
    noPrice,
    title: m.question,
    clobTokenIds: m.clobTokenIds,
    outcomes: m.outcomes,
  }
})

const categoryText = computed(() => {
  const s = eventDetail.value?.series?.[0]?.title
  const t = eventDetail.value?.tags?.[0]?.label
  return [s, t].filter(Boolean).join(' · ') || ''
})

function formatVolume(volume: number | undefined): string {
  if (volume == null || !Number.isFinite(volume)) return t('eventMarkets.volumeZero')
  if (volume >= 1000) return `$${(volume / 1000).toFixed(1)}k Vol.`
  return `$${Math.round(volume)} Vol.`
}

function formatExpiresAt(endDate: string | undefined): string {
  if (!endDate) return ''
  try {
    const d = new Date(endDate)
    if (Number.isNaN(d.getTime())) return endDate
    return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })
  } catch {
    return endDate
  }
}

const eventVolume = computed(() => {
  const v = eventDetail.value?.volume
  return v != null ? formatVolume(v) : ''
})

const currentChance = computed(() => {
  const m = selectedMarket.value
  if (!m) return 0
  return marketChance(m)
})

const selectedMarketVolume = computed(() => formatVolume(selectedMarket.value?.volume))
const marketExpiresAt = computed(() => {
  const endDate = eventDetail.value?.endDate
  return endDate ? formatExpiresAt(endDate) : ''
})
const resolutionDate = computed(() => {
  const s = marketExpiresAt.value
  return s ? s.replace(/,?\s*\d{4}$/, '').trim() || '' : ''
})

const isResolutionSourceUrl = computed(() => {
  const src = eventDetail.value?.resolutionSource
  return typeof src === 'string' && (src.startsWith('http://') || src.startsWith('https://'))
})

const timeRanges = [
  { label: '1H', value: '1H' },
  { label: '6H', value: '6H' },
  { label: '1D', value: '1D' },
  { label: '1W', value: '1W' },
  { label: '1M', value: '1M' },
  { label: 'ALL', value: 'ALL' },
]
const selectedTimeRange = ref('1D')
const chartContainerRef = ref<HTMLElement | null>(null)

type ChartSeriesItem = { name: string; data: [number, number][] }
const chartData = ref<ChartSeriesItem[]>([])
const chartLoading = ref(false)
let chartInstance: IChartApi | null = null
const chartSeriesList = ref<ISeriesApi<'Line'>[]>([])

const LINE_COLORS = [
  '#2563eb',
  '#dc2626',
  '#16a34a',
  '#ca8a04',
  '#9333ea',
  '#0891b2',
  '#ea580c',
  '#4f46e5',
]
const MOBILE_BREAKPOINT = 600

/** 按市场依次请求 getPmPriceHistoryPublic，market 传 clobTokenIds[0]（YES token） */
async function loadChartFromApi(): Promise<ChartSeriesItem[]> {
  const list = markets.value
  const range = selectedTimeRange.value
  // 增加每次请求的 points 数量，避免图表在较长时间粒度下出现“最新数据提前被截断”
  const pageSizeByRange: Record<string, number> = {
    '1H': 200,
    '6H': 600,
    '1D': 800,
    '1W': 1200,
    '1M': 1500,
    ALL: 2000,
  }
  const pageSize = pageSizeByRange[range] ?? 500
  const results: ChartSeriesItem[] = []
  for (let i = 0; i < list.length; i++) {
    const market = list[i]
    if (!market) continue
    const yesTokenId = getClobTokenId(market, 0)
    const base = (market.question || t('eventMarkets.marketPlaceholder')).slice(0, 32)
    const baseName = base + (base.length >= 32 ? '…' : '')
    const name = list.length > 1 ? `${baseName} (${i + 1}/${list.length})` : baseName
    if (!yesTokenId) {
      results.push({ name, data: [] })
      continue
    }
    try {
      const ev = eventDetail.value
      const timeRange = getTimeRangeSeconds(range, ev ? { startDate: ev.startDate, endDate: ev.endDate } : undefined)
      const res = await getPmPriceHistoryPublic({
        market: yesTokenId,
        page: 1,
        pageSize,
        ...(timeRange && { startTs: timeRange.startTs, endTs: timeRange.endTs }),
      })
      const points = priceHistoryToChartData(res.data?.list ?? [])
      results.push({ name, data: points })
    } catch {
      results.push({ name, data: [] })
    }
  }
  return results
}

function setChartSeries(seriesArr: ChartSeriesItem[]) {
  if (!chartInstance) return
  chartSeriesList.value.forEach((s) => chartInstance!.removeSeries(s))
  chartSeriesList.value = []
  seriesArr.forEach((s, i) => {
    const color = LINE_COLORS[i % LINE_COLORS.length]
    const series = chartInstance!.addSeries(LineSeries, {
      color,
      lineWidth: 2,
      lineType: LineType.Curved,
      lastPriceAnimation: LastPriceAnimationMode.OnDataUpdate,
      crosshairMarkerVisible: true,
      lastValueVisible: true,
      priceFormat: { type: 'percent', precision: 1 },
    })
    series.setData(toLwcData(s.data))
    chartSeriesList.value.push(series)
  })
}

async function initChart() {
  if (!chartContainerRef.value || markets.value.length === 0) return
  chartLoading.value = true
  try {
    chartData.value = await loadChartFromApi()
    const el = chartContainerRef.value
    chartInstance = createChart(el, {
      width: el.clientWidth,
      height: 320,
      layout: {
        background: { color: '#ffffff' },
        textColor: '#6b7280',
        fontFamily: 'inherit',
        fontSize: 9,
        attributionLogo: false,
      },
      grid: { vertLines: { color: '#f3f4f6' }, horzLines: { color: '#f3f4f6' } },
      rightPriceScale: { borderColor: '#e5e7eb', scaleMargins: { top: 0.1, bottom: 0.1 } },
      timeScale: { borderColor: '#e5e7eb', timeVisible: true, secondsVisible: false },
      handleScroll: false,
      handleScale: false,
      crosshair: { vertLine: { labelVisible: false }, horzLine: { labelVisible: true } },
    })
    setChartSeries(chartData.value)
  } finally {
    chartLoading.value = false
  }
}

async function updateChartData() {
  chartLoading.value = true
  try {
    chartData.value = await loadChartFromApi()
    setChartSeries(chartData.value)
  } finally {
    chartLoading.value = false
  }
}

function selectTimeRange(range: string) {
  selectedTimeRange.value = range
  updateChartData()
}

const handleResize = () => {
  if (!chartInstance || !chartContainerRef.value) return
  chartInstance.resize(chartContainerRef.value.clientWidth, 320)
}

function selectMarket(index: number) {
  selectedMarketIndex.value = index
}

/** 点击 Buy Yes/No：选中该市场并把数据和方向传给购买组件；移动端直接弹出交易弹窗 */
function openTrade(market: PmEventMarketItem, index: number, side: 'yes' | 'no') {
  selectedMarketIndex.value = index
  tradeInitialOption.value = side
  if (isMobile.value) {
    tradeSheetOpen.value = true
  }
}

/** 移动端底部栏：点击 Yes/No 时打开交易弹窗 */
function openSheetWithOption(side: 'yes' | 'no') {
  tradeInitialOption.value = side
  tradeSheetOpen.value = true
}

/** 从底部栏三点菜单打开 Merge 弹窗 */
function openMergeFromBar() {
  mobileMenuOpen.value = false
  pendingMergeSplitDialog.value = 'merge'
  tradeSheetOpen.value = true
}

/** 从底部栏三点菜单打开 Split 弹窗 */
function openSplitFromBar() {
  mobileMenuOpen.value = false
  pendingMergeSplitDialog.value = 'split'
  tradeSheetOpen.value = true
}

function onTradeSubmit(payload: {
  side: 'buy' | 'sell'
  option: 'yes' | 'no'
  limitPrice: number
  shares: number
  expirationEnabled: boolean
  expirationTime: string
  marketId?: string
}) {
  // 可在此调用下单 API，payload 含 marketId（当前市场）
}

const toastStore = useToastStore()
function onOrderSuccess() {
  tradeSheetOpen.value = false
  toastStore.show(t('toast.orderSuccess'))
}

function marketChance(market: PmEventMarketItem): number {
  const raw = market?.outcomePrices?.[0]
  if (raw == null) return 0
  const yesPrice = parseFloat(String(raw))
  if (!Number.isFinite(yesPrice)) return 0
  return Math.min(100, Math.max(0, Math.round(yesPrice * 100)))
}

function yesLabel(market: PmEventMarketItem): string {
  return market?.outcomes?.[0] ?? 'Yes'
}

function noLabel(market: PmEventMarketItem): string {
  return market?.outcomes?.[1] ?? 'No'
}

function yesPrice(market: PmEventMarketItem): string {
  const raw = market?.outcomePrices?.[0]
  if (raw == null) return '0¢'
  const p = parseFloat(String(raw))
  if (!Number.isFinite(p)) return '0¢'
  return `${Math.round(p * 100)}¢`
}

function noPrice(market: PmEventMarketItem): string {
  const raw = market?.outcomePrices?.[1]
  if (raw == null) return '0¢'
  const p = parseFloat(String(raw))
  if (!Number.isFinite(p)) return '0¢'
  return `${Math.round(p * 100)}¢`
}

function goToTradeDetail(market: PmEventMarketItem, side?: 'yes' | 'no') {
  const eventId = route.params.id
  const marketId = market.ID != null ? String(market.ID) : undefined
  router.push({
    path: `/trade-detail/${eventId}`,
    query: {
      title: market.question ?? eventDetail.value?.title,
      marketId,
      marketInfo: formatVolume(market.volume),
      chance: String(marketChance(market)),
      ...(side && { side }),
      ...(eventDetail.value?.slug && { slug: eventDetail.value.slug }),
    },
  })
}

async function loadEventDetail() {
  const idRaw = route.params.id
  const idStr = String(idRaw ?? '').trim()
  if (!idStr) {
    detailError.value = t('error.invalidId')
    eventDetail.value = null
    return
  }
  const numId = parseInt(idStr, 10)
  const isNumericId = Number.isFinite(numId) && String(numId) === idStr && numId >= 1
  const slugFromQuery = (route.query.slug as string)?.trim()
  const params: FindPmEventParams = {
    id: isNumericId ? numId : undefined,
    slug: isNumericId ? slugFromQuery || undefined : idStr,
  }

  detailError.value = null
  detailLoading.value = true
  try {
    const res = await findPmEvent(params, {
      headers: userStore.getAuthHeaders(),
    })
    if (res.code === 0 || res.code === 200) {
      eventDetail.value = res.data ?? null
      detailError.value = null
    } else {
      const fallback = USE_MOCK_EVENT && isNumericId ? getMockEventById(numId) : null
      if (fallback) {
        eventDetail.value = fallback
        detailError.value = null
      } else {
        detailError.value = res.msg || t('error.loadFailed')
        eventDetail.value = null
      }
    }
  } catch (e) {
    const fallback = USE_MOCK_EVENT && isNumericId ? getMockEventById(numId) : null
    if (fallback) {
      eventDetail.value = fallback
      detailError.value = null
    } else {
      detailError.value = e instanceof Error ? e.message : t('error.loadFailed')
      eventDetail.value = null
    }
  } finally {
    detailLoading.value = false
  }
}

onMounted(() => {
  loadEventDetail()
  window.addEventListener('resize', handleResize)
})
let tradeSheetUnmountTimer: ReturnType<typeof setTimeout> | undefined
let tradeSheetMountTimer: ReturnType<typeof setTimeout> | undefined
watch(tradeSheetOpen, (open) => {
  if (open) {
    if (tradeSheetUnmountTimer) {
      clearTimeout(tradeSheetUnmountTimer)
      tradeSheetUnmountTimer = undefined
    }
    if (tradeSheetMountTimer) clearTimeout(tradeSheetMountTimer)
    tradeSheetMountTimer = setTimeout(() => {
      tradeSheetRenderContent.value = true
      tradeSheetMountTimer = undefined
      nextTick(() => {
        const pending = pendingMergeSplitDialog.value
        if (pending === 'merge') {
          pendingMergeSplitDialog.value = null
          tradeComponentRef.value?.openMergeDialog?.()
        } else if (pending === 'split') {
          pendingMergeSplitDialog.value = null
          tradeComponentRef.value?.openSplitDialog?.()
        }
      })
    }, 50)
  } else {
    pendingMergeSplitDialog.value = null
    if (tradeSheetMountTimer) {
      clearTimeout(tradeSheetMountTimer)
      tradeSheetMountTimer = undefined
    }
    tradeSheetUnmountTimer = setTimeout(() => {
      tradeSheetRenderContent.value = false
      tradeSheetUnmountTimer = undefined
    }, 350)
  }
}, { immediate: true })

onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
  chartInstance?.remove()
  chartInstance = null
  chartSeriesList.value = []
  if (tradeSheetUnmountTimer) clearTimeout(tradeSheetUnmountTimer)
  if (tradeSheetMountTimer) clearTimeout(tradeSheetMountTimer)
})

watch(
  () => markets.value.length,
  (len) => {
    if (len > 0) {
      nextTick(() => initChart())
    }
  },
)
watch(
  () => route.params.id,
  () => loadEventDetail(),
)

// 监听语言切换，语言变化时重新加载数据
watch(
  () => localeStore.currentLocale,
  () => {
    loadEventDetail()
  },
)
</script>

<style scoped>
.event-markets-container {
  padding: 24px;
  min-height: 100vh;
}

.event-markets-row {
  display: flex;
  flex-wrap: wrap;
}

.chart-col {
  flex: 1 1 0%;
  min-width: 0;
}

.trade-col {
  margin-top: 32px;
}

.trade-sidebar {
  position: sticky;
  top: 24px;
  width: 400px;
  max-width: 100%;
  flex-shrink: 0;
}

@media (min-width: 960px) {
  .event-markets-row {
    flex-wrap: nowrap;
  }
  .chart-col {
    flex: 1 1 0% !important;
    min-width: 0;
    max-width: none !important;
  }
  .trade-col {
    flex: 0 0 400px !important;
    max-width: 400px !important;
    margin-top: 32px;
  }
  .trade-sidebar {
    width: 400px;
  }
}

@media (max-width: 959px) {
  .trade-sidebar {
    position: static;
    width: 100%;
  }
}

/* 与列表页、单 market 页保持一致的左右间距 */
@media (max-width: 599px) {
  .event-markets-container {
    padding: 16px;
    padding-left: 16px;
    padding-right: 16px;
  }

  .chart-card.polymarket-chart {
    padding: 16px;
  }
}

/* 分时图卡片（扁平化） */
.chart-card.polymarket-chart {
  margin-bottom: 24px;
  padding: 20px 24px 16px;
  background-color: #ffffff;
  border: 1px solid #e7e7e7;
  border-radius: 12px;
  box-shadow: none;
}

.chart-header {
  margin-bottom: 16px;
}

.chart-title {
  font-size: 1.25rem;
  font-weight: 600;
  color: #111827;
  margin: 0 0 4px 0;
  line-height: 1.3;
}

.chart-meta {
  font-size: 14px;
  color: #6b7280;
  margin: 0 0 8px 0;
  line-height: 1.4;
}

.chart-controls-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}

.past-btn {
  font-size: 13px;
  color: #6b7280;
  text-transform: none;
}

.date-pill {
  background-color: #111827 !important;
  color: #fff !important;
  font-size: 12px;
  font-weight: 500;
  text-transform: none;
}

.chart-chance {
  font-size: 1.5rem;
  font-weight: 700;
  color: #2563eb;
}

.chart-legend-hint {
  font-size: 0.875rem;
  color: #6b7280;
  margin: 0 0 8px 0;
}

.chart-wrapper {
  position: relative;
  width: 100%;
  margin-bottom: 12px;
}

.chart-loading-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.7);
  z-index: 1;
}

.chart-container {
  width: 100%;
  height: 320px;
  min-height: 260px;
}

.chart-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding-top: 12px;
  border-top: 1px solid #f3f4f6;
}

.chart-footer-left {
  font-size: 12px;
  color: #6b7280;
}

.chart-expires {
  margin-left: 4px;
}

.chart-time-ranges {
  display: flex;
  gap: 4px;
  flex-wrap: wrap;
}

.time-range-btn {
  font-size: 12px;
  text-transform: none;
  min-width: 36px;
  color: #6b7280;
}

.time-range-btn.active {
  color: #111827;
  font-weight: 600;
}

.time-range-btn:hover {
  color: #111827;
}

.loading-card,
.error-card {
  padding: 48px;
  text-align: center;
}

.loading-placeholder p,
.error-text {
  margin-top: 16px;
  color: #6b7280;
}

.error-text {
  color: #dc2626;
}

.rules-card {
  margin-top: 16px;
  border: 1px solid #e7e7e7;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: none;
}

.rules-card .rules-pane {
  padding: 16px 20px;
}

.rules-card .rules-section {
  margin-bottom: 16px;
}

.rules-card .rules-section:last-child {
  margin-bottom: 0;
}

.rules-card .rules-title {
  font-size: 13px;
  font-weight: 600;
  color: #6b7280;
  margin: 0 0 8px 0;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.rules-card .rules-text {
  font-size: 14px;
  color: #374151;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
}

.rules-card .rules-link {
  font-size: 14px;
  color: #2563eb;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.rules-card .rules-link:hover {
  text-decoration: underline;
}

.markets-list-card {
  margin-top: 16px;
  border: 1px solid #e7e7e7;
  border-radius: 12px;
  overflow: hidden;
  box-shadow: none;
}

.markets-list {
  display: flex;
  flex-direction: column;
}

.market-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 16px 20px;
  border-bottom: 1px solid #f0f0f0;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.market-row:last-child {
  border-bottom: none;
}

.market-row:hover {
  background-color: #f9fafb;
}

.market-row.selected {
  background-color: #eff6ff;
}

.market-row-main {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 12px;
}

.market-question {
  font-size: 15px;
  font-weight: 500;
  color: #111827;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.market-chance {
  font-size: 15px;
  font-weight: 700;
  color: #111827;
  flex-shrink: 0;
}

.market-row-vol {
  font-size: 14px;
  color: #6b7280;
  flex-shrink: 0;
}

.market-row-actions {
  display: flex;
  gap: 10px;
  flex: 1 1 100%;
  min-width: 0;
  margin-top: 2px;
}

/* 宽屏时按钮与问题同行，节省垂直空间 */
@media (min-width: 768px) {
  .market-row-actions {
    flex: 0 0 auto;
    margin-top: 0;
    margin-left: auto;
  }
}

.buy-yes-btn,
.buy-no-btn {
  flex: 1;
  min-width: 72px;
  max-width: 140px;
  white-space: nowrap;
  text-transform: none;
  font-weight: 500;
}

.buy-yes-btn {
  background-color: #b8e0b8 !important;
  color: #006600 !important;
}

.buy-no-btn {
  background-color: #f0b8b8 !important;
  color: #cc0000 !important;
}

/* 移动端底部交易栏 */
.mobile-trade-bar-spacer {
  height: 72px;
}

.mobile-trade-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 100;
  display: flex;
  align-items: stretch;
  gap: 10px;
  width: 100%;
  padding: 12px 16px;
  padding-bottom: max(12px, env(safe-area-inset-bottom));
  background: #fff;
  border-top: 1px solid #eee;
}

.mobile-bar-btn {
  border: none;
  border-radius: 6px;
  font-size: 15px;
  font-weight: 500;
  cursor: pointer;
  flex-shrink: 0;
  text-transform: none;
}

.mobile-bar-yes {
  flex: 1;
  min-width: 0;
  background: #b8e0b8 !important;
  color: #006600 !important;
  padding: 14px 16px;
}

.mobile-bar-no {
  flex: 1;
  min-width: 0;
  background: #f0b8b8 !important;
  color: #cc0000 !important;
  padding: 14px 16px;
}

.mobile-bar-more-btn {
  flex-shrink: 0;
  width: 46px;
  height: 46px;
  min-width: 46px;
  min-height: 46px;
  padding: 0 !important;
  border-radius: 50%;
  background: #e5e7eb !important;
  color: #6b7280;
  align-self: center;
}
</style>
