<template>
  <div class="detail-page" v-if="activity">
    <!-- 活动头部 -->
    <div class="detail-hero">
      <img v-if="activity.coverUrl" :src="activity.coverUrl" class="hero-cover" />
      <div v-else class="hero-placeholder">
        <span>{{ activity.contestName?.charAt(0) }}</span>
      </div>
      <div class="hero-overlay">
        <a-button shape="round" size="small" @click="$router.back()" class="back-btn">
          <arrow-left-outlined /> 返回
        </a-button>
        <div class="hero-badge">{{ stageLabel }}</div>
      </div>
    </div>

    <!-- 活动信息 -->
    <div class="detail-card">
      <h1 class="detail-title">{{ activity.contestName }}</h1>
      <div class="detail-meta">
        <div class="meta-row">
          <calendar-outlined />
          <span>{{ formatDate(activity.startTime) }} - {{ formatDate(activity.endTime) }}</span>
        </div>
        <div class="meta-row">
          <tag-outlined />
          <span>{{ activity.contestType === 'individual' ? '个人参与' : '团队参与' }}</span>
        </div>
        <div class="meta-row" v-if="activity.registerStartTime">
          <clock-circle-outlined />
          <span>报名：{{ formatDate(activity.registerStartTime) }} - {{ formatDate(activity.registerEndTime) }}</span>
        </div>
        <div class="meta-row" v-if="activity.ageMin || activity.ageMax">
          <team-outlined />
          <span>年龄要求：{{ activity.ageMin || 0 }} - {{ activity.ageMax || '不限' }} 岁</span>
        </div>
        <div class="meta-row" v-if="activity.targetCities?.length">
          <environment-outlined />
          <span>面向城市：{{ (activity.targetCities as string[]).join('、') }}</span>
        </div>
      </div>

      <!-- 参赛作品被评委标记违规 -->
      <a-alert v-if="showWorkViolationBanner" type="error" show-icon class="work-violation-alert" message="参赛作品被标记为违规"
        :description="violationBannerDescription" />

      <!-- 操作按钮（根据阶段动态展示） -->
      <div class="action-area">
        <!-- 报名阶段 -->
        <template v-if="currentStage === 'register'">
          <a-button v-if="!isLoggedIn" type="primary" size="large" block class="action-btn" @click="goLogin">
            登录后报名
          </a-button>
          <a-button v-else-if="!hasRegistered" type="primary" size="large" block class="action-btn"
            @click="showRegisterModal = true">
            立即报名
          </a-button>
          <a-button v-else-if="registrationState === 'pending'" size="large" block class="action-btn-info">
            <hourglass-outlined /> 报名审核中
          </a-button>
          <a-button v-else-if="registrationState === 'rejected'" size="large" block class="action-btn-disabled">
            <close-circle-outlined /> 报名未通过
          </a-button>
          <a-button v-else size="large" block class="action-btn-done">
            <check-circle-outlined /> 已报名
          </a-button>
        </template>

        <!-- 提交阶段 -->
        <template v-else-if="currentStage === 'submit'">
          <a-button v-if="!isLoggedIn" type="primary" size="large" block class="action-btn" @click="goLogin">
            登录后查看作品
          </a-button>
          <a-button v-else-if="!hasRegistered && isRegisterOpen" type="primary" size="large" block class="action-btn"
            @click="showRegisterModal = true">
            立即报名
          </a-button>
          <a-button v-else-if="!hasRegistered" size="large" block disabled class="action-btn-disabled">
            报名已截止
          </a-button>
          <a-button v-else-if="registrationState === 'pending'" size="large" block class="action-btn-info">
            <hourglass-outlined /> 报名审核中，通过后可提交作品
          </a-button>
          <a-button v-else-if="registrationState === 'rejected'" size="large" block disabled
            class="action-btn-disabled">
            <close-circle-outlined /> 报名未通过，无法提交作品
          </a-button>
          <a-button v-else-if="!hasSubmittedWork" type="primary" size="large" block class="action-btn"
            @click="openSubmitWork">
            <picture-outlined /> 从作品库选择
          </a-button>
          <a-button v-else-if="canResubmit" type="primary" size="large" block class="action-btn"
            @click="openSubmitWork">
            <picture-outlined /> 重新提交
          </a-button>
          <a-button v-else size="large" block class="action-btn-done">
            <check-circle-outlined /> 作品已提交
          </a-button>
        </template>

        <!-- 评审阶段 -->
        <template v-else-if="currentStage === 'review'">
          <a-button v-if="hasRegistered" size="large" block class="action-btn-info">
            <hourglass-outlined /> 您已报名，评审中请耐心等待
          </a-button>
          <a-button v-else size="large" block disabled class="action-btn-disabled">
            报名已结束
          </a-button>
        </template>

        <!-- 已结束 -->
        <template v-else-if="currentStage === 'finished'">
          <a-button type="primary" size="large" block class="action-btn" @click="activeTab = 'results'">
            查看成果
          </a-button>
        </template>

        <!-- 未开始 -->
        <template v-else>
          <a-button size="large" block disabled class="action-btn-disabled">
            活动即将开始
          </a-button>
        </template>
      </div>
    </div>

    <!-- Tab 内容 -->
    <div class="detail-card">
      <a-tabs v-model:activeKey="activeTab">
        <a-tab-pane key="info" tab="活动详情">
          <div class="rich-content" v-html="activityContentHtml"></div>
          <!-- 附件 -->
          <div v-if="activity.attachments?.length" class="attachments">
            <h4>相关附件</h4>
            <div v-for="att in activity.attachments" :key="att.id" class="att-item">
              <a :href="att.fileUrl" target="_blank">
                <paper-clip-outlined /> {{ att.fileName }}
              </a>
            </div>
          </div>
        </a-tab-pane>
        <a-tab-pane key="notices" tab="活动公告">
          <div v-if="!activity.notices?.length" class="empty-tab">
            <a-empty description="暂无公告" />
          </div>
          <div v-else>
            <div v-for="notice in activity.notices" :key="notice.id" class="notice-item">
              <h4>{{ notice.title }}</h4>
              <div class="notice-content" v-html="sanitizeNoticeContent(notice.content)"></div>
              <span class="notice-time">{{ formatNoticeTime(notice) }}</span>
            </div>
          </div>
        </a-tab-pane>
        <a-tab-pane key="works" tab="参赛作品">
          <a-spin :spinning="contestWorksLoading">
            <template v-if="contestWorksList.length > 0 || contestWorksLoading">
              <div v-if="contestWorksList.length > 0" class="activity-works-panel">
                <div class="works-grid">
                  <div v-for="work in contestWorksList" :key="work.contestWorkId" class="work-card"
                    :class="{ 'work-card--no-nav': work.id == null }" @click="openContestWork(work)">
                    <div class="card-cover">
                      <img v-if="work.coverUrl" :src="work.coverUrl" :alt="work.title || ''" />
                      <div v-else class="cover-placeholder">
                        <picture-outlined />
                      </div>
                      <div v-if="work.originalImageUrl && work.originalImageUrl !== work.coverUrl" class="cover-pip"
                        title="原图">
                        <img :src="work.originalImageUrl" alt="原图" />
                      </div>
                    </div>
                    <div class="card-body">
                      <h3>{{ work.title || '未命名作品' }}</h3>
                      <div class="card-author">
                        <a-avatar :size="20" :src="work.creator?.avatar">
                          {{ work.creator?.nickname?.charAt(0) }}
                        </a-avatar>
                        <span>{{ work.creator?.nickname }}</span>
                      </div>
                      <div class="card-stats">
                        <span :class="['like-btn', { liked: work.id != null && likedSet.has(work.id) }]"
                          @click.stop="handleContestWorkLike(work)">
                          <heart-filled v-if="work.id != null && likedSet.has(work.id)" />
                          <heart-outlined v-else />
                          {{ work.likeCount || 0 }}
                        </span>
                        <span><eye-outlined /> {{ work.viewCount || 0 }}</span>
                      </div>
                    </div>
                  </div>
                </div>
                <div v-if="contestWorksTotal > contestWorksPageSize" class="results-pagination-wrap">
                  <a-pagination :current="contestWorksPage" :total="contestWorksTotal" :page-size="contestWorksPageSize"
                    :show-size-changer="false" show-less-items :show-total="(t: number) => `共 ${t} 条`"
                    @change="onContestWorksPageChange" />
                </div>
              </div>
              <div v-else class="loading-wrap"><a-spin /></div>
            </template>
            <div v-else class="empty-tab">
              <a-empty description="暂无参赛作品" />
            </div>
          </a-spin>
        </a-tab-pane>
        <a-tab-pane key="results" tab="活动成果" v-if="activity.resultState === 'published'">
          <div class="results-panel">
            <div class="results-hero">
              <trophy-outlined class="results-icon" />
              <p class="results-hero-text">活动成果已发布</p>
            </div>
            <p v-if="activity.resultPublishTime" class="results-publish-time">
              发布时间：{{ formatDateTime(activity.resultPublishTime) }}
            </p>
            <p class="results-hint-line">以下排名与得分以主办方发布为准。</p>
            <a-spin :spinning="resultsLoading">
              <template v-if="resultsList.length > 0 || resultsLoading">
                <div class="results-cards">
                  <div v-for="record in resultsList" :key="record.id" class="result-card" :class="{
                    'result-card--top1': record.rank === 1,
                    'result-card--top2': record.rank === 2,
                    'result-card--top3': record.rank === 3,
                  }">
                    <div class="result-card__rank">
                      <span v-if="record.rank != null" class="rank-pill">{{ record.rank }}</span>
                      <span v-else class="rank-pill rank-pill--muted">-</span>
                    </div>
                    <div class="result-card__body">
                      <div class="result-card__title-row">
                        <span class="result-card__name">{{ record.participantName || '-' }}</span>
                        <a-tag v-if="record.awardName" color="gold" class="result-card__award">
                          {{ record.awardName }}
                        </a-tag>
                      </div>
                      <div class="result-card__meta">
                        <span class="result-card__meta-item">
                          <span class="meta-label">作品编号</span>
                          {{ record.workNo || '-' }}
                        </span>
                        <span class="result-card__meta-item">
                          <span class="meta-label">得分</span>
                          <span v-if="record.finalScore != null" class="score-text">
                            {{ Number(record.finalScore).toFixed(2) }}
                          </span>
                          <span v-else class="text-muted">-</span>
                        </span>
                      </div>
                    </div>
                  </div>
                </div>
                <div v-if="resultsTotal > resultsPageSize" class="results-pagination-wrap">
                  <a-pagination :current="resultsPage" :total="resultsTotal" :page-size="resultsPageSize"
                    :show-size-changer="false" show-less-items :show-total="(t: number) => `共 ${t} 条`"
                    @change="onResultsPageChange" />
                </div>
              </template>
              <div v-else class="empty-tab">
                <a-empty description="暂无公示信息" />
              </div>
            </a-spin>
          </div>
        </a-tab-pane>
      </a-tabs>
    </div>

    <!-- 报名弹窗 -->
    <a-modal v-model:open="showRegisterModal" title="活动报名" :footer="null" :width="420">
      <div class="register-modal">
        <template v-if="isChildUser">
          <p class="modal-desc">将使用当前账号报名，确认参加本活动吗？</p>
        </template>
        <template v-else>
          <p class="modal-desc">请选择参与者：</p>
          <a-radio-group v-model:value="participantForm.participantType" class="participant-options">
            <div class="participant-option">
              <a-radio value="self">我自己</a-radio>
            </div>
            <template v-if="children.length">
              <div v-for="child in children" :key="child.id" class="participant-option">
                <a-radio :value="'child_' + child.id">
                  子女：{{ child.name }}
                  <span class="child-detail" v-if="child.grade">（{{ child.grade }}）</span>
                </a-radio>
              </div>
            </template>
          </a-radio-group>
          <a-button type="link" @click="$router.push('/p/mine/children')" class="add-child-link">
            + 添加新的子女
          </a-button>
        </template>
        <a-button type="primary" block size="large" :loading="registering" @click="handleRegister" class="confirm-btn">
          确认报名
        </a-button>
      </div>
    </a-modal>

    <!-- 作品选择器弹窗 -->
    <WorkSelector v-model:open="showWorkSelector" :redirect-url="route.fullPath" @select="handleWorkSelected" />
  </div>

  <div v-else class="loading-page">
    <a-spin size="large" />
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted, onBeforeUnmount, reactive } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { message } from 'ant-design-vue'
import {
  ArrowLeftOutlined, CalendarOutlined, TagOutlined,
  ClockCircleOutlined, PaperClipOutlined, CheckCircleOutlined,
  PictureOutlined, HourglassOutlined, TrophyOutlined,
  TeamOutlined, EnvironmentOutlined, CloseCircleOutlined,
  HeartOutlined, HeartFilled, EyeOutlined,
} from '@ant-design/icons-vue'
import {
  publicActivitiesApi,
  publicChildrenApi,
  publicInteractionApi,
  type PublicActivityDetail,
  type PublicActivityMyRegistration,
  type PublicActivityNotice,
  type PublicActivityResultItem,
  type PublicActivityContestWorkItem,
  type UserWork,
} from '@/api/public'
import WorkSelector from './components/WorkSelector.vue'
import { sanitizeHtml } from '@/utils/sanitize'
import dayjs from 'dayjs'

