<template>
  <section class="store-monitoring">
    <el-alert
      title="这里只监测 Apple App Store 与鸿蒙应用市场的官方状态，不会上传安装包、提交审核或执行发布。当前仅判断中国大陆（CHN）是否可下载。"
      type="info"
      show-icon
      :closable="false"
    />

    <div class="section-heading">
      <div>
        <h3>商店绑定</h3>
        <p>监测凭据加密保存，页面只展示是否已配置，不会回显密钥正文。</p>
      </div>
      <el-button :loading="loadingBindings" @click="loadBindings">刷新</el-button>
    </div>

    <div class="binding-grid">
      <el-card
        v-for="definition in STORE_DEFINITIONS"
        :key="definition.storeType"
        shadow="never"
        class="binding-card"
      >
        <template #header>
          <div class="card-header">
            <div>
              <strong>{{ definition.label }}</strong>
              <div class="card-subtitle">{{ definition.platformLabel }} · 中国大陆</div>
            </div>
            <el-tag :type="bindingFor(definition.storeType)?.enabled ? 'success' : 'info'">
              {{ bindingFor(definition.storeType)?.enabled ? '监测中' : '未启用' }}
            </el-tag>
          </div>
        </template>

        <template v-if="bindingFor(definition.storeType)">
          <el-descriptions :column="1" size="small" border>
            <el-descriptions-item label="应用标识">
              {{ bindingFor(definition.storeType)?.packageIdentifier }}
            </el-descriptions-item>
            <el-descriptions-item label="官方应用 ID">
              {{ bindingFor(definition.storeType)?.officialAppId || '同步后识别' }}
            </el-descriptions-item>
            <el-descriptions-item label="监测凭据">
              <el-tag
                :type="bindingFor(definition.storeType)?.monitorCredentialConfigured ? 'success' : 'danger'"
                size="small"
              >
                {{ bindingFor(definition.storeType)?.monitorCredentialConfigured ? '已配置' : '未配置' }}
              </el-tag>
            </el-descriptions-item>
            <el-descriptions-item label="最近同步">
              {{ displayTime(bindingFor(definition.storeType)?.lastSyncedAt) }}
            </el-descriptions-item>
          </el-descriptions>

          <el-alert
            v-if="bindingFor(definition.storeType)?.lastSyncStatus === 'FAILED'"
            :title="bindingFor(definition.storeType)?.lastSyncError || '最近一次同步失败'"
            type="error"
            show-icon
            :closable="false"
            class="sync-error"
          />
        </template>
        <el-empty v-else description="尚未绑定" :image-size="56" />

        <div class="card-actions">
          <el-button @click="openBindingDialog(definition.storeType)">
            {{ bindingFor(definition.storeType) ? '修改绑定' : '创建绑定' }}
          </el-button>
          <el-button
            type="primary"
            plain
            :disabled="!bindingFor(definition.storeType)?.enabled"
            :loading="syncingStore === definition.storeType"
            @click="synchronize(definition.storeType)"
          >
            手动同步
          </el-button>
          <el-button
            :disabled="!bindingFor(definition.storeType)"
            @click="selectBinding(definition.storeType)"
          >
            查看监测结果
          </el-button>
        </div>
      </el-card>
    </div>

    <template v-if="selectedBinding">
      <div class="section-heading result-heading">
        <div>
          <h3>{{ storeLabel(selectedBinding.storeType) }}监测结果</h3>
          <p>“已在中国大陆上架”只在官方库存确认 CHN 可下载时显示。</p>
        </div>
      </div>

      <el-tabs v-model="resultTab" @tab-change="handleResultTabChange">
        <el-tab-pane label="版本状态" name="versions">
          <el-table :data="versions" v-loading="loadingVersions" border stripe>
            <el-table-column prop="versionName" label="版本" min-width="110" />
            <el-table-column prop="buildVersion" label="构建号" min-width="110">
              <template #default="{ row }">{{ row.buildVersion || '—' }}</template>
            </el-table-column>
            <el-table-column label="状态" min-width="170">
              <template #default="{ row }">
                <el-tag :type="stateTagType(row.state)">{{ stateLabel(row.state) }}</el-tag>
              </template>
            </el-table-column>
            <el-table-column label="中国大陆" min-width="145">
              <template #default="{ row }">
                <el-tag :type="row.chinaAvailable ? 'success' : 'info'">
                  {{ row.chinaAvailable ? '已可下载' : '尚不可下载' }}
                </el-tag>
              </template>
            </el-table-column>
            <el-table-column prop="rawState" label="官方原始状态" min-width="170">
              <template #default="{ row }">{{ row.rawState || '—' }}</template>
            </el-table-column>
            <el-table-column label="状态时间" min-width="170">
              <template #default="{ row }">{{ displayTime(row.stateOccurredAt) }}</template>
            </el-table-column>
            <el-table-column label="最近同步" min-width="170">
              <template #default="{ row }">{{ displayTime(row.lastSyncedAt) }}</template>
            </el-table-column>
            <el-table-column label="Xuqm 更新草稿" min-width="245" fixed="right">
              <template #default="{ row }">
                <div v-if="draftResults[row.id]" class="draft-result">
                  <el-tag
                    :type="draftResults[row.id].publishStatus === 'DRAFT' ? 'success' : 'info'"
                    size="small"
                  >
                    {{ draftResults[row.id].publishStatus }}
                  </el-tag>
                  <span>AppVersion ID：{{ draftResults[row.id].appVersionId }}</span>
                </div>
                <el-button
                  v-else-if="canCreateUpdateDraft(row)"
                  link
                  type="primary"
                  :loading="creatingDraftVersionId === row.id"
                  :disabled="creatingDraftVersionId === row.id"
                  @click="createUpdateDraft(row)"
                >
                  创建 Xuqm 更新草稿
                </el-button>
                <span v-else class="ineligible-draft">上架且 CHN 可下载后可创建</span>
              </template>
            </el-table-column>
          </el-table>
          <el-empty v-if="!loadingVersions && versions.length === 0" description="暂无官方版本记录" />
          <el-alert
            title="此操作在尚未关联时只创建 Xuqm 版本管理中的 DRAFT 草稿，不会向 Apple 或鸿蒙应用市场提交审核，也不会发布更新。"
            type="warning"
            :closable="false"
            show-icon
            class="draft-hint"
          />
        </el-tab-pane>

        <el-tab-pane label="事件时间线" name="events">
          <div v-loading="loadingEvents" class="timeline-wrap">
            <el-timeline v-if="events.length">
              <el-timeline-item
                v-for="event in events"
                :key="event.id"
                :timestamp="displayTime(event.occurredAt || event.receivedAt)"
                placement="top"
                :type="stateTagType(event.currentState)"
              >
                <el-card shadow="never">
                  <div class="event-title">{{ eventLabel(event.eventType) }}</div>
                  <div class="event-state">
                    <template v-if="event.previousState">
                      {{ stateLabel(event.previousState) }} →
                    </template>
                    {{ stateLabel(event.currentState) }}
                  </div>
                  <div class="event-meta">
                    来源：{{ sourceLabel(event.source) }}
                    <span v-if="event.rawState"> · 官方状态：{{ event.rawState }}</span>
                  </div>
                </el-card>
              </el-timeline-item>
            </el-timeline>
            <el-empty v-else-if="!loadingEvents" description="暂无状态事件" />
          </div>
        </el-tab-pane>
      </el-tabs>
    </template>

    <el-divider />

    <div class="section-heading">
      <div>
        <h3>状态通知</h3>
        <p>邮件和 Webhook 默认关闭；即使通知关闭，商店状态事件仍会保留在时间线中。</p>
      </div>
      <el-button
        type="primary"
        :loading="savingNotification"
        @click="saveNotificationPolicy"
      >
        保存通知策略
      </el-button>
    </div>

    <el-form
      v-loading="loadingNotification"
      :model="notificationForm"
      label-width="150px"
      class="notification-form"
    >
      <el-form-item label="邮件通知">
        <el-switch v-model="notificationForm.emailEnabled" />
        <span class="form-tip">默认关闭</span>
      </el-form-item>
      <el-form-item v-if="notificationForm.emailEnabled" label="收件人">
        <el-select
          v-model="notificationForm.emailRecipients"
          multiple
          filterable
          allow-create
          default-first-option
          placeholder="输入邮箱后按回车，可添加多个"
          class="full-width"
        />
      </el-form-item>
      <el-form-item label="Webhook 通知">
        <el-switch v-model="notificationForm.webhookEnabled" />
        <span class="form-tip">默认关闭，启用后请求包含事件 ID 与签名</span>
      </el-form-item>
      <template v-if="notificationForm.webhookEnabled">
        <el-form-item label="Webhook 地址">
          <el-input
            v-model.trim="notificationForm.webhookUrl"
            placeholder="https://example.com/hooks/xuqm-store"
          />
        </el-form-item>
        <el-form-item label="签名密钥">
          <el-input
            v-model="notificationForm.webhookSecret"
            type="password"
            show-password
            autocomplete="new-password"
            :placeholder="notificationForm.webhookSecretConfigured ? '已配置；留空表示不变' : '首次启用必须填写'"
          />
          <span class="form-tip">密钥只写入、不回显。</span>
        </el-form-item>
      </template>
      <el-form-item label="通知事件">
        <el-checkbox-group v-model="notificationForm.eventTypes">
          <el-checkbox value="STORE_VERSION_DISCOVERED">发现新版本</el-checkbox>
          <el-checkbox value="STORE_STATE_CHANGED">版本状态变化</el-checkbox>
        </el-checkbox-group>
        <div class="event-tip">不选择表示订阅全部商店状态事件。</div>
      </el-form-item>
    </el-form>

    <el-dialog
      v-model="bindingDialogVisible"
      :title="`${bindingFor(bindingForm.storeType) ? '修改' : '创建'}${storeLabel(bindingForm.storeType)}监测绑定`"
      width="620px"
      :close-on-click-modal="false"
    >
      <el-alert
        v-if="bindingFor(bindingForm.storeType)?.monitorCredentialConfigured"
        title="监测凭据已经配置。密钥字段全部留空时保留现有凭据；填写后将整体替换。"
        type="info"
        :closable="false"
        show-icon
        class="dialog-alert"
      />
      <el-form :model="bindingForm" label-width="140px">
        <el-form-item label="应用标识" required>
          <el-input
            v-model.trim="bindingForm.packageIdentifier"
            :placeholder="bindingForm.storeType === 'APP_STORE' ? 'iOS Bundle ID' : '鸿蒙 Bundle Name'"
          />
        </el-form-item>
        <el-form-item label="应用市场地址">
          <el-input v-model.trim="bindingForm.marketUrl" placeholder="可选，只用于记录跳转地址" />
        </el-form-item>
        <el-form-item label="启用定时监测">
          <el-switch v-model="bindingForm.enabled" />
        </el-form-item>
        <el-form-item label="凭据名称">
          <el-input v-model.trim="bindingForm.credentialDisplayName" placeholder="例如：生产只读监测凭据" />
        </el-form-item>
        <template v-if="bindingForm.storeType === 'APP_STORE'">
          <el-form-item label="Issuer ID">
            <el-input v-model.trim="bindingForm.issuerId" autocomplete="off" />
          </el-form-item>
          <el-form-item label="Key ID">
            <el-input v-model.trim="bindingForm.keyId" autocomplete="off" />
          </el-form-item>
          <el-form-item label=".p8 私钥">
            <el-input
              v-model="bindingForm.privateKey"
              type="textarea"
              :rows="6"
              autocomplete="off"
              placeholder="粘贴包含 BEGIN/END 标记的完整 PEM 内容"
            />
          </el-form-item>
        </template>
        <template v-else>
          <el-form-item label="Client ID">
            <el-input v-model.trim="bindingForm.clientId" autocomplete="off" />
          </el-form-item>
          <el-form-item label="Client Secret">
            <el-input
              v-model="bindingForm.clientSecret"
              type="password"
              show-password
              autocomplete="new-password"
            />
          </el-form-item>
        </template>
      </el-form>
      <template #footer>
        <el-button @click="bindingDialogVisible = false">取消</el-button>
        <el-button type="primary" :loading="savingBinding" @click="saveBinding">保存绑定</el-button>
      </template>
    </el-dialog>
  </section>
