/**
 * Design study "Horizon" — v2 mockup.
 *
 * Fully self-contained: static mock data, no hooks into the API, no auth.
 * View at /design-horizon with `npm run dev` — no backend or DB needed.
 *
 * Direction: space void + dim Mars horizon (glow stays atmosphere, never data),
 * one focal "what should I do today" card, zero classic tables, drill-down
 * everywhere. Chart colors validated (CVD + contrast) against the dark surface.
 */
import { useMemo, useRef, useState } from 'react';

/* ------------------------------------------------------------------ */
/* Mock data                                                            */
/* ------------------------------------------------------------------ */

const heroSetup = {
  symbol: 'VRT',
  name: 'Vertiv Holdings',
  direction: 'long' as const,
  entry: 92.1,
  stop: 86.4,
  current: 94.3,
  target: 107.0,
  rr: 2.6,
  targetProb: 58,
  residualPct: 94,
  conviction: 'High',
  sizeHint: 'vol-adjusted size 6.2% of book',
};

const positions = [
  {
    symbol: 'ANET', name: 'Arista Networks', direction: 'long', r: 1.4,
    entry: 118.4, current: 131.2, shares: 25, opened: 'May 28',
    stop: 121.8, stopNote: 'trailed from 111.10', target: 140.0,
    alphaUsd: 310, exit: 'ATR trailing stop',
    spark: [118.4, 119.2, 121.5, 120.8, 123.4, 125.1, 124.2, 126.8, 128.3, 127.5, 129.9, 131.2],
    stopTrail: [111.1, 111.1, 111.1, 112.6, 114.2, 114.2, 115.8, 117.4, 117.4, 119.5, 121.8, 121.8],
  },
  {
    symbol: 'VRT', name: 'Vertiv Holdings', direction: 'long', r: 1.1,
    entry: 88.3, current: 94.3, shares: 40, opened: 'Jun 12',
    stop: 86.9, stopNote: 'trailed from 83.10', target: 103.0,
    alphaUsd: 205, exit: 'ATR trailing stop',
    spark: [88.3, 89.1, 88.6, 90.2, 91.4, 90.8, 92.1, 93.0, 92.4, 93.6, 94.1, 94.3],
    stopTrail: [83.1, 83.1, 84.0, 84.0, 84.9, 84.9, 85.6, 85.6, 86.2, 86.2, 86.9, 86.9],
  },
  {
    symbol: 'CLS', name: 'Celestica', direction: 'long', r: 0.4,
    entry: 61.2, current: 62.9, shares: 60, opened: 'Jun 30',
    stop: 57.1, stopNote: 'initial stop', target: 71.5,
    alphaUsd: 84, exit: 'ATR trailing stop',
    spark: [61.2, 61.8, 61.1, 62.3, 62.0, 62.6, 63.1, 62.7, 62.4, 62.9, 63.2, 62.9],
    stopTrail: [57.1, 57.1, 57.1, 57.1, 57.1, 57.1, 57.1, 57.1, 57.1, 57.1, 57.1, 57.1],
  },
  {
    symbol: 'SMCI', name: 'Super Micro Computer', direction: 'short', r: -0.6,
    entry: 44.8, current: 46.1, shares: 80, opened: 'Jul 2',
    stop: 47.0, stopNote: 'initial stop', target: 38.5,
    alphaUsd: -57, exit: 'ATR trailing stop',
    spark: [44.8, 44.2, 45.0, 45.6, 45.1, 45.9, 46.4, 45.8, 46.2, 46.0, 46.3, 46.1],
    stopTrail: [47.0, 47.0, 47.0, 47.0, 47.0, 47.0, 47.0, 47.0, 47.0, 47.0, 47.0, 47.0],
  },
];

const radar = [
  {
    rank: 2, symbol: 'CLS', name: 'Celestica', direction: 'long',
    residual: 91, rr: '2.2:1', prob: 61, qualified: true, note: 'clears EV gate',
  },
  {
    rank: 3, symbol: 'APP', name: 'AppLovin', direction: 'long',
    residual: 89, rr: '2.4:1', prob: 55, qualified: true, note: 'clears EV gate',
  },
  {
    rank: 4, symbol: 'NVDA', name: 'NVIDIA', direction: 'long',
    residual: 87, rr: '1.6:1', prob: 63, qualified: false, note: 'EV below gate — payoff too thin',
  },
  {
    rank: 5, symbol: 'AMD', name: 'Advanced Micro Devices', direction: 'long',
    residual: 84, rr: '2.1:1', prob: 48, qualified: false, note: 'extended — 12% above entry zone',
  },
  {
    rank: 6, symbol: 'PLTR', name: 'Palantir', direction: 'short',
    residual: 82, rr: '1.9:1', prob: 44, qualified: false, note: 'counter-trend in neutral regime',
  },
];

const watchlist = [
  { symbol: 'VRT', pct: 3.1 }, { symbol: 'ANET', pct: 2.4 },
  { symbol: 'NVDA', pct: 1.8 }, { symbol: 'AVGO', pct: 1.5 },
  { symbol: 'CRWD', pct: 0.9 }, { symbol: 'MSFT', pct: 0.3 },
  { symbol: 'PLTR', pct: -0.9 }, { symbol: 'META', pct: -1.2 },
];

/* Weekly closes since January, indexed to 100 — one axis, common base. */
const perfPortfolio = [100, 101.2, 100.6, 102.3, 103.8, 103.1, 105.0, 106.4, 105.2, 107.9, 109.6, 108.8, 111.3, 110.1, 112.6, 114.9, 113.8, 116.2, 118.4, 117.1, 119.8, 121.6, 120.4, 123.1, 125.0, 126.4];
const perfSpy = [100, 100.8, 100.2, 101.5, 102.1, 101.4, 102.6, 103.3, 102.5, 103.9, 104.6, 103.8, 104.9, 104.1, 105.2, 106.0, 105.3, 106.4, 107.2, 106.5, 107.4, 108.1, 107.3, 108.0, 108.6, 108.2];
const perfStart = new Date(2026, 0, 9);
const perfDates = perfPortfolio.map((_, i) => {
  const d = new Date(perfStart);
  d.setDate(d.getDate() + i * 7);
  return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
});

const alphaSpark = [0, 42, 30, 95, 150, 128, 210, 265, 231, 340, 415, 388, 470, 442, 508, 570, 538, 590, 642];

/* ~3 months of daily VRT candles, seeded so the mock is stable across reloads. */
type Candle = { d: Date; o: number; h: number; l: number; c: number; v: number };
const vrtCandles: Candle[] = (() => {
  let s = 42 >>> 0;
  const rnd = () => { s = (Math.imul(s, 1664525) + 1013904223) >>> 0; return s / 4294967296; };
  const days: Date[] = [];
  const cursor = new Date(2026, 6, 9);
  while (days.length < 64) {
    const dow = cursor.getDay();
    if (dow !== 0 && dow !== 6) days.unshift(new Date(cursor));
    cursor.setDate(cursor.getDate() - 1);
  }
  const drift = (i: number) => (i < 20 ? 0.30 : i < 28 ? -0.38 : i < 46 ? 0.44 : i < 53 ? -0.32 : 0.52);
  const out: Candle[] = [];
  let close = 73.6;
  for (let i = 0; i < 64; i++) {
    const chg = drift(i) + (rnd() - 0.5) * 2.4;
    const o = close;
    const c = o + chg;
    out.push({
      d: days[i], o, c,
      h: Math.max(o, c) + rnd() * 1.2,
      l: Math.min(o, c) - rnd() * 1.2,
      v: 1.4e6 * (0.55 + rnd()) * (1 + Math.abs(chg) / 2.5),
    });
    close = c;
  }
  const shift = 94.3 - close;
  return out.map((b) => ({ ...b, o: b.o + shift, h: b.h + shift, l: b.l + shift, c: b.c + shift }));
})();

const tickerLevels = {
  resistance: 96.4,
  supportLo: 88.7,
  supportHi: 90.1,
};

/* Score fingerprint — all axes 0–100 percentile, same order everywhere. */
const RADAR_AXES = ['Momentum', 'Trend', 'Setup', 'Sentiment', 'Fundam.'];
const RADAR_AXES_FULL = [
  'Residual momentum', 'Trend strength', 'Setup quality', 'News sentiment', 'Fundamentals',
];
const heroScores = [94, 88, 85, 71, 62];
const liveMedian = [68, 61, 57, 52, 55];
const qualifiedCompare = [
  { symbol: 'VRT', tag: 'top pick', scores: heroScores },
  { symbol: 'CLS', tag: 'rank 2', scores: [91, 82, 72, 58, 74] },
  { symbol: 'APP', tag: 'rank 3', scores: [89, 78, 69, 66, 81] },
];