const route = useRoute()
const router = useRouter()
const activity = ref<PublicActivityDetail | null>(null)
const activeTab = ref('info')
const children = ref<any[]>([])
const showRegisterModal = ref(false)
const registering = ref(false)
const hasRegistered = ref(false)
const registrationState = ref('')
const myRegistration = ref<PublicActivityMyRegistration | null>(null)
const hasSubmittedWork = ref(false)

// 作品提交
const showWorkSelector = ref(false)
const submittingWork = ref(false)

const participantForm = ref({
  participantType: 'self',
})

const formatDate = (d: string) => dayjs(d).format('YYYY-MM-DD')

const formatDateTime = (d: string) => dayjs(d).format('YYYY-MM-DD HH:mm')

/** 公示成果列表 */
const resultsLoading = ref(false)
const resultsList = ref<PublicActivityResultItem[]>([])
const resultsTotal = ref(0)
const resultsPage = ref(1)
const resultsPageSize = ref(10)

/** 参赛作品 Tab（公开列表） */
const contestWorksLoading = ref(false)
const contestWorksList = ref<PublicActivityContestWorkItem[]>([])
const contestWorksTotal = ref(0)
const contestWorksPage = ref(1)
const contestWorksPageSize = ref(10)
const likedSet = reactive(new Set<number>())

