import { useEffect, useState } from 'react'
import { Link } from 'react-router-dom'
import { LogoMark } from '@/components/brand/Logo'
import { TVChart, ChartSkeleton } from '@/components/viz/TVChart'
import { LiveFeed } from '@/components/viz/LiveFeed'
import { Orchestra } from '@/components/viz/Orchestra'
import { AgentWorkflow } from '@/components/viz/AgentWorkflow'
import { Onboarding, TOUR_EVENT } from '@/components/Onboarding'
import { useScreen } from '@/hooks/useHyperliquid'
import { fmtPrice, fmtPct, fmtCompact } from '@/lib/format'
import type { Direction, Vote } from '@/lib/signals'

const COINS = ['BTC', 'ETH', 'SOL']
const TIMEFRAMES = ['1m', '5m', '15m', '1h', '4h', '1d'] as const

const AGENT_META: Record<string, { label: string; reads: string }> = {
  TrendAgent: { label: 'Trend', reads: 'EMA 9/21 · RSI' },
  BreakoutAgent: { label: 'Breakout', reads: 'Bollinger %B' },
  MeanReversionAgent: { label: 'Mean-Rev', reads: 'RSI extremes' },
  FundingAgent: { label: 'Funding', reads: 'funding-Z' },
}
const AGENT_RULES: Record<string, string> = {
  TrendAgent: 'Trend — LONG when EMA9 > EMA21 and RSI > 50; SHORT on the reverse; else SKIP.',
  BreakoutAgent: 'Breakout — LONG when price pushes the upper Bollinger band (%B > 0.92); SHORT at the lower (< 0.08).',
  MeanReversionAgent: 'Mean-Rev — fade extremes: LONG when RSI < 32 in the lower band; SHORT when RSI > 68 at the upper.',
  FundingAgent: 'Funding — fade crowded funding: SHORT when funding-Z > 1.5; LONG when < −1.5.',
}
const METRIC_INFO: Record<string, string> = {
  Mark: 'Mark price — the fair price Hyperliquid uses for PnL & liquidation, not the last trade.',
  '24h Δ': 'Price change over the last 24 hours.',
  Funding: 'Funding rate — periodic longs↔shorts payment. Positive = longs pay (crowded longs).',
  ATR: 'Average True Range — volatility; it scales the verdict TP / SL.',
  'Open interest': 'Open interest — total USD value of open perpetual contracts.',
  '24h volume': '24-hour traded volume, in USD.',
  'RSI (14)': 'RSI — momentum 0–100; >70 overbought, <30 oversold. Feeds Mean-Rev.',
  'Bollinger %B': 'Where price sits in the Bollinger band (0 = lower, 1 = upper). Feeds Breakout.',
  'EMA 9/21': 'Fast vs slow moving average — trend direction. Feeds Trend.',
  'Funding-Z': 'Normalised funding skew. Feeds the Funding agent.',
  'MACD hist': 'MACD histogram — momentum (MACD line minus its signal).',
  'Net vote': 'Aggregate of the 4 agents (LONG +, SHORT −). Drives the verdict.',
}
const INK = 'var(--color-bone)'
const clampN = (n: number, lo: number, hi: number) => Math.max(lo, Math.min(hi, n))
const dirColor = (d: Direction) =>
  d === 'LONG' ? 'var(--color-long)' : d === 'SHORT' ? 'var(--color-short)' : 'var(--color-muted)'
const dirBg = (d: Direction) =>
  d === 'LONG' ? 'var(--color-long-dim)' : d === 'SHORT' ? 'var(--color-short-dim)' : 'var(--color-track)'
const sign = (n: number) => (n >= 0 ? '+' : '')

type Inspect = (s: string | null) => void

/* ── primitives ───────────────────────────────────────────────────────────── */

function Panel({
  title,
  meta,
  className = '',
  children,
}: {
  title: React.ReactNode
  meta?: React.ReactNode
  className?: string
  children: React.ReactNode
}) {
  return (
    <section className={`overflow-hidden rounded-md border border-line bg-panel ${className}`}>
      <header className="flex items-center justify-between gap-3 border-b border-line-soft px-3 py-2">
        <span className="label !text-[0.625rem]">{title}</span>
        {meta != null && <span className="font-mono text-micro text-faint">{meta}</span>}
      </header>
      {children}
    </section>
  )
}

