<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useI18n } from 'vue-i18n'
import { get, post, put } from '@/utils/request'
import request from '@/utils/request'
import { useCopyTradingStore } from '@/stores/copyTrading'
import { useAuthStore } from '@/stores/auth'
import { useI18nStore } from '@/stores/i18n'
import { useToast } from '@/composables/useToast'
import { cmsLang as resolveCmsLang } from '@/utils/backendLang'

const router = useRouter()
const copyTradingStore = useCopyTradingStore()
const authStore = useAuthStore()
const { t, locale } = useI18n()
const toast = useToast()
const i18nStore = useI18nStore()

function cmsLang(): string {
  return resolveCmsLang(i18nStore.current)
}

/** 图表/列表时间格式化用 Intl */
function intlLocaleForApp(loc: string): string {
  const map: Record<string, string> = {
    'zh-CN': 'zh-CN',
    'zh-TW': 'zh-TW',
    en: 'en-US',
    ko: 'ko-KR',
    ja: 'ja-JP',
    hi: 'hi-IN',
    id: 'id-ID',
  }
  if (map[loc]) {
    return map[loc]
  }
  return loc.includes('-') ? loc : `${loc}-${String(loc).toUpperCase()}`
}

function normalizeMarginMode(raw: unknown): string {
  const s = String(raw ?? '').trim()
  const lower = s.toLowerCase()
  if (!s || s === '全仓' || lower === 'cross' || s === '全倉') {
    return t('copyTrade.marginCrossMode')
  }
  if (s === '逐仓' || lower === 'isolated') {
    return t('copyTrade.marginIsolatedMode')
  }
  return s
}

// ── Types ──────────────────────────────────────────────────────────────────
interface CustomerInfo {
  id: string | number
  memberId: string | number
  nickName: string
  avatar: string | null
  description: string
  traderStatus: number  // 0=普通用户, 15=申请中, 20=带单员
}

interface Tag {
  id: string | number
  tagName: string
  selected?: boolean
}

interface Follower {
  id: string | number
  memberId: string | number
  name: string
  avatar: string | null
  balance: number           // 账户权益
  totalProfitSharing: number  // 累计分润
  lastProfitSharing: number   // 上期分润收益
  followTime: string          // "yyyy-MM-dd HH:mm:ss" formatted string from backend
}

interface LeadPosition {
  id: string | number
  symbol: string
  direction: number
  positionType: string  // 全仓 | 逐仓
  openPrice: number
  closePrice: number
  amount: number
  lever: number
  profit: number
  profitRate: number
  openTime: number
  closeTime?: number
}

// ── State ──────────────────────────────────────────────────────────────────
type Tab = 'followers' | 'current' | 'history' | 'settings'
const activeTab = ref<Tab>('followers')

const customer        = ref<CustomerInfo | null>(null)
const customerLoading = ref(true)
const applying        = ref(false)
const applyError      = ref('')

// Apply conditions (loaded for non-trader, non-applying users)
const conditionsLoaded   = ref(false)
const MIN_ASSET          = 1000         // hardcoded per app logic
const userContractBal    = ref(0)       // user's contract wallet balance
const userFollowingCount = ref(0)       // how many traders user currently follows
const agreedToTerms      = ref(false)

// Trader agreement modal
const showAgreement      = ref(false)
const agreementContent   = ref('')
const agreementLoading   = ref(false)

interface TraderInfo {
  following: number
  maxFollow: number
  registerDays: number
  moneyStrength: string
  profitAmount: number
  followCustomer: number
  tradingDays: number
  levelName: string  // e.g. "初级" "中级" "高级"
}
const traderInfo = ref<TraderInfo | null>(null)

// Canonical key format (no slashes/dashes). API may return "BTC/USDT" → normalized to "BTCUSDT"
const DEFAULT_SYMBOLS = ['BTCUSDT', 'ETHUSDT']
const SYMBOL_LABELS: Record<string, string> = { BTCUSDT: 'BTC/USDT', ETHUSDT: 'ETH/USDT' }
const normSym = (s: string) => s.toUpperCase().replace(/[/\-_ ]/g, '')

const allTags         = ref<Tag[]>([])
const myTags          = ref<Tag[]>([])
const mySymbols       = ref<string[]>([])

const followers       = ref<Follower[]>([])
const followersLoading = ref(false)

const positions       = ref<LeadPosition[]>([])
const posLoading      = ref(false)
const historyOrders   = ref<LeadPosition[]>([])
const histLoading     = ref(false)

// Settings form
const settingsForm = ref({
  nickName: '',
  description: '',
})
const settingsLoading = ref(false)
const settingsError   = ref('')
const settingsSuccess = ref(false)

// Symbol saving
const symbolsLoading = ref(false)
const symbolsSuccess = ref(false)

// Cancel trader
const cancelLoading   = ref(false)

// Avatar load error — fall back to initials when image 403s or fails
const avatarLoadError   = ref(false)
const avatarUploading   = ref(false)
const avatarUploadError = ref('')


// ── Computed ───────────────────────────────────────────────────────────────
// Flutter 约定：trader 字段 20=带单员，15=申请中
const isTrader   = computed(() => customer.value?.traderStatus === 20)
const isApplying = computed(() => customer.value?.traderStatus === 15)

const condBalancePassed   = computed(() => userContractBal.value >= MIN_ASSET)
const condNoFollowPassed  = computed(() => userFollowingCount.value === 0)
const allConditionsPassed = computed(() => condBalancePassed.value && condNoFollowPassed.value)