const loadPublicResults = async (page = 1) => {
  if (!activity.value?.id) return
  resultsLoading.value = true
  try {
    const res = await publicActivitiesApi.getPublishedResults(activity.value.id, {
      page,
      pageSize: resultsPageSize.value,
    })
    resultsList.value = res.list ?? []
    resultsTotal.value = Number(res.total ?? 0)
    resultsPage.value = Number(res.page ?? page)
  } catch (err: any) {
    message.error(err?.response?.data?.message || '加载成果列表失败')
    resultsList.value = []
    resultsTotal.value = 0
  } finally {
    resultsLoading.value = false
  }
}

const onResultsPageChange = (page: number) => {
  void loadPublicResults(page)
}

const loadActivityWorks = async (page = 1) => {
  if (!activity.value?.id) return
  contestWorksLoading.value = true
  try {
    const res = await publicActivitiesApi.getActivityWorks(activity.value.id, {
      page,
      pageSize: contestWorksPageSize.value,
    })
    contestWorksList.value = res.list ?? []
    contestWorksTotal.value = Number(res.total ?? 0)
    contestWorksPage.value = Number(res.page ?? page)
    likedSet.clear()
    if (isLoggedIn.value && contestWorksList.value.length > 0) {
      const ids = contestWorksList.value
        .map((w) => w.id)
        .filter((x): x is number => x != null)
      if (ids.length > 0) {
        try {
          const statuses = await publicInteractionApi.batchStatus(ids)
          for (const [id, status] of Object.entries(statuses)) {
            if ((status as { liked?: boolean }).liked) likedSet.add(Number(id))
          }
        } catch {
          /* 忽略点赞状态 */
        }
      }
    }
  } catch (err: any) {
    message.error(err?.response?.data?.message || '加载参赛作品失败')
    contestWorksList.value = []
    contestWorksTotal.value = 0
  } finally {
    contestWorksLoading.value = false
  }
}