/* ------------------------------------------------------------------ */
/* Small building blocks                                               */
/* ------------------------------------------------------------------ */

function fmt(n: number, digits = 2): string {
  return n.toLocaleString('en-US', { minimumFractionDigits: digits, maximumFractionDigits: digits });
}

function signed(n: number, unit = ''): string {
  return `${n > 0 ? '+' : n < 0 ? '−' : ''}${fmt(Math.abs(n))}${unit}`;
}

function DirTag({ direction }: { direction: string }) {
  return (
    <span className={`hzn-tag ${direction === 'long' ? 'hzn-tag-long' : 'hzn-tag-short'}`}>
      {direction}
    </span>
  );
}

/** 2px sparkline, endpoint dot with surface ring. Single series — no legend. */
function Spark({ data, color, w = 130, h = 34 }: { data: number[]; color: string; w?: number; h?: number }) {
  const min = Math.min(...data);
  const max = Math.max(...data);
  const span = max - min || 1;
  const px = (i: number) => 3 + (i / (data.length - 1)) * (w - 10);
  const py = (v: number) => h - 5 - ((v - min) / span) * (h - 10);
  const path = data.map((v, i) => `${i === 0 ? 'M' : 'L'}${px(i).toFixed(1)},${py(v).toFixed(1)}`).join(' ');
  return (
    <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} aria-hidden="true">
      <path d={path} fill="none" stroke={color} strokeWidth="2" strokeLinejoin="round" strokeLinecap="round" />
      <circle cx={px(data.length - 1)} cy={py(data[data.length - 1])} r="4" fill={color} stroke="var(--surface)" strokeWidth="2" />
    </svg>
  );
}

/** Diverging R-multiple bar: grows from a centered zero baseline. */
function RBar({ r, max = 1.6 }: { r: number; max?: number }) {
  const pct = Math.min(Math.abs(r) / max, 1) * 50;
  return (
    <div className="hzn-rbar" role="img" aria-label={`${signed(r)} R`}>
      <span className="hzn-rbar-zero" />
      <span
        className="hzn-rbar-fill"
        style={{
          left: r >= 0 ? '50%' : `${50 - pct}%`,
          width: `${pct}%`,
          background: r >= 0 ? 'var(--up)' : 'var(--down)',
          borderRadius: r >= 0 ? '0 4px 4px 0' : '4px 0 0 4px',
        }}
      />
    </div>
  );
}

/* ------------------------------------------------------------------ */
/* Radar — the score fingerprint (5 axes, 0–100 %ile, fixed order)      */
/* ------------------------------------------------------------------ */

function RadarChart({
  scores, reference, size = 110, labels = false,
}: { scores: number[]; reference?: number[]; size?: number; labels?: boolean }) {
  const [hover, setHover] = useState<number | null>(null);
  const pad = labels ? 78 : 10;
  const vb = size + pad * 2;
  const c = vb / 2;
  const r = size / 2;
  const pt = (v: number, i: number): [number, number] => {
    const a = ((-90 + i * 72) * Math.PI) / 180;
    return [c + (Math.cos(a) * r * v) / 100, c + (Math.sin(a) * r * v) / 100];
  };
  const poly = (vals: number[]) =>
    vals.map((v, i) => pt(v, i).map((n) => n.toFixed(1)).join(',')).join(' ');
  const rendered = vb * (labels ? 0.95 : 1);
  const tip = hover !== null ? pt(scores[hover], hover) : null;
  return (
    <div className="hzn-radar-wrap" style={{ width: rendered, height: rendered }}>
    <svg
      viewBox={`0 0 ${vb} ${vb}`}
      width={rendered}
      height={rendered}
      role="img"
      aria-label={`Score fingerprint: ${RADAR_AXES.map((ax, i) => `${ax} ${scores[i]}`).join(', ')} (0–100 percentile)`}
    >
      {[50, 100].map((ring) => (
        <polygon key={ring} points={poly(Array(5).fill(ring))} fill="none" stroke="var(--grid)" strokeWidth="1" />
      ))}
      {RADAR_AXES.map((ax, i) => {
        const [x, y] = pt(100, i);
        return <line key={ax} x1={c} y1={c} x2={x} y2={y} stroke="var(--grid)" strokeWidth="1" />;
      })}
      {reference && (
        <polygon points={poly(reference)} fill="none" stroke="var(--ink-3)" strokeWidth="1.5" opacity="0.85" />
      )}
      <polygon
        points={poly(scores)}
        fill="var(--up)" fillOpacity="0.13"
        stroke="var(--up)" strokeWidth="2" strokeLinejoin="round"
      />
      {scores.map((v, i) => {
        const [x, y] = pt(v, i);
        return (
          <circle
            key={i} cx={x} cy={y} r={hover === i ? 4.5 : 3}
            fill="var(--up)" stroke="var(--surface)" strokeWidth="1.5"
          />
        );
      })}
      {labels && RADAR_AXES.map((ax, i) => {
        const a = ((-90 + i * 72) * Math.PI) / 180;
        const x = c + Math.cos(a) * (r + 14);
        const y = c + Math.sin(a) * (r + 14);
        const anchor = Math.cos(a) > 0.3 ? 'start' : Math.cos(a) < -0.3 ? 'end' : 'middle';
        const dy = Math.sin(a) < -0.3 ? -2 : Math.sin(a) > 0.3 ? 9 : 4;
        return (
          <text key={ax} x={x} y={y + dy} textAnchor={anchor} className="hzn-radar-axis">
            {ax} <tspan className="hzn-radar-axisval">{scores[i]}</tspan>
          </text>
        );
      })}
      {/* hit targets on top — comfortably larger than the dots, keyboard-reachable */}
      {scores.map((v, i) => {
        const [x, y] = pt(v, i);
        return (
          <circle
            key={`hit-${i}`} cx={x} cy={y} r="13"
            fill="transparent" style={{ cursor: 'default', outline: 'none' }}
            tabIndex={0}
            aria-label={`${RADAR_AXES_FULL[i]}: ${scores[i]}th percentile${reference ? `, live-setup median ${reference[i]}` : ''}`}
            onMouseEnter={() => setHover(i)}
            onMouseLeave={() => setHover(null)}
            onFocus={() => setHover(i)}
            onBlur={() => setHover(null)}
          />
        );
      })}
    </svg>
    {hover !== null && tip && (
      <div
        className="hzn-radar-tip"
        style={{ left: `${(tip[0] / vb) * 100}%`, top: `${(tip[1] / vb) * 100}%` }}
      >
        <b>{RADAR_AXES_FULL[hover]}</b>
        <span className="num">{scores[hover]}th %ile</span>
        {reference && <i className="num">live-setup median {reference[hover]}</i>}
      </div>
    )}
    </div>
  );
}

/* ------------------------------------------------------------------ */
/* Trade chart — price since entry with entry / trailing stop / target  */
/* ------------------------------------------------------------------ */

type Position = (typeof positions)[number];