// ── Mappers ────────────────────────────────────────────────────────────────
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function mapCustomer(r: any): CustomerInfo {
  // 后端返回的是 trader 字段（不是 traderStatus），值 20=带单员，15=申请中
  const traderVal = parseInt(r.trader ?? r.traderStatus ?? r.traderLevel ?? '0', 10) || 0
  return {
    id: r.id ?? r.customerId ?? Math.random(),
    memberId: r.memberId ?? r.id,
    nickName: r.nickName ?? r.nickname ?? r.name ?? t('copyTrade.lead.defaultUser'),
    avatar: r.avatar ?? r.headImg ?? null,
    description: r.description ?? r.intro ?? '',
    traderStatus: traderVal,
  }
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function mapFollower(r: any): Follower {
  return {
    id: r.id ?? Math.random(),
    memberId: r.memberId ?? r.customerId,
    name: r.nickname ?? r.nickName ?? r.name ?? t('copyTrade.lead.defaultFollower'),
    avatar: r.avatar ?? r.headImg ?? null,
    balance:            parseFloat(r.balance ?? '0') || 0,
    totalProfitSharing: parseFloat(r.totalProfitSharing ?? '0') || 0,
    lastProfitSharing:  parseFloat(r.lastProfitSharing ?? '0') || 0,
    followTime: r.followTime ?? '',
  }
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function mapPosition(r: any): LeadPosition {
  return {
    id: r.positionId ?? r.id ?? Math.random(),
    symbol: normSym(r.symbol ?? r.coin ?? '') || '—',
    direction: parseInt(r.direction ?? '0', 10),
    positionType: normalizeMarginMode(r.positionType ?? r.marginMode),
    openPrice: parseFloat(r.openPrice ?? r.openRealPrice ?? '0') || 0,
    closePrice: parseFloat(r.closePrice ?? r.currentPrice ?? r.nowPrice ?? '0') || 0,
    amount: parseFloat(r.totalPosition ?? r.amount ?? r.volume ?? '0') || 0,
    lever: parseInt(r.leverage ?? r.lever ?? '1', 10) || 1,
    profit: parseFloat(r.profit ?? r.profitAmount ?? '0') || 0,
    profitRate: parseFloat(r.profitRate ?? r.yieldRate ?? '0') || 0,
    openTime: parseInt(r.openTime ?? r.createTime ?? '0', 10) || 0,
    closeTime: r.closeTime ? parseInt(r.closeTime, 10) : undefined,
  }
}

// ── API ────────────────────────────────────────────────────────────────────
async function loadCustomer() {
  customerLoading.value = true
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const res: any = await get('/follow/customer/')
    // 后端返回 data:[{...}] 数组，取第一个元素
    const item = Array.isArray(res) ? res[0] : res
    customer.value = mapCustomer(item ?? {})
    copyTradingStore.syncIsTraderFromItem(item ?? {})
    settingsForm.value.nickName    = customer.value.nickName
    settingsForm.value.description = customer.value.description
  } catch { /* silent */ } finally {
    customerLoading.value = false
  }
}

async function loadTags() {
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const [allRes, myRes]: any[] = await Promise.all([
      get('/follow/tag/'),
      get('/follow/trader-tag/'),
    ])
    const allList = Array.isArray(allRes) ? allRes : (allRes?.list ?? allRes?.data ?? [])
    const myList  = Array.isArray(myRes)  ? myRes  : (myRes?.list  ?? myRes?.data  ?? [])
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const myIds   = new Set(myList.map((t: any) => String(t.id ?? t.tagId)))
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    allTags.value = allList.map((t: any) => ({
      id: t.id ?? t.tagId,
      tagName: t.tagName ?? t.name ?? t.tag,
      selected: myIds.has(String(t.id ?? t.tagId)),
    }))
    myTags.value = allTags.value.filter(tag => tag.selected)
  } catch { /* silent */ }
}

async function loadTraderInfo() {
  if (!customer.value) return
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const res: any = await put(`/follow/customer/trader-info/${customer.value.id}`)
    const item = Array.isArray(res) ? res[0] : res
    traderInfo.value = {
      following:      parseInt(item?.following ?? '0', 10) || 0,
      maxFollow:      parseInt(item?.maxFollow ?? '0', 10) || 0,
      registerDays:   parseInt(item?.registerDays ?? item?.settledDays ?? '0', 10) || 0,
      moneyStrength:  item?.moneyStrength ?? '--',
      profitAmount:   parseFloat(item?.profitAmount ?? item?.totalFollowProfit ?? '0') || 0,
      followCustomer: parseInt(item?.followCustomer ?? '0', 10) || 0,
      tradingDays:    parseInt(item?.tradingDays ?? '0', 10) || 0,
      levelName:      item?.levelName ?? item?.traderLevelName ?? '',
    }
  } catch { /* silent */ }
}

async function loadMySymbols() {
  if (!customer.value) return
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const res: any = await put(`/follow/trader-symbol/${customer.value.id}`)
    const list = Array.isArray(res) ? res : (res?.list ?? res?.data ?? [])
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    // Normalize to canonical form, e.g. "BTC/USDT" → "BTCUSDT"
    mySymbols.value = list.map((s: any) => normSym(s.symbol ?? s))
  } catch { /* silent */ }
}

async function loadFollowers() {
  followersLoading.value = true
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const res: any = await post('/follow/follow/followers', { currentPage: 1, pageSize: 50 })
    const list = Array.isArray(res) ? res : (res?.records ?? res?.list ?? res?.data ?? [])
    followers.value = list.map(mapFollower)
  } catch { /* silent */ } finally {
    followersLoading.value = false
  }
}

async function loadPositions() {
  if (positions.value.length) return
  posLoading.value = true
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const res: any = await post('/follow/position/lead', {
      traderId: customer.value?.id,
      type: 'current',
      currentPage: 1,
      pageSize: 50,
    })
    const list = Array.isArray(res) ? res : (res?.records ?? res?.list ?? res?.data ?? [])
    positions.value = list.map(mapPosition)
  } catch { /* silent */ } finally {
    posLoading.value = false
  }
}

async function loadHistory() {
  if (historyOrders.value.length) return
  histLoading.value = true
  try {
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const res: any = await post('/follow/position/lead', {
      traderId: customer.value?.id,
      type: 'history',
      currentPage: 1,
      pageSize: 50,
    })
    const list = Array.isArray(res) ? res : (res?.records ?? res?.list ?? res?.data ?? [])
    historyOrders.value = list.map(mapPosition)
  } catch { /* silent */ } finally {
    histLoading.value = false
  }
}

async function loadApplyConditions() {
  if (conditionsLoaded.value) return
  try {
    // App logic: min asset hardcoded to 1000, balance read from contract wallet
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const [walletRes, followRes]: any[] = await Promise.all([
      get('/swap/wallet-new/get'),
      post('/follow/follow/following', { currentPage: 1, pageSize: 1 }),
    ])
    userContractBal.value = parseFloat(
      walletRes?.balance ?? walletRes?.walletBalance ?? walletRes?.availableBalance ?? '0'
    ) || 0
    const list = Array.isArray(followRes) ? followRes : (followRes?.records ?? followRes?.list ?? followRes?.data ?? [])
    userFollowingCount.value = list.length
    conditionsLoaded.value = true
  } catch { /* silent */ }
}

async function openAgreement() {
  showAgreement.value = true
  if (agreementContent.value) return
  agreementLoading.value = true
  try {
    // Same endpoint & params as Flutter app: AnnouncementService.getProtocolList()
    // get(url, params) → axios.get(url, { params }) — pass flat object, NOT { params: {...} }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const res: any = await get('/cms/help/list', { categoryCode: 'FOLLOW_PROTOCOL', lang: cmsLang() })
    const list = Array.isArray(res) ? res : (res?.list ?? res?.data ?? res?.records ?? [])
    if (list.length > 0) {
      // Flutter uses item.content (WebInfoContent.fromJson)
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      const item = list[0] as any
      agreementContent.value = item?.content ?? item?.answer ?? item?.body ?? ''
    }
  } catch { /* silent */ } finally {
    agreementLoading.value = false
  }
}

async function applyTrader() {
  applying.value   = true
  applyError.value = ''
  try {
    const token = localStorage.getItem('token') ?? ''
    await request.get('/follow/customer/apply-trader', { headers: { Authorization: token } })
    await loadCustomer()
  } catch (e: unknown) {
    applyError.value = (e as Error).message || t('copyTrade.lead.applyFailed')
  } finally {
    applying.value = false
  }
}

async function cancelTrader() {
  if (!confirm(t('copyTrade.lead.confirmCancelLead'))) {
    return
  }
  cancelLoading.value = true
  try {
    await get('/follow/customer/cancel-trader')
    await loadCustomer()
  } catch (e: unknown) {
    toast.error((e as Error).message || t('copyTrade.lead.operationFailed'))
  } finally {
    cancelLoading.value = false
  }
}