const onContestWorksPageChange = (page: number) => {
  void loadActivityWorks(page)
}

const openContestWork = (work: PublicActivityContestWorkItem) => {
  if (work.id == null) {
    message.info('该作品暂无法查看详情')
    return
  }
  router.push(`/p/works/${work.id}`)
}

const handleContestWorkLike = async (work: PublicActivityContestWorkItem) => {
  if (work.id == null) return
  if (!isLoggedIn.value) {
    goLogin()
    return
  }
  const wid = work.id
  const wasLiked = likedSet.has(wid)
  if (wasLiked) {
    likedSet.delete(wid)
  } else {
    likedSet.add(wid)
  }
  work.likeCount = (work.likeCount || 0) + (wasLiked ? -1 : 1)
  try {
    const res = await publicInteractionApi.like(wid)
    if (res.liked) {
      likedSet.add(wid)
    } else {
      likedSet.delete(wid)
    }
    work.likeCount = res.likeCount
  } catch {
    if (wasLiked) {
      likedSet.add(wid)
    } else {
      likedSet.delete(wid)
    }
    work.likeCount = (work.likeCount || 0) + (wasLiked ? 1 : -1)
    message.error('操作失败')
  }
}

watch(activeTab, (k) => {
  if (k === 'results' && activity.value?.resultState === 'published') {
    void loadPublicResults(1)
  }
  if (k === 'works') {
    void loadActivityWorks(1)
  }
})