</template>

<script setup lang="ts">
import { onMounted, reactive, ref, watch } from 'vue'
import { ElMessage } from 'element-plus'
import {
  updateAdminApi,
  type StoreMonitoringBinding,
  type StoreMonitoringEvent,
  type StoreMonitoringType,
  type StoreMonitoringVersion,
  type StoreUpdateDraft,
  type StoreVersionState,
} from '@/api/update'
import { formatTime } from '@/utils/date'

const props = defineProps<{ appKey: string }>()

const STORE_DEFINITIONS: ReadonlyArray<{
  storeType: StoreMonitoringType
  label: string
  platformLabel: string
}> = [
  { storeType: 'APP_STORE', label: 'Apple App Store', platformLabel: 'iOS' },
  { storeType: 'HARMONY_APP', label: '鸿蒙应用市场', platformLabel: 'HarmonyOS' },
]

const bindings = ref<StoreMonitoringBinding[]>([])
const loadingBindings = ref(false)
const syncingStore = ref<StoreMonitoringType>()
const selectedBinding = ref<StoreMonitoringBinding>()
const versions = ref<StoreMonitoringVersion[]>([])
const events = ref<StoreMonitoringEvent[]>([])
const resultTab = ref<'versions' | 'events'>('versions')
const loadingVersions = ref(false)
const loadingEvents = ref(false)
const creatingDraftVersionId = ref<string>()
const draftResults = reactive<Record<string, StoreUpdateDraft>>({})