function Cell({
  label,
  value,
  tone,
  sub,
  bar,
  barTone,
  info,
  onInspect,
  loading,
}: {
  label: string
  value: string
  tone?: string
  sub?: string
  bar?: number
  barTone?: string
  info?: string
  onInspect?: Inspect
  loading?: boolean
}) {
  return (
    <div
      className={`bg-inset px-3 py-2 transition-colors ${info && !loading ? 'cursor-help hover:bg-panel-2' : ''}`}
      onMouseEnter={info && onInspect && !loading ? () => onInspect(info) : undefined}
      onMouseLeave={info && onInspect && !loading ? () => onInspect(null) : undefined}
    >
      <div className="label-sm !text-[0.5625rem]">{label}</div>
      {loading ? (
        <div className="skeleton mt-1.5 h-3.5 w-3/5" />
      ) : (
        <div className="tnum mt-1 font-mono text-data font-medium" style={{ color: tone ?? INK }}>
          {value}
        </div>
      )}
      {sub && !loading && <div className="mt-0.5 font-mono text-micro text-faint">{sub}</div>}
      {bar != null && !loading && (
        <div className="mt-1.5 h-0.5 w-full overflow-hidden rounded-full" style={{ background: 'var(--color-track)' }}>
          <div
            className="h-full rounded-full"
            style={{ width: `${clampN(bar, 0, 100)}%`, background: barTone ?? 'var(--color-bone-dim)', transition: 'width .5s cubic-bezier(.22,1,.36,1)' }}
          />
        </div>
      )}
    </div>
  )
}

function DivergeBar({ direction, score }: { direction: Direction; score: number }) {
  const col = dirColor(direction)
  return (
    <div className="relative h-2 flex-1 overflow-hidden rounded-full" style={{ background: 'var(--color-track)' }}>
      <div className="absolute inset-y-0 left-1/2 w-px" style={{ background: 'var(--color-line-strong)' }} />
      {direction === 'LONG' && (
        <div className="absolute inset-y-0.5 rounded-r-full" style={{ left: '50%', width: `${score * 50}%`, background: col, transition: 'width .5s cubic-bezier(.22,1,.36,1)' }} />
      )}
      {direction === 'SHORT' && (
        <div className="absolute inset-y-0.5 rounded-l-full" style={{ right: '50%', width: `${score * 50}%`, background: col, transition: 'width .5s cubic-bezier(.22,1,.36,1)' }} />
      )}
      {direction === 'SKIP' && (
        <div className="absolute inset-y-0.5 left-1/2 w-1 -translate-x-1/2 rounded-full" style={{ background: 'var(--color-muted)' }} />
      )}
    </div>
  )
}

/* ── command bar ──────────────────────────────────────────────────────────── */

function StatusBar({ live, ago, stale, onReload }: { live: boolean; ago: number | null; stale: boolean; onReload: () => void }) {
  const [now, setNow] = useState(() => new Date())
  const [spin, setSpin] = useState(false)
  useEffect(() => {
    const id = setInterval(() => setNow(new Date()), 1000)
    return () => clearInterval(id)
  }, [])
  const reload = () => {
    onReload()
    setSpin(true)
    setTimeout(() => setSpin(false), 600)
  }
  const clock = now.toISOString().slice(11, 19)
  const statusCol = stale ? 'var(--color-accent)' : live ? 'var(--color-long)' : 'var(--color-muted)'
  const statusText = stale ? 'DATA STALE' : live ? 'LIVE · HL' : 'CONNECTING'
  return (
    <header className="sticky top-0 z-50 border-b border-line bg-paper/90 backdrop-blur-md">
      <div className="mx-auto flex h-10 max-w-none items-center justify-between gap-4 px-4 sm:px-6">
        <div className="flex items-center gap-2.5">
          <Link to="/" className="flex items-center gap-2.5" aria-label="Home">
            <LogoMark className="h-5 w-5" />
            <span className="font-display text-sm font-bold tracking-tight text-bone">
              Quant<span className="text-muted"> Agent</span>
            </span>
          </Link>
          <span className="label-sm hidden border-l border-line-soft pl-2.5 !text-faint sm:inline">Terminal</span>
        </div>

        <div className="flex items-center gap-3 font-mono text-micro uppercase tracking-[0.1em]">
          <span className="flex items-center gap-1.5" style={{ color: statusCol }}>
            <span className={stale ? 'inline-block h-1.5 w-1.5 rounded-full' : 'blink inline-block h-1.5 w-1.5 rounded-full'} style={{ background: statusCol }} />
            {statusText}
          </span>
          <button type="button" onClick={reload} title="Refresh now (r)" aria-label="Refresh now" className="flex cursor-pointer items-center gap-1 text-faint transition-colors hover:text-bone">
            <span className={spin ? 'inline-block animate-spin' : 'inline-block'} style={{ animationDuration: '0.6s' }} aria-hidden>↻</span>
            {ago != null && <span className="tnum hidden sm:inline">{ago}s</span>}
          </button>
          <span className="tnum hidden text-bone-dim md:inline">{clock} UTC</span>
        </div>
      </div>
    </header>
  )
}