function TradeChart({ p }: { p: Position }) {
  const w = 560; const h = 150;
  const padL = 8; const padR = 96; const padT = 10; const padB = 12;
  const isShort = p.direction === 'short';
  const vals = [...p.spark, ...p.stopTrail, p.entry];
  let lo = Math.min(...vals);
  let hi = Math.max(...vals);
  const range = hi - lo || 1;
  // Only stretch the scale to the target when it doesn't flatten the price action.
  const targetFits = isShort ? lo - p.target <= range * 0.9 : p.target - hi <= range * 0.9;
  if (targetFits) { lo = Math.min(lo, p.target); hi = Math.max(hi, p.target); }
  const pad = (hi - lo) * 0.07;
  lo -= pad; hi += pad;
  const plotW = w - padL - padR;
  const plotH = h - padT - padB;
  const px = (i: number) => padL + (i / (p.spark.length - 1)) * plotW;
  const py = (v: number) => padT + plotH - ((v - lo) / (hi - lo)) * plotH;
  const pricePath = p.spark.map((v, i) => `${i === 0 ? 'M' : 'L'}${px(i).toFixed(1)},${py(v).toFixed(1)}`).join(' ');
  let stopPath = `M${px(0).toFixed(1)},${py(p.stopTrail[0]).toFixed(1)}`;
  for (let i = 1; i < p.stopTrail.length; i++) {
    stopPath += `H${px(i).toFixed(1)}V${py(p.stopTrail[i]).toFixed(1)}`;
  }
  const col = p.r >= 0 ? 'var(--up)' : 'var(--down)';
  const labelX = w - padR + 10;
  const entryY = py(p.entry);
  let stopY = py(p.stopTrail[p.stopTrail.length - 1]);
  if (Math.abs(stopY - entryY) < 11) stopY = entryY + (stopY >= entryY ? 11 : -11);
  const lastI = p.spark.length - 1;
  return (
    <svg
      viewBox={`0 0 ${w} ${h}`}
      className="hzn-tradechart"
      role="img"
      aria-label={`${p.symbol}: price ${fmt(p.current)}, entry ${fmt(p.entry)}, trailing stop ${fmt(p.stop)}, target ${fmt(p.target)}`}
    >
      <line x1={padL} x2={w - padR} y1={entryY} y2={entryY} stroke="var(--ink-3)" strokeWidth="1" opacity="0.5" />
      <text x={labelX} y={entryY + 3.5} className="hzn-lvl">entry {fmt(p.entry)}</text>
      <path d={stopPath} fill="none" stroke="var(--down)" strokeWidth="1.5" opacity="0.85" />
      <text x={labelX} y={stopY + 3.5} className="hzn-lvl hzn-lvl-down">stop {fmt(p.stop)}</text>
      {targetFits ? (
        <>
          <line x1={padL} x2={w - padR} y1={py(p.target)} y2={py(p.target)} stroke="var(--up)" strokeWidth="1" opacity="0.6" />
          <text x={labelX} y={py(p.target) + 3.5} className="hzn-lvl hzn-lvl-up">target {fmt(p.target)}</text>
        </>
      ) : (
        <text x={labelX} y={isShort ? h - padB : padT + 4} className="hzn-lvl hzn-lvl-up">
          target {fmt(p.target)} {isShort ? '↓' : '↑'}
        </text>
      )}
      <path d={pricePath} fill="none" stroke={col} strokeWidth="2" strokeLinejoin="round" strokeLinecap="round" />
      <circle cx={px(lastI)} cy={py(p.spark[lastI])} r="4" fill={col} stroke="var(--surface)" strokeWidth="2" />
    </svg>
  );
}

/* ------------------------------------------------------------------ */
/* The price rail — stop → entry → current → target, laid out spatially */
/* ------------------------------------------------------------------ */

function PriceRail({ s }: { s: typeof heroSetup }) {
  const lo = s.stop - (s.target - s.stop) * 0.06;
  const hi = s.target + (s.target - s.stop) * 0.06;
  const pct = (v: number) => ((v - lo) / (hi - lo)) * 100;
  const rNow = (s.current - s.entry) / (s.entry - s.stop);
  return (
    <div className="hzn-rail">
      <div className="hzn-rail-track" />
      <div
        className="hzn-rail-risk"
        style={{ left: `${pct(s.stop)}%`, width: `${pct(s.entry) - pct(s.stop)}%` }}
      />
      <div
        className="hzn-rail-progress"
        style={{ left: `${pct(s.entry)}%`, width: `${pct(s.current) - pct(s.entry)}%` }}
      />
      {/* markers */}
      <div className="hzn-rail-mark" style={{ left: `${pct(s.stop)}%` }}>
        <span className="hzn-rail-tick" style={{ background: 'var(--down)' }} />
        <span className="hzn-rail-label">
          <em>stop</em>
          <b>{fmt(s.stop)}</b>
          <i>−1R</i>
        </span>
      </div>
      <div className="hzn-rail-mark" style={{ left: `${pct(s.entry)}%` }}>
        <span className="hzn-rail-tick" style={{ background: 'var(--ink-2)' }} />
        <span className="hzn-rail-label">
          <em>entry</em>
          <b>{fmt(s.entry)}</b>
        </span>
      </div>
      <div className="hzn-rail-mark hzn-rail-now" style={{ left: `${pct(s.current)}%` }}>
        <span className="hzn-rail-dot" />
        <span className="hzn-rail-label hzn-rail-label-top">
          <em>now</em>
          <b>{fmt(s.current)}</b>
          <i>{signed(rNow)}R</i>
        </span>
      </div>
      <div className="hzn-rail-mark" style={{ left: `${pct(s.target)}%` }}>
        <span className="hzn-rail-ring" />
        <span className="hzn-rail-label">
          <em>target</em>
          <b>{fmt(s.target)}</b>
          <i>+{fmt(s.rr, 1)}R</i>
        </span>
      </div>
    </div>
  );
}

/* ------------------------------------------------------------------ */
/* Performance chart — indexed to 100, crosshair + tooltip on hover     */
/* ------------------------------------------------------------------ */

const CHART = { w: 760, h: 220, top: 14, right: 64, bottom: 26, left: 40 };

function PerfChart() {
  const [hover, setHover] = useState<number | null>(null);
  const svgRef = useRef<SVGSVGElement>(null);

  const { w, h, top, right, bottom, left } = CHART;
  const plotW = w - left - right;
  const plotH = h - top - bottom;
  const yMin = 95;
  const yMax = 130;
  const px = (i: number) => left + (i / (perfPortfolio.length - 1)) * plotW;
  const py = (v: number) => top + plotH - ((v - yMin) / (yMax - yMin)) * plotH;
  const line = (data: number[]) =>
    data.map((v, i) => `${i === 0 ? 'M' : 'L'}${px(i).toFixed(1)},${py(v).toFixed(1)}`).join(' ');

  const yTicks = [100, 110, 120, 130];
  const xTicks = useMemo(
    () => [0, 5, 10, 15, 20, 25].map((i) => ({ i, label: perfDates[i] })),
    [],
  );

  const onMove = (e: React.MouseEvent<SVGSVGElement>) => {
    const rect = svgRef.current?.getBoundingClientRect();
    if (!rect) return;
    const x = ((e.clientX - rect.left) / rect.width) * w;
    const i = Math.round(((x - left) / plotW) * (perfPortfolio.length - 1));
    setHover(Math.max(0, Math.min(perfPortfolio.length - 1, i)));
  };

  const last = perfPortfolio.length - 1;

  return (
    <div className="hzn-chart">
      <div className="hzn-chart-head">
        <div>
          <p className="hzn-eyebrow">Performance</p>
          <p className="hzn-chart-title">Paper book vs S&amp;P 500 · indexed to 100 · since January</p>
        </div>
        <div className="hzn-legend">
          <span><i style={{ background: 'var(--up)' }} /> Book</span>
          <span><i style={{ background: 'var(--ink-3)' }} /> S&amp;P 500</span>
        </div>
      </div>
      <svg
        ref={svgRef}
        viewBox={`0 0 ${w} ${h}`}
        className="hzn-chart-svg"
        onMouseMove={onMove}
        onMouseLeave={() => setHover(null)}
        role="img"
        aria-label="Paper book up 26.4% versus S&P 500 up 8.2% since January, indexed to 100"
      >
        {yTicks.map((t) => (
          <g key={t}>
            <line x1={left} x2={w - right} y1={py(t)} y2={py(t)} stroke="var(--grid)" strokeWidth="1" />
            <text x={left - 8} y={py(t) + 3.5} textAnchor="end" className="hzn-axis">{t}</text>
          </g>
        ))}
        {xTicks.map(({ i, label }) => (
          <text key={i} x={px(i)} y={h - 6} textAnchor="middle" className="hzn-axis">{label}</text>
        ))}
        <path d={line(perfSpy)} fill="none" stroke="var(--ink-3)" strokeWidth="2" strokeLinejoin="round" />
        <path d={line(perfPortfolio)} fill="none" stroke="var(--up)" strokeWidth="2" strokeLinejoin="round" />
        {hover !== null && (
          <g>
            <line x1={px(hover)} x2={px(hover)} y1={top} y2={top + plotH} stroke="var(--ink-3)" strokeWidth="1" />
            <circle cx={px(hover)} cy={py(perfPortfolio[hover])} r="4.5" fill="var(--up)" stroke="var(--surface)" strokeWidth="2" />
            <circle cx={px(hover)} cy={py(perfSpy[hover])} r="4.5" fill="var(--ink-3)" stroke="var(--surface)" strokeWidth="2" />
          </g>
        )}
        {/* direct end labels */}
        <circle cx={px(last)} cy={py(perfPortfolio[last])} r="4" fill="var(--up)" stroke="var(--surface)" strokeWidth="2" />
        <circle cx={px(last)} cy={py(perfSpy[last])} r="4" fill="var(--ink-3)" stroke="var(--surface)" strokeWidth="2" />
        <text x={px(last) + 10} y={py(perfPortfolio[last]) + 4} className="hzn-endlabel">{fmt(perfPortfolio[last], 1)}</text>
        <text x={px(last) + 10} y={py(perfSpy[last]) + 4} className="hzn-endlabel hzn-endlabel-dim">{fmt(perfSpy[last], 1)}</text>
      </svg>
      <div className="hzn-chart-tip" aria-live="polite">
        {hover !== null
          ? <>week of {perfDates[hover]} — book <b>{fmt(perfPortfolio[hover], 1)}</b> · S&amp;P 500 <b>{fmt(perfSpy[hover], 1)}</b></>
          : <>hover for weekly values</>}
      </div>
    </div>
  );
}