const bindingDialogVisible = ref(false)
const savingBinding = ref(false)
const bindingForm = reactive({
  storeType: 'APP_STORE' as StoreMonitoringType,
  packageIdentifier: '',
  marketUrl: '',
  enabled: true,
  credentialDisplayName: '',
  issuerId: '',
  keyId: '',
  privateKey: '',
  clientId: '',
  clientSecret: '',
})

const loadingNotification = ref(false)
const savingNotification = ref(false)
const notificationForm = reactive({
  emailEnabled: false,
  emailRecipients: [] as string[],
  webhookEnabled: false,
  webhookUrl: '',
  webhookSecret: '',
  webhookSecretConfigured: false,
  eventTypes: [] as string[],
})

function bindingFor(storeType: StoreMonitoringType) {
  return bindings.value.find(binding => binding.storeType === storeType)
}

function storeLabel(storeType?: StoreMonitoringType) {
  return STORE_DEFINITIONS.find(item => item.storeType === storeType)?.label ?? '应用商店'
}

function displayTime(value?: string) {
  return value ? formatTime(value) : '—'
}

function stateLabel(state?: StoreVersionState) {
  const labels: Partial<Record<StoreVersionState, string>> = {
    DISCOVERED: '已发现',
    PREPARING: '准备中',
    SUBMITTED: '已提交',
    WAITING_FOR_REVIEW: '等待审核',
    IN_REVIEW: '审核中',
    REJECTED: '审核被拒',
    APPROVED_PENDING_RELEASE: '已审核待发布',
    RELEASE_SCHEDULED: '已安排发布',
    RELEASE_REQUESTED: '已请求发布',
    PROCESSING_DISTRIBUTION: '分发处理中',
    PARTIALLY_AVAILABLE: '部分地区可用',
    AVAILABLE: '已上架',
    WITHDRAWN: '已撤回',
    REMOVED: '已下架',
    UNKNOWN: '未知',
    SYNC_FAILED: '同步失败',
  }
  return state ? labels[state] ?? state : '—'
}