async function saveSettings() {
  settingsLoading.value = true
  settingsError.value   = ''
  settingsSuccess.value = false
  try {
    await post('/follow/customer/update', settingsForm.value)
    await loadCustomer()
    settingsSuccess.value = true
    setTimeout(() => { settingsSuccess.value = false }, 3000)
  } catch (e: unknown) {
    settingsError.value = (e as Error).message || t('copyTrade.lead.saveFailed')
  } finally {
    settingsLoading.value = false
  }
}

async function saveTags() {
  try {
    const selectedIds = allTags.value.filter(tag => tag.selected).map(tag => tag.id)
    await post('/follow/trader-tag/update', selectedIds)
  } catch { /* silent */ }
}

function toggleSymbol(sym: string) {
  if (mySymbols.value.includes(sym)) {
    mySymbols.value = mySymbols.value.filter(s => s !== sym)
  } else {
    mySymbols.value = [...mySymbols.value, sym]
  }
}

async function saveSymbols() {
  symbolsLoading.value = true
  symbolsSuccess.value = false
  try {
    // Send back in "BTC/USDT" format (label) since that's how the backend stores it
    const toSend = mySymbols.value.map(s => SYMBOL_LABELS[s] ?? s)
    await post('/follow/trader-symbol/update', toSend)
    symbolsSuccess.value = true
    setTimeout(() => { symbolsSuccess.value = false }, 3000)
  } catch { /* silent */ } finally {
    symbolsLoading.value = false
  }
}

async function uploadAvatar(event: Event) {
  const input = event.target as HTMLInputElement
  const file = input.files?.[0]
  if (!file) return
  avatarUploading.value  = true
  avatarUploadError.value = ''
  try {
    const form = new FormData()
    form.append('avatar', file)
    await request.post('/follow/customer/update-avatar', form, {
      headers: { 'Content-Type': 'multipart/form-data' },
    })
    avatarLoadError.value = false
    await loadCustomer()
    authStore.setMemberAvatar(customer.value?.avatar ?? null)
  } catch (e: unknown) {
    avatarUploadError.value = (e as Error).message || t('copyTrade.lead.uploadFailed')
  } finally {
    avatarUploading.value = false
    input.value = ''
  }
}

async function removeFollower(f: Follower) {
  if (!confirm(t('copyTrade.lead.confirmRemoveFollower', { name: f.name }))) {
    return
  }
  try {
    await request.put(`/follow/follow/remove-follow/${f.memberId}`)
    followers.value = followers.value.filter(fl => fl.memberId !== f.memberId)
  } catch (e: unknown) {
    toast.error((e as Error).message || t('copyTrade.lead.operationFailed'))
  }
}

function switchTab(tab: Tab) {
  activeTab.value = tab
  if (tab === 'followers') loadFollowers()
  if (tab === 'current')   loadPositions()
  if (tab === 'history')   loadHistory()
  if (tab === 'settings')  { loadTags(); loadMySymbols(); }
}

// ── Helpers ────────────────────────────────────────────────────────────────
function initials(name: string) { return name.charAt(0).toUpperCase() }

function fmtNum(v: number, d = 2) {
  return v.toLocaleString('en-US', { minimumFractionDigits: d, maximumFractionDigits: d })
}

function fmtPnl(v: number) {
  return (v >= 0 ? '+' : '') + fmtNum(v)
}

// 4 decimal places for profit amounts (matches app precision)
function fmtProfit(v: number) {
  return (v >= 0 ? '+' : '') + v.toLocaleString('en-US', { minimumFractionDigits: 4, maximumFractionDigits: 4 })
}

function fmtTime(ts: number) {
  if (!ts) {
    return '—'
  }
  return new Date(ts).toLocaleString(intlLocaleForApp(locale.value), {
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
  })
}

// "BTCUSDT" → "BTC/USDT"
function fmtSymbol(sym: string) {
  if (sym.endsWith('USDT')) return sym.slice(0, -4) + '/USDT'
  if (sym.endsWith('BTC'))  return sym.slice(0, -3)  + '/BTC'
  if (sym.endsWith('ETH'))  return sym.slice(0, -3)  + '/ETH'
  return sym
}

// "BTCUSDT" → "BTC"  (base asset for quantity label)
function baseAsset(sym: string) {
  if (sym.endsWith('USDT')) return sym.slice(0, -4)
  if (sym.endsWith('BTC'))  return sym.slice(0, -3)
  if (sym.endsWith('ETH'))  return sym.slice(0, -3)
  return sym
}

// Quantity with up to 4 decimal places, no trailing zeros
function fmtQty(v: number) {
  if (v === 0) return '0'
  return parseFloat(v.toFixed(4)).toString()
}

// ── Init ───────────────────────────────────────────────────────────────────
watch(() => customer.value?.avatar, () => { avatarLoadError.value = false })

onMounted(async () => {
  await loadCustomer()
  if (isTrader.value) { loadTraderInfo(); loadFollowers(); loadTags(); loadMySymbols(); }
  else if (!isApplying.value) { loadApplyConditions(); }
})
</script>