/* ── compact verdict bar (the call — dense, not a hero) ───────────────────── */

function VerdictBar({ decision, confidence, sizePct, tpPct, slPct, net, votes, reasoning, live, loading }: {
  decision: Direction; confidence: number; sizePct: number; tpPct: number; slPct: number; net: number; votes: Vote[]; reasoning: string; live: boolean; loading: boolean
}) {
  if (loading) {
    return (
      <div className="flex items-center gap-4 rounded-md border border-line bg-panel py-2.5 pl-3 pr-4" style={{ borderLeft: '2px solid var(--color-line-strong)' }} aria-busy="true">
        <span className="label-sm !text-faint">Verdict</span>
        <div className="skeleton h-6 w-24" />
        <div className="skeleton h-3.5 w-12" />
        <div className="skeleton h-3.5 w-14" />
        <div className="skeleton hidden h-3.5 w-12 sm:block" />
        <div className="skeleton hidden h-3.5 w-14 sm:block" />
        <div className="skeleton hidden h-3.5 w-14 sm:block" />
      </div>
    )
  }
  const active = votes.filter((v) => v.direction !== 'SKIP')
  const agree = active.filter((v) => v.direction === decision)
  const rr = slPct ? tpPct / slPct : 0
  const col = dirColor(decision)
  const Sep = () => <span className="hidden h-4 w-px bg-line-soft sm:block" />
  const Field = ({ k, v, c }: { k: string; v: string; c?: string }) => (
    <span className="flex items-baseline gap-1.5">
      <span className="label-sm !text-[0.5625rem] !text-faint">{k}</span>
      <span className="tnum font-mono text-data font-medium" style={{ color: c ?? INK }}>{v}</span>
    </span>
  )
  return (
    <div className="flex flex-wrap items-center gap-x-4 gap-y-2 rounded-md border border-line bg-panel py-2.5 pl-3 pr-4" style={{ borderLeft: `2px solid ${col}` }}>
      <span className="label-sm !text-faint">Verdict</span>
      <span className="font-display text-2xl font-bold leading-none tracking-tight" style={{ color: col }}>{decision}</span>
      <Field k="conf" v={`${Math.round(confidence * 100)}%`} c={col} />
      <Field k="net" v={`${sign(net)}${net.toFixed(2)}`} c={net > 0 ? 'var(--color-long)' : net < 0 ? 'var(--color-short)' : INK} />
      <span className="font-mono text-micro text-muted">{decision === 'SKIP' ? 'no consensus' : `${agree.length}/${active.length} agree`}</span>
      <Sep />
      <Field k="size" v={`${sizePct}%`} />
      <Field k="TP" v={fmtPct(tpPct)} c="var(--color-long)" />
      <Field k="SL" v={fmtPct(-slPct)} c="var(--color-short)" />
      <Field k="R:R" v={rr ? rr.toFixed(1) : '—'} />
      {!live && (
        <span className="label-sm rounded-sm px-1.5 py-0.5 !text-accent" style={{ background: 'var(--color-accent-dim)' }}>seed</span>
      )}
      <span className="ml-auto hidden max-w-sm truncate font-mono text-micro text-muted xl:block">{reasoning}</span>
    </div>
  )
}