function stateTagType(state?: StoreVersionState) {
  if (state === 'AVAILABLE') return 'success'
  if (state === 'REJECTED' || state === 'REMOVED' || state === 'SYNC_FAILED') return 'danger'
  if (state === 'IN_REVIEW' || state === 'WAITING_FOR_REVIEW' || state === 'APPROVED_PENDING_RELEASE') {
    return 'warning'
  }
  return 'info'
}

function sourceLabel(source: StoreMonitoringEvent['source']) {
  if (source === 'WEBHOOK') return '官方回调'
  if (source === 'MANUAL') return '人工操作'
  if (source === 'IMPORT') return '历史迁移'
  return '定时轮询'
}

function eventLabel(eventType: string) {
  if (eventType === 'STORE_VERSION_DISCOVERED') return '发现商店版本'
  if (eventType === 'STORE_STATE_CHANGED') return '商店状态变化'
  return eventType
}

async function loadBindings() {
  if (!props.appKey) return
  loadingBindings.value = true
  try {
    const response = await updateAdminApi.listStoreMonitoringBindings(props.appKey)
    bindings.value = response.data.data
    if (selectedBinding.value) {
      selectedBinding.value = bindingFor(selectedBinding.value.storeType)
      if (selectedBinding.value) await loadVersions()
    }
  } finally {
    loadingBindings.value = false
  }
}

function clearCredentialFields() {
  bindingForm.issuerId = ''
  bindingForm.keyId = ''
  bindingForm.privateKey = ''
  bindingForm.clientId = ''
  bindingForm.clientSecret = ''
}