/* ------------------------------------------------------------------ */
/* Ticker drill-down — candlesticks + volume + trade levels             */
/* ------------------------------------------------------------------ */

function TickerPanel() {
  const [hover, setHover] = useState<number | null>(null);
  const svgRef = useRef<SVGSVGElement>(null);

  const w = 900; const padT = 10; const padB = 20; const padL = 8; const padR = 96;
  const priceH = 290; const volH = 54; const gap = 16;
  const H = padT + priceH + gap + volH + padB;
  const n = vrtCandles.length;
  const slot = (w - padL - padR) / n;
  const bodyW = Math.min(7, slot * 0.62);

  const hi = Math.max(...vrtCandles.map((b) => b.h), heroSetup.target + 1.5);
  const lo = Math.min(...vrtCandles.map((b) => b.l)) - 1;
  const maxV = Math.max(...vrtCandles.map((b) => b.v));
  const px = (i: number) => padL + (i + 0.5) * slot;
  const py = (v: number) => padT + priceH - ((v - lo) / (hi - lo)) * priceH;
  const vy = (v: number) => padT + priceH + gap + volH - (v / maxV) * volH;

  // Skip ticks whose right-gutter label would collide with a level label.
  const levelYs = [
    heroSetup.entry, heroSetup.stop, heroSetup.target,
    tickerLevels.resistance, (tickerLevels.supportLo + tickerLevels.supportHi) / 2,
  ];
  const yTicks = [75, 85, 95, 105].filter(
    (t) => t > lo && t < hi
      && levelYs.every((l) => Math.abs(((t - l) / (hi - lo)) * priceH) >= 13),
  );
  const monthTicks = vrtCandles
    .map((b, i) => ({ b, i }))
    .filter(({ b, i }) => i === 0 || b.d.getMonth() !== vrtCandles[i - 1].d.getMonth())
    .map(({ b, i }) => ({ i, label: b.d.toLocaleDateString('en-US', { month: 'short' }) }));

  const onMove = (e: React.MouseEvent<SVGSVGElement>) => {
    const rect = svgRef.current?.getBoundingClientRect();
    if (!rect) return;
    const x = ((e.clientX - rect.left) / rect.width) * w;
    const i = Math.floor((x - padL) / slot);
    setHover(Math.max(0, Math.min(n - 1, i)));
  };

  const labelX = w - padR + 10;
  const hb = hover !== null ? vrtCandles[hover] : null;

  return (
    <section className="hzn-chart hzn-ticker" aria-label="Ticker drill-down: VRT">
      <div className="hzn-ticker-top">
        <div>
          <p className="hzn-eyebrow">Drill-down · Ticker</p>
          <p className="hzn-tk-title">
            <b>VRT</b>
            <span>Vertiv Holdings</span>
          </p>
          <p className="hzn-tk-price">
            <span className="num">94.30</span>
            <b className="hzn-up num">+1.9%</b>
            <i>today</i>
          </p>
          <div className="hzn-tk-chips">
            <span className="hzn-chip">composite score 82</span>
            <span className="hzn-chip">ATR 2.90 · 3.1%</span>
            <span className="hzn-chip">earnings Aug 5</span>
          </div>
        </div>
        <div className="hzn-tk-radar">
          <RadarChart scores={heroScores} reference={liveMedian} size={128} labels />
          <p className="hzn-legend">
            <span><i style={{ background: 'var(--up)' }} /> VRT</span>
            <span><i style={{ background: 'var(--ink-3)' }} /> live-setup median</span>
          </p>
        </div>
      </div>

      <div className="hzn-tk-bars">
        <nav className="hzn-tk-tabs" aria-label="Ticker sections">
          <a className="hzn-tk-tab-on" href="#">Analysis</a>
          <a href="#">Indicators</a>
          <a href="#">S/R levels</a>
          <a href="#">Sentiment</a>
          <a href="#">Fundamentals</a>
        </nav>
        <div className="hzn-tk-ranges" role="group" aria-label="Time range">
          {(['1M', '3M', '6M', 'YTD', '1Y', 'All'] as const).map((r) => (
            <button key={r} className={r === '3M' ? 'hzn-tk-range-on' : ''}>{r}</button>
          ))}
        </div>
      </div>

      <svg
        ref={svgRef}
        viewBox={`0 0 ${w} ${H}`}
        className="hzn-chart-svg"
        onMouseMove={onMove}
        onMouseLeave={() => setHover(null)}
        role="img"
        aria-label="Daily candlestick chart for VRT with entry, trailing stop, target, support and resistance levels"
      >
        {yTicks.map((t) => (
          <g key={t}>
            <line x1={padL} x2={w - padR} y1={py(t)} y2={py(t)} stroke="var(--grid)" strokeWidth="1" />
            <text x={labelX} y={py(t) + 3.5} className="hzn-axis">{t}</text>
          </g>
        ))}
        {monthTicks.map(({ i, label }) => (
          <text key={label + i} x={px(i)} y={H - 5} textAnchor="middle" className="hzn-axis">{label}</text>
        ))}

        {/* support zone + resistance (nearest S/R only — full list stays in its tab) */}
        <rect
          x={padL} width={w - padR - padL}
          y={py(tickerLevels.supportHi)}
          height={py(tickerLevels.supportLo) - py(tickerLevels.supportHi)}
          fill="var(--up)" opacity="0.07"
        />
        <text x={labelX} y={py((tickerLevels.supportLo + tickerLevels.supportHi) / 2) + 3.5} className="hzn-lvl">
          sup {fmt(tickerLevels.supportLo, 1)}–{fmt(tickerLevels.supportHi, 1)}
        </text>
        <line x1={padL} x2={w - padR} y1={py(tickerLevels.resistance)} y2={py(tickerLevels.resistance)} stroke="var(--ink-3)" strokeWidth="1" opacity="0.7" />
        <text x={labelX} y={py(tickerLevels.resistance) + 3.5} className="hzn-lvl">resist {fmt(tickerLevels.resistance)}</text>

        {/* trade levels */}
        <line x1={padL} x2={w - padR} y1={py(heroSetup.entry)} y2={py(heroSetup.entry)} stroke="var(--ink-2)" strokeWidth="1" opacity="0.55" />
        <text x={labelX} y={py(heroSetup.entry) + 3.5} className="hzn-lvl hzn-lvl-ink">entry {fmt(heroSetup.entry)}</text>
        <line x1={padL} x2={w - padR} y1={py(heroSetup.stop)} y2={py(heroSetup.stop)} stroke="var(--down)" strokeWidth="1" opacity="0.8" />
        <text x={labelX} y={py(heroSetup.stop) + 3.5} className="hzn-lvl hzn-lvl-down">stop {fmt(heroSetup.stop)}</text>
        <line x1={padL} x2={w - padR} y1={py(heroSetup.target)} y2={py(heroSetup.target)} stroke="var(--up)" strokeWidth="1" opacity="0.8" />
        <text x={labelX} y={py(heroSetup.target) + 3.5} className="hzn-lvl hzn-lvl-up">target {fmt(heroSetup.target)}</text>

        {/* candles */}
        {vrtCandles.map((b, i) => {
          const up = b.c >= b.o;
          const col = up ? 'var(--up)' : 'var(--down)';
          const bodyY = py(Math.max(b.o, b.c));
          const bodyH = Math.max(1.5, Math.abs(py(b.o) - py(b.c)));
          return (
            <g key={i} opacity={hover === null || hover === i ? 1 : 0.55}>
              <line x1={px(i)} x2={px(i)} y1={py(b.h)} y2={py(b.l)} stroke={col} strokeWidth="1" />
              <rect x={px(i) - bodyW / 2} y={bodyY} width={bodyW} height={bodyH} fill={col} rx="1" />
              <rect x={px(i) - bodyW / 2} y={vy(b.v)} width={bodyW} height={padT + priceH + gap + volH - vy(b.v)} fill="var(--ink-3)" opacity="0.55" rx="1" />
            </g>
          );
        })}

        {hover !== null && (
          <line x1={px(hover)} x2={px(hover)} y1={padT} y2={padT + priceH + gap + volH} stroke="var(--ink-3)" strokeWidth="1" opacity="0.6" />
        )}
      </svg>

      <div className="hzn-chart-tip" aria-live="polite">
        {hb ? (
          <>
            {hb.d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })} — O <b>{fmt(hb.o)}</b> H <b>{fmt(hb.h)}</b> L <b>{fmt(hb.l)}</b> C <b>{fmt(hb.c)}</b> · vol <b>{(hb.v / 1e6).toFixed(1)}M</b>
          </>
        ) : (
          <>hover for daily OHLC · volume below</>
        )}
      </div>

      <p className="hzn-fresh">
        <span><i /> prices 2h ago</span>
        <span><i /> indicators 2h ago</span>
        <span><i /> sentiment 6h ago</span>
        <span><i /> fundamentals 3d ago</span>
        <a href="#">manage data →</a>
      </p>
    </section>
  );
}

