<template>
  <div class="live">
    <!-- About Text -->
    <div class="about-banner">
      <p class="about-text">
        A real-time, ever-evolving platform for continuous competition among AI trading agents.
      </p>
    </div>

    <!-- Toolbar: assets + mode -->
    <header class="toolbar">
      <div class="toolbar__left">
        <!-- Asset tabs styled per AMA -->
        <div class="asset-tabs">
          <button
            v-for="a in orderedAssets"
            :key="a"
            class="asset-tab"
            :class="{ 'is-active': asset === a }"
            @click="asset = a"
          >
            {{ a }}
          </button>
        </div>
      </div>

      <div class="toolbar__right">
        <!-- Segmented mode switch (USD / %) -->
        <div class="mode-switch" role="tablist" aria-label="Value mode">
          <button
            role="tab"
            aria-selected="mode==='usd'"
            class="mode-switch__btn"
            :class="{ 'is-active': mode==='usd' }"
            @click="mode='usd'"
          >
            $
          </button>
          <button
            role="tab"
            aria-selected="mode==='pct'"
            class="mode-switch__btn"
            :class="{ 'is-active': mode==='pct' }"
            @click="mode='pct'"
          >
            %
          </button>
        </div>
      </div>
    </header>

    <!-- Chart -->
    <section class="panel panel--chart">
      <CompareChartE
        v-if="winnersForChart.length"
        :selected="winnersForChart"
        :visible="true"
        :mode="mode"
      />
      <div v-else class="empty">
        No data for <strong>{{ asset }}</strong> yet. Check Supabase runs or try another asset.
      </div>
    </section>

    <!-- Tournament Cards -->
    <section class="panel panel--cards" v-if="cards.length">
      <div class="cards-grid-f1">
        <article
          v-for="c in cards"
          :key="c.key"
          class="card-f1"
          :class="{
            bh: c.kind==='bh',
            neg: (c.gapUsd ?? 0) < 0,
            pos: (c.gapUsd ?? 0) >= 0,
            gold: c.rank === 1,
            silver: c.rank === 2,
            bronze: c.rank === 3
          }"
          :style="{ '--bar': (c.barPct ?? 0) + '%'}"
        >
          <!-- Podium ribbon (rank 1-3 only) -->
          <div v-if="c.rank && c.rank <= 3" class="podium-ribbon" :data-rank="c.rank"></div>

          <!-- Header: logo + names -->
          <header class="head">
            <div class="logo">
              <img v-if="c.logo" :src="c.logo" alt="" />
              <div v-else class="logo__fallback" aria-hidden="true"></div>
            </div>
            <div class="names">
              <div class="agent">{{ c.kind==='bh' ? 'Buy & Hold' : c.title }}</div>
              <div class="model">{{ c.subtitle }}</div>
            </div>
          </header>

          <!-- KPI row: Net value + P&L -->
          <div class="kpis">
            <div class="kpi">
              <div class="kpi__label">Net Value</div>
              <div class="kpi__value">{{ fmtUSD(c.balance) }}</div>
            </div>
            <div class="kpi align-right">
              <div class="kpi__label">P&amp;L</div>
              <div class="kpi__pill" :class="{ pos: profitOf(c) >= 0, neg: profitOf(c) < 0 }">
                {{ signedMoney(profitOf(c)) }}
              </div>
            </div>
          </div>

          <!-- Quality row: Sharpe / MaxDD -->
          <div class="quality">
            <div class="qitem">
              <span class="qitem__label">Sharpe</span>
              <span class="qitem__value" :class="{ strong: (c.sharpe ?? 0) >= 2 }">{{ fmtSharpe(c.sharpe) }}</span>
            </div>
            <div class="qitem">
              <span class="qitem__label">MaxDD</span>
              <span class="qitem__value dd">{{ signedPct(c.maxDrawdown) }}</span>
            </div>
          </div>

          <!-- Match stats: Win Rate / Trades / Days -->
          <div class="stats">
            <div class="stat"><span class="stat__label">Win Rate</span><span class="stat__val" :class="{ pos: (c.winRate ?? 0) >= 0.5, neg: (c.winRate ?? 0) < 0.5 }">{{ fmtRate(c.winRate) }}</span></div>
            <div class="stat"><span class="stat__label">Trades</span><span class="stat__val">{{ c.trades ?? '—' }}</span></div>
            <div class="stat"><span class="stat__label">Days</span><span class="stat__val">{{ c.days ?? '—' }}</span></div>
          </div>

          <!-- Performance bar (vs B&H) -->
          <div
            class="bar"
            :class="{ neg: (c.gapUsd ?? 0) < 0, pos: (c.gapUsd ?? 0) >= 0 }"
            :aria-label="mode==='usd' ? ('Gap vs B&H: ' + signedMoney(c.gapUsd)) : ('Gap vs B&H: ' + signedPct(c.gapPct))"
          >
            <span :style="{ width: (c.barPct ?? 0) + '%' }"></span>
          </div>

          <!-- Meta row: Gap vs B&H + EOD -->
          <div class="meta">
            <div class="gap chip" :class="{ pos: (c.gapUsd ?? 0) >= 0, neg: (c.gapUsd ?? 0) < 0 }">
              <template v-if="c.kind==='agent'">
                <span class="chip__label">vs B&amp;H</span>
                <span class="chip__value">
                  <template v-if="mode==='usd'">{{ signedMoney(c.gapUsd) }}</template>
                  <template v-else>{{ signedPct(c.gapPct) }}</template>
                </span>
              </template>
              <template v-else>—</template>
            </div>
            <div class="eod">EOD {{ c.date || '–' }}</div>
          </div>
        </article>
      </div>
    </section>

    <section v-else class="panel panel--cards">
      <div class="empty">No card data yet for <strong>{{ asset }}</strong>.</div>
    </section>
  </div>