function openBindingDialog(storeType: StoreMonitoringType) {
  const binding = bindingFor(storeType)
  bindingForm.storeType = storeType
  bindingForm.packageIdentifier = binding?.packageIdentifier ?? ''
  bindingForm.marketUrl = binding?.marketUrl ?? ''
  bindingForm.enabled = binding?.enabled ?? true
  bindingForm.credentialDisplayName = ''
  clearCredentialFields()
  bindingDialogVisible.value = true
}

function buildCredential() {
  if (bindingForm.storeType === 'APP_STORE') {
    const anyFilled = bindingForm.issuerId || bindingForm.keyId || bindingForm.privateKey
    if (!anyFilled) return undefined
    if (!bindingForm.issuerId || !bindingForm.keyId || !bindingForm.privateKey) {
      throw new Error('替换 App Store 凭据时必须同时填写 Issuer ID、Key ID 和 .p8 私钥')
    }
    return {
      issuerId: bindingForm.issuerId,
      keyId: bindingForm.keyId,
      privateKey: bindingForm.privateKey,
    }
  }
  const anyFilled = bindingForm.clientId || bindingForm.clientSecret
  if (!anyFilled) return undefined
  if (!bindingForm.clientId || !bindingForm.clientSecret) {
    throw new Error('替换鸿蒙监测凭据时必须同时填写 Client ID 和 Client Secret')
  }
  return {
    clientId: bindingForm.clientId,
    clientSecret: bindingForm.clientSecret,
  }
}

async function saveBinding() {
  if (!bindingForm.packageIdentifier) {
    ElMessage.warning('请填写应用标识')
    return
  }
  savingBinding.value = true
  try {
    const credential = buildCredential()
    if (!bindingFor(bindingForm.storeType) && !credential) {
      ElMessage.warning('首次绑定必须填写完整的监测凭据')
      return
    }
    await updateAdminApi.saveStoreMonitoringBinding(props.appKey, bindingForm.storeType, {
      packageIdentifier: bindingForm.packageIdentifier,
      marketUrl: bindingForm.marketUrl || undefined,
      enabled: bindingForm.enabled,
      credentialDisplayName: bindingForm.credentialDisplayName || undefined,
      ...(credential ? { credential } : {}),
    })
    bindingDialogVisible.value = false
    clearCredentialFields()
    await loadBindings()
    ElMessage.success('商店监测绑定已保存')
  } catch (error) {
    if (error instanceof Error && !('response' in error)) ElMessage.error(error.message)
  } finally {
    savingBinding.value = false
  }
}

async function synchronize(storeType: StoreMonitoringType) {
  syncingStore.value = storeType
  try {
    await updateAdminApi.synchronizeStoreMonitoring(props.appKey, storeType)
    await loadBindings()
    await selectBinding(storeType)
    ElMessage.success('已完成官方商店状态同步')
  } finally {
    syncingStore.value = undefined
  }
}

async function selectBinding(storeType: StoreMonitoringType) {
  selectedBinding.value = bindingFor(storeType)
  resultTab.value = 'versions'
  await loadVersions()
}

async function loadVersions() {
  if (!selectedBinding.value) return
  loadingVersions.value = true
  try {
    const response = await updateAdminApi.listStoreMonitoringVersions(
      props.appKey,
      selectedBinding.value.id,
    )
    versions.value = response.data.data
  } finally {
    loadingVersions.value = false
  }
}

async function loadEvents() {
  if (!selectedBinding.value) return
  loadingEvents.value = true
  try {
    const response = await updateAdminApi.listStoreMonitoringEvents(
      props.appKey,
      selectedBinding.value.id,
    )
    events.value = response.data.data
  } finally {
    loadingEvents.value = false
  }
}

function canCreateUpdateDraft(version: StoreMonitoringVersion) {
  return version.state === 'AVAILABLE' && version.chinaAvailable
}

async function createUpdateDraft(version: StoreMonitoringVersion) {
  if (!selectedBinding.value || !canCreateUpdateDraft(version) || draftResults[version.id]) return
  creatingDraftVersionId.value = version.id
  try {
    const response = await updateAdminApi.createStoreUpdateDraft(
      props.appKey,
      selectedBinding.value.id,
      version.id,
    )
    draftResults[version.id] = response.data.data
    const result = response.data.data
    ElMessage.success(
      result.publishStatus === 'DRAFT'
        ? `已创建 Xuqm 更新草稿：${result.appVersionId}`
        : `该商店版本已关联 Xuqm 版本：${result.appVersionId}`,
    )
  } finally {
    creatingDraftVersionId.value = undefined
  }
}