<template>
  <main class="ml-main">
    <!-- ── Top bar ── -->
    <div class="ml-topbar">
      <div class="page-container topbar-inner">
        <button class="back-btn" @click="router.push('/copy-trade')">
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 12H5m0 0l7 7m-7-7l7-7"/></svg>
          {{ t('copyTrade.followingPlaza') }}
        </button>
        <h1 class="page-title">{{ t('copyTrade.lead.pageTitle') }}</h1>
        <button v-if="!isTrader" class="nav-btn" @click="router.push('/copy-trade/my-following')">{{ t('copyTrade.lead.navMyFollowing') }}</button>
      </div>
    </div>

    <!-- Loading -->
    <div v-if="customerLoading" class="page-container sk-section">
      <div class="sk sk-header-card" />
    </div>

    <!-- Not a trader: Apply card -->
    <template v-else-if="!isTrader && !isApplying">
      <div class="page-container apply-section">
        <div class="apply-card dark-card">
          <div class="apply-icon">🚀</div>
          <h2 class="apply-title">{{ t('copyTrade.lead.becomeTitle') }}</h2>
          <p class="apply-desc">{{ t('copyTrade.lead.becomeDesc') }}</p>

          <!-- Conditions list -->
          <div class="apply-conditions">
            <div class="cond-item" :class="condBalancePassed ? 'cond-pass' : 'cond-fail'">
              <span class="cond-status-icon">
                <svg v-if="condBalancePassed" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
                <svg v-else width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
              </span>
              <span class="cond-text">{{ t('copyTrade.lead.condMinBalance', { min: MIN_ASSET.toLocaleString() }) }}</span>
              <a v-if="!condBalancePassed" class="cond-link" @click="router.push('/assets/transfer')">{{ t('copyTrade.lead.goTransfer') }}</a>
            </div>
            <div class="cond-item" :class="condNoFollowPassed ? 'cond-pass' : 'cond-fail'">
              <span class="cond-status-icon">
                <svg v-if="condNoFollowPassed" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg>
                <svg v-else width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
              </span>
              <span class="cond-text">{{ t('copyTrade.lead.condNotFollowing') }}</span>
            </div>
          </div>

          <!-- Agreement -->
          <label class="agree-label">
            <input type="checkbox" v-model="agreedToTerms" class="agree-checkbox" />
            {{ t('copyTrade.lead.agreePrefix') }}
            <span class="agree-link" @click.prevent="openAgreement">{{ t('copyTrade.lead.agreeLink') }}</span>
          </label>

          <div v-if="applyError" class="apply-error">{{ applyError }}</div>
          <button
            class="apply-btn"
            :disabled="applying || !allConditionsPassed || !agreedToTerms"
            @click="applyTrader"
          >
            {{ applying ? t('copyTrade.lead.submitting') : t('copyTrade.lead.submitApply') }}
          </button>
        </div>
      </div>
    </template>

    <!-- Applying state -->
    <template v-else-if="isApplying">
      <div class="page-container apply-section">
        <div class="applying-card dark-card">
          <div class="applying-icon">⏳</div>
          <h2 class="applying-title">{{ t('copyTrade.lead.reviewingTitle') }}</h2>
          <p class="applying-desc">{{ t('copyTrade.lead.reviewingDesc') }}</p>
        </div>
      </div>
    </template>

    <!-- Trader dashboard -->
    <template v-else-if="isTrader && customer">
      <!-- Profile summary -->
      <div class="ml-hero">
        <div class="page-container">
          <div class="hero-inner">
            <div class="hero-profile">
              <div class="hero-avatar-wrap">
                <img v-if="customer.avatar && !avatarLoadError" :src="customer.avatar" :alt="customer.nickName" class="hero-avatar-img" @error="avatarLoadError = true" />
                <div v-else class="hero-avatar">{{ initials(customer.nickName) }}</div>
                <span v-if="traderInfo?.levelName" class="hero-level-badge">{{ traderInfo.levelName }}</span>
              </div>
              <div>
                <div class="hero-name">{{ customer.nickName }} <span class="badge-trader">{{ t('copyTrade.lead.leadingBadge') }}</span></div>
                <div class="hero-desc">{{ customer.description || t('copyTrade.lead.noBio') }}</div>
                <div class="hero-tags">
                  <span v-for="tag in myTags" :key="tag.id" class="hero-tag">{{ tag.tagName }}</span>
                </div>
              </div>
            </div>
            <div class="hero-right-actions">
              <button class="btn-danger-outline" :disabled="cancelLoading" @click="cancelTrader">
                {{ cancelLoading ? t('copyTrade.lead.cancelLeadProcessing') : t('copyTrade.lead.cancelLeadApply') }}
              </button>
            </div>
          </div>

          <!-- Stats bar -->
          <div v-if="traderInfo" class="hero-stats">
            <div class="stats-row">
              <div class="stat-item">
                <div class="stat-label">{{ t('copyTrade.lead.statFollowers') }}</div>
                <div class="stat-val">{{ traderInfo.following }}<span class="stat-max"> / {{ traderInfo.maxFollow || '—' }}</span></div>
              </div>
              <div class="stat-item">
                <div class="stat-label">{{ t('copyTrade.lead.statRegisterDays') }}</div>
                <div class="stat-val">{{ traderInfo.registerDays }}</div>
              </div>
              <div class="stat-item">
                <div class="stat-label">{{ t('copyTrade.lead.statCapital') }}</div>
                <div class="stat-val">{{ traderInfo.moneyStrength }}</div>
              </div>
            </div>
            <div class="stats-row stats-row-2">
              <div class="stat-item">
                <div class="stat-label">{{ t('copyTrade.lead.statCumulativeProfit') }}</div>
                <div class="stat-val" :class="traderInfo.profitAmount >= 0 ? 'text-up' : 'text-down'">{{ fmtNum(traderInfo.profitAmount) }}</div>
              </div>
              <div class="stat-item">
                <div class="stat-label">{{ t('copyTrade.lead.statTotalFollowers') }}</div>
                <div class="stat-val">{{ traderInfo.followCustomer }}</div>
              </div>
              <div class="stat-item">
                <div class="stat-label">{{ t('copyTrade.lead.statTradingDays') }}</div>
                <div class="stat-val">{{ traderInfo.tradingDays }}</div>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- Tabs -->
      <div class="ml-tabs-wrap">
        <div class="page-container">
          <div class="ml-tabs">
            <button class="ml-tab" :class="{ active: activeTab === 'followers' }"  @click="switchTab('followers')">{{ t('copyTrade.lead.tabFollowers', { n: followers.length }) }}</button>
            <button class="ml-tab" :class="{ active: activeTab === 'current' }"    @click="switchTab('current')">{{ t('copyTrade.lead.tabCurrent') }}</button>
            <button class="ml-tab" :class="{ active: activeTab === 'history' }"    @click="switchTab('history')">{{ t('copyTrade.lead.tabHistory') }}</button>
            <button class="ml-tab" :class="{ active: activeTab === 'settings' }"   @click="switchTab('settings')">{{ t('copyTrade.lead.tabSettings') }}</button>
          </div>
        </div>
      </div>

      <div class="page-container tab-content">
        <!-- Followers -->
        <template v-if="activeTab === 'followers'">
          <div v-if="followersLoading" class="sk-rows">
            <div v-for="i in 3" :key="i" class="sk sk-card-row" />
          </div>
          <div v-else-if="followers.length === 0" class="empty-state">
            <div class="empty-icon">👥</div>
            <div class="empty-text">{{ t('copyTrade.lead.emptyFollowers') }}</div>
          </div>
          <div v-else class="follower-cards">
            <div v-for="(f, idx) in followers" :key="f.id" class="follower-card dark-card">
              <div class="fc-header">
                <div class="fc-rank">{{ idx + 1 }}</div>
                <div class="fc-name">{{ f.name }}</div>
                <button class="btn-sm-danger" @click="removeFollower(f)">{{ t('copyTrade.lead.removeFollower') }}</button>
              </div>
              <div class="fc-row">
                <div class="fc-col">
                  <div class="fc-label">{{ t('copyTrade.lead.followerEquity') }}</div>
                  <div class="fc-val num">{{ fmtNum(f.balance) }}</div>
                </div>
                <div class="fc-col fc-col-center">
                  <div class="fc-label">{{ t('copyTrade.lead.followerTotalShare') }}</div>
                  <div class="fc-val num" :class="f.totalProfitSharing > 0 ? 'text-up' : f.totalProfitSharing < 0 ? 'text-down' : ''">
                    {{ f.totalProfitSharing === 0 ? '--' : fmtPnl(f.totalProfitSharing) }}
                  </div>
                </div>
                <div class="fc-col fc-col-right">
                  <div class="fc-label">{{ t('copyTrade.lead.followerLastShare') }}</div>
                  <div class="fc-val num" :class="f.lastProfitSharing > 0 ? 'text-up' : f.lastProfitSharing < 0 ? 'text-down' : ''">
                    {{ f.lastProfitSharing === 0 ? '--' : fmtPnl(f.lastProfitSharing) }}
                  </div>
                </div>
              </div>
              <div class="fc-footer">
                <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="fc-time-icon"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></svg>
                <span class="fc-time">{{ t('copyTrade.lead.followerSince', { time: f.followTime || '—' }) }}</span>
              </div>
            </div>
          </div>
        </template>

        <!-- Current positions -->
        <template v-else-if="activeTab === 'current'">
          <div v-if="posLoading" class="sk-rows">
            <div v-for="i in 3" :key="i" class="sk sk-card-row" />
          </div>
          <div v-else-if="positions.length === 0" class="empty-state">
            <div class="empty-icon">📭</div>
            <div class="empty-text">{{ t('copyTrade.lead.emptyCurrent') }}</div>
          </div>
          <div v-else class="order-cards">
            <div v-for="p in positions" :key="p.id" class="order-card dark-card">
              <div class="oc-header">
                <span class="oc-symbol">{{ fmtSymbol(p.symbol) }}</span>
                <span class="oc-perp">{{ t('common.perpetual') }}</span>
                <span class="dir-badge" :class="p.direction === 0 ? 'dir-long' : 'dir-short'">{{ p.direction === 0 ? t('copyTrade.followingOpenLong') : t('copyTrade.followingOpenShort') }}</span>
                <span class="oc-pos-type">{{ p.positionType }}</span>
                <span class="oc-lever">{{ p.lever }}X</span>
              </div>
              <div class="oc-row">
                <div class="oc-col">
                  <div class="oc-label">{{ t('copyTrade.followingThQty') }}({{ baseAsset(p.symbol) }})</div>
                  <div class="oc-val num">{{ fmtQty(p.amount) }}</div>
                </div>
                <div class="oc-col oc-col-center">
                  <div class="oc-label">{{ t('copyTrade.followingThUnrealized') }}(USDT)</div>
                  <div class="oc-val num" :class="p.profit >= 0 ? 'pnl-up' : 'pnl-down'">{{ fmtProfit(p.profit) }}</div>
                </div>
                <div class="oc-col oc-col-right">
                  <div class="oc-label">{{ t('copyTrade.followingYieldRate') }}</div>
                  <div class="oc-val num" :class="p.profitRate >= 0 ? 'pnl-up' : 'pnl-down'">{{ fmtPnl(p.profitRate) }}%</div>
                </div>
              </div>
              <div class="oc-row oc-row-2col">
                <div class="oc-col">
                  <div class="oc-label">{{ t('copyTrade.followingAvgOpenUsdt') }}</div>
                  <div class="oc-val num">{{ fmtNum(p.openPrice, 2) }}</div>
                </div>
                <div class="oc-col oc-col-right">
                  <div class="oc-label">{{ t('copyTrade.followingThCurPrice') }}(USDT)</div>
                  <div class="oc-val num">{{ fmtNum(p.closePrice, 2) }}</div>
                </div>
              </div>
              <div class="oc-footer">
                <span class="oc-time">{{ fmtTime(p.openTime) }}</span>
              </div>
            </div>
          </div>
        </template>

        <!-- History -->
        <template v-else-if="activeTab === 'history'">
          <div v-if="histLoading" class="sk-rows">
            <div v-for="i in 3" :key="i" class="sk sk-card-row" />
          </div>
          <div v-else-if="historyOrders.length === 0" class="empty-state">
            <div class="empty-icon">📭</div>
            <div class="empty-text">{{ t('copyTrade.lead.emptyHistory') }}</div>
          </div>
          <div v-else class="order-cards">
            <div v-for="p in historyOrders" :key="p.id" class="order-card dark-card">
              <div class="oc-header">
                <span class="oc-symbol">{{ fmtSymbol(p.symbol) }}</span>
                <span class="oc-perp">{{ t('common.perpetual') }}</span>
                <span class="dir-badge" :class="p.direction === 0 ? 'dir-long' : 'dir-short'">{{ p.direction === 0 ? t('copyTrade.followingOpenLong') : t('copyTrade.followingOpenShort') }}</span>
                <span class="oc-pos-type">{{ p.positionType }}</span>
                <span class="oc-lever">{{ p.lever }}X</span>
              </div>
              <div class="oc-row">
                <div class="oc-col">
                  <div class="oc-label">{{ t('copyTrade.closeQtyWithBase', { base: baseAsset(p.symbol) }) }}</div>
                  <div class="oc-val num">{{ fmtQty(p.amount) }}</div>
                </div>
                <div class="oc-col oc-col-center">
                  <div class="oc-label">{{ t('copyTrade.followingRealizedPnlUsdt') }}</div>
                  <div class="oc-val num" :class="p.profit >= 0 ? 'pnl-up' : 'pnl-down'">{{ fmtProfit(p.profit) }}</div>
                </div>
                <div class="oc-col oc-col-right">
                  <div class="oc-label">{{ t('copyTrade.followingYieldRate') }}</div>
                  <div class="oc-val num" :class="p.profitRate >= 0 ? 'pnl-up' : 'pnl-down'">{{ fmtPnl(p.profitRate) }}%</div>
                </div>
              </div>
              <div class="oc-row oc-row-2col">
                <div class="oc-col">
                  <div class="oc-label">{{ t('copyTrade.followingAvgOpenUsdt') }}</div>
                  <div class="oc-val num">{{ fmtNum(p.openPrice, 2) }}</div>
                </div>
                <div class="oc-col oc-col-right">
                  <div class="oc-label">{{ t('copyTrade.followingAvgCloseUsdt') }}</div>
                  <div class="oc-val num">{{ fmtNum(p.closePrice, 2) }}</div>
                </div>
              </div>
              <div class="oc-footer">
                <span class="oc-time">{{ fmtTime(p.openTime) }}</span>
                <span class="oc-time-sep">→</span>
                <span class="oc-time">{{ fmtTime(p.closeTime ?? 0) }}</span>
              </div>
            </div>
          </div>
        </template>

        <!-- Settings -->
        <template v-else-if="activeTab === 'settings'">
          <div class="settings-grid">
            <!-- Profile settings -->
            <div class="settings-card dark-card">
              <h3 class="settings-title">{{ t('copyTrade.lead.settingsBasic') }}</h3>
              <div class="form-group">
                <label class="form-label">{{ t('copyTrade.lead.avatar') }}</label>
                <div class="avatar-upload-wrap">
                  <div class="avatar-upload-preview">
                    <img v-if="customer.avatar && !avatarLoadError" :src="customer.avatar" class="settings-avatar-img" @error="avatarLoadError = true" />
                    <div v-else class="settings-avatar-placeholder">{{ initials(customer.nickName) }}</div>
                    <label class="avatar-edit-overlay" :class="{ 'overlay-loading': avatarUploading }">
                      <svg v-if="!avatarUploading" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
                        <path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/>
                        <path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/>
                      </svg>
                      <span v-else class="overlay-spinner" />
                      <input type="file" accept="image/*" class="avatar-file-input" :disabled="avatarUploading" @change="uploadAvatar" />
                    </label>
                  </div>
                </div>
                <div v-if="avatarUploadError" class="form-error">{{ avatarUploadError }}</div>
              </div>
              <div class="form-group">
                <label class="form-label">{{ t('copyTrade.lead.nickname') }}</label>
                <input v-model="settingsForm.nickName" type="text" maxlength="10" class="form-input" :placeholder="t('copyTrade.lead.nicknamePlaceholder')" />
              </div>
              <div class="form-group">
                <label class="form-label">{{ t('copyTrade.lead.bio') }}</label>
                <textarea v-model="settingsForm.description" maxlength="25" class="form-textarea" :placeholder="t('copyTrade.lead.bioPlaceholder')" rows="2" />
              </div>
              <div v-if="settingsError"   class="form-error">{{ settingsError }}</div>
              <div v-if="settingsSuccess" class="form-success">{{ t('copyTrade.lead.saveSuccess') }}</div>
              <button class="save-btn" :disabled="settingsLoading" @click="saveSettings">
                {{ settingsLoading ? t('copyTrade.lead.saveBasicProcessing') : t('copyTrade.lead.saveBasic') }}
              </button>
            </div>

            <!-- Symbols & Tags -->
            <div class="settings-card dark-card">
              <h3 class="settings-title">{{ t('copyTrade.lead.leadSymbols') }}</h3>
              <div class="symbol-chips">
                <button
                  v-for="sym in DEFAULT_SYMBOLS"
                  :key="sym"
                  class="sym-chip"
                  :class="{ active: mySymbols.includes(sym) }"
                  @click="toggleSymbol(sym)"
                >{{ SYMBOL_LABELS[sym] ?? sym }}</button>
              </div>
              <div v-if="symbolsSuccess" class="form-success">{{ t('copyTrade.lead.saveSuccess') }}</div>
              <button class="save-btn" :disabled="symbolsLoading" @click="saveSymbols">
                {{ symbolsLoading ? t('copyTrade.lead.saveProcessing') : t('copyTrade.lead.save') }}
              </button>

              <div class="form-divider" />
              <h3 class="settings-title">{{ t('copyTrade.lead.tagsTitle') }}</h3>
              <div class="tag-chips">
                <button
                  v-for="tag in allTags"
                  :key="tag.id"
                  class="tag-chip"
                  :class="{ active: tag.selected }"
                  @click="tag.selected = !tag.selected; saveTags()"
                >{{ tag.tagName }}</button>
              </div>
            </div>
          </div>
        </template>
      </div>
    </template>
  </main>

  <!-- ── 交易员协议 Modal ── -->
  <Teleport to="body">
    <div v-if="showAgreement" class="agr-mask" @click.self="showAgreement = false">
      <div class="agr-box">
        <div class="agr-header">
          <button class="agr-back" @click="showAgreement = false">
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 12H5m0 0l7 7m-7-7l7-7"/></svg>
          </button>
          <span class="agr-title">{{ t('copyTrade.lead.agreementTitle') }}</span>
          <div style="width:36px" />
        </div>
        <div class="agr-body">
          <div v-if="agreementLoading" class="agr-loading">
            <div class="sk sk-line" style="width:100%;height:18px;margin-bottom:10px" />
            <div class="sk sk-line" style="width:85%;height:18px;margin-bottom:10px" />
            <div class="sk sk-line" style="width:92%;height:18px;margin-bottom:10px" />
            <div class="sk sk-line" style="width:70%;height:18px" />
          </div>
          <div v-else-if="agreementContent" class="agr-content" v-html="agreementContent" />
          <div v-else class="agr-empty">{{ t('copyTrade.lead.agreementEmpty') }}</div>
        </div>
      </div>
    </div>
  </Teleport>