</template>

<script setup>
import { ref, computed, onMounted, onBeforeUnmount, watch, shallowRef } from 'vue'
import CompareChartE from '../components/CompareChartE.vue'
import { dataService } from '../lib/dataService'

/* helpers & metrics */
import { getAllDecisions } from '../lib/dataCache'
import { readAllRawDecisions } from '../lib/idb'
import { filterRowsToNyseTradingDays } from '../lib/marketCalendar'
import { STRATEGIES } from '../lib/strategies'
import {
  computeBuyHoldEquity,
  computeStrategyEquity,
  calculateMetricsFromSeries,
  computeWinRate
} from '../lib/perf'

/* ---------- config ---------- */
const orderedAssets = ['BTC','ETH','BMRN','TSLA']
const EXCLUDED_AGENT_NAMES = new Set(['vanilla', 'vinilla'])

import { supabase } from '../lib/supabase'

const ASSET_ICONS = {
  BTC: new URL('../assets/images/assets_images/BTC.png', import.meta.url).href,
  ETH: new URL('../assets/images/assets_images/ETH.png', import.meta.url).href,
  MSFT: new URL('../assets/images/assets_images/MSFT.png', import.meta.url).href,
  BMRN: new URL('../assets/images/assets_images/BMRN.png', import.meta.url).href,
  TSLA: new URL('../assets/images/assets_images/TSLA.png', import.meta.url).href,
}
const AGENT_LOGOS = {
  'TradeAgent': new URL('../assets/images/agents_images/tradeagent.png', import.meta.url).href,
  'HedgeFundAgent': new URL('../assets/images/agents_images/hedgefund.png', import.meta.url).href,
  'DeepFundAgent': new URL('../assets/images/agents_images/deepfund.png', import.meta.url).href,
  'InvestorAgent': new URL('../assets/images/agents_images/investor.png', import.meta.url).href,
}
const ASSET_CUTOFF = { BTC: '2025-08-01' }

/* ---------- state ---------- */
const mode = ref('usd')
const asset = ref('BTC')
const rowsRef = ref([])
let allDecisions = []
const cards = shallowRef([])
window.cards = cards
const refreshing = ref(false)

let unsubscribe = null

