<script setup>
import { computed, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'

import {
  addAccount,
  batchStartAccounts,
  batchStopAccounts,
  clearAccounts,
  deleteAccount as apiDeleteAccount,
  fetchAccounts,
  startAccount,
  stopAccount,
  takeScreenshot,
  updateAccount,
  updateAccountRemark,
} from '../api/accounts'
import { fetchRunStats } from '../api/stats'
import { useSocket } from '../composables/useSocket'
import { useUserStore } from '../stores/user'

const userStore = useUserStore()
const socket = useSocket()

const loading = ref(false)
const statsLoading = ref(false)
const stats = reactive({
  today_completed: 0,
  today_failed: 0,
  current_running: 0,
  today_items: 0,
  today_attachments: 0,
})

const accountsById = reactive({})
const selectedIds = ref([])
const browseTypeById = reactive({})

const batchBrowseType = ref('应读')
const SCREENSHOT_TOGGLE_STORAGE_KEY = 'zsglpt:accounts:enable_screenshot'
function loadEnableScreenshot() {
  try {
    const raw = window.localStorage.getItem(SCREENSHOT_TOGGLE_STORAGE_KEY)
    if (raw === '0' || raw === 'false') return false
    if (raw === '1' || raw === 'true') return true
  } catch {
    // ignore
  }
  return true
}
const batchEnableScreenshot = ref(loadEnableScreenshot())
watch(batchEnableScreenshot, (value) => {
  try {
    window.localStorage.setItem(SCREENSHOT_TOGGLE_STORAGE_KEY, value ? '1' : '0')
  } catch {
    // ignore
  }
})

const addOpen = ref(false)
const editOpen = ref(false)
const upgradeOpen = ref(false)

const addForm = reactive({
  username: '',
  password: '',
  remark: '',
})

const editForm = reactive({
  id: '',
  username: '',
  password: '',
  remark: '',
  originalRemark: '',
})

const browseTypeOptions = [
  { label: '应读', value: '应读' },
  { label: '注册前未读', value: '注册前未读' },
]

const accounts = computed(() =>
  Object.values(accountsById).sort((a, b) => String(a.username || '').localeCompare(String(b.username || ''), 'zh-CN')),
)
const accountCount = computed(() => accounts.value.length)
const accountLimit = computed(() => (userStore.isVip ? 999 : 3))

const selectedCount = computed(() => selectedIds.value.length)
const allSelected = computed(() => accountCount.value > 0 && selectedCount.value === accountCount.value)

const showUpgradeBanner = computed(() => !userStore.isVip)

function normalizeAccountPayload(acc) {
  const base = accountsById[acc.id] || {}
  accountsById[acc.id] = { ...base, ...acc }
}

function replaceAccounts(list) {
  const nextList = Array.isArray(list) ? list : []
  const nextIds = new Set(nextList.map((acc) => String(acc?.id || '')))

  for (const existingId of Object.keys(accountsById)) {
    if (!nextIds.has(existingId)) delete accountsById[existingId]
  }
  for (const acc of nextList) normalizeAccountPayload(acc)
}

function ensureBrowseTypeDefaults() {
  for (const acc of accounts.value) {
    if (!browseTypeById[acc.id]) browseTypeById[acc.id] = '应读'
  }
}

watch(accounts, ensureBrowseTypeDefaults, { immediate: true })

function toggleSelectAll(value) {
  if (value) selectedIds.value = accounts.value.map((a) => a.id)
  else selectedIds.value = []
}

function requireVip(featureName) {
  if (userStore.isVip) return true
  ElMessage.warning(`${featureName}是VIP专属功能`)
  upgradeOpen.value = true
  return false
}

function toPercent(acc) {
  const total = Number(acc.total_items || 0)
  const done = Number(acc.progress_items || 0)
  if (!total) return 0
  return Math.max(0, Math.min(100, Math.round((done / total) * 100)))
}

function statusTagType(status = '') {
  const text = String(status)
  if (text.includes('已完成') || text.includes('完成')) return 'success'
  if (text.includes('失败') || text.includes('错误') || text.includes('异常') || text.includes('登录失败')) return 'danger'
  if (text.includes('排队') || text.includes('运行') || text.includes('截图')) return 'warning'
  return 'info'
}

function showRuntimeProgress(acc) {
  if (!acc?.is_running) return false
  const statusText = String(acc.status || '')
  const detailText = String(acc.detail_status || '')

  if (!statusText || statusText === '未开始') return false

  // 仅在“运行中”展示进度；排队/等待等非执行阶段不展示
  if (!statusText.includes('运行')) return false

  // 浏览完成后（包含等待截图/截图中等阶段）不再展示进度条与内容/附件
  if (statusText.includes('截图') || statusText.includes('等待截图')) return false
  if (detailText.includes('截图') || detailText.includes('等待截图')) return false
  if (detailText.includes('浏览完成') || detailText.includes('任务完成')) return false
  if (statusText.includes('已完成')) return false

  return true
}

async function refreshStats(options = {}) {
  const silent = Boolean(options?.silent)
  if (!silent) statsLoading.value = true
  try {
    const data = await fetchRunStats()
    stats.today_completed = Number(data?.today_completed || 0)
    stats.today_failed = Number(data?.today_failed || 0)
    stats.current_running = Number(data?.current_running || 0)
    stats.today_items = Number(data?.today_items || 0)
    stats.today_attachments = Number(data?.today_attachments || 0)
  } catch (e) {
    if (e?.response?.status === 401) window.location.href = '/login'
  } finally {
    if (!silent) statsLoading.value = false
  }
}

async function refreshAccounts() {
  loading.value = true
  try {
    const list = await fetchAccounts({ refresh: true })
    replaceAccounts(list)
  } catch (e) {
    if (e?.response?.status === 401) window.location.href = '/login'
  } finally {
    loading.value = false
  }
}

async function onStart(acc) {
  try {
    await startAccount(acc.id, { browse_type: browseTypeById[acc.id] || '应读', enable_screenshot: batchEnableScreenshot.value })
  } catch (e) {
    const data = e?.response?.data
    ElMessage.error(data?.error || '启动失败')
  }
}

async function onStop(acc) {
  try {
    await stopAccount(acc.id)
  } catch (e) {
    const data = e?.response?.data
    ElMessage.error(data?.error || '停止失败')
  }
}

async function onScreenshot(acc) {
  try {
    await takeScreenshot(acc.id, { browse_type: browseTypeById[acc.id] || '应读' })
    ElMessage.success('已提交截图')
  } catch (e) {
    const data = e?.response?.data
    ElMessage.error(data?.error || '截图失败')
  }
}

async function onDelete(acc) {
  try {
    await ElMessageBox.confirm(`确定要删除账号「${acc.username}」吗？`, '删除账号', {
      confirmButtonText: '删除',
      cancelButtonText: '取消',
      type: 'warning',
    })
  } catch {
    return
  }

  try {
    const res = await apiDeleteAccount(acc.id)
    if (res?.success) {
      delete accountsById[acc.id]
      selectedIds.value = selectedIds.value.filter((id) => id !== acc.id)
      ElMessage.success('已删除')
      await refreshStats()
    } else {
      ElMessage.error(res?.error || '删除失败')
    }
  } catch (e) {
    const data = e?.response?.data
    ElMessage.error(data?.error || '删除失败')
  }
}

function openAdd() {
  addForm.username = ''
  addForm.password = ''
  addForm.remark = ''
  addOpen.value = true
}

async function submitAdd() {
  const username = addForm.username.trim()
  if (!username || !addForm.password.trim()) {
    ElMessage.error('用户名和密码不能为空')
    return
  }

  try {
    await addAccount({
      username,
      password: addForm.password,
      remember: true,
      remark: addForm.remark.trim(),
    })
    ElMessage.success('添加成功')
    addOpen.value = false
    await refreshStats()
  } catch (e) {
    const data = e?.response?.data
    ElMessage.error(data?.error || '添加失败')
  }
}

function openEdit(acc) {
  editForm.id = acc.id
  editForm.username = acc.username
  editForm.password = ''
  editForm.remark = String(acc.remark || '')
  editForm.originalRemark = String(acc.remark || '')
  editOpen.value = true
}

async function submitEdit() {
  if (!editForm.id) return
  const newPassword = editForm.password.trim()
  const remarkText = editForm.remark.trim()

  if (!newPassword && remarkText === editForm.originalRemark) {
    ElMessage.info('没有修改')
    editOpen.value = false
    return
  }

  try {
    if (newPassword) {
      const res = await updateAccount(editForm.id, { password: newPassword, remember: true })
      if (res?.account) normalizeAccountPayload(res.account)
    }

    if (remarkText !== editForm.originalRemark) {
      await updateAccountRemark(editForm.id, { remark: remarkText })
      normalizeAccountPayload({ id: editForm.id, remark: remarkText })
    }

    ElMessage.success('已更新')
    editOpen.value = false
  } catch (e) {
    const data = e?.response?.data
    ElMessage.error(data?.error || '更新失败')
  }
}

async function batchStart() {
  if (!requireVip('批量操作')) return
  if (selectedIds.value.length === 0) {
    ElMessage.warning('请先选择账号')
    return
  }

  try {
    const res = await batchStartAccounts({
      account_ids: selectedIds.value,
      browse_type: batchBrowseType.value,
      enable_screenshot: batchEnableScreenshot.value,
    })
    ElMessage.success(`已启动 ${res?.started_count || 0} 个账号`)
  } catch (e) {
    const data = e?.response?.data
    ElMessage.error(data?.error || '操作失败')
  }
}

async function batchStop() {
  if (!requireVip('批量操作')) return
  if (selectedIds.value.length === 0) {
    ElMessage.warning('请先选择账号')
    return
  }

  try {
    const res = await batchStopAccounts({ account_ids: selectedIds.value })
    ElMessage.success(`已停止 ${res?.stopped_count || 0} 个账号`)
  } catch (e) {
    const data = e?.response?.data
    ElMessage.error(data?.error || '操作失败')
  }
}

async function startAll() {
  if (!requireVip('全部启动')) return
  if (accounts.value.length === 0) {
    ElMessage.warning('没有账号')
    return
  }

  try {
    await ElMessageBox.confirm('确定要启动全部账号吗？', '全部启动', {
      confirmButtonText: '启动',
      cancelButtonText: '取消',
      type: 'warning',
    })
  } catch {
    return
  }

  try {
    const res = await batchStartAccounts({
      account_ids: accounts.value.map((a) => a.id),
      browse_type: batchBrowseType.value,
      enable_screenshot: batchEnableScreenshot.value,
    })
    ElMessage.success(`已启动 ${res?.started_count || 0} 个账号`)
  } catch (e) {
    const data = e?.response?.data
    ElMessage.error(data?.error || '操作失败')
  }
}

async function stopAll() {
  if (!requireVip('全部停止')) return
  if (accounts.value.length === 0) {
    ElMessage.warning('没有账号')
    return
  }

  try {
    await ElMessageBox.confirm('确定要停止全部账号吗？', '全部停止', {
      confirmButtonText: '停止',
      cancelButtonText: '取消',
      type: 'warning',
    })
  } catch {
    return
  }

  try {
    const res = await batchStopAccounts({ account_ids: accounts.value.map((a) => a.id) })
    ElMessage.success(`已停止 ${res?.stopped_count || 0} 个账号`)
  } catch (e) {
    const data = e?.response?.data
    ElMessage.error(data?.error || '操作失败')
  }
}

async function clearAll() {
  if (accounts.value.length === 0) {
    ElMessage.warning('没有账号')
    return
  }

  try {
    await ElMessageBox.confirm('确定要清空所有账号吗？此操作不可恢复！', '清空账号', {
      confirmButtonText: '继续',
      cancelButtonText: '取消',
      type: 'warning',
    })
    await ElMessageBox.confirm('再次确认：真的要删除所有账号吗？', '二次确认', {
      confirmButtonText: '删除',
      cancelButtonText: '取消',
      type: 'warning',
    })
  } catch {
    return
  }

  try {
    const res = await clearAccounts()
    if (res?.success) {
      replaceAccounts([])
      selectedIds.value = []
      ElMessage.success('已清空所有账号')
      await refreshStats()
      return
    }
    ElMessage.error(res?.error || '操作失败')
  } catch (e) {
    const data = e?.response?.data
    ElMessage.error(data?.error || '操作失败')
  }
}

function bindSocket() {
  const onAccountsList = (list) => {
    replaceAccounts(list)
  }
  const onAccountUpdate = (acc) => {
    normalizeAccountPayload(acc)
  }
  const onTaskProgress = (payload) => {
    if (!payload?.account_id) return
    normalizeAccountPayload({
      id: payload.account_id,
      detail_status: payload.stage || '',
      total_items: payload.total_items,
      progress_items: payload.browsed_items,
      total_attachments: payload.total_attachments,
      progress_attachments: payload.viewed_attachments,
      elapsed_seconds: payload.elapsed_seconds,
      elapsed_display: payload.elapsed_display,
    })
  }

  socket.on('accounts_list', onAccountsList)
  socket.on('account_update', onAccountUpdate)
  socket.on('task_progress', onTaskProgress)

  if (!socket.connected) socket.connect()

  return () => {
    socket.off('accounts_list', onAccountsList)
    socket.off('account_update', onAccountUpdate)
    socket.off('task_progress', onTaskProgress)
  }
}

let unbindSocket = null
let statsTimer = null

const shouldPollStats = computed(() => {
  // 仅在“真正执行中”才轮询（排队中不轮询，避免空转导致页面闪烁）
  return accounts.value.some((acc) => {
    if (!acc?.is_running) return false
    const statusText = String(acc.status || '')
    if (statusText.includes('排队')) return false
    return true
  })
})

function stopStatsPolling() {
  if (!statsTimer) return
  window.clearInterval(statsTimer)
  statsTimer = null
}

function startStatsPolling() {
  if (statsTimer) return
  statsTimer = window.setInterval(() => refreshStats({ silent: true }), 10_000)
}

function syncStatsPolling(prevRunning = null) {
  const running = shouldPollStats.value

  // 任务从“运行中 -> 空闲”时，补拉一次统计以确保最终数据正确，再停止轮询
  if (prevRunning === true && running === false) refreshStats({ silent: true }).catch(() => {})

  if (running) startStatsPolling()
  else stopStatsPolling()
}

watch(shouldPollStats, (running, prevRunning) => {
  syncStatsPolling(prevRunning)
})

onMounted(async () => {
  if (!userStore.vipInfo) {
    userStore.refreshVipInfo().catch(() => {
      window.location.href = '/login'
    })
  }

  unbindSocket = bindSocket()

  await refreshAccounts()
  await refreshStats()
  syncStatsPolling()
})

onBeforeUnmount(() => {
  if (unbindSocket) unbindSocket()
  stopStatsPolling()
})
</script>

<template>
  <div class="page">
    <el-row :gutter="12" class="stats-row">
      <el-col :xs="12" :sm="8" :md="4">
        <el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
          <div class="stat-label app-muted">今日完成</div>
          <div class="stat-value">{{ stats.today_completed }}</div>
        </el-card>
      </el-col>
      <el-col :xs="12" :sm="8" :md="4">
        <el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
          <div class="stat-label app-muted">今日失败</div>
          <div class="stat-value">{{ stats.today_failed }}</div>
        </el-card>
      </el-col>
      <el-col :xs="12" :sm="8" :md="4">
        <el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
          <div class="stat-label app-muted">运行中</div>
          <div class="stat-value">{{ stats.current_running }}</div>
        </el-card>
      </el-col>
      <el-col :xs="12" :sm="8" :md="4">
        <el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
          <div class="stat-label app-muted">浏览内容</div>
          <div class="stat-value">{{ stats.today_items }}</div>
        </el-card>
      </el-col>
      <el-col :xs="12" :sm="8" :md="4">
        <el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
          <div class="stat-label app-muted">查看附件</div>
          <div class="stat-value">{{ stats.today_attachments }}</div>
        </el-card>
      </el-col>
      <el-col :xs="12" :sm="8" :md="4">
        <el-card shadow="never" class="stat-card" :body-style="{ padding: '14px' }">
          <div class="stat-label app-muted">账号数</div>
          <div class="stat-value">
            {{ accountCount }}<span class="stat-suffix app-muted">/ {{ userStore.isVip ? '∞' : accountLimit }}</span>
          </div>
        </el-card>
      </el-col>
    </el-row>

    <el-alert
      v-if="showUpgradeBanner"
      type="info"
      show-icon
      :closable="false"
      class="upgrade-banner"
      title="升级 VIP，解锁更多功能：无限账号 · 优先排队 · 定时任务 · 批量操作"
    >
      <template #default>
        <div class="upgrade-actions">
          <el-button type="primary" plain @click="upgradeOpen = true">了解VIP特权</el-button>
        </div>
      </template>
    </el-alert>

    <el-card shadow="never" class="panel" :body-style="{ padding: '14px' }">
      <div class="panel-head">
        <div class="panel-title">账号管理</div>
        <div class="panel-actions">
          <el-button :loading="loading" @click="refreshAccounts">刷新</el-button>
          <el-button type="primary" @click="openAdd">添加账号</el-button>
        </div>
      </div>

      <div class="toolbar">
        <div class="toolbar-left">
          <el-checkbox :model-value="allSelected" @change="toggleSelectAll">全选</el-checkbox>
          <span class="app-muted">已选 {{ selectedCount }} 个</span>
        </div>

        <div class="toolbar-middle">
          <el-select v-model="batchBrowseType" size="small" style="width: 120px">
            <el-option v-for="opt in browseTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
          </el-select>
          <el-switch v-model="batchEnableScreenshot" inline-prompt active-text="截图" inactive-text="不截图" />
        </div>

        <div class="toolbar-right">
          <el-button type="primary" @click="batchStart">批量启动</el-button>
          <el-button @click="batchStop">批量停止</el-button>
          <el-button type="success" plain @click="startAll">全部启动</el-button>
          <el-button type="danger" plain @click="stopAll">全部停止</el-button>
          <el-button type="danger" text @click="clearAll">清空</el-button>
        </div>
      </div>

      <el-skeleton v-if="loading" :rows="5" animated />
      <template v-else>
        <el-empty v-if="accounts.length === 0" description="暂无账号，点击右上角添加" />
        <div v-else class="grid">
          <el-card v-for="acc in accounts" :key="acc.id" shadow="never" class="account-card" :body-style="{ padding: '14px' }">
            <div class="card-top">
              <el-checkbox-group v-model="selectedIds" class="card-check">
                <el-checkbox :value="acc.id" />
              </el-checkbox-group>

              <div class="card-main">
            <div class="card-title">
              <span class="card-name">{{ acc.username }}</span>
              <el-tag size="small" :type="statusTagType(acc.status)" effect="light">{{ acc.status }}</el-tag>
            </div>
	            <div class="card-sub app-muted">
	              {{ acc.remark || '—' }}
	              <span v-if="showRuntimeProgress(acc) && acc.detail_status"> · {{ acc.detail_status }}</span>
	              <span v-if="showRuntimeProgress(acc) && acc.elapsed_display"> · {{ acc.elapsed_display }}</span>
	              <span v-if="String(acc.status || '').includes('排队') && acc.queue_ahead != null">
	                · 前面 {{ acc.queue_ahead }} 个 · 运行中 {{ acc.queue_running_total ?? 0 }} 个
	              </span>
	              <span v-else-if="showRuntimeProgress(acc) && (acc.queue_pending_total != null || acc.queue_running_total != null)">
	                · 排队 {{ acc.queue_pending_total ?? 0 }} 个 · 运行中 {{ acc.queue_running_total ?? 0 }} 个
	              </span>
	            </div>
	          </div>
	        </div>

	            <div v-if="showRuntimeProgress(acc)" class="progress">
	              <el-progress :percentage="toPercent(acc)" :stroke-width="10" :show-text="false" />
	              <div class="progress-meta app-muted">
	                <span>内容 {{ acc.progress_items || 0 }}</span>
	              </div>
	            </div>

            <div class="card-controls">
              <el-select v-model="browseTypeById[acc.id]" size="small" style="width: 130px">
                <el-option v-for="opt in browseTypeOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
              </el-select>

              <div class="card-buttons">
                <el-button size="small" type="primary" :disabled="acc.is_running" @click="onStart(acc)">启动</el-button>
                <el-button size="small" :disabled="!acc.is_running" @click="onStop(acc)">停止</el-button>
                <el-button size="small" :disabled="acc.is_running" @click="onScreenshot(acc)">截图</el-button>
                <el-button size="small" :disabled="acc.is_running" @click="openEdit(acc)">编辑</el-button>
                <el-button size="small" type="danger" text @click="onDelete(acc)">删除</el-button>
              </div>
            </div>
          </el-card>
        </div>
      </template>
    </el-card>

    <el-dialog v-model="addOpen" title="添加账号" width="min(560px, 92vw)">
      <el-form label-position="top">
        <el-form-item label="账号">
          <el-input v-model="addForm.username" placeholder="请输入账号" autocomplete="off" />
        </el-form-item>
        <el-form-item label="密码">
          <el-input v-model="addForm.password" type="password" show-password placeholder="请输入密码" autocomplete="off" />
        </el-form-item>
        <el-form-item label="备注（可选，最多200字）">
          <el-input v-model="addForm.remark" type="textarea" :rows="3" maxlength="200" show-word-limit placeholder="例如：部门/用途" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="addOpen = false">取消</el-button>
        <el-button type="primary" @click="submitAdd">添加</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="editOpen" title="编辑账号" width="min(560px, 92vw)">
      <el-form label-position="top">
        <el-form-item label="账号">
          <el-input v-model="editForm.username" disabled />
        </el-form-item>
        <el-form-item label="新密码（可选）">
          <el-input
            v-model="editForm.password"
            type="password"
            show-password
            placeholder="留空表示不修改密码"
            autocomplete="off"
          />
        </el-form-item>
        <el-form-item label="备注（可选，最多200字）">
          <el-input v-model="editForm.remark" type="textarea" :rows="3" maxlength="200" show-word-limit placeholder="例如：部门/用途" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="editOpen = false">取消</el-button>
        <el-button type="primary" @click="submitEdit">保存</el-button>
      </template>
    </el-dialog>

    <el-dialog v-model="upgradeOpen" title="VIP 特权" width="min(560px, 92vw)">
      <el-alert
        type="info"
        :closable="false"
        title="升级 VIP 后可解锁：无限账号、优先排队、定时任务、批量操作。"
        show-icon
      />
      <div class="vip-body">
        <div class="vip-tip app-muted">升级方式：请通过“反馈”联系管理员开通（与后台一致）。</div>
      </div>
      <template #footer>
        <el-button type="primary" @click="upgradeOpen = false">我知道了</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<style scoped>
.page {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.stat-card,
.panel {
  border-radius: var(--app-radius);
  border: 1px solid var(--app-border);
}

.stat-label {
  font-size: 12px;
}

.stat-value {
  margin-top: 6px;
  font-size: 22px;
  font-weight: 900;
  letter-spacing: 0.2px;
}

.stat-suffix {
  margin-left: 6px;
  font-size: 12px;
  font-weight: 600;
}

.upgrade-banner {
  border-radius: var(--app-radius);
  border: 1px solid var(--app-border);
}

.upgrade-actions {
  margin-top: 10px;
}

.panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
  flex-wrap: wrap;
}

.panel-title {
  font-size: 16px;
  font-weight: 900;
}

.panel-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 10px;
  border: 1px dashed rgba(17, 24, 39, 0.14);
  border-radius: 12px;
  background: rgba(246, 247, 251, 0.6);
}