</template>

<style scoped>
.ml-main { padding-top: var(--header-height); background: var(--color-bg-primary); min-height: 100vh; }

/* ── Top bar ── */
.ml-topbar { background: var(--color-bg-secondary); border-bottom: 1px solid var(--color-border); padding: 12px 0; }
.topbar-inner { display: flex; align-items: center; gap: 16px; }
.back-btn {
  display: flex; align-items: center; gap: 6px;
  color: var(--color-text-secondary); background: none; border: none; cursor: pointer;
  font-size: 14px; padding: 6px 0; transition: color 0.2s; white-space: nowrap;
}
.back-btn:hover { color: var(--color-text-primary); }
.page-title { font-size: 16px; font-weight: 600; color: var(--color-text-primary); flex: 1; }
.nav-btn {
  background: transparent; border: 1px solid var(--color-border);
  color: var(--color-text-muted); font-size: 13px; padding: 6px 14px;
  border-radius: 8px; cursor: pointer; transition: all 0.2s; white-space: nowrap;
}
.nav-btn:hover { border-color: var(--color-primary); color: var(--color-primary); }

/* ── Skeleton ── */
.sk-section { padding: 32px 0; }
.sk { background: rgba(255,255,255,0.06); border-radius: 8px; animation: sk-pulse 1.4s ease infinite; }
.sk-header-card { height: 200px; }
.sk-row { height: 44px; }
.sk-rows { display: flex; flex-direction: column; gap: 8px; padding-top: 12px; }
@keyframes sk-pulse { 0%,100% { opacity:1 } 50% { opacity:.35 } }