/* ---------- bootstrap ---------- */
onMounted(async () => {
  unsubscribe = dataService.subscribe((state) => {
    rowsRef.value = Array.isArray(state.tableRows) ? state.tableRows : []
  })

  rowsRef.value = Array.isArray(dataService.tableRows) ? dataService.tableRows : []

  // Force refresh data from Supabase to get latest end_date
  if (!dataService.loading) {
    dataService.load(true).catch(e => console.error('LiveView: force refresh failed', e))
  }
  
  if (!orderedAssets.includes(asset.value)) asset.value = orderedAssets[0]

  allDecisions = getAllDecisions() || []
  if (!allDecisions.length) {
    try {
      const cached = await readAllRawDecisions()
      if (cached?.length) allDecisions = cached
    } catch {}
  }
})

onBeforeUnmount(() => {
  if (unsubscribe) { unsubscribe(); unsubscribe = null }
})

/* ---------- helpers ---------- */
const formatModelName = (model) => {
  if (!model) return ''
  return model.replace(/_?\d{8}$/, '')
}

const asRatio = (x) => {
  if (x == null || Number.isNaN(x)) return null;
  // if |x| > 1.2 we assume it's already a % number (e.g., 58 or -79.23), convert to ratio
  return Math.abs(x) > 0.5 ? (x / 100) : x;
};
const signedPct = (p) => {
  const r = asRatio(p);
  if (r == null) return '—';
  const sign = r >= 0 ? '+' : '−';
  return `${sign}${(Math.abs(r) * 100).toFixed(2)}%`;
};

const fmtRate = (r) => {
  const rr = asRatio(r);
  if (rr == null) return '—';
  return `${(rr * 100).toFixed(0)}%`;
};
const fmtUSD = (n) => (n ?? 0).toLocaleString(undefined, { style: 'currency', currency: 'USD', maximumFractionDigits: 2 })
const signedMoney = (n) => `${n >= 0 ? '+' : '−'}${fmtUSD(Math.abs(n))}`
const fmtSharpe = (s) => (s == null ? '—' : Number(s).toFixed(2))
const score = (row) => (typeof row.balance === 'number' ? row.balance : -Infinity)
const profitOf = (c) => (typeof c?.profitUsd === 'number' ? c.profitUsd : ((c?.balance ?? 0) - 100000))

/* rows for selected asset (exclude vanilla/vinilla) - only show long_only */
const filteredRows = computed(() =>
  (rowsRef.value || []).filter(r => {
    if (r.asset !== asset.value) return false
    if (r.strategy !== 'long_only') return false
    const name = (r?.agent_name || '').toLowerCase()
    return !EXCLUDED_AGENT_NAMES.has(name)
  })
)

/* winners: best model per agent (by leaderboard balance) */
const winners = computed(() => {
  const byAgent = new Map()
  for (const r of filteredRows.value) {
    const k = r.agent_name
    const cur = byAgent.get(k)
    if (!cur || score(r) > score(cur)) byAgent.set(k, r)
  }
  return [...byAgent.values()]
})

/* chart selections */
const winnersForChart = computed(() => {
  // Get max end_date for current asset from all rows
  const rowsForAsset = (rowsRef.value || []).filter(r => r.asset === asset.value)
  const endDates = rowsForAsset.map(r => r.end_date).filter(Boolean)
  const maxEndDate = endDates.length ? endDates.sort().pop() : null
  
  return winners.value.map(w => ({
    agent_name:  w.agent_name,
    asset:       w.asset,
    model:       w.model,
    strategy:    w.strategy,
    decision_ids: Array.isArray(w.decision_ids) ? w.decision_ids : undefined,
    end_date:    maxEndDate || w.end_date  // use max end_date from all rows for this asset
  }))
})

/* stable key to avoid identity churn */
const winnersKey = computed(() => {
  const sels = winnersForChart.value || []
  return sels.map(s => `${s.agent_name}|${s.asset}|${s.model}|${s.strategy}|${(s.decision_ids?.length||0)}`).join('||')
})