.toolbar-left,
.toolbar-middle,
.toolbar-right {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.toolbar-right {
  margin-left: auto;
  justify-content: flex-end;
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 12px;
  align-items: start;
}

.account-card {
  border-radius: 14px;
  border: 1px solid var(--app-border);
}

.card-top {
  display: flex;
  gap: 10px;
}

.card-check {
  padding-top: 2px;
}

.card-main {
  min-width: 0;
  flex: 1;
}

.card-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.card-name {
  font-size: 14px;
  font-weight: 900;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.card-sub {
  margin-top: 6px;
  font-size: 12px;
  line-height: 1.4;
  word-break: break-word;
}

.progress {
  margin-top: 12px;
}

.progress-meta {
  margin-top: 6px;
  display: flex;
  justify-content: space-between;
  gap: 10px;
  font-size: 12px;
}

.card-controls {
  margin-top: 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.card-buttons {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.vip-body {
  padding: 12px 0 0;
}

.vip-tip {
  margin-top: 10px;
  font-size: 13px;
  line-height: 1.6;
}

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

@media (max-width: 768px) {
  .panel-actions {
    width: 100%;
    justify-content: flex-end;
  }

  .toolbar-left,
  .toolbar-middle,
  .toolbar-right {
    width: 100%;
  }

  .toolbar-right {
    margin-left: 0;
    justify-content: flex-end;
  }
}
</style>