/* ------------------------------------------------------------------ */
/* Page                                                                */
/* ------------------------------------------------------------------ */

export default function DesignHorizonPage() {
  const [expanded, setExpanded] = useState<string | null>('ANET');
  const [showTicker, setShowTicker] = useState(true);

  return (
    <div className="hzn">
      <style>{CSS}</style>

      {/* atmosphere — stays behind everything, never carries data */}
      <div className="hzn-stars" aria-hidden="true" />
      <div className="hzn-horizon" aria-hidden="true">
        <div className="hzn-rim" />
        <div className="hzn-planet" />
      </div>

      <div className="hzn-page">
        {/* command bar */}
        <header className="hzn-bar">
          <span className="hzn-wordmark">SIGNAL<i /></span>
          <nav className="hzn-nav" aria-label="Sections">
            <a className="hzn-nav-on" href="#">Overview</a>
            <a href="#">Market</a>
            <a href="#">Signals</a>
            <a href="#">Regime</a>
          </nav>
          <div className="hzn-bar-right">
            <span className="hzn-regime"><i /> Neutral regime · SPY above 50-day, breadth mixed</span>
            <span className="hzn-mock">mockup · static data</span>
          </div>
        </header>

        {/* the verdict */}
        <section className="hzn-hero">
          <p className="hzn-eyebrow">Thursday, July 9</p>
          <h1>One setup clears the gate today.</h1>
          <p className="hzn-hero-sub">
            3 qualified of 14 live setups · 4 open positions · <b className="hzn-up">+2.3R</b> unrealized
          </p>
        </section>

        {/* focal setup card */}
        <section className="hzn-focus" aria-label="Top qualified setup">
          <div className="hzn-focus-head">
            <div className="hzn-focus-id">
              <span className="hzn-pick">top pick</span>
              <h2>{heroSetup.symbol}</h2>
              <div>
                <p className="hzn-focus-name">{heroSetup.name}</p>
                <p className="hzn-focus-tags">
                  <DirTag direction={heroSetup.direction} />
                  <span className="hzn-chip">conviction {heroSetup.conviction}</span>
                  <span className="hzn-chip">residual momentum {heroSetup.residualPct}th %ile</span>
                </p>
              </div>
            </div>
            <div className="hzn-focus-stats">
              <div>
                <p className="hzn-stat-label">reward / risk</p>
                <p className="hzn-stat-value">{fmt(heroSetup.rr, 1)}<span> : 1</span></p>
              </div>
              <div>
                <p className="hzn-stat-label">target probability</p>
                <p className="hzn-stat-value">{heroSetup.targetProb}<span>%</span></p>
                <div className="hzn-meter"><span style={{ width: `${heroSetup.targetProb}%` }} /></div>
              </div>
            </div>
          </div>

          <PriceRail s={heroSetup} />

          <div className="hzn-focus-foot">
            <span className="hzn-note">cleared the expected-value gate · {heroSetup.sizeHint}</span>
            <span className="hzn-actions">
              <button className="hzn-btn" onClick={() => setShowTicker((v) => !v)} aria-expanded={showTicker}>
                {showTicker ? 'Hide ticker details' : 'Ticker details'}
              </button>
              <a className="hzn-btn hzn-btn-ghost" href="#">All 14 setups</a>
            </span>
          </div>
        </section>

        {showTicker && <TickerPanel />}

        {/* KPI band */}
        <section className="hzn-kpis" aria-label="Account status">
          <div className="hzn-tile">
            <p className="hzn-stat-label">open risk</p>
            <p className="hzn-stat-value">$1,240</p>
            <p className="hzn-tile-sub">4 open · distance to stops</p>
          </div>
          <div className="hzn-tile">
            <p className="hzn-stat-label">unrealized</p>
            <p className="hzn-stat-value hzn-up">+2.3R</p>
            <p className="hzn-tile-sub">+$1,875 · 3 up, 1 down</p>
          </div>
          <div className="hzn-tile hzn-tile-spark">
            <div>
              <p className="hzn-stat-label">alpha vs S&amp;P 500</p>
              <p className="hzn-stat-value hzn-up">+$642</p>
              <p className="hzn-tile-sub">open trades vs buy-and-hold SPY</p>
            </div>
            <Spark data={alphaSpark} color="var(--up)" />
          </div>
          <div className="hzn-tile">
            <p className="hzn-stat-label">gate this week</p>
            <p className="hzn-stat-value">3<span className="hzn-stat-dim"> / 14</span></p>
            <p className="hzn-tile-sub">setups clearing the EV gate</p>
          </div>
        </section>

        <div className="hzn-cols">
          {/* open positions — diverging R bars, expandable rows */}
          <section className="hzn-panel" aria-label="Open positions">
            <div className="hzn-panel-head">
              <p className="hzn-eyebrow">Open positions</p>
              <p className="hzn-panel-hint">R-multiple to entry · select a row for detail</p>
            </div>
            <ul className="hzn-poslist">
              {positions.map((p) => {
                const open = expanded === p.symbol;
                return (
                  <li key={p.symbol} className={open ? 'hzn-pos-open' : ''}>
                    <button
                      className="hzn-pos"
                      onClick={() => setExpanded(open ? null : p.symbol)}
                      aria-expanded={open}
                    >
                      <span className="hzn-pos-id">
                        <b>{p.symbol}</b>
                        <DirTag direction={p.direction} />
                      </span>
                      <span className="hzn-pos-px num">{fmt(p.entry)} → {fmt(p.current)}</span>
                      <RBar r={p.r} />
                      <span className={`hzn-pos-r num ${p.r >= 0 ? 'hzn-up' : 'hzn-down'}`}>{signed(p.r)}R</span>
                      <span className={`hzn-caret ${open ? 'hzn-caret-open' : ''}`} aria-hidden="true">▾</span>
                    </button>
                    {open && (
                      <div className="hzn-pos-detail">
                        <dl>
                          <div><dt>opened</dt><dd>{p.opened} · {p.shares} shares</dd></div>
                          <div><dt>stop</dt><dd className="num">{fmt(p.stop)} <i>{p.stopNote}</i></dd></div>
                          <div><dt>target</dt><dd className="num">{fmt(p.target)}</dd></div>
                          <div><dt>exit rule</dt><dd>{p.exit}</dd></div>
                          <div>
                            <dt>alpha vs SPY</dt>
                            <dd className={`num ${p.alphaUsd >= 0 ? 'hzn-up' : 'hzn-down'}`}>{`${p.alphaUsd >= 0 ? '+' : '−'}$${fmt(Math.abs(p.alphaUsd), 0)}`}</dd>
                          </div>
                        </dl>
                        <div className="hzn-pos-chart">
                          <p className="hzn-stat-label">since entry · entry / trailing stop / target</p>
                          <TradeChart p={p} />
                        </div>
                      </div>
                    )}
                  </li>
                );
              })}
            </ul>
          </section>

          {/* radar — ranked next setups with reasons */}
          <section className="hzn-panel" aria-label="Setup radar">
            <div className="hzn-panel-head">
              <p className="hzn-eyebrow">Radar</p>
              <p className="hzn-panel-hint">ranked by strategy score · why each does or doesn't qualify</p>
            </div>
            <div className="hzn-cmp-row">
              {qualifiedCompare.map((q) => (
                <figure key={q.symbol} className="hzn-cmp-fig">
                  <RadarChart scores={q.scores} size={96} />
                  <figcaption>
                    <b>{q.symbol}</b>
                    <span className={q.tag === 'top pick' ? 'hzn-cmp-pick' : ''}>{q.tag}</span>
                  </figcaption>
                </figure>
              ))}
              <p className="hzn-cmp-axes">
                the 3 qualified setups<br />
                same axes as the ticker fingerprint · 0–100 %ile
              </p>
            </div>
            <ul className="hzn-radar">
              {radar.map((r) => (
                <li key={r.symbol} className={r.qualified ? '' : 'hzn-radar-dim'}>
                  <span className="hzn-radar-rank num">{r.rank}</span>
                  <span className="hzn-radar-id">
                    <b>{r.symbol}</b>
                    <small>{r.name}</small>
                  </span>
                  <DirTag direction={r.direction} />
                  <span className="hzn-radar-mom">
                    <span className="hzn-radar-momtrack">
                      <i style={{ width: `${r.residual}%`, background: r.qualified ? 'var(--up)' : 'var(--ink-3)' }} />
                    </span>
                    <small className="num">{r.residual}%ile</small>
                  </span>
                  <span className="hzn-radar-rr num">{r.rr}</span>
                  <span className={`hzn-radar-note ${r.qualified ? 'hzn-radar-yes' : ''}`}>
                    {r.qualified ? '✓ ' : ''}{r.note}
                  </span>
                </li>
              ))}
            </ul>
          </section>
        </div>

        <PerfChart />

        {/* watchlist strip */}
        <section className="hzn-watch" aria-label="Watchlist">
          <p className="hzn-eyebrow">Watchlist</p>
          <div className="hzn-watch-chips">
            {watchlist.map((c) => (
              <a key={c.symbol} href="#" className="hzn-wchip">
                <b>{c.symbol}</b>
                <span className={`num ${c.pct > 0.05 ? 'hzn-up' : c.pct < -0.05 ? 'hzn-down' : ''}`}>
                  {c.pct > 0 ? '+' : ''}{fmt(c.pct)}%
                </span>
              </a>
            ))}
          </div>
        </section>

        <footer className="hzn-foot">
          HORIZON · design study v2 · static mock data, nothing live
        </footer>
      </div>
    </div>
  );
}