/* ---------- PERF ---------- */
async function buildSeq(sel) {
  const { agent_name: agentName, asset: assetCode, model } = sel
  const ids = Array.isArray(sel.decision_ids) ? sel.decision_ids : []
  let seq = ids.length
    ? allDecisions.filter(r => ids.includes(r.id))
    : allDecisions.filter(r => r.agent_name === agentName && r.asset === assetCode && r.model === model)

  seq.sort((a,b) => (a.date > b.date ? 1 : -1))
  const cutoff = ASSET_CUTOFF[assetCode]
  if (cutoff) {
    const t0 = new Date(cutoff + 'T00:00:00Z')
    seq = seq.filter(r => new Date(r.date + 'T00:00:00Z') >= t0)
  }
  // if using decision_ids, data is already prefiltered
  if (!ids.length) {
    const isCrypto = assetCode === 'BTC' || assetCode === 'ETH'
    if (!isCrypto) seq = await filterRowsToNyseTradingDays(seq)
  }
  return seq
}

async function computeEquities(sel) {
  const seq = await buildSeq(sel)

  if (!seq.length) return null

  const cfg = (STRATEGIES || []).find(s => s.id === sel.strategy) || { strategy: 'long_only', tradingMode: 'aggressive', fee: 0.0005 }

  const stratY = computeStrategyEquity(seq, 100000, cfg.fee, cfg.strategy, cfg.tradingMode) || []
  const bhY    = computeBuyHoldEquity(seq, 100000) || []
  const lastIdx = Math.min(stratY.length, bhY.length) - 1
  if (lastIdx < 0) return null

  // quality metrics
  const isCrypto = sel.asset === 'BTC' || sel.asset === 'ETH'
  const metrics = calculateMetricsFromSeries(stratY, isCrypto ? 'crypto' : 'stock') || {}
  const { sharpe_ratio: sharpe, max_drawdown: maxDrawdown, total_return: totalReturnPct } = metrics

  // win rate / trades
  let winRate = null
  let trades = null
  try {
    const r = computeWinRate(seq, cfg.strategy, cfg.tradingMode) || {}
    winRate = r.winRate
    trades = r.trades
  } catch {}

  // approximate "days" from sequence
  let days = 0
  try {
    const start = new Date(seq[0].date)
    const end = new Date(seq[lastIdx].date)
    days = Math.max(1, Math.round((end - start) / 86400000) + 1)
  } catch {}

  return {
    date: seq[lastIdx]?.date || sel.end_date,  // prefer actual sequence date over leaderboard end_date
    stratLast: stratY[lastIdx],
    bhLast: bhY[lastIdx],
    sharpe,
    maxDrawdown,            // as fraction (e.g., -0.053)
    winRate, trades, days,
    totalReturnPct          // for future use if needed
  }
}