/* ── committee (selectable, dense) ────────────────────────────────────────── */

function Committee({ votes, net, activeAgent, onSelect, onHover, loading }: {
  votes: Vote[]; net: number; activeAgent?: string | null; onSelect?: (a: string | null) => void; onHover?: (a: string | null) => void; loading?: boolean
}) {
  if (loading) {
    return (
      <Panel title="Committee · analytics" meta="4 · L3" className="flex h-full flex-col">
        <div className="flex flex-1 flex-col divide-y divide-line-soft" aria-busy="true">
          {[0, 1, 2, 3].map((i) => (
            <div key={i} className="grid grid-cols-[5rem_1fr] gap-x-3 px-3 py-2.5">
              <div className="space-y-1.5 self-center">
                <div className="skeleton h-3 w-12" />
                <div className="skeleton h-2 w-16" />
              </div>
              <div className="flex items-center gap-2.5">
                <div className="skeleton h-2 flex-1" />
                <div className="skeleton h-3 w-10" />
              </div>
            </div>
          ))}
        </div>
      </Panel>
    )
  }
  const active = votes.filter((v) => v.direction !== 'SKIP')
  const lean = active.length ? clampN(net / active.length, -1, 1) : 0
  return (
    <Panel title="Committee · analytics" meta={`${votes.length} · L3`} className="flex h-full flex-col">
      <div className="flex flex-1 flex-col divide-y divide-line-soft">
        {votes.map((v) => {
          const meta = AGENT_META[v.agent] ?? { label: v.agent.replace('Agent', ''), reads: '' }
          const signal = v.direction !== 'SKIP'
          const col = dirColor(v.direction)
          const on = activeAgent === v.agent
          return (
            <button
              key={v.agent}
              type="button"
              onClick={() => onSelect?.(on ? null : v.agent)}
              onMouseEnter={() => onHover?.(v.agent)}
              onMouseLeave={() => onHover?.(null)}
              aria-pressed={on}
              className={['grid w-full flex-1 cursor-pointer grid-cols-[5rem_1fr] content-center gap-x-3 border-l-2 px-3 py-2.5 text-left transition-colors', on ? 'border-accent bg-panel-2' : 'border-transparent hover:bg-panel-2'].join(' ')}
            >
              <div className="self-center">
                <div className="font-mono text-data font-medium text-bone">{meta.label}</div>
                <div className="label-sm !text-[0.5625rem] !text-faint">{meta.reads}</div>
              </div>
              <div className="flex items-center gap-2.5">
                <DivergeBar direction={v.direction} score={v.score} />
                <span className="tnum w-6 shrink-0 text-right font-mono text-micro text-muted">{Math.round(v.score * 100)}</span>
                <span className="w-12 shrink-0 rounded-sm px-1 py-0.5 text-center font-mono text-[0.5625rem] font-semibold uppercase tracking-[0.04em]" style={{ color: signal ? col : 'var(--color-muted)', background: dirBg(v.direction) }}>
                  {signal ? v.direction : 'skip'}
                </span>
              </div>
              <p className="col-start-2 mt-1 font-mono text-micro leading-snug text-bone-dim">{v.reason}</p>
              {on && AGENT_RULES[v.agent] && (
                <p className="reveal col-start-2 mt-1 font-mono text-micro leading-snug text-faint" style={{ animationDuration: '0.4s' }}>{AGENT_RULES[v.agent]}</p>
              )}
            </button>
          )
        })}
      </div>
      <div className="grid grid-cols-[5rem_1fr] items-center gap-x-3 border-t border-line-strong bg-inset px-3 py-2.5">
        <span className="label-sm !text-[0.5625rem] !text-bone-dim">net lean</span>
        <div className="flex items-center gap-2.5">
          <div className="relative h-2 flex-1 overflow-hidden rounded-full" style={{ background: 'var(--color-track)' }}>
            <div className="absolute inset-y-0 left-1/2 w-px" style={{ background: 'var(--color-line-strong)' }} />
            {lean >= 0 ? (
              <div className="absolute inset-y-0.5 rounded-r-full" style={{ left: '50%', width: `${lean * 50}%`, background: 'var(--color-long)' }} />
            ) : (
              <div className="absolute inset-y-0.5 rounded-l-full" style={{ right: '50%', width: `${-lean * 50}%`, background: 'var(--color-short)' }} />
            )}
            <div className="absolute inset-y-0 w-0.5" style={{ left: `${50 + lean * 50}%`, background: 'var(--color-accent)' }} />
          </div>
          <span className="tnum w-6 shrink-0 text-right font-mono text-micro text-bone">{net.toFixed(1)}</span>
          <span className="w-12 shrink-0" />
        </div>
      </div>
    </Panel>
  )
}