/* ------------------------------------------------------------------ */
/* Styles — scoped under .hzn, independent of the app theme            */
/* ------------------------------------------------------------------ */

const CSS = `
@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap');

.hzn {
  /* tokens — chart colors validated on the dark surface (#11131c) */
  --void: #0a0b11;
  --surface: #11131c;
  --panel: rgba(226, 231, 245, 0.032);
  --panel-glass: rgba(15, 17, 26, 0.72);
  --panel-line: rgba(226, 231, 245, 0.085);
  --grid: rgba(226, 231, 245, 0.07);
  --ink: #edeef3;
  --ink-2: #9aa0b0;
  --ink-3: #5d6373;
  --up: #2f9db2;          /* marks */
  --up-text: #6ec9db;     /* small text tint */
  --down: #e36a58;
  --down-text: #ef9182;
  --amber: #c67f22;
  --amber-text: #dfa356;
  --ember: #ff6a45;       /* reserved: horizon, wordmark, top-pick */

  position: relative;
  z-index: 0;
  min-height: 100vh;
  background: var(--void);
  color: var(--ink);
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: 15px;
  line-height: 1.5;
  overflow-x: hidden;
}
.hzn h1, .hzn h2 { font-family: 'Space Grotesk', system-ui, sans-serif; }
.hzn .num { font-family: 'IBM Plex Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums; }
.hzn a { color: inherit; text-decoration: none; }
.hzn :focus-visible { outline: 2px solid var(--up-text); outline-offset: 2px; border-radius: 4px; }

/* ------- atmosphere ------- */
.hzn-stars {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background-image:
    radial-gradient(1px 1px at 12% 18%, rgba(237,238,243,.55) 50%, transparent 51%),
    radial-gradient(1px 1px at 68% 8%,  rgba(237,238,243,.4) 50%, transparent 51%),
    radial-gradient(1.5px 1.5px at 84% 32%, rgba(159,216,232,.5) 50%, transparent 51%),
    radial-gradient(1px 1px at 33% 44%, rgba(237,238,243,.35) 50%, transparent 51%),
    radial-gradient(1px 1px at 91% 64%, rgba(237,238,243,.3) 50%, transparent 51%),
    radial-gradient(1.5px 1.5px at 22% 71%, rgba(237,238,243,.42) 50%, transparent 51%),
    radial-gradient(1px 1px at 55% 27%, rgba(255,150,120,.35) 50%, transparent 51%),
    radial-gradient(1px 1px at 45% 87%, rgba(237,238,243,.3) 50%, transparent 51%),
    radial-gradient(1px 1px at 76% 82%, rgba(159,216,232,.35) 50%, transparent 51%),
    radial-gradient(1px 1px at 5% 55%,  rgba(237,238,243,.35) 50%, transparent 51%);
  background-size: 900px 700px;
  background-repeat: repeat;
  opacity: .8;
}
.hzn-horizon {
  position: fixed; left: 0; right: 0; bottom: 0; height: 24vh;
  z-index: 0; pointer-events: none; overflow: hidden;
}
.hzn-planet {
  position: absolute; left: 50%; top: 58%;
  width: 300vw; height: 300vw; transform: translateX(-50%);
  border-radius: 50%;
  background:
    radial-gradient(ellipse 55% 14% at 50% 0.4%, rgba(255,120,80,.22), transparent 60%),
    radial-gradient(ellipse 120% 26% at 50% 0%, #3f130b 0%, #260a06 32%, #130504 58%, #0a0b11 86%);
}
.hzn-rim {
  position: absolute; left: 50%; top: calc(58% - 2px);
  width: 300vw; height: 300vw; transform: translateX(-50%);
  border-radius: 50%;
  background: linear-gradient(180deg, rgba(213,240,250,.55), rgba(159,216,232,.16) 40%, transparent 60%);
  filter: blur(1px);
  box-shadow: 0 -14px 50px rgba(159,216,232,.10), 0 -50px 140px rgba(228,87,61,.08);
}

/* ------- layout ------- */
.hzn-page {
  position: relative; z-index: 1;
  max-width: 1180px; margin: 0 auto;
  padding: 28px 32px 22vh;
  display: flex; flex-direction: column; gap: 34px;
}

/* ------- command bar ------- */
.hzn-bar { display: flex; align-items: center; gap: 28px; flex-wrap: wrap; }
.hzn-wordmark {
  font-family: 'Space Grotesk', sans-serif; font-weight: 700;
  letter-spacing: .42em; font-size: 15px;
}
.hzn-wordmark i {
  display: inline-block; width: 7px; height: 7px; border-radius: 50%;
  background: var(--ember); margin-left: 2px;
  box-shadow: 0 0 10px rgba(255,106,69,.7);
}
.hzn-nav { display: flex; gap: 22px; font-size: 13.5px; color: var(--ink-2); }
.hzn-nav a:hover { color: var(--ink); }
.hzn-nav-on { color: var(--ink); border-bottom: 1px solid var(--up); padding-bottom: 2px; }
.hzn-bar-right { margin-left: auto; display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.hzn-regime { font-size: 12.5px; color: var(--ink-2); display: inline-flex; align-items: center; gap: 8px; }
.hzn-regime i { width: 7px; height: 7px; border-radius: 50%; background: var(--amber-text); display: inline-block; }
.hzn-mock {
  font-family: 'IBM Plex Mono', monospace; font-size: 10px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-3);
  border: 1px solid var(--panel-line); border-radius: 99px; padding: 3px 10px;
}

/* ------- hero ------- */
.hzn-eyebrow {
  font-family: 'IBM Plex Mono', monospace; font-size: 10.5px;
  letter-spacing: .28em; text-transform: uppercase; color: var(--ink-3);
}
.hzn-hero { margin-top: 6px; }
.hzn-hero h1 {
  font-size: clamp(28px, 4.2vw, 44px); font-weight: 600;
  letter-spacing: -0.015em; margin-top: 10px;
}
.hzn-hero-sub { margin-top: 8px; color: var(--ink-2); font-size: 15px; }
.hzn-up { color: var(--up-text); }
.hzn-down { color: var(--down-text); }

/* ------- focal setup ------- */
.hzn-focus {
  background: var(--panel-glass); border: 1px solid var(--panel-line);
  border-radius: 16px; padding: 26px 28px 22px;
  backdrop-filter: blur(14px);
}
.hzn-focus-head { display: flex; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.hzn-focus-id { display: flex; align-items: flex-start; gap: 18px; }
.hzn-pick {
  font-family: 'IBM Plex Mono', monospace; font-size: 9.5px; letter-spacing: .2em;
  text-transform: uppercase; color: var(--ember);
  border: 1px solid rgba(255,106,69,.4); border-radius: 99px;
  padding: 3px 9px; margin-top: 10px; white-space: nowrap;
}
.hzn-focus h2 { font-size: 46px; font-weight: 700; letter-spacing: -0.01em; line-height: 1; }
.hzn-focus-name { color: var(--ink-2); font-size: 13.5px; margin-top: 4px; }
.hzn-focus-tags { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.hzn-tag {
  font-family: 'IBM Plex Mono', monospace; font-size: 9.5px; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase;
  border-radius: 4px; padding: 2.5px 7px;
}
.hzn-tag-long { color: var(--up-text); background: rgba(47,157,178,.14); }
.hzn-tag-short { color: var(--down-text); background: rgba(227,106,88,.14); }
.hzn-chip {
  font-size: 11.5px; color: var(--ink-2);
  border: 1px solid var(--panel-line); border-radius: 99px; padding: 2.5px 10px;
}
.hzn-focus-stats { display: flex; gap: 40px; text-align: right; }
.hzn-stat-label {
  font-family: 'IBM Plex Mono', monospace; font-size: 10px;
  letter-spacing: .18em; text-transform: uppercase; color: var(--ink-3);
}
.hzn-stat-value {
  font-family: 'Space Grotesk', sans-serif; font-size: 30px; font-weight: 600;
  margin-top: 4px; line-height: 1.1;
}
.hzn-stat-value span { font-size: 17px; color: var(--ink-2); }
.hzn-stat-dim { color: var(--ink-3); }
.hzn-meter {
  width: 120px; height: 4px; border-radius: 2px; margin-top: 8px; margin-left: auto;
  background: rgba(47,157,178,.16);
}
.hzn-meter span { display: block; height: 100%; border-radius: 2px; background: var(--up); }

/* ------- price rail ------- */
.hzn-rail { position: relative; height: 108px; margin: 34px 8px 4px; }
.hzn-rail-track {
  position: absolute; left: 0; right: 0; top: 50%; height: 1px;
  background: var(--grid);
}
.hzn-rail-risk {
  position: absolute; top: calc(50% - 2px); height: 4px;
  background: rgba(227,106,88,.16); border-radius: 2px;
}
.hzn-rail-progress {
  position: absolute; top: calc(50% - 2px); height: 4px;
  background: var(--up); border-radius: 2px;
}
.hzn-rail-mark { position: absolute; top: 0; bottom: 0; width: 0; }
.hzn-rail-tick {
  position: absolute; top: calc(50% - 7px); left: -1px;
  width: 2px; height: 14px; border-radius: 1px;
}
.hzn-rail-dot {
  position: absolute; top: calc(50% - 6px); left: -6px;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--up); border: 2px solid var(--surface);
  box-shadow: 0 0 0 1px var(--up), 0 0 14px rgba(110,201,219,.55);
}
.hzn-rail-ring {
  position: absolute; top: calc(50% - 6px); left: -6px;
  width: 12px; height: 12px; border-radius: 50%;
  border: 2px solid var(--up); background: var(--void);
}
.hzn-rail-label {
  position: absolute; top: calc(50% + 16px); left: 0; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  white-space: nowrap;
}
.hzn-rail-label-top { top: auto; bottom: calc(50% + 16px); }
.hzn-rail-label em {
  font-style: normal; font-family: 'IBM Plex Mono', monospace; font-size: 9.5px;
  letter-spacing: .18em; text-transform: uppercase; color: var(--ink-3);
}
.hzn-rail-label b {
  font-family: 'IBM Plex Mono', monospace; font-weight: 500; font-size: 13px;
  color: var(--ink);
}
.hzn-rail-label i {
  font-style: normal; font-family: 'IBM Plex Mono', monospace; font-size: 10.5px;
  color: var(--ink-2);
}
.hzn-rail-now .hzn-rail-label b { color: var(--up-text); }

.hzn-focus-foot {
  display: flex; justify-content: space-between; align-items: center;
  gap: 16px; flex-wrap: wrap; margin-top: 18px;
  border-top: 1px solid var(--grid); padding-top: 16px;
}
.hzn-note { font-size: 12.5px; color: var(--ink-3); }
.hzn-actions { display: flex; gap: 10px; }
.hzn-btn {
  font-size: 13px; font-weight: 600; border-radius: 8px; padding: 7px 16px;
  background: rgba(47,157,178,.16); color: var(--up-text);
  border: 1px solid rgba(47,157,178,.35);
  transition: background .15s ease, border-color .15s ease;
  font-family: inherit; cursor: pointer;
}
.hzn-btn:hover { background: rgba(47,157,178,.26); border-color: rgba(110,201,219,.5); }
.hzn-btn-ghost { background: transparent; color: var(--ink-2); border-color: var(--panel-line); }
.hzn-btn-ghost:hover { color: var(--ink); background: rgba(226,231,245,.04); }

/* ------- KPI band ------- */
.hzn-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.hzn-tile {
  background: var(--panel-glass); border: 1px solid var(--panel-line);
  border-radius: 14px; padding: 18px 20px;
  backdrop-filter: blur(14px);
}
.hzn-tile .hzn-stat-value { font-size: 26px; }
.hzn-tile-sub { font-size: 12px; color: var(--ink-3); margin-top: 4px; }
.hzn-tile-spark { display: flex; justify-content: space-between; align-items: flex-end; gap: 10px; }

/* ------- panels / columns ------- */
.hzn-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: start; }
.hzn-panel {
  background: var(--panel-glass); border: 1px solid var(--panel-line);
  border-radius: 14px; padding: 20px 22px;
  backdrop-filter: blur(14px);
}
.hzn-panel-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 14px; }
.hzn-panel-hint { font-size: 11.5px; color: var(--ink-3); }

/* positions */
.hzn-poslist { list-style: none; display: flex; flex-direction: column; }
.hzn-poslist > li { border-top: 1px solid var(--grid); }
.hzn-poslist > li:first-child { border-top: 0; }
.hzn-pos {
  display: grid; grid-template-columns: 92px 1fr 130px 64px 16px;
  align-items: center; gap: 12px;
  width: 100%; text-align: left; background: none; border: 0; color: inherit;
  font: inherit; padding: 11px 4px; cursor: pointer;
  transition: background .15s ease; border-radius: 8px;
}
.hzn-pos:hover { background: rgba(226,231,245,.035); }
.hzn-pos-id { display: flex; align-items: center; gap: 8px; }
.hzn-pos-id b { font-weight: 600; }
.hzn-pos-px { font-size: 12px; color: var(--ink-2); }
.hzn-pos-r { text-align: right; font-size: 13px; font-weight: 600; }
.hzn-caret { color: var(--ink-3); font-size: 10px; transition: transform .15s ease; }
.hzn-caret-open { transform: rotate(180deg); }
.hzn-rbar { position: relative; height: 10px; }
.hzn-rbar-zero {
  position: absolute; left: 50%; top: -3px; bottom: -3px; width: 1px;
  background: var(--panel-line);
}
.hzn-rbar-fill { position: absolute; top: 0; bottom: 0; }
.hzn-pos-detail {
  display: flex; flex-direction: column; gap: 16px;
  padding: 6px 8px 16px; font-size: 12.5px;
}
.hzn-pos-detail dl { display: grid; grid-template-columns: repeat(3, minmax(0, auto)); gap: 10px 34px; }
.hzn-pos-detail dt {
  font-family: 'IBM Plex Mono', monospace; font-size: 9.5px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-3);
}
.hzn-pos-detail dd { margin-top: 2px; color: var(--ink); }
.hzn-pos-detail dd i { font-style: normal; color: var(--ink-3); font-size: 11px; margin-left: 6px; }
.hzn-pos-chart { width: 100%; }
.hzn-tradechart { width: 100%; height: auto; display: block; margin-top: 8px; }
.hzn-lvl {
  fill: var(--ink-3); font-family: 'IBM Plex Mono', monospace; font-size: 10px;
}
.hzn-lvl-up { fill: var(--up-text); }
.hzn-lvl-down { fill: var(--down-text); }
.hzn-lvl-ink { fill: var(--ink-2); }

/* radar */
.hzn-radar { list-style: none; display: flex; flex-direction: column; }
.hzn-radar li {
  display: grid; grid-template-columns: 20px 118px 44px 1fr 52px minmax(120px, 1.2fr);
  align-items: center; gap: 10px;
  padding: 10px 4px; border-top: 1px solid var(--grid);
  border-radius: 8px; transition: background .15s ease;
}
.hzn-radar li:first-child { border-top: 0; }
.hzn-radar li:hover { background: rgba(226,231,245,.035); }
.hzn-radar-dim { opacity: .62; }
.hzn-radar-rank { color: var(--ink-3); font-size: 11px; }
.hzn-radar-id b { font-weight: 600; display: block; }
.hzn-radar-id small { color: var(--ink-3); font-size: 10.5px; display: block; max-width: 110px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hzn-radar-mom { display: flex; align-items: center; gap: 8px; }
.hzn-radar-momtrack {
  flex: 1; height: 4px; border-radius: 2px; background: rgba(226,231,245,.07);
  overflow: hidden;
}
.hzn-radar-momtrack i { display: block; height: 100%; border-radius: 2px; }
.hzn-radar-mom small { color: var(--ink-3); font-size: 10px; }
.hzn-radar-rr { text-align: right; font-size: 12.5px; color: var(--ink-2); }
.hzn-radar-note { font-size: 11.5px; color: var(--ink-3); text-align: right; }
.hzn-radar-yes { color: var(--up-text); }

/* ------- chart ------- */
.hzn-chart {
  background: var(--panel-glass); border: 1px solid var(--panel-line);
  border-radius: 14px; padding: 20px 22px 12px;
  backdrop-filter: blur(14px);
}
.hzn-chart-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px; flex-wrap: wrap; }
.hzn-chart-title { font-size: 13px; color: var(--ink-2); margin-top: 5px; }
.hzn-legend { display: flex; gap: 16px; font-size: 12px; color: var(--ink-2); }
.hzn-legend i {
  display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  margin-right: 6px; vertical-align: -1px;
}
.hzn-chart-svg { width: 100%; height: auto; margin-top: 10px; display: block; }
.hzn-axis { fill: var(--ink-3); font-family: 'IBM Plex Mono', monospace; font-size: 10px; }
.hzn-endlabel { fill: var(--ink); font-family: 'IBM Plex Mono', monospace; font-size: 11px; font-weight: 600; }
.hzn-endlabel-dim { fill: var(--ink-2); font-weight: 400; }
.hzn-chart-tip {
  font-family: 'IBM Plex Mono', monospace; font-size: 11px; color: var(--ink-3);
  padding: 8px 2px 4px; min-height: 28px;
}
.hzn-chart-tip b { color: var(--ink); font-weight: 500; }

/* ------- radar fingerprint ------- */
.hzn-radar-wrap { position: relative; display: inline-block; }
.hzn-radar-tip {
  position: absolute; transform: translate(-50%, calc(-100% - 12px));
  background: rgba(21, 24, 35, 0.96); border: 1px solid var(--panel-line);
  border-radius: 8px; padding: 6px 10px; white-space: nowrap;
  pointer-events: none; z-index: 5; box-shadow: 0 6px 24px rgba(0,0,0,.45);
  font-size: 12px;
}
.hzn-radar-tip b { display: block; color: var(--ink); font-weight: 600; }
.hzn-radar-tip span { display: block; color: var(--up-text); font-size: 11px; margin-top: 1px; }
.hzn-radar-tip i { display: block; font-style: normal; color: var(--ink-3); font-size: 10px; margin-top: 1px; }
.hzn-radar-axis {
  fill: var(--ink-3); font-family: 'IBM Plex Mono', monospace; font-size: 9.5px;
  letter-spacing: .04em;
}
.hzn-radar-axisval { fill: var(--ink-2); font-weight: 600; }
.hzn-tk-radar { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.hzn-cmp-row {
  display: flex; gap: 14px; align-items: center; flex-wrap: wrap;
  border-bottom: 1px solid var(--grid); padding-bottom: 12px; margin-bottom: 10px;
}
.hzn-cmp-fig { text-align: center; }
.hzn-cmp-fig figcaption b { display: block; font-size: 13px; font-weight: 600; margin-top: -2px; }
.hzn-cmp-fig figcaption span {
  font-family: 'IBM Plex Mono', monospace; font-size: 9px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-3);
}
.hzn-cmp-fig .hzn-cmp-pick { color: var(--ember); }
.hzn-cmp-axes {
  font-family: 'IBM Plex Mono', monospace; font-size: 10px; line-height: 1.7;
  color: var(--ink-3); margin-left: auto; text-align: right; max-width: 220px;
}

/* ------- ticker drill-down ------- */
.hzn-ticker-top { display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap; }
.hzn-tk-title { display: flex; align-items: baseline; gap: 10px; margin-top: 8px; }
.hzn-tk-title b { font-family: 'Space Grotesk', sans-serif; font-size: 30px; font-weight: 700; }
.hzn-tk-title span { color: var(--ink-2); font-size: 13px; }
.hzn-tk-price { display: flex; align-items: baseline; gap: 10px; margin-top: 4px; }
.hzn-tk-price .num:first-child { font-size: 18px; color: var(--ink); }
.hzn-tk-price b { font-size: 13px; }
.hzn-tk-price i { font-style: normal; font-size: 11.5px; color: var(--ink-3); }
.hzn-tk-chips { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }
.hzn-tk-bars {
  display: flex; justify-content: space-between; align-items: center; gap: 14px;
  flex-wrap: wrap; margin-top: 16px; border-bottom: 1px solid var(--grid); padding-bottom: 10px;
}
.hzn-tk-tabs { display: flex; gap: 18px; font-size: 13px; color: var(--ink-2); }
.hzn-tk-tabs a:hover { color: var(--ink); }
.hzn-tk-tab-on { color: var(--ink); border-bottom: 1px solid var(--up); padding-bottom: 2px; }
.hzn-tk-ranges { display: flex; gap: 4px; }
.hzn-tk-ranges button {
  font-family: 'IBM Plex Mono', monospace; font-size: 10.5px; color: var(--ink-3);
  background: none; border: 1px solid transparent; border-radius: 6px;
  padding: 3px 8px; cursor: pointer;
}
.hzn-tk-ranges button:hover { color: var(--ink-2); }
.hzn-tk-ranges .hzn-tk-range-on {
  color: var(--up-text); border-color: rgba(47,157,178,.35); background: rgba(47,157,178,.12);
}
.hzn-fresh {
  display: flex; gap: 16px; flex-wrap: wrap; align-items: center;
  font-family: 'IBM Plex Mono', monospace; font-size: 10px; letter-spacing: .06em;
  color: var(--ink-3); border-top: 1px solid var(--grid); padding-top: 10px; margin-top: 4px;
}
.hzn-fresh span { display: inline-flex; align-items: center; gap: 6px; }
.hzn-fresh i {
  width: 5px; height: 5px; border-radius: 50%; background: var(--up); display: inline-block;
}
.hzn-fresh a { color: var(--ink-2); margin-left: auto; }
.hzn-fresh a:hover { color: var(--ink); }

/* ------- watchlist ------- */
.hzn-watch-chips { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
.hzn-wchip {
  display: inline-flex; align-items: baseline; gap: 8px;
  border: 1px solid var(--panel-line); border-radius: 99px;
  padding: 6px 14px; font-size: 13px;
  transition: border-color .15s ease, background .15s ease;
}
.hzn-wchip:hover { border-color: rgba(110,201,219,.4); background: rgba(226,231,245,.03); }
.hzn-wchip b { font-weight: 600; }
.hzn-wchip span { font-size: 11.5px; color: var(--ink-2); }

/* ------- footer ------- */
.hzn-foot {
  font-family: 'IBM Plex Mono', monospace; font-size: 10px;
  letter-spacing: .3em; text-transform: uppercase; color: var(--ink-3);
  text-align: center; margin-top: 10px;
}

/* ------- responsive ------- */
@media (max-width: 980px) {
  .hzn-kpis { grid-template-columns: repeat(2, 1fr); }
  .hzn-cols { grid-template-columns: 1fr; }
  .hzn-radar li { grid-template-columns: 20px 110px 44px 1fr 48px; }
  .hzn-radar-note { grid-column: 2 / -1; text-align: left; padding-bottom: 2px; }
}
@media (max-width: 640px) {
  .hzn-page { padding: 20px 16px 24vh; }
  .hzn-kpis { grid-template-columns: 1fr; }
  .hzn-focus-stats { text-align: left; }
  .hzn-meter { margin-left: 0; }
  .hzn-pos { grid-template-columns: 86px 1fr 60px 14px; }
  .hzn-pos-px { display: none; }
}

/* ------- motion ------- */
@media (prefers-reduced-motion: no-preference) {
  .hzn-page { animation: hzn-rise .5s ease-out both; }
  @keyframes hzn-rise {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
  }
}
`;