function handleResultTabChange(name: string | number) {
  if (name === 'events') void loadEvents()
}

async function loadNotificationPolicy() {
  if (!props.appKey) return
  loadingNotification.value = true
  try {
    const response = await updateAdminApi.getStoreNotificationPolicy(props.appKey)
    const policy = response.data.data
    notificationForm.emailEnabled = policy.emailEnabled
    notificationForm.emailRecipients = [...policy.emailRecipients]
    notificationForm.webhookEnabled = policy.webhookEnabled
    notificationForm.webhookUrl = policy.webhookUrl ?? ''
    notificationForm.webhookSecret = ''
    notificationForm.webhookSecretConfigured = policy.webhookSecretConfigured
    notificationForm.eventTypes = [...policy.eventTypes]
  } finally {
    loadingNotification.value = false
  }
}

async function saveNotificationPolicy() {
  if (notificationForm.emailEnabled && notificationForm.emailRecipients.length === 0) {
    ElMessage.warning('启用邮件通知时至少添加一个收件人')
    return
  }
  if (notificationForm.webhookEnabled && !notificationForm.webhookUrl) {
    ElMessage.warning('启用 Webhook 通知时必须填写地址')
    return
  }
  if (
    notificationForm.webhookEnabled &&
    !notificationForm.webhookSecretConfigured &&
    !notificationForm.webhookSecret
  ) {
    ElMessage.warning('首次启用 Webhook 通知时必须填写签名密钥')
    return
  }
  savingNotification.value = true
  try {
    const response = await updateAdminApi.saveStoreNotificationPolicy(props.appKey, {
      emailEnabled: notificationForm.emailEnabled,
      emailRecipients: notificationForm.emailRecipients,
      webhookEnabled: notificationForm.webhookEnabled,
      webhookUrl: notificationForm.webhookUrl || undefined,
      webhookSecret: notificationForm.webhookSecret || undefined,
      eventTypes: notificationForm.eventTypes,
    })
    notificationForm.webhookSecret = ''
    notificationForm.webhookSecretConfigured = response.data.data.webhookSecretConfigured
    notificationForm.eventTypes = [...response.data.data.eventTypes]
    ElMessage.success('通知策略已保存')
  } finally {
    savingNotification.value = false
  }
}

async function initialize() {
  await Promise.all([loadBindings(), loadNotificationPolicy()])
}

watch(() => props.appKey, () => {
  selectedBinding.value = undefined
  versions.value = []
  events.value = []
  void initialize()
})

onMounted(() => void initialize())
</script>

<style scoped>
.store-monitoring {
  min-width: 0;
}

.section-heading {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 22px 0 14px;
}

.section-heading h3 {
  margin: 0;
  font-size: 17px;
}

.section-heading p {
  margin: 5px 0 0;
  color: var(--el-text-color-secondary);
  font-size: 13px;
}

.binding-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.binding-card {
  min-width: 0;
}

.card-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.card-subtitle,
.event-meta,
.form-tip,
.event-tip {
  color: var(--el-text-color-secondary);
  font-size: 12px;
}

.card-subtitle {
  margin-top: 4px;
}

.card-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 16px;
}

.card-actions :deep(.el-button + .el-button) {
  margin-left: 0;
}

.sync-error,
.dialog-alert {
  margin-top: 12px;
}

.result-heading {
  margin-top: 28px;
}

.timeline-wrap {
  min-height: 140px;
  padding: 12px 6px 0;
}

.event-title {
  font-weight: 600;
}

.event-state {
  margin-top: 6px;
}

.event-meta {
  margin-top: 6px;
}

.draft-result {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
  font-size: 12px;
  word-break: break-all;
}

.ineligible-draft {
  color: var(--el-text-color-placeholder);
  font-size: 12px;
}

.draft-hint {
  margin-top: 14px;
}

.notification-form {
  max-width: 820px;
}

.full-width {
  width: 100%;
}

.form-tip {
  margin-left: 10px;
}

.event-tip {
  width: 100%;
  margin-top: 4px;
}

@media (max-width: 900px) {
  .binding-grid {
    grid-template-columns: 1fr;
  }

  .section-heading {
    align-items: flex-start;
  }
}
</style>