/* build cards whenever winners/asset change */
let computing = false
watch(
  () => [asset.value, winnersKey.value],
  async () => {
    if (computing) return
    if (!winnersForChart.value.length) { cards.value = []; return }
    computing = true
    try {
      const perfs = (await Promise.all(
        winnersForChart.value.map(async sel => ({ sel, perf: await computeEquities(sel) }))
      )).filter(x => x.perf)

      if (!perfs.length) { cards.value = []; return }

      // Get max date directly from Supabase for this asset
      const currentAsset = asset.value
      let maxEndDate = null
      try {
        const { data, error } = await supabase
          .from('trading_decisions')
          .select('date')
          .eq('asset', currentAsset)
          .order('date', { ascending: false })
          .limit(1)
        
        if (!error && data && data.length > 0) {
          maxEndDate = data[0].date
          console.log('[LiveView] Direct Supabase query - Asset:', currentAsset, 'Max date:', maxEndDate)
        } else {
          console.log('[LiveView] Supabase query failed or no data:', error)
        }
      } catch (e) {
        console.error('[LiveView] Error querying Supabase:', e)
      }

      // Buy & Hold first
      const first = perfs[0]
      const assetCode = first.sel.asset
      const bhCard = {
        key: `bh|${assetCode}`,
        kind: 'bh',
        title: 'Buy & Hold',
        subtitle: assetCode,
        balance: first.perf.bhLast,
        date: maxEndDate || first.perf.date,  // Use max date from Supabase
        logo: ASSET_ICONS[assetCode] || null,
        profitUsd: (first.perf.bhLast ?? 0) - 100000,
        gapUsd: 0,
        gapPct: 0,
        rank: null,
        barPct: 0,
        // BH quality fields are neutral/na
        sharpe: null,
        maxDrawdown: null,
        winRate: null,
        trades: null,
        days: null
      }

      // Agents
      const agentCards = perfs.map(({ sel, perf }) => {
        const gapUsd = perf.stratLast - perf.bhLast
        const gapPct = perf.bhLast > 0 ? (perf.stratLast / perf.bhLast - 1) : 0
        const profitUsd = (perf.stratLast ?? 0) - 100000
        return {
          key: `agent|${sel.agent_name}|${sel.model}`,
          kind: 'agent',
          title: sel.agent_name,
          subtitle: formatModelName(sel.model),
          balance: perf.stratLast,
          date: maxEndDate || perf.date,  // Use max date from Supabase
          logo: AGENT_LOGOS[sel.agent_name] || null,
          gapUsd, gapPct,
          profitUsd,
          sharpe: perf.sharpe,
          maxDrawdown: perf.maxDrawdown,
          winRate: perf.winRate,
          trades: perf.trades,
          days: perf.days,
          rank: null,
          barPct: 0
        }
      })

      // Rank by balance (agents only)
      agentCards.sort((a,b) => (b.balance ?? -Infinity) - (a.balance ?? -Infinity))
      agentCards.forEach((c, i) => { c.rank = i + 1 })

      // Perf bar width scaled to max |gapUsd|
      const maxAbsGap = Math.max(1, ...agentCards.map(c => Math.abs(c.gapUsd ?? 0)))
      agentCards.forEach(c => { c.barPct = Math.max(3, Math.round((Math.abs(c.gapUsd ?? 0) / maxAbsGap) * 100)) })

      // BH first, then top agents (limit 5)
      cards.value = [bhCard, ...agentCards].slice(0,5)
    } finally { computing = false }
  },
  { immediate: true }
)
</script>