/* ── Apply ── */
.apply-section { padding: 48px 0; display: flex; justify-content: center; }
.apply-card {
  max-width: 560px; width: 100%; padding: 40px;
  text-align: center; display: flex; flex-direction: column; align-items: center;
}
.apply-icon { font-size: 48px; margin-bottom: 16px; }
.apply-title { font-size: 22px; font-weight: 700; color: var(--color-text-primary); margin-bottom: 12px; }
.apply-desc { font-size: 14px; color: var(--color-text-secondary); line-height: 1.7; margin-bottom: 24px; }
/* Conditions */
.apply-conditions { display: flex; flex-direction: column; gap: 10px; width: 100%; margin-bottom: 20px; }
.cond-item {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px; border-radius: 8px; border: 1px solid transparent;
  font-size: 14px;
}
.cond-pass {
  background: rgba(14,203,129,0.06); border-color: rgba(14,203,129,0.2);
}
.cond-fail {
  background: rgba(246,70,93,0.06); border-color: rgba(246,70,93,0.2);
}
.cond-status-icon {
  flex-shrink: 0; width: 20px; height: 20px;
  display: flex; align-items: center; justify-content: center; border-radius: 50%;
}
.cond-pass .cond-status-icon { color: #0ecb81; }
.cond-fail .cond-status-icon { color: #f6465d; }
.cond-text { flex: 1; color: var(--color-text-primary); }
.cond-link {
  font-size: 12px; color: var(--color-primary); cursor: pointer;
  white-space: nowrap; flex-shrink: 0;
}
.cond-link:hover { text-decoration: underline; }

/* Agreement */
.agree-label {
  display: flex; align-items: center; gap: 8px;
  font-size: 13px; color: var(--color-text-secondary); cursor: pointer;
  margin-bottom: 16px; width: 100%;
}
.agree-checkbox { width: 15px; height: 15px; cursor: pointer; flex-shrink: 0; accent-color: var(--color-primary); }
.agree-link { color: var(--color-primary); }
.agree-link:hover { text-decoration: underline; }

.apply-error { color: #f6465d; font-size: 13px; margin-bottom: 12px; }
.apply-btn {
  width: 100%; padding: 13px; background: var(--color-primary);
  color: #000; font-size: 15px; font-weight: 600; border-radius: 10px;
  border: none; cursor: pointer; transition: opacity 0.2s;
}
.apply-btn:hover:not(:disabled) { opacity: 0.85; }
.apply-btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* Applying */
.applying-card { max-width: 480px; width: 100%; padding: 48px; text-align: center; }
.applying-icon { font-size: 48px; margin-bottom: 16px; }
.applying-title { font-size: 20px; font-weight: 700; color: var(--color-text-primary); margin-bottom: 12px; }
.applying-desc { font-size: 14px; color: var(--color-text-secondary); line-height: 1.6; }

/* ── Hero ── */
.ml-hero { background: var(--color-bg-secondary); border-bottom: 1px solid var(--color-border); padding: 24px 0; }
.hero-inner { display: flex; align-items: center; justify-content: space-between; gap: 20px; }
.hero-profile { display: flex; align-items: flex-start; gap: 16px; }
.hero-avatar-wrap { position: relative; flex-shrink: 0; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.hero-avatar-img { width: 64px; height: 64px; border-radius: 14px; object-fit: cover; }
.hero-avatar {
  width: 64px; height: 64px; border-radius: 14px;
  background: linear-gradient(135deg, #5b6ef5 0%, #8b5cf6 100%); color: #fff;
  font-size: 22px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.hero-level-badge {
  display: inline-block; font-size: 11px; font-weight: 600; padding: 2px 10px;
  background: #e6962a; color: #fff; border-radius: 10px;
  white-space: nowrap;
}
.hero-name { font-size: 18px; font-weight: 700; color: var(--color-text-primary); margin-bottom: 4px; margin-top: 4px; }
.badge-trader {
  font-size: 11px; font-weight: 600;
  background: rgba(240,185,11,0.12); color: var(--color-primary);
  border: 1px solid rgba(240,185,11,0.3); border-radius: 4px; padding: 2px 8px;
  margin-left: 8px; vertical-align: middle;
}
.hero-desc { font-size: 13px; color: var(--color-text-muted); margin-bottom: 6px; }
.hero-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }
.hero-tag {
  font-size: 11px; padding: 2px 10px; border-radius: 4px;
  background: rgba(82,130,255,0.12); color: #6b8cff;
  border: 1px solid rgba(82,130,255,0.3);
}

/* ── Stats bar ── */
.hero-stats { margin-top: 20px; border-top: 1px solid var(--color-border); padding-top: 16px; }
.stats-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; }
.stats-row-2 { margin-top: 12px; }
.stat-item { padding: 0 16px; border-right: 1px solid var(--color-border); }
.stat-item:first-child { padding-left: 0; }
.stat-item:last-child  { border-right: none; }
.stat-label { font-size: 11px; color: var(--color-text-muted); margin-bottom: 4px; }
.stat-val { font-size: 15px; font-weight: 600; font-family: var(--font-family-num); color: var(--color-text-primary); }
.stat-max { font-size: 13px; color: var(--color-text-muted); font-weight: 400; }

.btn-danger-outline {
  padding: 9px 20px; background: transparent; color: #f6465d;
  border: 1px solid rgba(246,70,93,0.4); border-radius: 8px;
  font-size: 13px; cursor: pointer; transition: all 0.2s;
}
.btn-danger-outline:hover:not(:disabled) { background: rgba(246,70,93,0.08); }
.btn-danger-outline:disabled { opacity: 0.5; cursor: not-allowed; }

/* ── Tabs ── */
.ml-tabs-wrap { background: var(--color-bg-secondary); border-bottom: 1px solid var(--color-border); position: sticky; top: var(--header-height); z-index: 10; }
.ml-tabs { display: flex; }
.ml-tab {
  padding: 13px 24px; font-size: 14px; font-weight: 500;
  color: var(--color-text-muted); background: transparent;
  border: none; cursor: pointer; border-bottom: 2px solid transparent; transition: all 0.2s;
}
.ml-tab:hover { color: var(--color-text-primary); }
.ml-tab.active { color: var(--color-primary); border-bottom-color: var(--color-primary); }

.tab-content { padding: 24px 0 48px; }

/* ── Overview ── */
.overview-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.ov-card { padding: 20px; }
.ov-label { font-size: 12px; color: var(--color-text-muted); margin-bottom: 12px; font-weight: 500; }
.ov-info { display: flex; flex-direction: column; gap: 10px; }
.ov-item { display: flex; justify-content: space-between; align-items: center; }
.ov-key { font-size: 13px; color: var(--color-text-secondary); }
.ov-val { font-size: 14px; font-weight: 600; font-family: var(--font-family-num); color: var(--color-text-primary); }
.ov-actions { display: flex; flex-direction: column; gap: 10px; }
.ov-action-btn {
  padding: 9px 16px; background: rgba(255,255,255,0.04); border: 1px solid var(--color-border);
  border-radius: 8px; color: var(--color-text-secondary); font-size: 13px; cursor: pointer; transition: all 0.2s;
  text-align: left;
}
.ov-action-btn:hover { border-color: var(--color-primary); color: var(--color-primary); }

/* ── Settings ── */
.settings-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.settings-card { padding: 24px; display: flex; flex-direction: column; gap: 16px; }
.settings-title { font-size: 14px; font-weight: 600; color: var(--color-text-primary); }
.settings-hint  { font-size: 12px; color: var(--color-text-muted); margin-top: -8px; }
.form-divider { height: 1px; background: var(--color-border); }
.form-group { display: flex; flex-direction: column; gap: 6px; }
.form-label { font-size: 12px; color: var(--color-text-muted); }
.form-input {
  padding: 9px 12px; background: rgba(255,255,255,0.05); border: 1px solid var(--color-border);
  border-radius: 8px; color: var(--color-text-primary); font-size: 14px; outline: none;
}
.form-input:focus { border-color: var(--color-primary); }
.form-textarea {
  padding: 9px 12px; background: rgba(255,255,255,0.05); border: 1px solid var(--color-border);
  border-radius: 8px; color: var(--color-text-primary); font-size: 14px; outline: none;
  resize: vertical; font-family: inherit;
}
.form-textarea:focus { border-color: var(--color-primary); }
.form-error   { font-size: 13px; color: #f6465d; padding: 8px 12px; background: rgba(246,70,93,0.08); border-radius: 6px; }
.form-success { font-size: 13px; color: #0ecb81; padding: 8px 12px; background: rgba(14,203,129,0.08); border-radius: 6px; }
.save-btn {
  padding: 10px; background: var(--color-primary); color: #000;
  font-size: 14px; font-weight: 600; border-radius: 8px; border: none; cursor: pointer;
  transition: opacity 0.2s;
}
.save-btn:hover:not(:disabled) { opacity: 0.85; }
.save-btn:disabled { opacity: 0.5; cursor: not-allowed; }

/* Symbol toggle chips */
.symbol-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 4px; }
.sym-chip {
  padding: 6px 18px; font-size: 13px; font-weight: 600; border-radius: 20px;
  border: 1px solid var(--color-border); background: transparent;
  color: var(--color-text-muted); cursor: pointer; transition: all 0.2s;
}
.sym-chip.active {
  background: rgba(240,185,11,0.08); border-color: rgba(240,185,11,0.4);
  color: var(--color-primary);
}

/* Tags */
.tag-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.tag-chip {
  padding: 5px 14px; font-size: 12px; border-radius: 6px;
  border: 1px solid var(--color-border); background: transparent;
  color: var(--color-text-muted); cursor: pointer; transition: all 0.2s;
}
.tag-chip.active { border-color: var(--color-primary); color: var(--color-primary); background: rgba(240,185,11,0.06); }

/* ── Follower cards ── */
.follower-cards { display: flex; flex-direction: column; gap: 10px; }
.follower-card  { padding: 16px; display: flex; flex-direction: column; gap: 12px; }

.fc-header { display: flex; align-items: center; gap: 12px; }
.fc-rank {
  width: 36px; height: 36px; border-radius: 50%; flex-shrink: 0;
  background: #e6962a; color: #fff;
  font-size: 14px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.fc-name { flex: 1; font-size: 14px; font-weight: 600; color: var(--color-text-primary); }

.fc-row { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 4px; }
.fc-col { display: flex; flex-direction: column; gap: 4px; }
.fc-col-center { text-align: center; }
.fc-col-right  { text-align: right; }
.fc-label { font-size: 11px; color: var(--color-text-muted); }
.fc-val   { font-size: 14px; font-weight: 600; font-family: var(--font-family-num); color: var(--color-text-primary); }

.fc-footer { display: flex; align-items: center; gap: 5px; }
.fc-time-icon { color: var(--color-text-muted); flex-shrink: 0; }
.fc-time { font-size: 12px; color: var(--color-text-muted); }
.btn-sm-danger {
  padding: 5px 12px; font-size: 12px; border-radius: 6px;
  background: transparent; border: 1px solid rgba(246,70,93,0.4);
  color: #f6465d; cursor: pointer; transition: all 0.2s;
}
.btn-sm-danger:hover { background: rgba(246,70,93,0.08); }

/* ── Order cards ── */
.order-cards { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.order-card  { padding: 16px; display: flex; flex-direction: column; gap: 10px; }

.oc-header { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.oc-symbol { font-size: 14px; font-weight: 700; color: var(--color-text-primary); }
.oc-perp   { font-size: 11px; color: var(--color-text-muted); }
.oc-pos-type { font-size: 11px; color: var(--color-text-muted); padding: 1px 6px; border: 1px solid var(--color-border); border-radius: 3px; }
.oc-lever    { font-size: 11px; color: var(--color-text-muted); padding: 1px 6px; border: 1px solid var(--color-border); border-radius: 3px; }

.oc-row     { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 4px; padding-top: 6px; border-top: 1px solid rgba(255,255,255,0.05); }
.oc-row-2col { grid-template-columns: 1fr 1fr; }
.oc-col { display: flex; flex-direction: column; gap: 4px; }
.oc-col-center { text-align: center; }
.oc-col-right  { text-align: right; }
.oc-label { font-size: 11px; color: var(--color-text-muted); white-space: nowrap; }
.oc-val   { font-size: 13px; font-weight: 600; color: var(--color-text-primary); }

.oc-footer { display: flex; align-items: center; gap: 6px; padding-top: 6px; border-top: 1px solid rgba(255,255,255,0.05); }
.oc-time   { font-size: 11px; color: var(--color-text-muted); }
.oc-time-sep { font-size: 11px; color: var(--color-text-muted); }

.dir-badge { display: inline-block; font-size: 11px; font-weight: 600; padding: 2px 7px; border-radius: 3px; }
.dir-long  { background: rgba(14,203,129,0.12); color: #0ecb81; }
.dir-short { background: rgba(246,70,93,0.12);  color: #f6465d; }

/* Scoped PnL color — avoids global .text-up/.text-down specificity conflict with .oc-val */
.pnl-up   { color: #0ecb81; }
.pnl-down { color: #f6465d; }

.sk-card-row { height: 120px; border-radius: 10px; }

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

/* ── Empty ── */
.empty-state { text-align: center; padding: 60px 20px; }
.empty-icon { font-size: 36px; margin-bottom: 12px; }
.empty-text { color: var(--color-text-muted); font-size: 14px; }

/* ── Avatar upload ── */
.avatar-upload-wrap { display: flex; flex-direction: column; gap: 8px; }
.avatar-upload-preview { position: relative; width: 72px; height: 72px; }
.settings-avatar-img {
  width: 72px; height: 72px; border-radius: 14px; object-fit: cover;
}
.settings-avatar-placeholder {
  width: 72px; height: 72px; border-radius: 14px;
  background: linear-gradient(135deg, #5b6ef5 0%, #8b5cf6 100%);
  color: #fff; font-size: 24px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.avatar-edit-overlay {
  position: absolute; inset: 0; border-radius: 14px;
  background: rgba(0,0,0,0.5); opacity: 0;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; transition: opacity 0.2s;
}
.avatar-upload-preview:hover .avatar-edit-overlay { opacity: 1; }
.avatar-edit-overlay.overlay-loading { opacity: 1; }
.avatar-edit-overlay svg { color: #fff; pointer-events: none; }
.avatar-file-input { position: absolute; inset: 0; opacity: 0; cursor: pointer; width: 100%; height: 100%; }
.overlay-spinner {
  width: 20px; height: 20px; border-radius: 50%;
  border: 2px solid rgba(255,255,255,0.3);
  border-top-color: #fff;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ── Agreement Modal ── */
.agr-mask {
  position: fixed; inset: 0; background: var(--color-bg-primary);
  display: flex; align-items: center; justify-content: center;
  z-index: 2000;
}
.agr-box {
  background: var(--color-bg-primary);
  width: 100%; max-width: 680px; height: 100%;
  display: flex; flex-direction: column;
  overflow: hidden;
}
.agr-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px; border-bottom: 1px solid rgba(255,255,255,0.08); flex-shrink: 0;
  background: var(--color-bg-primary);
}
.agr-back {
  display: flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 8px;
  background: none; border: none; cursor: pointer;
  color: var(--color-text-secondary); transition: background 0.2s;
}
.agr-back:hover { background: rgba(255,255,255,0.06); color: var(--color-text-primary); }
.agr-title { font-size: 15px; font-weight: 600; color: var(--color-text-primary); }
.agr-body { flex: 1; overflow-y: auto; padding: 20px 24px; }
.agr-loading { display: flex; flex-direction: column; }
.agr-content {
  font-size: 14px; color: var(--color-text-secondary);
  line-height: 1.8; white-space: pre-wrap; word-break: break-word;
}
.agr-content :deep(p)  { margin-bottom: 12px; }
.agr-content :deep(h1), .agr-content :deep(h2), .agr-content :deep(h3) {
  color: var(--color-text-primary); margin: 16px 0 8px;
}
.agr-empty { text-align: center; padding: 32px 0; color: var(--color-text-muted); font-size: 14px; }

/* ── Responsive ── */
@media (max-width: 800px) {
  .settings-grid { grid-template-columns: 1fr; }
  .stats-row     { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 600px) {
  .hero-inner { flex-direction: column; align-items: flex-start; }
  .ml-tab { padding: 10px 12px; font-size: 12px; }
  .stats-row { grid-template-columns: 1fr 1fr; }
  .stats-row .stat-item:nth-child(2n) { border-right: none; }
}
</style>