const formatNoticeTime = (n: PublicActivityNotice) =>
  formatDate(n.publishTime || n.createTime || '')

/** 安全过滤公告内容 */
const sanitizeNoticeContent = (content: string) => sanitizeHtml(content)

/** 活动详情富文本：后端字段为 content，使用 DOMPurify 过滤 XSS */
const activityContentHtml = computed(() => {
  const a = activity.value
  if (!a) return ''
  return sanitizeHtml(a.content || a.description || '')
})

/** 子女账号：直接报名，不选参与者、不添加子女 */
const isChildUser = computed(() => {
  const raw = localStorage.getItem('public_user')
  if (!raw) return false
  try {
    return JSON.parse(raw).userType === 'child'
  } catch {
    return false
  }
})

const isLoggedIn = computed(() => !!localStorage.getItem('public_token'))

// 报名是否仍在开放中
const isRegisterOpen = computed(() => {
  if (!activity.value) return false
  const now = dayjs()
  return !now.isBefore(activity.value.registerStartTime) && now.isBefore(activity.value.registerEndTime)
})

// 是否允许重新提交：活动允许多次提交，或最新参赛作品被标记违规需重提
const canResubmit = computed(() => {
  if (!hasSubmittedWork.value || !activity.value) return false
  const st = myRegistration.value?.latestWorkStatus
  return activity.value.submitRule === 'resubmit' || st === 'violation'
})

/** 最新参赛作品为违规（报名已通过） */
const showWorkViolationBanner = computed(
  () =>
    hasRegistered.value &&
    registrationState.value === 'passed' &&
    myRegistration.value?.latestWorkStatus === 'violation',
)

const violationBannerDescription = computed(() => {
  const r = myRegistration.value?.violationReason?.trim()
  return r || '请根据说明修改作品后，在提交期内重新从作品库选择作品提交。'
})

// 活动当前阶段
const currentStage = computed(() => {
  if (!activity.value) return 'pending'
  const now = dayjs()
  const a = activity.value
  if (now.isBefore(a.registerStartTime)) return 'pending'
  // 提交阶段优先：如果到了提交时间且在提交截止前，优先显示提交（报名与提交可能重叠）
  if (a.submitStartTime && !now.isBefore(a.submitStartTime) && a.submitEndTime && now.isBefore(a.submitEndTime)) return 'submit'
  if (now.isBefore(a.registerEndTime)) return 'register'
  if (a.reviewStartTime && now.isBefore(a.reviewEndTime)) return 'review'
  if (a.status === 'finished' || a.resultState === 'published') return 'finished'
  return 'review'
})

const stageLabel = computed(() => {
  const map: Record<string, string> = {
    pending: '即将开始', register: '报名中', submit: '提交中',
    review: '评审中', finished: '已结束',
  }
  return map[currentStage.value] || '进行中'
})

const goLogin = () => router.push({ path: '/p/login', query: { redirect: route.fullPath } })

const fetchDetail = async () => {
  const id = Number(route.params.id)
  try {
    activity.value = await publicActivitiesApi.detail(id)
  } catch {
    message.error('活动不存在')
    router.push('/p/activities')
  }
}

const fetchChildren = async () => {
  if (!isLoggedIn.value) return
  try {
    children.value = await publicChildrenApi.list()
  } catch { /* ignore */ }
}

// 检查报名状态和作品提交状态
const checkRegistrationStatus = async () => {
  if (!isLoggedIn.value || !activity.value) return
  try {
    const reg = await publicActivitiesApi.getMyRegistration(activity.value.id)
    // 只有当 reg 存在且有 id 时才认为已报名
    if (reg && reg.id) {
      hasRegistered.value = true
      registrationState.value = reg.registrationState || ''
      myRegistration.value = reg
      // 检查是否已提交作品
      hasSubmittedWork.value = reg.hasSubmittedWork || false
    }
  } catch (e) {
    // 未报名或查询失败，保持 hasRegistered = false
    console.log('查询报名状态失败或未报名')
  }
}