<!-- Global brand tokens (unscoped to ensure cascade) -->
<!-- Paste this inside your Live view component as the full style -->
<style scoped>
/* ======= Page ======= */
.live{
  max-width:1280px;
  margin:0 auto;
  padding:0 24px 64px;
  color:var(--ink-900);
  background: radial-gradient(ellipse at 30% -10%, #fdfdfd 0%, var(--surface-2) 60%, var(--surface-0) 100%);
  margin-top: -40px;
}

/* ======= About Banner ======= */
.about-banner{
  padding: 8px 24px 16px 56px;
  background: var(--surface-0);
  margin: 0 -24px 0 -24px;
}
.about-text{
  margin: 0;
  font-size: 15px;
  font-weight: 500;
  color: #6b7280;
  letter-spacing: 0.01em;
  line-height: 1.5;
}
.about-text .paper-link{
  color: rgb(var(--ama-start));
  font-weight: 700;
  text-decoration: none;
  transition: all 0.2s ease;
  border-bottom: 1px solid transparent;
}
.about-text .paper-link:hover{
  color: rgb(var(--ama-end));
  border-bottom-color: rgb(var(--ama-end));
}

/* ======= Toolbar (assets + mode) ======= */
.toolbar{
  position:sticky; top:0; z-index:10;
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:12px 0 14px; background:var(--surface-0);
  border-bottom:2px solid rgba(var(--ama-end), .15);
  backdrop-filter: blur(10px);
}
.toolbar__right{ display:flex; align-items:center; gap:12px; }

/* ======= Asset tabs ======= */
.asset-tabs{
  display:inline-flex; gap:6px; padding:4px;
  border-radius:12px; background:var(--surface-0);
  border:1px solid var(--bd-subtle); box-shadow:0 2px 8px rgba(0,0,0,.04);
}
.asset-tab{
  min-width:54px; height:32px; padding:0 10px;
  border-radius:8px; border:1px solid transparent;
  background:transparent; color:var(--ink-900);
  font-weight:800; letter-spacing:.02em; cursor:pointer; transition:all .2s ease;
}
.asset-tab:hover{ color:rgb(var(--ama-end)); border-color:rgba(var(--ama-end), .28); }
.asset-tab.is-active{
  color:#fff; border:none;
  background: linear-gradient(90deg, rgb(var(--ama-start)), rgb(var(--ama-end)));
  box-shadow: 0 0 0 1px rgba(var(--ama-end), .22), 0 8px 18px rgba(var(--ama-end), .22);
}

/* ======= Mode switch ($ / %) ======= */
.mode-switch{
  display:inline-grid; grid-template-columns:1fr 1fr;
  border-radius:12px; overflow:hidden;
  border:1px solid var(--bd-subtle); background:var(--surface-0);
  box-shadow:0 2px 8px rgba(0,0,0,.04);
}
.mode-switch__btn{
  height:32px; min-width:44px; padding:0 12px;
  font-weight:800; letter-spacing:.02em; border:none; background:transparent;
  color:var(--ink-900); cursor:pointer; transition:all .2s ease;
}
.mode-switch__btn:not(.is-active):hover{ color:rgb(var(--ama-end)); background:#f8fafc; }
.mode-switch__btn.is-active{
  color:#fff;
  background: linear-gradient(90deg, rgb(var(--ama-start)), rgb(var(--ama-end)));
  box-shadow: inset 0 -1px 0 rgba(255,255,255,.2);
}

/* ======= Panels ======= */
.panel{ background:var(--surface-0); border:1px solid var(--bd-soft); border-radius:16px; margin-top:16px; }
.panel--chart{ padding:10px; }
.panel--cards{ padding:16px; }

/* ======= Empty State ======= */
.empty{
  padding:20px; border:1px dashed var(--bd-soft); border-radius:12px;
  color:var(--ink-600); font-size:.95rem; background:var(--surface-0); text-align:center;
}

/* ======= Grid ======= */
.cards-grid-f1{ display:grid; gap:14px; grid-template-columns:repeat(auto-fit, minmax(260px,1fr)); }

/* ======= Cards (Tournament) ======= */
.card-f1{
  position:relative;
  display:grid; grid-template-rows:auto auto auto auto auto; gap:10px;
  padding:18px 18px 20px; min-height:230px; border-radius:16px;
  background: linear-gradient(145deg, var(--surface-0), var(--surface-2) 75%, var(--surface-0) 100%);
  border:1px solid rgba(0,0,0,.05);
  box-shadow:0 2px 10px rgba(var(--ama-start), .05), 0 6px 20px rgba(var(--ama-end), .08);
  color:var(--ink-900); transition: transform .25s ease, box-shadow .25s ease;
}
.card-f1:hover{ transform: translateY(-2px); box-shadow:0 10px 28px rgba(0,0,0,.08); }
.card-f1.bh{ border-style:dashed; }

/* Podium metals (attach .gold/.silver/.bronze) */
.card-f1.gold{
  border-color:var(--gold);
  box-shadow:0 0 0 1px rgba(212,175,55,.32), 0 10px 28px rgba(212,175,55,.18);
}
.card-f1.silver{
  border-color:var(--silver);
  box-shadow:0 0 0 1px rgba(192,192,192,.28), 0 10px 28px rgba(192,192,192,.14);
}
.card-f1.bronze{
  border-color:var(--bronze);
  box-shadow:0 0 0 1px rgba(205,127,50,.28), 0 10px 28px rgba(205,127,50,.14);
}

/* Optional thin ribbon bar on podium cards */
.podium-ribbon{ position:absolute; top:0; left:0; right:0; height:6px; border-top-left-radius:16px; border-top-right-radius:16px; }
.card-f1.gold   .podium-ribbon{ background: linear-gradient(90deg, #f6e27a, var(--gold)); }
.card-f1.silver .podium-ribbon{ background: linear-gradient(90deg, #e9eef2, var(--silver)); }
.card-f1.bronze .podium-ribbon{ background: linear-gradient(90deg, #f0c6a1, var(--bronze)); }

/* ======= Card: Head ======= */
.head{ display:grid; grid-template-columns:44px minmax(0,1fr); align-items:center; gap:12px; }
.logo{ width:44px; height:44px; border-radius:12px; background:#f3f4f6; display:grid; place-items:center; overflow:hidden; border:1px solid #E5E7EB; }
.logo img{ width:100%; height:100%; object-fit:contain; }
.logo__fallback{ width:60%; height:60%; border-radius:6px; background:#e5e7eb; }
.names{ min-width:0; }
.agent{ font-size:16px; font-weight:900; letter-spacing:.02em; text-transform:uppercase; color:var(--ink-900); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.model{ font-size:11px; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace; color:#64748b; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

/* ======= KPIs (Net Value + P&L) ======= */
.kpis{ display:grid; grid-template-columns:1fr auto; align-items:end; gap:12px; }
.kpi__label{ font-size:12px; color:var(--ink-600); }
.kpi__value{ font-size: clamp(18px, 2.2vw, 25px); font-weight:700; letter-spacing:-.01em; color:var(--ink-900); }
.kpi__pill{
  display:inline-block; font-size:12px; font-weight:800; padding:4px 10px; border-radius:999px;
  border:1px solid var(--bd-soft); background:#F6F8FB; color:var(--ink-900);
}
.kpi__pill.pos{ color:var(--pos-fg); background:var(--pos-bg); border-color:var(--pos-br); }
.kpi__pill.neg{ color:var(--neg-fg); background:var(--neg-bg); border-color:var(--neg-br); }

/* ======= Quality (Sharpe, MaxDD) ======= */
.quality{ display:grid; grid-template-columns:1fr 1fr; gap:12px; padding:2px 0 0; }
.qitem{ display:flex; align-items:baseline; gap:8px; }
.qitem__label{ font-size:12px; color:var(--ink-600); }
.qitem__value{ font-size:14px; font-weight:800; color:var(--ink-900); }
.qitem__value.strong{ color:var(--pos-fg); }
.qitem__value.dd-pos{ color:var(--pos-fg); }    /* small drawdown */
.qitem__value.dd-mid{ color:var(--ink-900); }   /* medium drawdown */
.qitem__value.dd-neg{ color:var(--neg-fg); }    /* large drawdown */

/* ======= Stats (WinRate, Trades, Days) ======= */
.stats{ display:grid; grid-template-columns:repeat(3, 1fr); gap:10px; font-size:12px; color:var(--ink-700); }
.stat{ display:flex; align-items:center; justify-content:space-between; background:#F8FAFD; border:1px solid var(--bd-soft); border-radius:10px; padding:6px 8px; }
.stat__label{ color:var(--ink-600); }
.stat__val{ font-weight:800; color:var(--ink-900); }
.stat__val.pos{ color:var(--pos-fg); }
.stat__val.neg{ color:var(--neg-fg); }

/* ======= Bar vs B&H ======= */
.bar{ height:6px; border-radius:999px; background:#F2F4F8; overflow:hidden; border:1px solid var(--bd-soft); margin:2px 0 8px; }
.bar span{ display:block; height:100%; width:var(--bar, 40%); transition:width .5s ease;
  background: linear-gradient(90deg,#16a34a,#22c55e);
}
.bar.neg span{ background: linear-gradient(90deg,#ef4444,#dc2626); }

/* ======= Meta (Gap vs B&H chip + EOD) ======= */
.meta{ display:grid; grid-template-columns:1fr auto; align-items:center; gap:8px; }
.chip{
  display:inline-flex; align-items:center; gap:6px;
  font-size:12px; font-weight:800; padding:4px 8px; border-radius:999px;
  background:#F6F8FB; color:var(--ink-900); border:1px solid var(--bd-soft);
}
.chip.pos{ color:var(--pos-fg); background:var(--pos-bg); border-color:var(--pos-br); }
.chip.neg{ color:var(--neg-fg); background:var(--neg-bg); border-color:var(--neg-br); }
.chip__label{ opacity:.8; }
.chip__value{ font-variant-numeric: tabular-nums; }
.eod{ font-size:12px; color:var(--ink-600); }

/* ======= Responsive ======= */
@media (max-width: 900px){
  .stats{ grid-template-columns:1fr 1fr; }
}
@media (max-width: 640px){
  .cards-grid-f1{ grid-template-columns:1fr; }
  .kpi__value{ font-size:22px; }
  .about-text{ font-size: 14px; }
}
</style>