/* ── help card (opened from the ? in the toolbar) ─────────────────────────── */

const GUIDE = [
  { t: 'The verdict', d: "The committee's single call — LONG (up), SHORT (down) or SKIP (no edge), with confidence and the suggested size / TP / SL." },
  { t: 'The committee', d: 'Four strategies each vote. The graph shows them feeding the verdict; the list shows each vote and why.' },
  { t: 'Interact', d: 'Switch timeframe & coin up top, hover any field to inspect it, click an agent to pin it, ↻ to refresh. Keys: 1/2/3 coin · r refresh · Esc clear.' },
]
function GuideCard({ onClose }: { onClose: () => void }) {
  return (
    <section className="overflow-hidden rounded-md border border-line bg-panel">
      <div className="flex items-center justify-between gap-3 border-b border-line-soft px-3 py-2">
        <span className="label !text-bone">How to read this terminal</span>
        <div className="flex items-center gap-2">
          <button
            type="button"
            onClick={() => { onClose(); window.dispatchEvent(new Event(TOUR_EVENT)) }}
            className="rounded-sm border border-line px-2 py-0.5 font-mono text-micro uppercase tracking-[0.08em] text-muted transition-colors hover:border-accent hover:text-accent"
          >
            ▷ replay intro
          </button>
          <button type="button" onClick={onClose} className="rounded-sm border border-line px-2 py-0.5 font-mono text-micro uppercase tracking-[0.08em] text-muted transition-colors hover:border-line-strong hover:text-bone">close ✕</button>
        </div>
      </div>
      <div className="grid grid-cols-1 gap-px bg-line-soft sm:grid-cols-3">
        {GUIDE.map((g, i) => (
          <div key={g.t} className="bg-inset px-3 py-2.5">
            <div className="flex items-center gap-2">
              <span className="tnum flex h-4 w-4 items-center justify-center rounded-full font-mono text-[0.6rem] font-bold" style={{ background: 'var(--color-accent)', color: 'var(--color-ink)' }}>{i + 1}</span>
              <span className="font-mono text-data font-semibold text-bone">{g.t}</span>
            </div>
            <p className="mt-1.5 font-mono text-micro leading-relaxed text-bone-dim">{g.d}</p>
          </div>
        ))}
      </div>
    </section>
  )
}

/* ── page ─────────────────────────────────────────────────────────────────── */