// 打开作品选择器
const openSubmitWork = () => {
  if (!isLoggedIn.value) { goLogin(); return }
  showWorkSelector.value = true
}

// 从作品库选择作品后提交
const handleWorkSelected = async (work: UserWork) => {
  if (!myRegistration.value) {
    message.error('请先报名活动')
    return
  }
  submittingWork.value = true
  try {
    await publicActivitiesApi.submitWork(activity.value.id, {
      registrationId: myRegistration.value.id,
      userWorkId: work.id,
    })
    message.success('作品提交成功！')
    showWorkSelector.value = false
    hasSubmittedWork.value = true
    await checkRegistrationStatus()
  } catch (err: any) {
    message.error(err?.response?.data?.message || '提交失败')
  } finally {
    submittingWork.value = false
  }
}

const handleRegister = async () => {
  if (!isLoggedIn.value) {
    router.push({ path: '/p/login', query: { redirect: route.fullPath } })
    return
  }
  if (!activity.value) return

  registering.value = true
  try {
    if (isChildUser.value) {
      await publicActivitiesApi.register(activity.value.id, { participantType: 'self' })
    } else {
      const val = participantForm.value.participantType
      const isChild = val.startsWith('child_')
      await publicActivitiesApi.register(activity.value.id, {
        participantType: isChild ? 'child' : 'self',
        childId: isChild ? parseInt(val.replace('child_', '')) : undefined,
      })
    }
    message.success('报名成功！')
    showRegisterModal.value = false
    hasRegistered.value = true
    // 重新查询报名状态以获取准确的 registrationState
    await checkRegistrationStatus()
  } catch (err: any) {
    message.error(err?.response?.data?.message || '报名失败')
  } finally {
    registering.value = false
  }
}

// AbortController 用于取消异步请求（防止组件卸载后的竞态更新）
let abortController: AbortController | null = null

onMounted(async () => {
  // 每次挂载创建新的 AbortController，组件卸载时取消
  abortController = new AbortController()
  const signal = abortController.signal

  try {
    await fetchDetail()
    // 检查是否已取消（快速切换页面时）
    if (signal.aborted) return
    await fetchChildren()
    if (signal.aborted) return
    await checkRegistrationStatus()
  } catch {
    // 组件已卸载导致的取消，忽略
  }
})

onBeforeUnmount(() => {
  // 组件卸载时取消所有进行中的请求
  if (abortController) {
    abortController.abort()
    abortController = null
  }
})
</script>

<style scoped lang="scss">
$primary: #6366f1;

.loading-page {
  display: flex;
  justify-content: center;
  padding: 100px 0;
}

.detail-hero {
  position: relative;
  min-height: 150px;
  display: flex;
  // height: 220px;
  border-radius: 20px;
  overflow: hidden;
  margin-bottom: 16px;

  .hero-cover {
    width: 100%;
    // height: 100%;
    object-fit: contain;
    margin: auto;
  }

  .hero-placeholder {
    width: 100%;
    height: 100%;
    background: linear-gradient(135deg, #c7d2fe, #fbcfe8, #a7f3d0);
    display: flex;
    align-items: center;
    justify-content: center;

    span {
      font-size: 60px;
      font-weight: 800;
      color: rgba(255, 255, 255, 0.6);
    }
  }

  .hero-overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(0, 0, 0, 0.3) 0%, transparent 40%, transparent 60%, rgba(0, 0, 0, 0.3) 100%);
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    padding: 16px;
  }

  .back-btn {
    background: rgba(255, 255, 255, 0.2);
    backdrop-filter: blur(8px);
    border: 1px solid rgba(255, 255, 255, 0.3);
    color: #fff;
  }

  .hero-badge {
    padding: 4px 16px;
    border-radius: 20px;
    font-size: 12px;
    font-weight: 600;
    color: #fff;
    background: linear-gradient(135deg, $primary, #ec4899);
  }
}

.detail-card {
  background: #fff;
  border-radius: 16px;
  padding: 24px;
  margin-bottom: 16px;
  border: 1px solid rgba($primary, 0.06);
}

.detail-title {
  font-size: 22px;
  font-weight: 800;
  color: #1e1b4b;
  margin: 0 0 16px;
  line-height: 1.4;
}

.detail-meta {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 20px;

  .meta-row {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: #6b7280;
  }
}

.work-violation-alert {
  margin-bottom: 20px;
}

.action-area {
  .action-btn {
    height: 48px !important;
    border-radius: 14px !important;
    font-size: 16px !important;
    font-weight: 700 !important;
    background: linear-gradient(135deg, $primary, #ec4899) !important;
    border: none !important;
    box-shadow: 0 4px 16px rgba($primary, 0.3);
  }

  .action-btn-done {
    height: 48px !important;
    border-radius: 14px !important;
    font-size: 15px !important;
    font-weight: 600 !important;
    background: #ecfdf5 !important;
    color: #059669 !important;
    border: 1px solid #a7f3d0 !important;
  }

  .action-btn-info {
    height: 48px !important;
    border-radius: 14px !important;
    font-size: 15px !important;
    font-weight: 600 !important;
    background: #eef2ff !important;
    color: $primary !important;
    border: 1px solid #c7d2fe !important;
  }

  .action-btn-disabled {
    height: 48px !important;
    border-radius: 14px !important;
    font-size: 15px !important;
    font-weight: 600 !important;
    background: #f3f4f6 !important;
    color: #9ca3af !important;
    border: 1px solid #e5e7eb !important;
  }
}

.results-panel {
  .results-hero {
    text-align: center;
    padding: 8px 0 16px;

    .results-icon {
      font-size: 40px;
      color: #6366f1;
      margin-bottom: 8px;
      display: block;
    }

    .results-hero-text {
      font-size: 15px;
      font-weight: 600;
      color: #374151;
      margin: 0;
    }
  }

  .results-publish-time {
    font-size: 13px;
    color: #6b7280;
    margin: 0 0 8px;
    text-align: center;
  }

  .results-hint-line {
    font-size: 12px;
    color: #9ca3af;
    margin: 0 0 16px;
    text-align: center;
  }

  .results-cards {
    display: flex;
    flex-direction: column;
    gap: 12px;
  }

  .result-card {
    display: flex;
    gap: 14px;
    align-items: stretch;
    padding: 14px 16px;
    background: #faf9fe;
    border-radius: 14px;
    border: 1px solid rgba($primary, 0.12);
    transition: box-shadow 0.2s, border-color 0.2s;

    &:hover {
      border-color: rgba($primary, 0.22);
      box-shadow: 0 4px 14px rgba($primary, 0.08);
    }

    &--top1 {
      border-color: rgba(234, 179, 8, 0.45);
      background: linear-gradient(135deg, #fffbeb 0%, #faf9fe 100%);
    }

    &--top2 {
      border-color: rgba(148, 163, 184, 0.5);
      background: linear-gradient(135deg, #f8fafc 0%, #faf9fe 100%);
    }

    &--top3 {
      border-color: rgba(217, 119, 6, 0.35);
      background: linear-gradient(135deg, #fff7ed 0%, #faf9fe 100%);
    }
  }

  .result-card__rank {
    flex-shrink: 0;
    display: flex;
    align-items: center;
  }

  .result-card__body {
    flex: 1;
    min-width: 0;
  }

  .result-card__title-row {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
    margin-bottom: 8px;
  }

  .result-card__name {
    font-size: 15px;
    font-weight: 700;
    color: #1e1b4b;
    line-height: 1.4;
    word-break: break-word;
  }

  .result-card__award {
    flex-shrink: 0;
    margin: 0 !important;
  }

  .result-card__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 12px 20px;
    font-size: 13px;
    color: #6b7280;
  }

  .result-card__meta-item {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
  }

  .meta-label {
    color: #9ca3af;
    font-size: 12px;
  }

  .results-pagination-wrap {
    display: flex;
    justify-content: center;
    margin-top: 20px;
    padding-top: 4px;
  }

  .rank-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    padding: 2px 8px;
    border-radius: 8px;
    font-weight: 700;
    font-size: 13px;
    background: linear-gradient(135deg, #eef2ff, #fce7f3);
    color: #4f46e5;

    &--muted {
      background: #f3f4f6;
      color: #9ca3af;
      font-weight: 600;
    }
  }

  .score-text {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    color: #1e1b4b;
  }

  .text-muted {
    color: #9ca3af;
  }
}

/* 参赛作品 Tab：与作品广场 Gallery 网格一致 */
.activity-works-panel {
  .results-pagination-wrap {
    display: flex;
    justify-content: center;
    margin-top: 20px;
    padding-top: 4px;
  }
}

.loading-wrap {
  padding: 60px 0;
  display: flex;
  justify-content: center;
}

.works-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;

  @media (min-width: 640px) {
    grid-template-columns: repeat(3, 1fr);
  }
}

.work-card {
  background: #fff;
  border-radius: 14px;
  overflow: hidden;
  cursor: pointer;
  transition: all 0.2s;
  border: 1px solid rgba($primary, 0.04);

  &:hover {
    box-shadow: 0 4px 20px rgba($primary, 0.1);
    transform: translateY(-2px);
  }

  &.work-card--no-nav {
    cursor: default;

    &:hover {
      transform: none;
      box-shadow: none;
    }
  }

  .card-cover {
    position: relative;
    aspect-ratio: 3/4;
    background: #f5f3ff;

    img {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }

    .cover-placeholder {
      display: flex;
      align-items: center;
      justify-content: center;
      height: 100%;
      font-size: 28px;
      color: #d1d5db;
    }

    .cover-pip {
      position: absolute;
      right: 6px;
      bottom: 6px;
      width: 34%;
      aspect-ratio: 1 / 1;
      border-radius: 7px;
      overflow: hidden;
      border: 2px solid #fff;
      background: #fff;
      box-shadow: 0 3px 10px rgba(15, 12, 41, 0.25);
      transition: transform 0.2s;

      img {
        width: 100%;
        height: 100%;
        object-fit: cover;
      }
    }
  }

  &:hover .cover-pip {
    transform: scale(1.05);
  }

  .card-body {
    padding: 10px 12px;

    h3 {
      font-size: 13px;
      font-weight: 600;
      color: #1e1b4b;
      margin: 0 0 6px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    .card-author {
      display: flex;
      align-items: center;
      gap: 6px;
      margin-bottom: 6px;

      span {
        font-size: 11px;
        color: #6b7280;
      }
    }

    .card-stats {
      display: flex;
      gap: 12px;

      span {
        font-size: 11px;
        color: #9ca3af;
        display: flex;
        align-items: center;
        gap: 3px;
      }

      .like-btn {
        cursor: pointer;
        transition: color 0.2s;

        &:hover {
          color: #ec4899;
        }

        &.liked {
          color: #ec4899;

          :deep(.anticon) {
            animation: activityWorkPop 0.3s ease;
          }
        }
      }
    }
  }
}

@keyframes activityWorkPop {
  0% {
    transform: scale(1);
  }

  50% {
    transform: scale(1.3);
  }

  100% {
    transform: scale(1);
  }
}

.rich-content {
  font-size: 14px;
  line-height: 1.8;
  color: #374151;

  :deep(img) {
    max-width: 100%;
    border-radius: 8px;
  }
}

.attachments {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid #f0ecf9;

  h4 {
    font-size: 14px;
    font-weight: 600;
    color: #374151;
    margin: 0 0 10px;
  }

  .att-item a {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    color: $primary;
    padding: 6px 0;
  }
}

.notice-item {
  padding: 16px;
  background: #faf9fe;
  border-radius: 12px;
  margin-bottom: 12px;

  h4 {
    font-size: 15px;
    font-weight: 600;
    color: #1e1b4b;
    margin: 0 0 8px;
  }

  .notice-content {
    font-size: 14px;
    color: #6b7280;
    line-height: 1.6;
  }

  .notice-time {
    font-size: 12px;
    color: #9ca3af;
    margin-top: 8px;
    display: block;
  }
}

.empty-tab {
  padding: 40px 0;
}

// 报名弹窗
.register-modal {
  .modal-desc {
    font-size: 14px;
    color: #374151;
    margin: 0 0 16px;
    font-weight: 500;
  }

  .participant-options {
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: 100%;
  }

  .participant-option {
    padding: 12px 16px;
    background: #faf9fe;
    border-radius: 12px;
    transition: background 0.2s;

    &:hover {
      background: #eef2ff;
    }

    .child-detail {
      color: #9ca3af;
      font-size: 12px;
    }
  }

  .add-child-link {
    margin: 12px 0;
    padding: 0;
    font-size: 13px;
  }

  .confirm-btn {
    margin-top: 8px;
    height: 44px !important;
    border-radius: 12px !important;
    font-weight: 600 !important;
  }
}

@media (max-width: 640px) {
  .detail-hero {
    // height: 180px;
    border-radius: 16px;
  }

  .detail-card {
    padding: 18px;
    border-radius: 14px;
  }

  .detail-title {
    font-size: 18px;
  }
}
</style>