export function Terminal() {
  const [coin, setCoin] = useState('BTC')
  const [tf, setTf] = useState<string>('1h')
  const [selectedAgent, setSelectedAgent] = useState<string | null>(null)
  const [hoverAgent, setHoverAgent] = useState<string | null>(null)
  const [inspect, setInspect] = useState<string | null>(null)
  const [guideOpen, setGuideOpen] = useState(false)
  const activeAgent = hoverAgent ?? selectedAgent
  const { data, live, updatedAt, error, reload } = useScreen(coin, tf, 12_000)
  const ta = data?.ta
  const v = data?.verdict
  const stat = data?.stat
  const votes = data?.votes ?? []
  const candles = data?.candles ?? []

  const [, setTick] = useState(0)
  useEffect(() => {
    const id = setInterval(() => setTick((t) => t + 1), 1000)
    return () => clearInterval(id)
  }, [])
  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      const el = e.target as HTMLElement | null
      if (el && (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.isContentEditable)) return
      if (e.metaKey || e.ctrlKey || e.altKey) return
      if (e.key === '1' || e.key === '2' || e.key === '3') setCoin(COINS[+e.key - 1])
      else if (e.key.toLowerCase() === 'r') reload()
      else if (e.key === 'Escape') {
        setSelectedAgent(null)
        setGuideOpen(false)
      }
    }
    window.addEventListener('keydown', onKey)
    return () => window.removeEventListener('keydown', onKey)
  }, [reload])

  const ago = updatedAt ? Math.max(0, Math.round((Date.now() - updatedAt) / 1000)) : null
  const stale = Boolean(error) || (ago != null && ago > 40)
  const loading = updatedAt === 0 // no live data for this instrument yet → show skeletons

  const changePct = stat?.changePct ?? 0
  const changeTone = changePct >= 0 ? 'var(--color-long)' : 'var(--color-short)'
  const funding = stat?.funding ?? 0
  const fundingTone = funding >= 0 ? 'var(--color-short)' : 'var(--color-long)'
  const macdHist = ta?.macdHist ?? 0
  const macdTone = macdHist >= 0 ? 'var(--color-long)' : 'var(--color-short)'
  const emaBull = (ta?.ema9 ?? 0) >= (ta?.ema21 ?? 0)
  const emaTone = emaBull ? 'var(--color-long)' : 'var(--color-short)'
  const net = v?.net ?? 0
  const netTone = net > 0.001 ? 'var(--color-long)' : net < -0.001 ? 'var(--color-short)' : INK
  const rsi = ta?.rsi ?? 50
  const rsiTone = rsi < 32 ? 'var(--color-long)' : rsi > 68 ? 'var(--color-short)' : INK
  const decision = (v?.decision ?? 'SKIP') as Direction
  const marketMeta = live ? 'LIVE · HL' : updatedAt > 0 ? 'STALE' : 'CONNECTING…'

  // brief live summary per Orchestra status category (live / computed / the call / paper)
  const orchestraStatus = {
    live: live
      ? `$${fmtPrice(stat?.mark ?? ta?.price ?? 0)} · ${sign(changePct)}${changePct.toFixed(2)}%`
      : updatedAt > 0 ? 'stale feed' : 'connecting…',
    computed: ta ? `RSI ${rsi.toFixed(0)} · MACD ${macdHist >= 0 ? '▲' : '▼'} · ATR ${(ta.atrPct ?? 0).toFixed(2)}%` : '—',
    call: `${decision} · conf ${Math.round((v?.confidence ?? 0.5) * 100)}%`,
    callTone: dirColor(decision),
    paper: decision === 'SKIP' ? 'no position' : `${decision} ${(v?.sizePct ?? 0).toFixed(1)}%`,
  }

  const onAgentHover = (a: string | null) => {
    setHoverAgent(a)
    setInspect(a ? AGENT_RULES[a] ?? null : null)
  }

  return (
    <div className="min-h-dvh bg-paper">
      <StatusBar live={live} ago={ago} stale={stale} onReload={reload} />

      <main className="mx-auto max-w-none space-y-2.5 px-4 py-3 sm:px-6">
        {/* ── command bar — terminal grid: identity · instrument · timeframe ── */}
        <div className="overflow-hidden rounded-md border border-line bg-panel">
          <div className="grid grid-cols-1 gap-px bg-line-soft sm:grid-cols-[minmax(0,1fr)_auto_auto]">
            {/* identity + help */}
            <div className="flex items-center gap-2.5 bg-panel px-3 py-2">
              <h1 className="font-display text-lg font-bold leading-none tracking-tight text-bone">
                {coin}<span className="text-muted">-PERP</span>
              </h1>
              <span className="tnum font-mono text-data text-bone-dim">${fmtPrice(ta?.price ?? 0)}</span>
              <span className="tnum font-mono text-micro" style={{ color: changeTone }}>
                {sign(changePct)}{changePct.toFixed(2)}%
              </span>
              <button type="button" onClick={() => setGuideOpen((o) => !o)} aria-label="Help"
                className="ml-auto flex h-6 w-6 shrink-0 cursor-pointer items-center justify-center rounded-sm border border-line font-mono text-micro text-muted transition-colors hover:border-line-strong hover:text-bone">?</button>
            </div>

            {/* instrument switch — uniform grid cells */}
            <div className="flex flex-col justify-center bg-panel px-3 py-2">
              <div className="label-sm mb-1.5 !text-[0.5625rem] !text-faint">Instrument</div>
              <div className="grid grid-cols-3 gap-px overflow-hidden rounded-sm bg-line-soft" role="tablist" aria-label="Instrument">
                {COINS.map((c) => {
                  const on = c === coin
                  return (
                    <button key={c} role="tab" aria-selected={on} onClick={() => setCoin(c)}
                      style={on ? { boxShadow: 'inset 0 1.5px 0 var(--color-accent)' } : undefined}
                      className={['cursor-pointer px-3 py-1.5 text-center font-mono text-[0.625rem] font-semibold uppercase tracking-[0.06em] transition-colors', on ? 'bg-panel-2 text-accent' : 'bg-inset text-muted hover:bg-panel-2 hover:text-bone'].join(' ')}>
                      {c}
                    </button>
                  )
                })}
              </div>
            </div>

            {/* timeframe switch — uniform grid cells */}
            <div className="flex flex-col justify-center bg-panel px-3 py-2">
              <div className="label-sm mb-1.5 !text-[0.5625rem] !text-faint">Timeframe</div>
              <div className="grid grid-cols-6 gap-px overflow-hidden rounded-sm bg-line-soft sm:min-w-[18rem]" role="tablist" aria-label="Timeframe">
                {TIMEFRAMES.map((t) => {
                  const on = t === tf
                  return (
                    <button key={t} role="tab" aria-selected={on} onClick={() => setTf(t)}
                      style={on ? { boxShadow: 'inset 0 1.5px 0 var(--color-accent)' } : undefined}
                      className={['cursor-pointer px-2 py-1.5 text-center font-mono text-[0.625rem] font-semibold uppercase transition-colors', on ? 'bg-panel-2 text-accent' : 'bg-inset text-muted hover:bg-panel-2 hover:text-bone'].join(' ')}>
                      {t}
                    </button>
                  )
                })}
              </div>
            </div>
          </div>
        </div>

        {guideOpen && <GuideCard onClose={() => setGuideOpen(false)} />}

        {/* ── workspace · chart with side blocks (moved to top — first) ── */}
        <div className="grid items-stretch gap-2.5 lg:grid-cols-[250px_minmax(0,1fr)_330px]">
          {/* LEFT — stats + pipeline */}
          <div className="space-y-2.5">
            <Panel title="Market" meta={marketMeta}>
              <div className="grid grid-cols-2 gap-px bg-line-soft">
                <Cell label="Mark" value={`$${fmtPrice(stat?.mark ?? ta?.price ?? 0)}`} info={METRIC_INFO.Mark} onInspect={setInspect} loading={loading} />
                <Cell label="24h Δ" value={`${sign(changePct)}${changePct.toFixed(2)}%`} tone={changeTone} info={METRIC_INFO['24h Δ']} onInspect={setInspect} loading={loading} />
                <Cell label="Funding" value={`${sign(funding)}${(funding * 100).toFixed(4)}%`} tone={fundingTone} info={METRIC_INFO.Funding} onInspect={setInspect} loading={loading} />
                <Cell label="ATR" value={`${(ta?.atrPct ?? 0).toFixed(2)}%`} info={METRIC_INFO.ATR} onInspect={setInspect} loading={loading} />
                <Cell label="Open interest" value={`$${fmtCompact(stat?.oiUsd ?? 0)}`} info={METRIC_INFO['Open interest']} onInspect={setInspect} loading={loading} />
                <Cell label="24h volume" value={`$${fmtCompact(stat?.dayVolumeUsd ?? 0)}`} info={METRIC_INFO['24h volume']} onInspect={setInspect} loading={loading} />
              </div>
            </Panel>
            <Panel title="Indicators" meta="→ committee">
              <div className="grid grid-cols-2 gap-px bg-line-soft">
                <Cell label="RSI (14)" value={rsi.toFixed(1)} tone={rsiTone} sub="→ Mean-Rev" bar={rsi} barTone={rsiTone} info={METRIC_INFO['RSI (14)']} onInspect={setInspect} loading={loading} />
                <Cell label="Bollinger %B" value={(ta?.pctB ?? 0.5).toFixed(2)} sub="→ Breakout" bar={(ta?.pctB ?? 0.5) * 100} info={METRIC_INFO['Bollinger %B']} onInspect={setInspect} loading={loading} />
                <Cell label="EMA 9/21" value={emaBull ? 'BULL ▲' : 'BEAR ▼'} tone={emaTone} sub="→ Trend" info={METRIC_INFO['EMA 9/21']} onInspect={setInspect} loading={loading} />
                <Cell label="Funding-Z" value={(ta?.fundingZ ?? 0).toFixed(2)} sub="→ Funding" info={METRIC_INFO['Funding-Z']} onInspect={setInspect} loading={loading} />
                <Cell label="MACD hist" value={`${macdHist >= 0 ? '▲' : '▼'} ${macdHist.toFixed(2)}`} tone={macdTone} info={METRIC_INFO['MACD hist']} onInspect={setInspect} loading={loading} />
                <Cell label="Net vote" value={`${sign(net)}${net.toFixed(2)}`} tone={netTone} info={METRIC_INFO['Net vote']} onInspect={setInspect} loading={loading} />
              </div>
            </Panel>
          </div>

          {/* CENTER — chart (fills the row height; fixed height only when stacked) */}
          <Panel title={`${coin}-PERP · OHLC`} meta={live ? `LIVE · ${tf.toUpperCase()} · 120` : marketMeta} className="lg:flex lg:flex-col">
            <div className="h-[440px] bg-inset px-2 py-2 sm:px-3 lg:h-auto lg:min-h-0 lg:flex-1">
              {updatedAt > 0 ? <TVChart candles={candles} fitKey={`${coin}-${tf}`} /> : <ChartSkeleton />}
            </div>
          </Panel>

          {/* RIGHT — committee */}
          <div className="space-y-2.5">
            <Committee votes={votes} net={net} activeAgent={activeAgent} onSelect={setSelectedAgent} onHover={onAgentHover} loading={loading} />
          </div>
        </div>

        {/* ── the call (compact) ── */}
        <VerdictBar
          decision={decision}
          confidence={v?.confidence ?? 0.5}
          sizePct={v?.sizePct ?? 1}
          tpPct={v?.tpPct ?? 2}
          slPct={v?.slPct ?? 1.2}
          net={net}
          votes={votes}
          reasoning={v?.reasoning ?? 'Awaiting live market data…'}
          live={live}
          loading={loading}
        />

        {/* ── pipeline row · Orchestra (left) ‖ Agent flow graph (right) ── */}
        <div className="grid grid-cols-1 items-stretch gap-2.5 xl:grid-cols-[minmax(0,0.85fr)_minmax(0,1.15fr)]">
          <Orchestra votes={votes} decision={decision} status={orchestraStatus} activeAgent={activeAgent} onSelect={setSelectedAgent} onHover={onAgentHover} onInspect={setInspect} loading={loading} gridClass="grid-cols-2 sm:grid-cols-3 lg:grid-cols-6 xl:grid-cols-3" />
          <AgentWorkflow data={data} decision={decision} activeAgent={activeAgent} onSelect={setSelectedAgent} onHover={onAgentHover} onInspect={setInspect} updatedAt={updatedAt} live={live} loading={loading} />
        </div>

        {/* ── live feed · the agent chain streaming in real time ── */}
        <LiveFeed data={data} coin={coin} tf={tf} updatedAt={updatedAt} live={live} loading={loading} onInspect={setInspect} />

        {/* ── inspector / status footer ── */}
        <div className="flex items-center gap-3 rounded-md border border-line bg-panel px-3 py-2 font-mono text-micro">
          <span className="label-sm shrink-0 !text-[0.5625rem]" style={{ color: 'var(--color-accent)' }}>Inspect</span>
          <span className="min-w-0 flex-1 truncate text-bone-dim">
            {inspect ?? 'Hover any field, agent or pipeline stage to inspect it.'}
          </span>
        </div>
      </main>

      <Onboarding />
    </div>
  )
}
