// ===== Signal Viewer \u2014 Admin Signal Log Browser =====

function SignalsPage() {
  const toast = useToast();
  const [mode, setMode] = React.useState('');
  const [selectedDate, setSelectedDate] = React.useState(() => {
    // Default to today in IST (UTC+5:30)
    var now = new Date();
    var istOffset = 5.5 * 60 * 60 * 1000;
    var ist = new Date(now.getTime() + (now.getTimezoneOffset() * 60000) + istOffset);
    return ist.getFullYear() + '-' + String(ist.getMonth() + 1).padStart(2, '0') + '-' + String(ist.getDate()).padStart(2, '0');
  });
  const [minConf, setMinConf] = React.useState(0.60);
  const [signals, setSignals] = React.useState([]);
  const [stats, setStats] = React.useState(null);
  const [market, setMarket] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [expanded, setExpanded] = React.useState(new Set());
  const [filter, setFilter] = React.useState('entry');    // all | entry | exit
  const [sourceFilter, setSourceFilter] = React.useState('Phantom');
  const [sideFilter, setSideFilter] = React.useState('');   // '' | CE | PE
  const [mlFilter, setMlFilter] = React.useState('');        // '' | BUY | SELL | HOLD
  const [searchText, setSearchText] = React.useState('');
  const [searchInput, setSearchInput] = React.useState('');
  const searchTimerRef = React.useRef(null);
  const [sortCol, setSortCol] = React.useState('time');
  const [sortAsc, setSortAsc] = React.useState(false);      // newest first by default
  const [page, setPage] = React.useState(1);
  const [pageSize] = React.useState(500);
  const [totalCount, setTotalCount] = React.useState(0);
  const [totalPages, setTotalPages] = React.useState(1);
  const [perf, setPerf] = React.useState(null);
  const [perfDays, setPerfDays] = React.useState(1);
  const [perfUseRange, setPerfUseRange] = React.useState(false);
  const [perfFromDate, setPerfFromDate] = React.useState('');
  const [perfToDate, setPerfToDate] = React.useState('');
  const [perfLoading, setPerfLoading] = React.useState(false);
  const [activeTab, setActiveTab] = React.useState('performance'); // 'performance' | 'signals'
  const [timeRange, setTimeRange] = React.useState('');  // e.g. '09:15-09:30'

  React.useEffect(() => { setPage(1); }, [mode, selectedDate, minConf, filter, sourceFilter, sideFilter, mlFilter, searchText, sortCol, sortAsc, timeRange]);
  React.useEffect(() => { loadData(); }, [mode, selectedDate, minConf, page, filter, sourceFilter, sideFilter, mlFilter, searchText, sortCol, sortAsc, timeRange]);

  // Auto-refresh every 30s
  React.useEffect(() => {
    const iv = setInterval(() => loadData(), 30000);
    return () => clearInterval(iv);
  }, [mode, selectedDate, minConf, page, filter, sourceFilter, sideFilter, mlFilter, searchText, sortCol, sortAsc, timeRange]);

  // Load market status separately — only depends on mode, not signal filters
  React.useEffect(() => { loadMarketStatus(); }, [mode]);
  React.useEffect(() => {
    const iv = setInterval(() => loadMarketStatus(), 30000);
    return () => clearInterval(iv);
  }, [mode]);

  async function loadMarketStatus() {
    try {
      const modeParam = mode ? `&mode=${mode}` : '';
      const res = await API.get(`/api/signal/active?minConfidence=0.70${modeParam}`);
      setMarket(res.marketStatus || null);
    } catch (err) {
      console.warn('Market status load failed:', err.message);
    }
  }

  // Generate 15-min IST time slots for dropdown
  const timeSlots = React.useMemo(() => {
    const slots = [];
    for (let h = 9; h <= 15; h++) {
      for (let m = 0; m < 60; m += 15) {
        if (h === 9 && m === 0) continue; // market starts 9:15
        if (h === 15 && m > 30) continue; // market ends ~15:30
        const startH = String(h).padStart(2, '0');
        const startM = String(m).padStart(2, '0');
        const endMin = m + 15;
        const endH = endMin >= 60 ? String(h + 1).padStart(2, '0') : startH;
        const endM = String(endMin % 60).padStart(2, '0');
        slots.push({ value: `${startH}:${startM}-${endH}:${endM}`, label: `${startH}:${startM} – ${endH}:${endM}` });
      }
    }
    return slots;
  }, []);

  async function loadData() {
    try {
      const modeParam = mode ? `&mode=${mode}` : '';
      let filterParams = '';
      if (filter && filter !== 'all') filterParams += `&signalType=${filter}`;
      if (sourceFilter) filterParams += `&source=${encodeURIComponent(sourceFilter)}`;
      if (sideFilter) filterParams += `&optionType=${sideFilter}`;
      if (mlFilter) filterParams += `&mlPrediction=${encodeURIComponent(mlFilter)}`;
      if (searchText) filterParams += `&search=${encodeURIComponent(searchText)}`;
      if (sortCol) filterParams += `&sortCol=${sortCol}`;
      filterParams += `&sortAsc=${sortAsc}`;
      if (timeRange) {
        const [tf, tt] = timeRange.split('-');
        filterParams += `&timeFrom=${tf}&timeTo=${tt}`;
      }
      const historyRes = await API.get(`/api/signal/history?date=${selectedDate}&page=${page}&pageSize=${pageSize}&minConfidence=${minConf}${modeParam}${filterParams}`);
      setSignals(historyRes.signals || []);
      setStats(historyRes.stats || null);
      setTotalCount(historyRes.totalCount || 0);
      setTotalPages(historyRes.totalPages || 1);
    } catch (err) {
      toast(err.message, 'error');
    } finally {
      setLoading(false);
    }
  }

  // Load performance data
  React.useEffect(() => {
    if (perfUseRange && (!perfFromDate || !perfToDate)) return;
    loadPerf();
  }, [mode, perfDays, perfUseRange, perfFromDate, perfToDate]);

  async function loadPerf() {
    setPerfLoading(true);
    try {
      const modeParam = mode ? `&mode=${mode}` : '';
      const dateParam = perfUseRange && perfFromDate && perfToDate
        ? `from=${perfFromDate}&to=${perfToDate}`
        : `days=${perfDays}`;
      const res = await API.get(`/api/signal/performance?${dateParam}${modeParam}`);
      setPerf(res);
    } catch (err) {
      console.warn('Performance load failed:', err.message);
    } finally {
      setPerfLoading(false);
    }
  }

  // Chart refs
  const dailyChartRef = React.useRef(null);
  const sourceChartRef = React.useRef(null);
  const confChartRef = React.useRef(null);
  const sideChartRef = React.useRef(null);
  const dailyCanvasRef = React.useRef(null);
  const sourceCanvasRef = React.useRef(null);
  const confCanvasRef = React.useRef(null);
  const sideCanvasRef = React.useRef(null);

  // Render charts when perf data changes.
  // Depend on loading & perfLoading too: if loadPerf finishes before loadData,
  // the canvas elements don't exist yet (component shows <Loading>), so we must
  // re-run once loading is false and canvases are in the DOM.
  React.useEffect(() => {
    if (loading || perfLoading || !perf || typeof Chart === 'undefined') return;
    // Small delay lets the browser finish CSS grid layout so Chart.js
    // can measure the canvas parent dimensions correctly.
    const raf = requestAnimationFrame(() => {
      renderDailyChart();
      renderSourceChart();
      renderConfChart();
      renderSideChart();
    });
    return () => {
      cancelAnimationFrame(raf);
      [dailyChartRef, sourceChartRef, confChartRef, sideChartRef].forEach(ref => {
        if (ref.current) { ref.current.destroy(); ref.current = null; }
      });
    };
  }, [perf, loading, perfLoading]);

  function renderDailyChart() {
    if (dailyChartRef.current) dailyChartRef.current.destroy();
    const canvas = dailyCanvasRef.current;
    if (!canvas || !perf.daily || perf.daily.length === 0) return;
    dailyChartRef.current = new Chart(canvas.getContext('2d'), {
      type: 'line',
      data: {
        labels: perf.daily.map(d => d.date),
        datasets: [
          {
            label: 'Daily P&L (\u20B9)',
            data: perf.daily.map(d => d.totalPnL),
            borderColor: '#2563eb',
            backgroundColor: 'rgba(37,99,235,0.08)',
            fill: true,
            tension: 0.35,
            pointRadius: 4,
            pointBackgroundColor: perf.daily.map(d => d.totalPnL >= 0 ? '#16a34a' : '#dc2626'),
            borderWidth: 2,
          },
          {
            label: 'Cumulative P&L',
            data: perf.daily.map(d => d.cumulativePnL),
            borderColor: '#8b5cf6',
            borderDash: [5, 5],
            fill: false,
            tension: 0.35,
            pointRadius: 3,
            borderWidth: 2,
          }
        ]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
          legend: { position: 'top', labels: { usePointStyle: true, font: { size: 11 } } },
          tooltip: { callbacks: { label: ctx => ctx.dataset.label + ': \u20B9' + ctx.parsed.y.toFixed(2) } }
        },
        scales: {
          y: { grid: { color: '#f1f5f9' }, ticks: { callback: v => '\u20B9' + v } },
          x: { grid: { display: false } }
        }
      }
    });
  }

  function renderSourceChart() {
    if (sourceChartRef.current) sourceChartRef.current.destroy();
    const canvas = sourceCanvasRef.current;
    if (!canvas || !perf.bySource || perf.bySource.length === 0) return;
    const sources = perf.bySource.filter(s => s.tradedCount > 0);
    if (sources.length === 0) return;
    sourceChartRef.current = new Chart(canvas.getContext('2d'), {
      type: 'bar',
      data: {
        labels: sources.map(s => s.source),
        datasets: [
          {
            label: 'Win Rate %',
            data: sources.map(s => s.winRate),
            backgroundColor: sources.map(s => s.winRate >= 50 ? 'rgba(22,163,74,0.7)' : 'rgba(220,38,38,0.7)'),
            borderRadius: 6,
            barPercentage: 0.6,
          },
          {
            label: 'Total P&L (\u20B9)',
            data: sources.map(s => s.totalPnL),
            backgroundColor: sources.map(s => s.totalPnL >= 0 ? 'rgba(37,99,235,0.6)' : 'rgba(239,68,68,0.6)'),
            borderRadius: 6,
            barPercentage: 0.6,
            yAxisID: 'y1',
          }
        ]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: { legend: { position: 'top', labels: { usePointStyle: true, font: { size: 11 } } } },
        scales: {
          y: { position: 'left', grid: { color: '#f1f5f9' }, ticks: { callback: v => v + '%' }, title: { display: true, text: 'Win Rate', font: { size: 10 } } },
          y1: { position: 'right', grid: { display: false }, ticks: { callback: v => '\u20B9' + v }, title: { display: true, text: 'P&L', font: { size: 10 } } },
          x: { grid: { display: false } }
        }
      }
    });
  }

  function renderConfChart() {
    if (confChartRef.current) confChartRef.current.destroy();
    const canvas = confCanvasRef.current;
    if (!canvas || !perf.byConfidence || perf.byConfidence.length === 0) return;
    const bands = perf.byConfidence.filter(b => b.tradedCount > 0);
    if (bands.length === 0) return;
    confChartRef.current = new Chart(canvas.getContext('2d'), {
      type: 'bar',
      data: {
        labels: bands.map(b => b.band),
        datasets: [
          {
            label: 'Win Rate %',
            data: bands.map(b => b.winRate),
            backgroundColor: bands.map(b => {
              if (b.winRate >= 60) return 'rgba(22,163,74,0.75)';
              if (b.winRate >= 45) return 'rgba(217,119,6,0.75)';
              return 'rgba(220,38,38,0.75)';
            }),
            borderRadius: 6,
            barPercentage: 0.7,
          },
          {
            label: 'Avg P&L (\u20B9)',
            data: bands.map(b => b.avgPnL),
            type: 'line',
            borderColor: '#8b5cf6',
            pointBackgroundColor: '#8b5cf6',
            pointRadius: 5,
            borderWidth: 2,
            fill: false,
            yAxisID: 'y1',
          }
        ]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: { legend: { position: 'top', labels: { usePointStyle: true, font: { size: 11 } } } },
        scales: {
          y: { grid: { color: '#f1f5f9' }, ticks: { callback: v => v + '%' }, title: { display: true, text: 'Win Rate', font: { size: 10 } } },
          y1: { position: 'right', grid: { display: false }, ticks: { callback: v => '\u20B9' + v }, title: { display: true, text: 'Avg P&L', font: { size: 10 } } },
          x: { grid: { display: false } }
        }
      }
    });
  }

  function renderSideChart() {
    if (sideChartRef.current) sideChartRef.current.destroy();
    const canvas = sideCanvasRef.current;
    if (!canvas || !perf.byOptionType || perf.byOptionType.length === 0) return;
    const data = perf.byOptionType;
    sideChartRef.current = new Chart(canvas.getContext('2d'), {
      type: 'doughnut',
      data: {
        labels: data.map(d => d.optionType + ' (\u20B9' + d.totalPnL.toFixed(0) + ')'),
        datasets: [{
          data: data.map(d => d.tradedCount),
          backgroundColor: data.map(d => d.optionType === 'CE' ? 'rgba(22,163,74,0.75)' : 'rgba(220,38,38,0.75)'),
          borderWidth: 2,
          borderColor: '#fff',
          hoverOffset: 8,
        }]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        cutout: '55%',
        plugins: {
          legend: { position: 'bottom', labels: { usePointStyle: true, font: { size: 12 }, padding: 16 } },
          tooltip: { callbacks: { label: ctx => {
            var d = data[ctx.dataIndex];
            return d.optionType + ': ' + d.tradedCount + ' trades, WR ' + d.winRate + '%, P&L \u20B9' + d.totalPnL.toFixed(2);
          }}}
        }
      }
    });
  }

  // Filtering & sorting is now server-side; signals from API are already filtered and sorted.

  // Unique values for dropdowns
  const sources = [...new Set(signals.map(s => s.signalSource))].sort();
  const mlPredictions = [...new Set(signals.map(s => s.mlPrediction).filter(Boolean))].sort();

  // Stat helpers
  const entryCount = signals.filter(s => !s.isExitSignal).length;
  const exitCount  = signals.filter(s => s.isExitSignal).length;
  const ceCount    = signals.filter(s => s.optionType === 'CE').length;
  const peCount    = signals.filter(s => s.optionType === 'PE').length;
  const avgConf    = signals.length > 0
    ? (signals.reduce((a, s) => a + s.confidence, 0) / signals.length * 100).toFixed(1) + '%'
    : '\u2014';
  const highConf   = signals.filter(s => s.confidence >= 0.90).length;

  // Active filter count (how many filters are non-default)
  const activeFilterCount = [
    filter !== 'entry',
    sourceFilter !== '',
    sideFilter !== '',
    mlFilter !== '',
    searchText !== '',
    minConf !== 0.60,
    timeRange !== ''
  ].filter(Boolean).length;

  function resetFilters() {
    setFilter('entry');
    setSourceFilter('');
    setSideFilter('');
    setMlFilter('');
    setSearchText('');
    setSearchInput('');
    setMinConf(0.60);
    setTimeRange('');
  }

  function toggleSort(col) {
    if (sortCol === col) {
      setSortAsc(!sortAsc);
    } else {
      setSortCol(col);
      setSortAsc(col === 'symbol' || col === 'mode'); // alpha cols default ascending
    }
  }

  // ── Badge helpers ──
  function confColor(c) {
    if (c >= 0.90) return 'var(--success, #16a34a)';
    if (c >= 0.80) return 'var(--primary, #2563eb)';
    if (c >= 0.70) return 'var(--warning, #d97706)';
    return 'var(--danger, #dc2626)';
  }

  function confBar(c) {
    const pct = Math.min(c * 100, 100);
    const col = c >= 0.90 ? '#16a34a' : c >= 0.80 ? '#2563eb' : c >= 0.70 ? '#d97706' : '#dc2626';
    return React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '6px' } },
      React.createElement('div', {
        style: { width: '48px', height: '6px', borderRadius: '3px', background: '#e2e8f0', overflow: 'hidden', flexShrink: 0 }
      },
        React.createElement('div', { style: { width: pct + '%', height: '100%', borderRadius: '3px', background: col, transition: 'width 0.3s' } })
      ),
      React.createElement('span', {
        style: { fontWeight: '700', color: col, fontFamily: 'var(--mono, monospace)', fontSize: '0.78rem', minWidth: '40px' }
      }, (c * 100).toFixed(1) + '%')
    );
  }

  function formatTime(iso) {
    if (!iso) return '\u2014';
    try {
      const d = new Date(iso);
      return d.toLocaleString('en-IN', { day: '2-digit', month: 'short', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true, timeZone: 'Asia/Kolkata' });
    } catch { return iso; }
  }

  function formatTimeShort(iso) {
    if (!iso) return '\u2014';
    try {
      const d = new Date(iso);
      return d.toLocaleString('en-IN', { hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: true, timeZone: 'Asia/Kolkata' });
    } catch { return iso; }
  }

  function mlBadge(prediction) {
    if (!prediction) return React.createElement('span', { style: { color: '#9ca3af', fontSize: '0.75rem' } }, '\u2014');
    const cfg = {
      'BUY':  { bg: '#dcfce7', color: '#166534', border: '#bbf7d0', icon: '\u25B2' },
      'SELL': { bg: '#fee2e2', color: '#991b1b', border: '#fecaca', icon: '\u25BC' },
      'HOLD': { bg: '#fef9c3', color: '#854d0e', border: '#fde68a', icon: '\u25CF' },
    };
    const c = cfg[prediction] || { bg: '#f1f5f9', color: '#475569', border: '#e2e8f0', icon: '' };
    return React.createElement('span', {
      style: {
        display: 'inline-flex', alignItems: 'center', gap: '3px',
        padding: '2px 8px', borderRadius: '6px', fontSize: '0.72rem',
        fontWeight: '600', background: c.bg, color: c.color, border: `1px solid ${c.border}`,
        letterSpacing: '0.5px'
      }
    }, c.icon ? React.createElement('span', { style: { fontSize: '0.6rem' } }, c.icon) : null, prediction);
  }

  function typeBadge(isExit) {
    const icon = isExit ? '\u2B07' : '\u2B06';    // ⬇ ⬆
    const label = isExit ? 'EXIT' : 'ENTRY';
    return React.createElement('span', {
      style: {
        display: 'inline-flex', alignItems: 'center', gap: '3px',
        padding: '2px 8px', borderRadius: '6px', fontSize: '0.7rem',
        fontWeight: '600', letterSpacing: '0.5px',
        background: isExit ? '#fef3c7' : '#dbeafe',
        color: isExit ? '#92400e' : '#1e40af',
        border: `1px solid ${isExit ? '#fde68a' : '#bfdbfe'}`
      }
    }, React.createElement('span', { style: { fontSize: '0.65rem' } }, icon), label);
  }

  function sideBadge(side, optionType, isExit) {
    if (!optionType) return React.createElement('span', { style: { color: '#9ca3af', fontSize: '0.78rem' } }, '\u2014');
    const isCE = optionType === 'CE';
    if (isExit) {
      return React.createElement('span', {
        style: {
          display: 'inline-flex', alignItems: 'center', gap: '4px',
          padding: '2px 8px', borderRadius: '6px', fontSize: '0.75rem', fontWeight: '600',
          background: '#fef3c7', color: '#92400e', border: '1px solid #fde68a'
        },
        title: isCE ? 'CE premium falling \u2014 exit signal' : 'PE premium falling \u2014 exit signal'
      },
        React.createElement('span', { style: { fontSize: '0.65rem' } }, '\u25BC'),
        optionType + ' Exit'
      );
    }
    // Entry: derive market direction from side + option type
    const isBullish = (side === 'BUY' && isCE) || (side === 'SELL' && !isCE);
    return React.createElement('span', {
      style: {
        display: 'inline-flex', alignItems: 'center', gap: '4px',
        padding: '2px 8px', borderRadius: '6px', fontSize: '0.75rem', fontWeight: '600',
        background: isBullish ? '#dcfce7' : '#fee2e2',
        color: isBullish ? '#166534' : '#991b1b',
        border: `1px solid ${isBullish ? '#bbf7d0' : '#fecaca'}`
      },
      title: isBullish ? 'Bullish \u2014 buying Call option' : 'Bearish \u2014 buying Put option'
    },
      React.createElement('span', { style: { fontSize: '0.65rem' } }, isBullish ? '\u25B2' : '\u25BC'),
      optionType + (isBullish ? ' Bullish' : ' Bearish')
    );
  }

  function sourceBadge(src) {
    const cfgMap = {
      'OnnxModel':          { bg: '#ecfeff', color: '#0e7490', icon: '\u2699\uFE0F' },
      'Phantom':            { bg: '#f3e8ff', color: '#7c3aed', icon: '\uD83D\uDC7B' },
    };
    const c = cfgMap[src] || { bg: '#f1f5f9', color: '#475569', icon: '\uD83D\uDCCA' };
    return React.createElement('span', {
      style: {
        display: 'inline-flex', alignItems: 'center', gap: '3px',
        padding: '2px 8px', borderRadius: '6px', fontSize: '0.72rem',
        fontWeight: '500', background: c.bg, color: c.color, border: `1px solid ${c.bg}`
      }
    }, React.createElement('span', { style: { fontSize: '0.7rem' } }, c.icon), src);
  }

  function modeBadge(m) {
    const isNifty = m === 'NIFTY';
    return React.createElement('span', {
      style: {
        padding: '2px 8px', borderRadius: '6px', fontSize: '0.72rem', fontWeight: '600',
        background: isNifty ? '#ede9fe' : '#fce7f3',
        color: isNifty ? '#6d28d9' : '#be185d'
      }
    }, isNifty ? '\uD83D\uDFE3 ' + m : '\uD83D\uDFE0 ' + m);
  }

  function trapBadge(detected, combinedScore) {
    if (!detected) return React.createElement('span', { style: { color: '#9ca3af', fontSize: '0.78rem' } }, '\u2014');
    const score = combinedScore || 0;
    const severe = score >= 0.3;
    return React.createElement('span', {
      style: {
        display: 'inline-flex', alignItems: 'center', gap: '3px',
        padding: '2px 6px', borderRadius: '6px', fontSize: '0.72rem', fontWeight: '600',
        background: severe ? '#fee2e2' : '#fef3c7',
        color: severe ? '#991b1b' : '#92400e',
        border: `1px solid ${severe ? '#fecaca' : '#fde68a'}`
      }
    }, React.createElement('span', null, '\u26A0\uFE0F'), severe ? 'High' : 'Yes');
  }

  function bagBadge(detected) {
    if (!detected) return React.createElement('span', { style: { color: '#9ca3af', fontSize: '0.78rem' } }, '\u2014');
    return React.createElement('span', {
      style: {
        display: 'inline-flex', alignItems: 'center', gap: '3px',
        padding: '2px 6px', borderRadius: '6px', fontSize: '0.72rem', fontWeight: '600',
        background: '#fff7ed', color: '#c2410c', border: '1px solid #fed7aa'
      }
    }, React.createElement('span', null, '\uD83D\uDCC8'), 'Gap');
  }

  function gatesBadge(passed, blocked) {
    const p = (passed || []).length;
    const b = (blocked || []).length;
    if (p === 0 && b === 0) return React.createElement('span', { style: { color: '#9ca3af', fontSize: '0.78rem' } }, '\u2014');
    return React.createElement('div', { style: { display: 'flex', gap: '4px', alignItems: 'center' } },
      p > 0 && React.createElement('span', {
        title: passed.join(', '),
        style: {
          display: 'inline-flex', alignItems: 'center', gap: '2px',
          padding: '1px 6px', borderRadius: '4px', fontSize: '0.72rem', fontWeight: '600',
          background: '#dcfce7', color: '#166534'
        }
      }, '\u2713', p),
      b > 0 && React.createElement('span', {
        title: blocked.join(', '),
        style: {
          display: 'inline-flex', alignItems: 'center', gap: '2px',
          padding: '1px 6px', borderRadius: '4px', fontSize: '0.72rem', fontWeight: '600',
          background: '#fee2e2', color: '#991b1b'
        }
      }, '\u2717', b)
    );
  }

  // Sortable header cell
  function th(label, col, extraStyle) {
    const isSorted = sortCol === col;
    const arrow = isSorted ? (sortAsc ? ' \u25B2' : ' \u25BC') : '';
    return React.createElement('th', {
      key: label,
      style: Object.assign({
        padding: '10px 12px', textAlign: 'left', fontWeight: '600',
        fontSize: '0.72rem', textTransform: 'uppercase', letterSpacing: '0.5px',
        color: isSorted ? '#1e40af' : '#6b7280', whiteSpace: 'nowrap',
        cursor: col ? 'pointer' : 'default', userSelect: 'none',
        borderBottom: isSorted ? '2px solid #2563eb' : '2px solid #e2e8f0'
      }, extraStyle || {}),
      onClick: col ? () => toggleSort(col) : undefined
    }, label + arrow);
  }

  // ── Render ──
  if (loading) return React.createElement(Loading, { text: 'Loading signals\u2026' });

  return React.createElement('div', { className: 'page-content' },

    // Header
    React.createElement('div', { className: 'page-header', style: { marginBottom: '12px' } },
      React.createElement('h1', { className: 'page-title' }, '\uD83D\uDCE1 Signal Log Viewer'),
      React.createElement('p', { className: 'page-subtitle' },
        'Real-time ML/ONNX signal stream \u2014 entry & exit signals, model predictions, gate filtering')
    ),

    // Market Status Bar
    market && React.createElement('div', {
      style: {
        display: 'flex', alignItems: 'center', gap: '12px',
        padding: '10px 16px', borderRadius: 'var(--radius-lg, 12px)', marginBottom: '16px',
        background: market.isOpen
          ? 'linear-gradient(135deg, #dcfce7, #d1fae5)'
          : 'linear-gradient(135deg, #fee2e2, #fecaca)',
        border: `1px solid ${market.isOpen ? '#86efac' : '#fca5a5'}`,
        fontSize: '0.85rem', fontWeight: '500'
      }
    },
      React.createElement('span', {
        style: {
          width: '10px', height: '10px', borderRadius: '50%', flexShrink: 0,
          background: market.isOpen ? '#16a34a' : '#dc2626',
          boxShadow: market.isOpen ? '0 0 8px #16a34a' : 'none',
          animation: market.isOpen ? 'pulse 2s infinite' : 'none'
        }
      }),
      React.createElement('span', { style: { fontWeight: '600' } }, market.isOpen ? 'Market OPEN' : 'Market CLOSED'),
      market.niftySpot && React.createElement('span', { style: { color: '#475569', fontSize: '0.82rem' } },
        '\uD83D\uDFE3 NIFTY: ', React.createElement('strong', null, market.niftySpot.toFixed(0))),
      market.sensexSpot && React.createElement('span', { style: { color: '#475569', fontSize: '0.82rem' } },
        '\uD83D\uDFE0 SENSEX: ', React.createElement('strong', null, market.sensexSpot.toFixed(0)))
    ),

    // Sideways Market Warning Banner (auto-hides when market is trending)
    market && (market.niftyIsSideways || market.sensexIsSideways) && React.createElement('div', {
      style: {
        display: 'flex', alignItems: 'flex-start', gap: '12px',
        padding: '12px 16px', borderRadius: 'var(--radius-lg, 12px)', marginBottom: '16px',
        background: 'linear-gradient(135deg, #fef3c7, #fde68a)',
        border: '1px solid #f59e0b',
        fontSize: '0.84rem', color: '#92400e'
      }
    },
      React.createElement('span', { style: { fontSize: '1.3rem', flexShrink: 0, lineHeight: 1 } }, '\u26A0\uFE0F'),
      React.createElement('div', { style: { flex: 1 } },
        React.createElement('div', { style: { fontWeight: '700', marginBottom: '4px', fontSize: '0.88rem' } },
          'Unfavorable Market Regime \u2014 New Orders Blocked'),
        React.createElement('div', { style: { lineHeight: 1.5 } },
          'The underlying index is in a choppy/sideways regime (detected from TradingView indicators). Auto-trading (paper & live) will not place new entry orders until conditions improve. Existing open positions continue to be managed normally.',
          market.niftyIsSideways && React.createElement('div', { style: { marginTop: '6px', fontSize: '0.8rem', fontFamily: 'var(--mono, monospace)' } },
            '\uD83D\uDFE3 NIFTY: ', market.niftySidewaysReason || 'sideways',
            market.niftyAdx != null && (' | ADX=' + market.niftyAdx.toFixed(1)),
            market.niftyBollingerBw != null && (' | BBW=' + market.niftyBollingerBw.toFixed(2) + '%'),
            market.niftyChopIndex != null && (' | Chop=' + market.niftyChopIndex.toFixed(1))
          ),
          market.sensexIsSideways && React.createElement('div', { style: { marginTop: '4px', fontSize: '0.8rem', fontFamily: 'var(--mono, monospace)' } },
            '\uD83D\uDFE0 SENSEX: ', market.sensexSidewaysReason || 'sideways',
            market.sensexAdx != null && (' | ADX=' + market.sensexAdx.toFixed(1)),
            market.sensexBollingerBw != null && (' | BBW=' + market.sensexBollingerBw.toFixed(2) + '%'),
            market.sensexChopIndex != null && (' | Chop=' + market.sensexChopIndex.toFixed(1))
          )
        )
      )
    ),

    // ── Tab Bar ──
    React.createElement('div', {
      style: {
        display: 'flex', gap: '0', marginBottom: '20px',
        borderBottom: '2px solid #e2e8f0', background: '#fff',
        borderRadius: '12px 12px 0 0', overflow: 'hidden'
      }
    },
      [
        { key: 'performance', icon: '\uD83D\uDCC8', label: 'Performance' },
        { key: 'signals',     icon: '\uD83D\uDCE1', label: 'Signal Log' }
      ].map(tab => React.createElement('button', {
        key: tab.key,
        onClick: () => setActiveTab(tab.key),
        style: {
          flex: 1, padding: '12px 16px', border: 'none', cursor: 'pointer',
          fontSize: '0.88rem', fontWeight: activeTab === tab.key ? '700' : '500',
          color: activeTab === tab.key ? '#1565C0' : '#64748b',
          background: activeTab === tab.key ? '#E3F2FD' : 'transparent',
          borderBottom: activeTab === tab.key ? '3px solid #1565C0' : '3px solid transparent',
          transition: 'all 0.2s', display: 'flex', alignItems: 'center',
          justifyContent: 'center', gap: '6px'
        }
      },
        React.createElement('span', null, tab.icon),
        tab.label
      ))
    ),

    // ═══ PERFORMANCE TAB ═══
    activeTab === 'performance' && React.createElement(React.Fragment, null,

    // ── Performance Analytics Section ──
    React.createElement('div', { style: { marginBottom: '20px' } },

      // Section Header
      React.createElement('div', {
        style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '16px' }
      },
        React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '10px' } },
          React.createElement('h2', {
            style: { fontSize: '1.1rem', fontWeight: '700', color: '#1e293b', margin: 0 }
          }, '\uD83D\uDCC8 Signal Performance'),
          React.createElement('span', {
            style: {
              padding: '2px 8px', borderRadius: '6px', fontSize: '0.7rem',
              fontWeight: '600', background: '#ede9fe', color: '#6d28d9'
            }
          }, 'Paper Trading P&L')
        ),
        React.createElement('div', { style: { display: 'flex', gap: '6px', alignItems: 'center', flexWrap: 'wrap' } },
          React.createElement('button', {
            className: `filter-chip ${!perfUseRange ? 'active' : ''}`,
            style: { padding: '5px 12px', borderRadius: '8px', border: '1px solid #e2e8f0', background: !perfUseRange ? '#2563eb' : '#f8fafc', color: !perfUseRange ? '#fff' : '#475569', cursor: 'pointer', fontSize: '0.78rem', fontWeight: '600' },
            onClick: () => { setPerfUseRange(false); setPerfDays(1); }
          }, 'Today'),
          React.createElement('button', {
            className: `filter-chip ${perfUseRange ? 'active' : ''}`,
            style: { padding: '5px 12px', borderRadius: '8px', border: '1px solid #e2e8f0', background: perfUseRange ? '#2563eb' : '#f8fafc', color: perfUseRange ? '#fff' : '#475569', cursor: 'pointer', fontSize: '0.78rem', fontWeight: '600' },
            onClick: () => {
              if (!perfUseRange) {
                var now = new Date();
                var ist = new Date(now.getTime() + (now.getTimezoneOffset() * 60000) + (5.5 * 60 * 60 * 1000));
                var todayStr = ist.toISOString().split('T')[0];
                if (!perfFromDate) setPerfFromDate(todayStr);
                if (!perfToDate) setPerfToDate(todayStr);
              }
              setPerfUseRange(!perfUseRange);
            }
          }, '\uD83D\uDCC5 Date Range'),
          perfUseRange && React.createElement('input', {
            type: 'date', style: { width: '130px', padding: '4px 8px', fontSize: '12px', borderRadius: '6px', border: '1px solid #e2e8f0' },
            value: perfFromDate, onChange: (e) => setPerfFromDate(e.target.value)
          }),
          perfUseRange && React.createElement('span', { style: { fontSize: '0.75rem', color: '#94a3b8' } }, 'to'),
          perfUseRange && React.createElement('input', {
            type: 'date', style: { width: '130px', padding: '4px 8px', fontSize: '12px', borderRadius: '6px', border: '1px solid #e2e8f0' },
            value: perfToDate, onChange: (e) => setPerfToDate(e.target.value)
          }),
          React.createElement('button', {
            style: {
              padding: '5px 10px', borderRadius: '8px', border: '1px solid #e2e8f0',
              background: '#f8fafc', cursor: 'pointer', fontSize: '0.78rem', fontWeight: '500'
            },
            onClick: loadPerf
          }, '\u21BB')
        )
      ),

      // Performance Content
      perfLoading
        ? React.createElement('div', {
            className: 'card',
            style: { padding: '40px', textAlign: 'center', color: '#94a3b8', fontSize: '0.85rem' }
          }, '\u23F3 Loading performance data\u2026')
        : !perf || !perf.summary || perf.summary.tradedCount === 0
          ? React.createElement('div', {
              className: 'card',
              style: { padding: '40px', textAlign: 'center' }
            },
              React.createElement('div', { style: { fontSize: '2rem', marginBottom: '8px' } }, '\uD83D\uDCCA'),
              React.createElement('div', { style: { fontWeight: '600', color: '#475569', marginBottom: '4px' } },
                'No traded signals in this period'),
              React.createElement('div', { style: { fontSize: '0.82rem', color: '#94a3b8' } },
                'Performance analytics require signals that were executed by the paper trading engine.')
            )
          : React.createElement(React.Fragment, null,

              // ── Performance Stat Cards ──
              React.createElement('div', {
                style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(140px, 1fr))', gap: '10px', marginBottom: '20px' }
              },
                perfStatCard('\uD83D\uDCCA Total Signals', perf.summary.totalEntrySignals, null),
                perfStatCard('\uD83D\uDD04 Traded', perf.summary.tradedCount, null,
                  perf.summary.totalEntrySignals > 0 ?
                  Math.round(perf.summary.tradedCount / perf.summary.totalEntrySignals * 100) + '% of signals' : null),
                perfStatCard('\u2705 Wins', perf.summary.winCount, 'positive'),
                perfStatCard('\u274C Losses', perf.summary.lossCount, 'negative'),
                perfStatCard('\uD83C\uDFAF Win Rate', perf.summary.winRate.toFixed(1) + '%', perf.summary.winRate >= 50 ? 'positive' : 'negative'),
                perfStatCard('\uD83D\uDCB0 Total P&L', '\u20B9' + perf.summary.totalPnL.toFixed(2), perf.summary.totalPnL >= 0 ? 'positive' : 'negative'),
                perfStatCard('\uD83D\uDCCA Avg P&L', '\u20B9' + perf.summary.avgPnL.toFixed(2), perf.summary.avgPnL >= 0 ? 'positive' : 'negative',
                  perf.summary.avgPnLPercent.toFixed(2) + '% avg'),
                perfStatCard('\u2B50 Best Trade', '\u20B9' + perf.summary.bestTrade.toFixed(2), 'positive'),
                perfStatCard('\uD83D\uDCA5 Worst Trade', '\u20B9' + perf.summary.worstTrade.toFixed(2), 'negative'),
                perfStatCard('\u2696\uFE0F Profit Factor', perf.summary.profitFactor >= 999 ? '\u221E' : perf.summary.profitFactor.toFixed(2),
                  perf.summary.profitFactor >= 1.5 ? 'positive' : perf.summary.profitFactor >= 1 ? null : 'negative')
              ),

              // ── Charts Grid ──
              React.createElement('div', {
                style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(420px, 1fr))', gap: '16px', marginBottom: '20px' }
              },

                // Daily P&L Chart
                React.createElement('div', {
                  className: 'card',
                  style: { padding: '16px', overflow: 'hidden' }
                },
                  React.createElement('div', {
                    style: { fontSize: '0.82rem', fontWeight: '700', color: '#1e293b', marginBottom: '12px', display: 'flex', alignItems: 'center', gap: '6px' }
                  }, '\uD83D\uDCC5 Daily P&L Trend'),
                  React.createElement('div', { style: { height: '260px', position: 'relative' } },
                    React.createElement('canvas', { ref: dailyCanvasRef })
                  )
                ),

                // Source Performance Chart
                React.createElement('div', {
                  className: 'card',
                  style: { padding: '16px', overflow: 'hidden' }
                },
                  React.createElement('div', {
                    style: { fontSize: '0.82rem', fontWeight: '700', color: '#1e293b', marginBottom: '12px', display: 'flex', alignItems: 'center', gap: '6px' }
                  }, '\u2699\uFE0F Source Performance'),
                  React.createElement('div', { style: { height: '260px', position: 'relative' } },
                    React.createElement('canvas', { ref: sourceCanvasRef })
                  )
                ),

                // Confidence Band Chart
                React.createElement('div', {
                  className: 'card',
                  style: { padding: '16px', overflow: 'hidden' }
                },
                  React.createElement('div', {
                    style: { fontSize: '0.82rem', fontWeight: '700', color: '#1e293b', marginBottom: '12px', display: 'flex', alignItems: 'center', gap: '6px' }
                  }, '\uD83C\uDFAF Confidence Band Win Rate'),
                  React.createElement('div', { style: { height: '260px', position: 'relative' } },
                    React.createElement('canvas', { ref: confCanvasRef })
                  )
                ),

                // CE vs PE Donut
                React.createElement('div', {
                  className: 'card',
                  style: { padding: '16px', overflow: 'hidden' }
                },
                  React.createElement('div', {
                    style: { fontSize: '0.82rem', fontWeight: '700', color: '#1e293b', marginBottom: '12px', display: 'flex', alignItems: 'center', gap: '6px' }
                  }, '\u25C6 CE vs PE Breakdown'),
                  React.createElement('div', { style: { height: '260px', position: 'relative' } },
                    React.createElement('canvas', { ref: sideCanvasRef })
                  )
                )
              ),

              // ── Performance Detail Tables ──
              React.createElement('div', {
                style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(360px, 1fr))', gap: '16px' }
              },

                // Source Table
                perf.bySource && perf.bySource.length > 0 && React.createElement('div', {
                  className: 'card', style: { overflow: 'hidden' }
                },
                  React.createElement('div', {
                    style: { padding: '12px 16px', borderBottom: '1px solid #e2e8f0', fontSize: '0.82rem', fontWeight: '700', color: '#1e293b' }
                  }, '\u2699\uFE0F Performance by Source'),
                  React.createElement('div', { style: { overflowX: 'auto' } },
                  React.createElement('table', { style: { width: '100%', borderCollapse: 'collapse', fontSize: '0.78rem', minWidth: '420px' } },
                    React.createElement('thead', null,
                      React.createElement('tr', { style: { background: '#f8fafc' } },
                        perfTh('Source'), perfTh('Signals'), perfTh('Traded'), perfTh('Wins'), perfTh('Win%'), perfTh('P&L'))
                    ),
                    React.createElement('tbody', null,
                      perf.bySource.map((s, i) => React.createElement('tr', {
                        key: s.source,
                        style: { borderBottom: '1px solid #f1f5f9', background: i % 2 === 0 ? '#fff' : '#fafbfc' }
                      },
                        React.createElement('td', { style: perfTdStyle }, sourceBadge(s.source)),
                        React.createElement('td', { style: perfTdStyleMono }, s.signalCount),
                        React.createElement('td', { style: perfTdStyleMono }, s.tradedCount),
                        React.createElement('td', { style: perfTdStyleMono }, s.winCount),
                        React.createElement('td', { style: Object.assign({}, perfTdStyleMono, { color: s.winRate >= 50 ? '#16a34a' : '#dc2626', fontWeight: '700' }) },
                          s.tradedCount > 0 ? s.winRate.toFixed(1) + '%' : '\u2014'),
                        React.createElement('td', { style: Object.assign({}, perfTdStyleMono, { color: s.totalPnL >= 0 ? '#16a34a' : '#dc2626', fontWeight: '700' }) },
                          s.tradedCount > 0 ? '\u20B9' + s.totalPnL.toFixed(2) : '\u2014')
                      ))
                    )
                  )
                  )
                ),

                // Exit Reason Table
                perf.byExitReason && perf.byExitReason.length > 0 && React.createElement('div', {
                  className: 'card', style: { overflow: 'hidden' }
                },
                  React.createElement('div', {
                    style: { padding: '12px 16px', borderBottom: '1px solid #e2e8f0', fontSize: '0.82rem', fontWeight: '700', color: '#1e293b' }
                  }, '\uD83D\uDEAA Exit Reason Breakdown'),
                  React.createElement('div', { style: { overflowX: 'auto' } },
                  React.createElement('table', { style: { width: '100%', borderCollapse: 'collapse', fontSize: '0.78rem', minWidth: '360px' } },
                    React.createElement('thead', null,
                      React.createElement('tr', { style: { background: '#f8fafc' } },
                        perfTh('Reason'), perfTh('Count'), perfTh('Wins'), perfTh('Win%'), perfTh('Avg P&L'))
                    ),
                    React.createElement('tbody', null,
                      perf.byExitReason.map((e, i) => React.createElement('tr', {
                        key: e.reason,
                        style: { borderBottom: '1px solid #f1f5f9', background: i % 2 === 0 ? '#fff' : '#fafbfc' }
                      },
                        React.createElement('td', { style: perfTdStyle },
                          React.createElement('span', {
                            style: {
                              padding: '2px 8px', borderRadius: '6px', fontSize: '0.72rem', fontWeight: '500',
                              background: e.reason === 'TARGET' ? '#dcfce7' : e.reason === 'STOPLOSS' ? '#fee2e2' : '#f1f5f9',
                              color: e.reason === 'TARGET' ? '#166534' : e.reason === 'STOPLOSS' ? '#991b1b' : '#475569'
                            }
                          }, e.reason)
                        ),
                        React.createElement('td', { style: perfTdStyleMono }, e.count),
                        React.createElement('td', { style: perfTdStyleMono }, e.winCount),
                        React.createElement('td', { style: Object.assign({}, perfTdStyleMono, { color: e.winRate >= 50 ? '#16a34a' : '#dc2626', fontWeight: '700' }) },
                          e.winRate.toFixed(1) + '%'),
                        React.createElement('td', { style: Object.assign({}, perfTdStyleMono, { color: e.avgPnL >= 0 ? '#16a34a' : '#dc2626', fontWeight: '700' }) },
                          '\u20B9' + e.avgPnL.toFixed(2))
                      ))
                    )
                  )
                  )
                ),

                // Hourly Table
                perf.hourly && perf.hourly.length > 0 && React.createElement('div', {
                  className: 'card', style: { overflow: 'hidden' }
                },
                  React.createElement('div', {
                    style: { padding: '12px 16px', borderBottom: '1px solid #e2e8f0', fontSize: '0.82rem', fontWeight: '700', color: '#1e293b' }
                  }, '\u23F0 Hourly Performance (IST)'),
                  React.createElement('div', { style: { overflowX: 'auto' } },
                  React.createElement('table', { style: { width: '100%', borderCollapse: 'collapse', fontSize: '0.78rem', minWidth: '360px' } },
                    React.createElement('thead', null,
                      React.createElement('tr', { style: { background: '#f8fafc' } },
                        perfTh('Hour'), perfTh('Trades'), perfTh('Wins'), perfTh('Win%'), perfTh('P&L'))
                    ),
                    React.createElement('tbody', null,
                      perf.hourly.map((h, i) => React.createElement('tr', {
                        key: h.hour,
                        style: { borderBottom: '1px solid #f1f5f9', background: i % 2 === 0 ? '#fff' : '#fafbfc' }
                      },
                        React.createElement('td', { style: perfTdStyle },
                          React.createElement('span', {
                            style: { fontWeight: '600', color: '#475569', fontSize: '0.78rem' }
                          }, h.label)),
                        React.createElement('td', { style: perfTdStyleMono }, h.tradeCount),
                        React.createElement('td', { style: perfTdStyleMono }, h.winCount),
                        React.createElement('td', { style: Object.assign({}, perfTdStyleMono, { color: h.winRate >= 50 ? '#16a34a' : '#dc2626', fontWeight: '700' }) },
                          h.winRate.toFixed(1) + '%'),
                        React.createElement('td', { style: Object.assign({}, perfTdStyleMono, { color: h.totalPnL >= 0 ? '#16a34a' : '#dc2626', fontWeight: '700' }) },
                          '\u20B9' + h.totalPnL.toFixed(2))
                      ))
                    )
                  )
                  )
                )
              )
            )
    )
    ),

    // ═══ SIGNAL LOG TAB ═══
    activeTab === 'signals' && React.createElement(React.Fragment, null,

    // Stat Cards
    React.createElement('div', {
      style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(130px, 1fr))', gap: '10px', marginBottom: '16px' }
    },
      React.createElement(StatCard, { label: '\uD83D\uDCCA Total', value: signals.length }),
      React.createElement(StatCard, { label: '\u2B06\uFE0F Entry', value: entryCount, type: 'positive' }),
      React.createElement(StatCard, { label: '\u2B07\uFE0F Exit', value: exitCount, type: 'negative' }),
      React.createElement(StatCard, { label: '\uD83D\uDCC8 CE', value: ceCount, type: 'positive' }),
      React.createElement(StatCard, { label: '\uD83D\uDCC9 PE', value: peCount, type: 'negative' }),
      React.createElement(StatCard, { label: '\uD83C\uDFAF Avg Conf', value: avgConf }),
      React.createElement(StatCard, { label: '\uD83D\uDD25 High Conf', value: highConf, sub: '\u2265 90%' }),
      stats && stats.topSource && React.createElement(StatCard, { label: '\u2B50 Top Source', value: stats.topSource })
    ),

    // ── Filter Panel ──
    React.createElement('div', {
      className: 'card',
      style: { padding: '16px', marginBottom: '16px', borderLeft: activeFilterCount > 0 ? '3px solid #2563eb' : '3px solid transparent' }
    },

    // Filter header row
    React.createElement('div', {
      style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: '12px' }
    },
      React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } },
        React.createElement('span', { style: { fontSize: '0.85rem', fontWeight: '600', color: '#1e293b' } },
          '\uD83D\uDD0D Filters'),
        activeFilterCount > 0 && React.createElement('span', {
          style: {
            display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            width: '20px', height: '20px', borderRadius: '50%', fontSize: '0.7rem', fontWeight: '700',
            background: '#2563eb', color: '#fff'
          }
        }, activeFilterCount)
      ),
      React.createElement('div', { style: { display: 'flex', gap: '8px', alignItems: 'center' } },
        activeFilterCount > 0 && React.createElement('button', {
          style: {
            padding: '4px 10px', borderRadius: '6px', border: '1px solid #e2e8f0',
            background: '#fff', cursor: 'pointer', fontSize: '0.75rem', color: '#dc2626', fontWeight: '500'
          },
          onClick: resetFilters
        }, '\u2715 Clear Filters'),
        React.createElement('button', {
          className: 'btn btn-sm',
          style: {
            padding: '5px 12px', borderRadius: '8px', border: '1px solid #e2e8f0',
            background: '#f8fafc', cursor: 'pointer', fontSize: '0.8rem', fontWeight: '500'
          },
          onClick: () => { setLoading(true); loadData(); }
        }, '\u21BB Refresh')
      )
    ),

    // Filter grid
    React.createElement('div', {
      style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', gap: '12px', alignItems: 'end' }
    },

      // Search
      React.createElement('div', null,
        React.createElement('label', { style: labelStyle }, '\uD83D\uDD0E Search'),
        React.createElement('input', {
          type: 'text', value: searchInput, placeholder: 'Symbol, source, zone\u2026',
          style: inputStyle,
          onChange: e => {
            setSearchInput(e.target.value);
            clearTimeout(searchTimerRef.current);
            searchTimerRef.current = setTimeout(() => setSearchText(e.target.value), 400);
          }
        })
      ),

      // Mode
      React.createElement('div', null,
        React.createElement('label', { style: labelStyle }, '\uD83C\uDFDB\uFE0F Index'),
        React.createElement(SegmentedButton, {
          options: [
            { value: '', label: 'All' },
            { value: 'NIFTY', label: '\uD83D\uDFE3 Nifty' },
            { value: 'SENSEX', label: '\uD83D\uDFE0 Sensex' }
          ],
          value: mode,
          onChange: setMode
        })
      ),

      // Entry / Exit
      React.createElement('div', null,
        React.createElement('label', { style: labelStyle }, '\u2194\uFE0F Signal Type'),
        React.createElement(SegmentedButton, {
          options: [
            { value: 'all', label: 'All' },
            { value: 'entry', label: '\u2B06 Entry' },
            { value: 'exit', label: '\u2B07 Exit' }
          ],
          value: filter,
          onChange: setFilter
        })
      ),

      // Side (CE / PE)
      React.createElement('div', null,
        React.createElement('label', { style: labelStyle }, '\u25C6 Option Side'),
        React.createElement(SegmentedButton, {
          options: [
            { value: '', label: 'All' },
            { value: 'CE', label: '\u25B2 CE' },
            { value: 'PE', label: '\u25BC PE' }
          ],
          value: sideFilter,
          onChange: setSideFilter
        })
      ),

      // Date
      React.createElement('div', null,
        React.createElement('label', { style: labelStyle }, '\uD83D\uDCC5 Date (IST)'),
        React.createElement('input', {
          type: 'date', value: selectedDate,
          style: inputStyle,
          onChange: e => setSelectedDate(e.target.value)
        })
      ),

      // Source — toggle buttons for quick ONNX/Phantom filtering
      React.createElement('div', null,
        React.createElement('label', { style: labelStyle }, '\u2699\uFE0F Source'),
        React.createElement('div', { style: { display: 'flex', gap: '4px', flexWrap: 'wrap' } },
          React.createElement('button', {
            className: `toggle-btn ${sourceFilter === '' ? 'active' : ''}`,
            onClick: () => setSourceFilter('')
          }, 'All'),
          React.createElement('button', {
            className: `toggle-btn ${sourceFilter === 'OnnxModel' ? 'active' : ''}`,
            onClick: () => setSourceFilter(sourceFilter === 'OnnxModel' ? '' : 'OnnxModel')
          }, '\u2699\uFE0F ONNX'),
          React.createElement('button', {
            className: `toggle-btn ${sourceFilter === 'Phantom' ? 'active' : ''}`,
            onClick: () => setSourceFilter(sourceFilter === 'Phantom' ? '' : 'Phantom')
          }, '\uD83D\uDC7B Phantom'),
          sources.filter(s => s !== 'OnnxModel' && s !== 'Phantom').map(s =>
            React.createElement('button', {
              key: s,
              className: `toggle-btn ${sourceFilter === s ? 'active' : ''}`,
              onClick: () => setSourceFilter(sourceFilter === s ? '' : s)
            }, s)
          )
        )
      ),

      // ML Prediction
      mlPredictions.length > 0 && React.createElement('div', null,
        React.createElement('label', { style: labelStyle }, '\uD83E\uDD16 ML Prediction'),
        React.createElement(SegmentedButton, {
          options: [
            { value: '', label: 'All' },
            ...mlPredictions.map(p => ({
              value: p,
              label: (p === 'BUY' ? '\u25B2 ' : p === 'SELL' ? '\u25BC ' : '\u25CF ') + p
            }))
          ],
          value: mlFilter,
          onChange: setMlFilter
        })
      ),

      // Min Confidence
      React.createElement('div', null,
        React.createElement('label', { style: labelStyle }, '\uD83C\uDFAF Min Confidence'),
        React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } },
          React.createElement('input', {
            type: 'range', min: 0.3, max: 0.95, step: 0.05, value: minConf,
            style: { flex: 1, accentColor: '#2563eb', height: '6px' },
            onChange: e => setMinConf(parseFloat(e.target.value))
          }),
          React.createElement('span', {
            style: {
              fontSize: '0.82rem', fontWeight: '700', color: confColor(minConf),
              fontFamily: 'var(--mono, monospace)', minWidth: '40px', textAlign: 'right'
            }
          }, (minConf * 100).toFixed(0) + '%')
        )
      ),

      // Time Range (15-min IST slots)
      React.createElement('div', null,
        React.createElement('label', { style: labelStyle }, '\u23F0 Time Range (IST)'),
        React.createElement('select', {
          value: timeRange,
          onChange: e => setTimeRange(e.target.value),
          style: inputStyle
        },
          React.createElement('option', { value: '' }, 'Full Day'),
          timeSlots.map(s => React.createElement('option', { key: s.value, value: s.value }, s.label))
        )
      )
    )
    ),

    // ── Results summary + Pagination ──
    React.createElement('div', {
      style: {
        display: 'flex', alignItems: 'center', justifyContent: 'space-between',
        marginBottom: '8px', padding: '0 4px'
      }
    },
      React.createElement('span', { style: { fontSize: '0.82rem', color: '#64748b', fontWeight: '500' } },
        `Showing ${signals.length} of ${totalCount.toLocaleString()} total signals`,
        activeFilterCount > 0 ? ' (filtered)' : ''
      ),
      React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } },
        totalPages > 1 && React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '4px' } },
          React.createElement('button', {
            disabled: page <= 1,
            style: {
              padding: '4px 10px', borderRadius: '6px', border: '1px solid #e2e8f0',
              background: page <= 1 ? '#f1f5f9' : '#fff', cursor: page <= 1 ? 'default' : 'pointer',
              fontSize: '0.78rem', fontWeight: '500', color: page <= 1 ? '#94a3b8' : '#1e293b'
            },
            onClick: () => setPage(Math.max(1, page - 1))
          }, '\u25C0 Prev'),
          React.createElement('span', {
            style: { fontSize: '0.78rem', fontWeight: '600', color: '#475569', padding: '0 6px' }
          }, `Page ${page} of ${totalPages}`),
          React.createElement('button', {
            disabled: page >= totalPages,
            style: {
              padding: '4px 10px', borderRadius: '6px', border: '1px solid #e2e8f0',
              background: page >= totalPages ? '#f1f5f9' : '#fff', cursor: page >= totalPages ? 'default' : 'pointer',
              fontSize: '0.78rem', fontWeight: '500', color: page >= totalPages ? '#94a3b8' : '#1e293b'
            },
            onClick: () => setPage(Math.min(totalPages, page + 1))
          }, 'Next \u25B6')
        ),
        React.createElement('span', { style: { fontSize: '0.75rem', color: '#94a3b8' } },
          '\u21BB Auto-refresh 30s')
      )
    ),

    // ── Signal Table ──
    signals.length === 0
      ? React.createElement(EmptyState, {
          icon: '\uD83D\uDCED',
          title: 'No signals match filters',
          text: activeFilterCount > 0
            ? 'Try clearing some filters or expanding the time range.'
            : 'No signals generated yet today. Waiting for market signals\u2026'
        })
      : React.createElement('div', { className: 'card', style: { overflow: 'hidden' } },
          React.createElement('div', { style: { overflowX: 'auto' } },
            React.createElement('table', {
              style: { width: '100%', borderCollapse: 'collapse', fontSize: '0.82rem' }
            },
              // Header
              React.createElement('thead', null,
                React.createElement('tr', { style: { background: '#f8fafc' } },
                  th('Time', 'time'),
                  th('Type', null),
                  th('Index', 'mode'),
                  th('Symbol', 'symbol'),
                  th('Direction', null),
                  th('ML Pred.', null),
                  th('Source', null),
                  th('Confidence', 'confidence'),
                  th('Margin \u24D8', 'margin'),
                  th('Gates', null),
                  th('Trade', null)
                )
              ),

              // Body
              React.createElement('tbody', null,
                signals.map((s, i) => {
                  const isOpen = expanded.has(i);
                  const rowBg = s.isExitSignal ? '#fffbeb' : (i % 2 === 0 ? '#fff' : '#fafbfc');
                  return React.createElement(React.Fragment, { key: i },
                    // Main row
                    React.createElement('tr', {
                      style: {
                        borderBottom: '1px solid #f1f5f9', background: rowBg,
                        cursor: 'pointer', transition: 'background 0.15s'
                      },
                      onClick: () => setExpanded(prev => { const next = new Set(prev); if (next.has(i)) next.delete(i); else next.add(i); return next; }),
                      onMouseEnter: e => { e.currentTarget.style.background = '#eff6ff'; },
                      onMouseLeave: e => { e.currentTarget.style.background = rowBg; }
                    },
                      // Time
                      React.createElement('td', { style: tdStyle },
                        React.createElement('div', { style: { display: 'flex', flexDirection: 'column', lineHeight: 1.3 } },
                          React.createElement('span', { style: { fontWeight: '500', fontSize: '0.78rem' } }, formatTimeShort(s.generatedAtIst)),
                          React.createElement('span', { style: { fontSize: '0.68rem', color: '#94a3b8' } },
                            formatDate(s.generatedAtIst))
                        )
                      ),
                      // Type
                      React.createElement('td', { style: tdStyle }, typeBadge(s.isExitSignal)),
                      // Mode
                      React.createElement('td', { style: tdStyle }, modeBadge(s.mode)),
                      // Symbol
                      React.createElement('td', {
                        style: Object.assign({}, tdStyle, {
                          fontFamily: 'var(--mono, monospace)', fontSize: '0.78rem',
                          fontWeight: '500', maxWidth: '170px', overflow: 'hidden',
                          textOverflow: 'ellipsis', whiteSpace: 'nowrap'
                        }),
                        title: s.symbol
                      }, s.symbol),
                      // Direction
                      React.createElement('td', { style: tdStyle }, sideBadge(s.side, s.optionType, s.isExitSignal)),
                      // ML Prediction
                      React.createElement('td', { style: tdStyle }, mlBadge(s.mlPrediction)),
                      // Source
                      React.createElement('td', { style: tdStyle }, sourceBadge(s.signalSource)),
                      // Confidence
                      React.createElement('td', { style: tdStyle }, confBar(s.confidence)),
                      // Margin (prediction decisiveness)
                      React.createElement('td', {
                        style: Object.assign({}, tdStyle, {
                          fontFamily: 'var(--mono, monospace)', fontSize: '0.78rem',
                          color: s.margin >= 0.10 ? '#16a34a' : '#6b7280'
                        }),
                        title: 'Prediction margin: gap between top prediction score (' + (s.confidence * 100).toFixed(0) + '%) and second-best. Higher = more decisive prediction.'
                      }, (s.margin * 100).toFixed(1) + '%'),
                      // Gates
                      React.createElement('td', { style: tdStyle }, gatesBadge(s.gatesPassed, s.gatesBlocked)),
                      // Trade status
                      React.createElement('td', { style: tdStyle },
                        s.orderStatus
                          ? React.createElement('div', { style: { display: 'flex', flexDirection: 'column', gap: '2px', alignItems: 'flex-start' } },
                              React.createElement('span', {
                                style: {
                                  padding: '2px 8px', borderRadius: '4px', fontSize: '0.7rem', fontWeight: '600',
                                  background: s.orderStatus === 'OPEN' ? '#dbeafe' : s.orderPnL > 0 ? '#dcfce7' : s.orderPnL < 0 ? '#fee2e2' : '#f1f5f9',
                                  color: s.orderStatus === 'OPEN' ? '#1d4ed8' : s.orderPnL > 0 ? '#166534' : s.orderPnL < 0 ? '#991b1b' : '#475569'
                                }
                              }, s.orderStatus === 'OPEN' ? '\u23F3 OPEN' : s.orderStatus),
                              s.orderPnL != null && React.createElement('span', {
                                style: {
                                  fontSize: '0.72rem', fontWeight: '700', fontFamily: 'var(--mono, monospace)',
                                  color: s.orderPnL > 0 ? '#16a34a' : s.orderPnL < 0 ? '#dc2626' : '#6b7280'
                                }
                              }, (s.orderPnL >= 0 ? '+' : '') + '\u20B9' + s.orderPnL.toFixed(2))
                            )
                          : s.gateRejectionReason
                            ? React.createElement('span', {
                                style: {
                                  padding: '2px 6px', borderRadius: '4px', fontSize: '0.65rem', fontWeight: '600',
                                  background: '#fef3c7', color: '#92400e', whiteSpace: 'nowrap'
                                },
                                title: s.gateRejectionDetail || ('Gate that blocked this signal from trading: ' + s.gateRejectionReason)
                              }, '\u26D4 ' + s.gateRejectionReason)
                            : React.createElement('span', { style: { fontSize: '0.7rem', color: '#94a3b8' } }, '\u2014')
                      )
                    ),

                    // ── Expanded detail row ──
                    isOpen && React.createElement('tr', null,
                      React.createElement('td', { colSpan: 11, style: { padding: '0' } },
                        React.createElement('div', {
                          style: {
                            padding: '16px 20px',
                            background: 'linear-gradient(180deg, #f8fafc, #f1f5f9)',
                            borderBottom: '2px solid #e2e8f0',
                            borderLeft: '3px solid #2563eb'
                          }
                        },
                          // Section title
                          React.createElement('div', {
                            style: { fontSize: '0.82rem', fontWeight: '700', color: '#1e293b', marginBottom: '12px', display: 'flex', alignItems: 'center', gap: '6px' }
                          }, '\uD83D\uDCCB Signal Details'),

                          // Detail grid
                          React.createElement('div', {
                            style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', gap: '10px' }
                          },
                            signalDetail('\uD83D\uDCCD Symbol', s.symbol, 'mono'),
                            signalDetail('\u2699\uFE0F Source', s.signalSource),
                            signalDetail('\uD83E\uDD16 ML Prediction', s.mlPrediction
                              ? s.mlPrediction + (s.mlPrediction === 'BUY' ? ' (premium rising)' : s.mlPrediction === 'SELL' ? ' (premium falling)' : ' (flat)')
                              : '\u2014'),
                            signalDetail('\u2194\uFE0F Type', s.isExitSignal ? '\u2B07\uFE0F Exit Signal' : '\u2B06\uFE0F Entry Signal'),
                            signalDetail('\u25C6 Direction', s.optionType
                              ? s.isExitSignal
                                ? s.optionType + ' Exit (premium declining)'
                                : s.optionType + ((s.side === 'BUY' && s.optionType === 'CE') || (s.side === 'SELL' && s.optionType === 'PE') ? ' Bullish' : ' Bearish')
                              : '\u2014'),
                            signalDetail('\uD83C\uDFAF Confidence', (s.confidence * 100).toFixed(2) + '% \u2014 probability of prediction', null, confColor(s.confidence)),
                            signalDetail('\uD83D\uDCCA Margin', (s.margin * 100).toFixed(2) + '% \u2014 gap between top-2 scores'),
                            signalDetail('\uD83D\uDDFA\uFE0F Pivot Zone', s.pivotZone || '\u2014'),
                            signalDetail('\u23F0 Generated (IST)', formatTime(s.generatedAtIst))
                          ),

                          // SMC Direction Analysis (why traded / why not)
                          (() => {
                            try {
                              const fs = s.featureSnapshot
                                ? (typeof s.featureSnapshot === 'string' ? JSON.parse(s.featureSnapshot) : s.featureSnapshot)
                                : null;
                              if (!fs) return null;
                              const bos = fs.BreakOfStructure || 0;
                              const choch = fs.ChangeOfStructure || 0;
                              const undMom = fs.UnderlyingMomentum || 0;
                              const fvgDir = fs.FvgDirection || 0;
                              const liqSweep = fs.LiquiditySweepSignal || 0;
                              const bagSig = fs.BreakawayGapSignal || 0;
                              const rangeComp = fs.RangeCompression;
                              const rangePos = fs.PricePositionInRange;

                              // Determine SMC direction
                              var smcDir = 'Neutral';
                              var smcIcon = '\u25CF';
                              var smcColor = '#64748b';
                              var smcBg = '#f1f5f9';
                              var smcBorder = '#e2e8f0';
                              var smcDetail = '';

                              if (bos > 0) { smcDir = 'Bullish'; smcIcon = '\u25B2'; smcColor = '#166534'; smcBg = '#dcfce7'; smcBorder = '#bbf7d0'; smcDetail = 'BOS=+1 (Higher High confirmed)'; }
                              else if (bos < 0) { smcDir = 'Bearish'; smcIcon = '\u25BC'; smcColor = '#991b1b'; smcBg = '#fee2e2'; smcBorder = '#fecaca'; smcDetail = 'BOS=-1 (Lower Low confirmed)'; }
                              else if (choch > 0) { smcDir = 'Reversal Up'; smcIcon = '\u21BB'; smcColor = '#0e7490'; smcBg = '#ecfeff'; smcBorder = '#a5f3fc'; smcDetail = 'ChoCh=+1 (Bearish\u2192Bullish reversal)'; }
                              else if (choch < 0) { smcDir = 'Reversal Down'; smcIcon = '\u21BA'; smcColor = '#9333ea'; smcBg = '#faf5ff'; smcBorder = '#e9d5ff'; smcDetail = 'ChoCh=-1 (Bullish\u2192Bearish reversal)'; }
                              else { smcDetail = 'BOS=0, ChoCh=0 (No structural break \u2014 ML decides)'; }

                              // Determine alignment with signal
                              var isCE = s.optionType === 'CE';
                              var isPE = s.optionType === 'PE';
                              var isBullishBet = !s.isExitSignal ? isCE : isPE;
                              var isBearishBet = !s.isExitSignal ? isPE : isCE;

                              var alignment = 'neutral';
                              var alignIcon = '\u2714\uFE0F';
                              var alignLabel = 'ML Decides';
                              var alignColor = '#475569';
                              var alignBg = '#f1f5f9';
                              var alignReason = 'No structural break detected \u2014 signal allowed, ML model decides direction.';

                              if (bos > 0) {
                                if (isBullishBet) { alignment = 'aligned'; alignIcon = '\u2705'; alignLabel = 'Allowed \u2014 Aligned'; alignColor = '#166534'; alignBg = '#dcfce7'; alignReason = 'BOS=+1 (bullish) + Buy ' + s.optionType + ' = Trend-aligned entry. Signal allowed.'; }
                                else if (isBearishBet) { alignment = 'blocked'; alignIcon = '\u274C'; alignLabel = 'Counter-trend'; alignColor = '#991b1b'; alignBg = '#fee2e2'; alignReason = 'BOS=+1 (bullish) + Buy ' + s.optionType + ' = Counter-trend entry. Signal may be blocked by SMC gate.'; }
                              } else if (bos < 0) {
                                if (isBearishBet) { alignment = 'aligned'; alignIcon = '\u2705'; alignLabel = 'Allowed \u2014 Aligned'; alignColor = '#166534'; alignBg = '#dcfce7'; alignReason = 'BOS=-1 (bearish) + Buy ' + s.optionType + ' = Trend-aligned entry. Signal allowed.'; }
                                else if (isBullishBet) { alignment = 'blocked'; alignIcon = '\u274C'; alignLabel = 'Counter-trend'; alignColor = '#991b1b'; alignBg = '#fee2e2'; alignReason = 'BOS=-1 (bearish) + Buy ' + s.optionType + ' = Counter-trend entry. Signal may be blocked by SMC gate.'; }
                              } else if (choch > 0) {
                                if (isBullishBet) { alignment = 'aligned'; alignIcon = '\u2705'; alignLabel = 'Allowed \u2014 Reversal'; alignColor = '#0e7490'; alignBg = '#ecfeff'; alignReason = 'ChoCh=+1 (reversal up) + Buy ' + s.optionType + ' = Aligned with reversal. Signal allowed.'; }
                                else { alignment = 'blocked'; alignIcon = '\u274C'; alignLabel = 'Counter-reversal'; alignColor = '#991b1b'; alignBg = '#fee2e2'; alignReason = 'ChoCh=+1 (reversal up) + Buy ' + s.optionType + ' = Against reversal direction. Signal may be blocked.'; }
                              } else if (choch < 0) {
                                if (isBearishBet) { alignment = 'aligned'; alignIcon = '\u2705'; alignLabel = 'Allowed \u2014 Reversal'; alignColor = '#0e7490'; alignBg = '#ecfeff'; alignReason = 'ChoCh=-1 (reversal down) + Buy ' + s.optionType + ' = Aligned with reversal. Signal allowed.'; }
                                else { alignment = 'blocked'; alignIcon = '\u274C'; alignLabel = 'Counter-reversal'; alignColor = '#991b1b'; alignBg = '#fee2e2'; alignReason = 'ChoCh=-1 (reversal down) + Buy ' + s.optionType + ' = Against reversal direction. Signal may be blocked.'; }
                              }

                              // Build additional SMC context items
                              var smcItems = [];
                              if (fvgDir !== 0) smcItems.push({ label: 'FVG', value: fvgDir > 0 ? '\u25B2 Bullish gap' : '\u25BC Bearish gap', color: fvgDir > 0 ? '#166534' : '#991b1b' });
                              if (liqSweep !== 0) smcItems.push({ label: 'Liq Sweep', value: liqSweep > 0 ? 'Buy-side swept' : 'Sell-side swept', color: '#d97706' });
                              if (bagSig !== 0) smcItems.push({ label: 'BAG', value: bagSig > 0 ? '\u25B2 Bullish gap' : '\u25BC Bearish gap', color: bagSig > 0 ? '#166534' : '#991b1b' });
                              if (rangeComp != null) smcItems.push({ label: 'Compression', value: rangeComp.toFixed(2) + 'x' + (rangeComp < 0.5 ? ' (squeeze)' : ''), color: rangeComp < 0.5 ? '#d97706' : '#475569' });
                              if (rangePos != null) smcItems.push({ label: 'Range Pos', value: (rangePos * 100).toFixed(0) + '%', color: '#475569' });
                              if (undMom !== 0) smcItems.push({ label: 'Und. Momentum', value: (undMom > 0 ? '+' : '') + (undMom * 100).toFixed(2) + '%', color: undMom > 0 ? '#166534' : '#991b1b' });

                              return React.createElement('div', { style: { marginTop: '14px' } },
                                React.createElement('div', {
                                  style: { fontSize: '0.82rem', fontWeight: '700', color: '#1e293b', marginBottom: '10px', display: 'flex', alignItems: 'center', gap: '6px' }
                                }, '\uD83E\uDDE0 SMC Direction Analysis'),

                                // Main SMC direction + alignment row
                                React.createElement('div', {
                                  style: { display: 'flex', gap: '10px', flexWrap: 'wrap', marginBottom: '10px' }
                                },
                                  // SMC Direction badge
                                  React.createElement('div', {
                                    style: { padding: '8px 14px', borderRadius: '10px', background: smcBg, border: '1px solid ' + smcBorder, flex: '1 1 200px', minWidth: '200px' }
                                  },
                                    React.createElement('div', { style: { fontSize: '0.68rem', color: '#94a3b8', textTransform: 'uppercase', letterSpacing: '0.5px', marginBottom: '4px' } }, 'SMC Direction'),
                                    React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '6px' } },
                                      React.createElement('span', { style: { fontSize: '1rem' } }, smcIcon),
                                      React.createElement('span', { style: { fontSize: '0.88rem', fontWeight: '700', color: smcColor } }, smcDir)
                                    ),
                                    React.createElement('div', { style: { fontSize: '0.72rem', color: smcColor, marginTop: '4px', fontFamily: 'var(--mono, monospace)' } }, smcDetail)
                                  ),

                                  // Alignment verdict badge
                                  React.createElement('div', {
                                    style: { padding: '8px 14px', borderRadius: '10px', background: alignBg, border: '1px solid ' + (alignment === 'aligned' ? '#bbf7d0' : alignment === 'blocked' ? '#fecaca' : '#e2e8f0'), flex: '1 1 200px', minWidth: '200px' }
                                  },
                                    React.createElement('div', { style: { fontSize: '0.68rem', color: '#94a3b8', textTransform: 'uppercase', letterSpacing: '0.5px', marginBottom: '4px' } }, 'Signal Alignment'),
                                    React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '6px' } },
                                      React.createElement('span', { style: { fontSize: '1rem' } }, alignIcon),
                                      React.createElement('span', { style: { fontSize: '0.88rem', fontWeight: '700', color: alignColor } }, alignLabel)
                                    ),
                                    React.createElement('div', { style: { fontSize: '0.72rem', color: alignColor, marginTop: '4px', lineHeight: 1.4 } }, alignReason)
                                  )
                                ),

                                // Additional SMC context chips
                                smcItems.length > 0 && React.createElement('div', {
                                  style: { display: 'flex', flexWrap: 'wrap', gap: '6px' }
                                },
                                  smcItems.map(function(item, idx) {
                                    return React.createElement('span', {
                                      key: idx,
                                      style: {
                                        padding: '3px 8px', borderRadius: '6px', fontSize: '0.72rem',
                                        fontFamily: 'var(--mono, monospace)', fontWeight: '500',
                                        background: '#f1f5f9', color: item.color, border: '1px solid #e2e8f0'
                                      }
                                    }, item.label + ': ' + item.value);
                                  })
                                )
                              );
                            } catch (e) { return null; }
                          })(),

                          // Gate Rejection Detail (shown when signal was blocked by a gate)
                          s.gateRejectionReason && s.gateRejectionDetail && React.createElement('div', { style: { marginTop: '14px' } },
                            React.createElement('div', {
                              style: { fontSize: '0.82rem', fontWeight: '700', color: '#92400e', marginBottom: '8px', display: 'flex', alignItems: 'center', gap: '6px' }
                            }, '\u26D4 Gate Rejection: ' + s.gateRejectionReason),
                            React.createElement('div', {
                              style: {
                                padding: '10px 14px', borderRadius: '8px', background: '#fffbeb', border: '1px solid #fde68a',
                                fontSize: '0.78rem', fontFamily: 'var(--mono, monospace)', color: '#78350f', lineHeight: 1.6, whiteSpace: 'pre-wrap'
                              }
                            }, s.gateRejectionDetail)
                          ),

                          // Regime Detail (market regime classification at signal time)
                          s.regimeDetail && (() => {
                            const typeMatch = s.regimeDetail.match(/Type=(\w+)/);
                            const regimeType = typeMatch ? typeMatch[1] : null;
                            const scoreMatch = s.regimeDetail.match(/Score=(\d+\/\d+)/);
                            const scoreText = scoreMatch ? scoreMatch[1] : null;
                            const typeColors = {
                              Breakout: { bg: '#dcfce7', color: '#166534', icon: '\uD83D\uDE80' },
                              Trending: { bg: '#dbeafe', color: '#1d4ed8', icon: '\uD83D\uDCC8' },
                              Exhaustion: { bg: '#fee2e2', color: '#991b1b', icon: '\u26A0\uFE0F' },
                              Squeeze: { bg: '#f3e8ff', color: '#7e22ce', icon: '\uD83D\uDCA0' },
                              Choppy: { bg: '#fef3c7', color: '#92400e', icon: '\uD83C\uDF0A' },
                              Normal: { bg: '#f1f5f9', color: '#475569', icon: '\u2705' }
                            };
                            const tc = typeColors[regimeType] || typeColors.Normal;
                            return React.createElement('div', { style: { marginTop: '14px' } },
                              React.createElement('div', {
                                style: { fontSize: '0.82rem', fontWeight: '700', color: '#1e293b', marginBottom: '8px', display: 'flex', alignItems: 'center', gap: '6px' }
                              },
                                '\uD83C\uDFAF Market Regime',
                                regimeType && React.createElement('span', {
                                  style: {
                                    padding: '2px 8px', borderRadius: '4px', fontSize: '0.7rem', fontWeight: '600',
                                    background: tc.bg, color: tc.color
                                  }
                                }, tc.icon + ' ' + regimeType),
                                scoreText && React.createElement('span', {
                                  style: {
                                    padding: '2px 6px', borderRadius: '4px', fontSize: '0.68rem', fontWeight: '600',
                                    background: '#f1f5f9', color: '#64748b', border: '1px solid #e2e8f0'
                                  }
                                }, 'Score: ' + scoreText)
                              ),
                              React.createElement('div', {
                                style: {
                                  padding: '10px 14px', borderRadius: '8px', background: '#f8fafc', border: '1px solid #e2e8f0',
                                  fontSize: '0.78rem', fontFamily: 'var(--mono, monospace)', color: '#334155', lineHeight: 1.6, whiteSpace: 'pre-wrap'
                                }
                              }, s.regimeDetail),
                              // Zone position badge (extracted from regimeDetail)
                              (() => {
                                const zoneMatch = s.regimeDetail && s.regimeDetail.match(/Zone=(\w+)\s+x([\d.]+)/);
                                if (!zoneMatch) return null;
                                const zonePos = zoneMatch[1];
                                const zoneMult = parseFloat(zoneMatch[2]);
                                const zoneColors = {
                                  InDemandZone: { bg: '#dcfce7', color: '#166534', icon: '\uD83D\uDFE2', label: 'At Demand Zone (Buyers Defending)' },
                                  InSupplyZone: { bg: '#fee2e2', color: '#991b1b', icon: '\uD83D\uDD34', label: 'At Supply Zone (Sellers Defending)' },
                                  BreakoutAboveSupply: { bg: '#dbeafe', color: '#1d4ed8', icon: '\uD83D\uDE80', label: 'Breakout Above Supply' },
                                  BreakdownBelowDemand: { bg: '#fef3c7', color: '#92400e', icon: '\uD83D\uDCC9', label: 'Breakdown Below Demand' },
                                  Equilibrium: { bg: '#f1f5f9', color: '#475569', icon: '\u2696\uFE0F', label: 'Equilibrium (No Zone Edge)' },
                                  NoData: { bg: '#f1f5f9', color: '#94a3b8', icon: '\u2014', label: 'No Zone Data' }
                                };
                                const zc = zoneColors[zonePos] || zoneColors.NoData;
                                const multLabel = zoneMult > 1.0 ? `+${((zoneMult-1)*100).toFixed(0)}% lots` : zoneMult < 1.0 ? `${((1-zoneMult)*100).toFixed(0)}% less lots` : 'Normal lots';
                                return React.createElement('div', {
                                  style: { marginTop: '8px', display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }
                                },
                                  React.createElement('span', {
                                    style: { padding: '3px 10px', borderRadius: '6px', fontSize: '0.72rem', fontWeight: '600', background: zc.bg, color: zc.color }
                                  }, zc.icon + ' ' + zc.label),
                                  React.createElement('span', {
                                    style: { padding: '3px 8px', borderRadius: '4px', fontSize: '0.7rem', fontWeight: '600', background: zoneMult >= 1.25 ? '#dcfce7' : zoneMult <= 0.75 ? '#fee2e2' : '#f1f5f9', color: zoneMult >= 1.25 ? '#166534' : zoneMult <= 0.75 ? '#991b1b' : '#64748b', border: '1px solid #e2e8f0' }
                                  }, `Lot sizing: x${zoneMult.toFixed(2)} (${multLabel})`)
                                );
                              })()
                            );
                          })(),

                          // Paper Order section (if signal was traded)
                          s.orderStatus && React.createElement('div', { style: { marginTop: '14px' } },
                            React.createElement('div', {
                              style: { fontSize: '0.82rem', fontWeight: '700', color: '#1e293b', marginBottom: '8px', display: 'flex', alignItems: 'center', gap: '6px' }
                            }, '\uD83D\uDCB0 Paper Order'),
                            React.createElement('div', {
                              style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))', gap: '10px' }
                            },
                              signalDetail('\uD83D\uDCCB Status', s.orderStatus, null,
                                s.orderStatus === 'OPEN' ? '#2563eb' : s.orderPnL > 0 ? '#16a34a' : '#dc2626'),
                              signalDetail('\u2B06\uFE0F Entry Price', s.orderEntryPrice != null ? '\u20B9' + s.orderEntryPrice.toFixed(2) : '\u2014', 'mono'),
                              signalDetail('\u2B07\uFE0F Exit Price', s.orderExitPrice != null ? '\u20B9' + s.orderExitPrice.toFixed(2) : (s.orderStatus === 'OPEN' ? 'Awaiting\u2026' : '\u2014'), 'mono'),
                              signalDetail('\uD83D\uDCC8 P&L', s.orderPnL != null
                                ? (s.orderPnL >= 0 ? '+' : '') + '\u20B9' + s.orderPnL.toFixed(2) + ' (' + (s.orderPnLPct >= 0 ? '+' : '') + s.orderPnLPct.toFixed(2) + '%)'
                                : '\u2014', 'mono',
                                s.orderPnL > 0 ? '#16a34a' : s.orderPnL < 0 ? '#dc2626' : null),
                              s.orderExitReason && signalDetail('\uD83D\uDEAA Exit Reason', s.orderExitReason)
                            )
                          ),

                          // Gates Passed
                          s.gatesPassed && s.gatesPassed.length > 0 && React.createElement('div', { style: { marginTop: '14px' } },
                            React.createElement('div', {
                              style: {
                                fontSize: '0.75rem', fontWeight: '600', color: '#16a34a',
                                marginBottom: '6px', display: 'flex', alignItems: 'center', gap: '6px'
                              }
                            }, '\u2713 Gates Passed',
                              React.createElement('span', {
                                style: {
                                  display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                                  minWidth: '18px', height: '18px', borderRadius: '9px',
                                  background: '#dcfce7', fontSize: '0.7rem', fontWeight: '700'
                                }
                              }, s.gatesPassed.length)
                            ),
                            React.createElement('div', { style: { display: 'flex', flexWrap: 'wrap', gap: '6px' } },
                              s.gatesPassed.map((g, gi) => React.createElement('span', {
                                key: gi,
                                style: {
                                  padding: '3px 10px', borderRadius: '6px', fontSize: '0.72rem',
                                  fontWeight: '500', background: '#dcfce7', color: '#166534',
                                  border: '1px solid #bbf7d0'
                                }
                              }, '\u2713 ' + g))
                            )
                          ),

                          // Gates Blocked
                          s.gatesBlocked && s.gatesBlocked.length > 0 && React.createElement('div', { style: { marginTop: '10px' } },
                            React.createElement('div', {
                              style: {
                                fontSize: '0.75rem', fontWeight: '600', color: '#dc2626',
                                marginBottom: '6px', display: 'flex', alignItems: 'center', gap: '6px'
                              }
                            }, '\u2717 Gates Blocked',
                              React.createElement('span', {
                                style: {
                                  display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
                                  minWidth: '18px', height: '18px', borderRadius: '9px',
                                  background: '#fee2e2', fontSize: '0.7rem', fontWeight: '700'
                                }
                              }, s.gatesBlocked.length)
                            ),
                            React.createElement('div', { style: { display: 'flex', flexWrap: 'wrap', gap: '6px' } },
                              s.gatesBlocked.map((g, gi) => React.createElement('span', {
                                key: gi,
                                style: {
                                  padding: '3px 10px', borderRadius: '6px', fontSize: '0.72rem',
                                  fontWeight: '500', background: '#fee2e2', color: '#991b1b',
                                  border: '1px solid #fecaca'
                                }
                              }, '\u2717 ' + g))
                            )
                          ),

                          // Feature Snapshot (ML model input features at signal time)
                          s.featureSnapshot && (() => {
                            try {
                              const fs = typeof s.featureSnapshot === 'string' ? JSON.parse(s.featureSnapshot) : s.featureSnapshot;
                              // ── Phantom Mode Entry Conditions Panel ──
                              if (fs.phantom) {
                                const phantomFields = [
                                  { key: 'vwap', label: 'VWAP', fmt: v => v?.toFixed(2) || '—' },
                                  { key: 'supertrendDir5m', label: 'ST 5m', fmt: v => v > 0 ? '⬆ Bull' : v < 0 ? '⬇ Bear' : '—' },
                                  { key: 'ema21', label: 'EMA21', fmt: v => v?.toFixed(2) || '—' },
                                  { key: 'ema50', label: 'EMA50', fmt: v => v?.toFixed(2) || '—' },
                                  { key: 'adx14', label: 'ADX', fmt: v => v?.toFixed(1) || '—' },
                                  { key: 'rsi14', label: 'RSI', fmt: v => v?.toFixed(1) || '—', warn: v => v > 70 || v < 30 },
                                  { key: 'pcr', label: 'PCR', fmt: v => v?.toFixed(2) || '—' },
                                  { key: 'pcrDelta', label: 'PCR Δ', fmt: v => v?.toFixed(4) || '—' },
                                  { key: 'oiResistance', label: 'OI Resist', fmt: v => v?.toFixed(0) || '—' },
                                  { key: 'oiSupport', label: 'OI Support', fmt: v => v?.toFixed(0) || '—' },
                                  { key: 'smcBos', label: 'BOS', fmt: v => v > 0 ? '⬆' : v < 0 ? '⬇' : '—' },
                                  { key: 'smcChoCh', label: 'CHoCH', fmt: v => v > 0 ? '⬆' : v < 0 ? '⬇' : '—' },
                                  { key: 'buyRatio', label: 'Buy Ratio', fmt: v => (v * 100).toFixed(1) + '%' },
                                  { key: 'optBuyQty', label: 'Buy Qty', fmt: v => v?.toLocaleString() || '0' },
                                  { key: 'optSellQty', label: 'Sell Qty', fmt: v => v?.toLocaleString() || '0' },
                                  { key: 'optDelta', label: 'Delta', fmt: v => v?.toFixed(3) || '—' },
                                  { key: 'optGamma', label: 'Gamma', fmt: v => v?.toFixed(5) || '—' },
                                  { key: 'optTheta', label: 'Theta', fmt: v => v?.toFixed(2) || '—', warn: v => Math.abs(v) > 5 },
                                  { key: 'optVega', label: 'Vega', fmt: v => v?.toFixed(3) || '—' },
                                  { key: 'optIv', label: 'IV', fmt: v => v != null ? (v * 100).toFixed(1) + '%' : '—' },
                                  { key: 'optIvRank', label: 'IV Rank', fmt: v => v != null ? (v * 100).toFixed(0) + '%' : '—', warn: v => v > 0.85 },
                                ];
                                const entries = phantomFields.filter(f => fs[f.key] != null);
                                const cvScore = fs.convictionScore;
                                const cvMax = fs.convictionMax || 13;
                                const cvLevel = fs.convictionLevel;
                                const cvDetails = fs.gateDetails;
                                const cvColor = cvLevel === 'High' ? '#059669' : cvLevel === 'Medium' ? '#d97706' : '#dc2626';
                                const cvBg = cvLevel === 'High' ? '#ecfdf5' : cvLevel === 'Medium' ? '#fffbeb' : '#fef2f2';
                                const cvBorder = cvLevel === 'High' ? '#a7f3d0' : cvLevel === 'Medium' ? '#fde68a' : '#fecaca';
                                return React.createElement('div', { style: { marginTop: '14px' } },
                                  React.createElement('div', {
                                    style: { fontSize: '0.82rem', fontWeight: '700', color: '#7c3aed', marginBottom: '8px', display: 'flex', alignItems: 'center', gap: '6px' }
                                  }, '\uD83D\uDC7B Phantom Entry Conditions'),
                                  // Conviction score badge
                                  cvScore != null && React.createElement('div', {
                                    style: { marginBottom: '10px', display: 'flex', alignItems: 'center', gap: '8px', flexWrap: 'wrap' }
                                  },
                                    React.createElement('span', {
                                      style: {
                                        padding: '4px 12px', borderRadius: '8px', fontSize: '0.78rem',
                                        fontWeight: '700', background: cvBg, color: cvColor,
                                        border: '2px solid ' + cvBorder
                                      }
                                    }, (cvLevel === 'High' ? '\u2705' : cvLevel === 'Medium' ? '\u26A0\uFE0F' : '\u274C') + ' Conviction: ' + cvScore + '/' + cvMax + ' (' + cvLevel + ')'),
                                    // Individual gate scores as small pills
                                    cvDetails && cvDetails.split(' ').filter(Boolean).map(function(g, gi) {
                                      var isPass = g.indexOf(':+') !== -1;
                                      var isFail = g.indexOf(':0') !== -1 && g.indexOf(':0.') === -1;
                                      return React.createElement('span', {
                                        key: 'cv-' + gi,
                                        style: {
                                          padding: '2px 6px', borderRadius: '4px', fontSize: '0.68rem',
                                          fontFamily: 'var(--mono, monospace)', fontWeight: '500',
                                          background: isPass ? '#ecfdf5' : isFail ? '#fef2f2' : '#f3f4f6',
                                          color: isPass ? '#065f46' : isFail ? '#991b1b' : '#6b7280',
                                          border: '1px solid ' + (isPass ? '#a7f3d0' : isFail ? '#fecaca' : '#e5e7eb')
                                        }
                                      }, g);
                                    })
                                  ),
                                  React.createElement('div', {
                                    style: { display: 'flex', flexWrap: 'wrap', gap: '6px' }
                                  },
                                    entries.map((f, fi) => {
                                      const v = fs[f.key];
                                      const isWarn = f.warn && f.warn(v);
                                      return React.createElement('span', {
                                        key: fi,
                                        style: {
                                          padding: '3px 8px', borderRadius: '6px', fontSize: '0.72rem',
                                          fontFamily: 'var(--mono, monospace)', fontWeight: '500',
                                          background: isWarn ? '#fef3c7' : '#f3e8ff',
                                          color: isWarn ? '#92400e' : '#5b21b6',
                                          border: '1px solid ' + (isWarn ? '#fde68a' : '#ddd6fe')
                                        }
                                      }, f.label + ': ' + f.fmt(v));
                                    })
                                  )
                                );
                              }
                              const keyFeatures = [
                                { key: 'UnderlyingMomentum', label: 'Und. Momentum', fmt: v => (v * 100).toFixed(2) + '%' },
                                { key: 'BreakOfStructure', label: 'BOS', fmt: v => v > 0 ? '\u2B06 Bullish' : v < 0 ? '\u2B07 Bearish' : '\u2014 None' },
                                { key: 'PricePositionInRange', label: 'Range Pos', fmt: v => (v * 100).toFixed(0) + '%' },
                                { key: 'RangeCompression', label: 'Compression', fmt: v => v.toFixed(2) + 'x', warn: v => v < 0.5 },
                                { key: 'FvgDirection', label: 'FVG Dir', fmt: v => v > 0 ? '\u2B06 Bullish' : v < 0 ? '\u2B07 Bearish' : '\u2014 None' },
                                { key: 'OiDelta', label: 'OI Delta', fmt: v => (v * 100).toFixed(2) + '%' },
                                { key: 'VolumeSpike', label: 'Vol Spike', fmt: v => v.toFixed(2) + 'x', warn: v => v > 3 },
                                { key: 'OrderFlowImbalance', label: 'Flow Imbal', fmt: v => v.toFixed(3) },
                                { key: 'IvRank', label: 'IV Rank', fmt: v => (v * 100).toFixed(0) + '%' },
                                { key: 'PutCallRatio', label: 'PCR', fmt: v => v.toFixed(2) },
                                { key: 'Delta', label: 'Delta', fmt: v => v.toFixed(3) },
                                { key: 'Gamma', label: 'Gamma', fmt: v => v.toFixed(5) },
                                { key: 'Theta', label: 'Theta', fmt: v => v.toFixed(3) },
                                { key: 'Vega', label: 'Vega', fmt: v => v.toFixed(3) },
                                { key: 'TvChopIndex', label: 'TV Chop', fmt: v => v.toFixed(1), warn: v => v > 61.8 },
                                { key: 'TvAdx14', label: 'TV ADX', fmt: v => v.toFixed(1) },
                                { key: 'TvRsi14', label: 'TV RSI', fmt: v => v.toFixed(1), warn: v => v > 70 || v < 30 },
                                { key: 'TvBbWidth', label: 'TV BBW', fmt: v => v.toFixed(2) + '%' },
                                { key: 'TvAtrPercent', label: 'TV ATR%', fmt: v => v.toFixed(3) + '%' },
                                { key: 'TvSupertrendDir', label: 'TV Supertrend', fmt: v => v > 0 ? '\u2B06 Bull' : v < 0 ? '\u2B07 Bear' : '\u2014' },
                                { key: 'TvMfi14', label: 'TV MFI', fmt: v => v.toFixed(1), warn: v => v > 80 || v < 20 },
                                { key: 'TvVolumeOsc', label: 'TV VolOsc', fmt: v => v.toFixed(2) },
                                { key: 'TvRegimeScore', label: 'TV Regime', fmt: v => v.toFixed(1) },
                              ];
                              const entries = keyFeatures.filter(f => fs[f.key] != null);
                              if (entries.length === 0) return null;
                              return React.createElement('div', { style: { marginTop: '14px' } },
                                React.createElement('div', {
                                  style: { fontSize: '0.82rem', fontWeight: '700', color: '#1e293b', marginBottom: '8px', display: 'flex', alignItems: 'center', gap: '6px' }
                                }, '\uD83E\uDDE0 Feature Snapshot (Model Input)'),
                                React.createElement('div', {
                                  style: { display: 'flex', flexWrap: 'wrap', gap: '6px' }
                                },
                                  entries.map((f, fi) => {
                                    const v = fs[f.key];
                                    const isWarn = f.warn && f.warn(v);
                                    return React.createElement('span', {
                                      key: fi,
                                      style: {
                                        padding: '3px 8px', borderRadius: '6px', fontSize: '0.72rem',
                                        fontFamily: 'var(--mono, monospace)', fontWeight: '500',
                                        background: isWarn ? '#fef3c7' : '#f1f5f9',
                                        color: isWarn ? '#92400e' : '#334155',
                                        border: '1px solid ' + (isWarn ? '#fde68a' : '#e2e8f0')
                                      }
                                    }, f.label + ': ' + f.fmt(v));
                                  })
                                )
                              );
                            } catch (e) { return null; }
                          })()
                        )
                      )
                    )
                  );
                })
              )
            )
          ),

          // Footer
          React.createElement('div', {
            style: {
              padding: '10px 16px', borderTop: '1px solid #e2e8f0',
              fontSize: '0.78rem', color: '#6b7280', display: 'flex', justifyContent: 'space-between',
              alignItems: 'center'
            }
          },
            React.createElement('span', null,
              `Showing ${signals.length} of ${totalCount.toLocaleString()} total signals`,
              activeFilterCount > 0
                ? React.createElement('span', {
                    style: { marginLeft: '8px', color: '#2563eb', cursor: 'pointer', fontWeight: '500' },
                    onClick: resetFilters
                  }, '\u2014 show all')
                : null
            ),
            React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } },
              totalPages > 1 && React.createElement('div', { style: { display: 'flex', alignItems: 'center', gap: '4px' } },
                React.createElement('button', {
                  disabled: page <= 1,
                  style: {
                    padding: '3px 8px', borderRadius: '4px', border: '1px solid #e2e8f0',
                    background: page <= 1 ? '#f1f5f9' : '#fff', cursor: page <= 1 ? 'default' : 'pointer',
                    fontSize: '0.72rem', color: page <= 1 ? '#94a3b8' : '#1e293b'
                  },
                  onClick: () => setPage(Math.max(1, page - 1))
                }, '\u25C0'),
                React.createElement('span', { style: { fontSize: '0.72rem', fontWeight: '600' } },
                  `${page}/${totalPages}`),
                React.createElement('button', {
                  disabled: page >= totalPages,
                  style: {
                    padding: '3px 8px', borderRadius: '4px', border: '1px solid #e2e8f0',
                    background: page >= totalPages ? '#f1f5f9' : '#fff', cursor: page >= totalPages ? 'default' : 'pointer',
                    fontSize: '0.72rem', color: page >= totalPages ? '#94a3b8' : '#1e293b'
                  },
                  onClick: () => setPage(Math.min(totalPages, page + 1))
                }, '\u25B6')
              ),
              React.createElement('span', { style: { display: 'flex', alignItems: 'center', gap: '6px' } },
                React.createElement('span', {
                  style: { width: '6px', height: '6px', borderRadius: '50%', background: '#16a34a', animation: 'pulse 2s infinite' }
                }),
                'Live \u00B7 30s refresh'
              )
            )
           )
        )
    )
  );
}

// ── Shared inline styles ──
var labelStyle = {
  display: 'block', fontSize: '0.72rem', fontWeight: '600', color: '#64748b',
  textTransform: 'uppercase', letterSpacing: '0.5px', marginBottom: '4px'
};
var inputStyle = {
  width: '100%', padding: '7px 10px', borderRadius: '8px',
  border: '1px solid #e2e8f0', fontSize: '0.82rem', background: '#fff',
  outline: 'none', transition: 'border-color 0.2s'
};
var tdStyle = { padding: '8px 12px', whiteSpace: 'nowrap' };
var perfTdStyle = { padding: '8px 12px', whiteSpace: 'nowrap' };
var perfTdStyleMono = { padding: '8px 12px', whiteSpace: 'nowrap', fontFamily: 'var(--mono, monospace)', fontSize: '0.78rem', textAlign: 'center' };

// ── Performance table header cell ──
function perfTh(label) {
  return React.createElement('th', {
    style: {
      padding: '8px 12px', textAlign: 'center', fontWeight: '600',
      fontSize: '0.7rem', textTransform: 'uppercase', letterSpacing: '0.5px',
      color: '#6b7280', borderBottom: '2px solid #e2e8f0'
    }
  }, label);
}

// ── Performance stat card ──
function perfStatCard(label, value, type, sub) {
  var bg = '#fff';
  var borderColor = '#e2e8f0';
  var valueColor = '#1f2937';
  if (type === 'positive') { bg = '#f0fdf4'; borderColor = '#bbf7d0'; valueColor = '#16a34a'; }
  if (type === 'negative') { bg = '#fef2f2'; borderColor = '#fecaca'; valueColor = '#dc2626'; }
  return React.createElement('div', {
    style: {
      padding: '12px 14px', borderRadius: '12px', background: bg,
      border: '1px solid ' + borderColor, transition: 'transform 0.15s',
    }
  },
    React.createElement('div', {
      style: { fontSize: '0.68rem', color: '#94a3b8', textTransform: 'uppercase', letterSpacing: '0.5px', marginBottom: '4px' }
    }, label),
    React.createElement('div', {
      style: { fontSize: '1.1rem', fontWeight: '800', color: valueColor, fontFamily: 'var(--mono, monospace)' }
    }, value),
    sub && React.createElement('div', {
      style: { fontSize: '0.68rem', color: '#94a3b8', marginTop: '2px' }
    }, sub)
  );
}

// ── Helper: pivot zone color badge ──
function pivotZoneBadge(zone) {
  if (!zone) return React.createElement('span', { style: { color: '#9ca3af', fontSize: '0.75rem' } }, '\u2014');
  const zl = zone.toLowerCase();
  let bg = '#f1f5f9', color = '#475569';
  if (zl.includes('strong bullish') || zl.includes('extreme bullish') || zl.includes('above r')) {
    bg = '#dcfce7'; color = '#166534';
  } else if (zl.includes('bullish')) {
    bg = '#d1fae5'; color = '#065f46';
  } else if (zl.includes('strong bearish') || zl.includes('extreme bearish') || zl.includes('below s')) {
    bg = '#fee2e2'; color = '#991b1b';
  } else if (zl.includes('bearish')) {
    bg = '#fecaca'; color = '#b91c1c';
  }
  return React.createElement('span', {
    style: {
      padding: '2px 6px', borderRadius: '4px', fontSize: '0.7rem',
      fontWeight: '500', background: bg, color: color
    }
  }, zone);
}

// ── Helper: detail item for expanded row ──
function signalDetail(label, value, variant, color) {
  return React.createElement('div', {
    style: { padding: '6px 10px', background: '#fff', borderRadius: '8px', border: '1px solid #e2e8f0' }
  },
    React.createElement('div', {
      style: { fontSize: '0.68rem', color: '#94a3b8', textTransform: 'uppercase', letterSpacing: '0.5px', marginBottom: '2px' }
    }, label),
    React.createElement('div', {
      style: {
        fontSize: '0.82rem', fontWeight: '600', color: color || '#1f2937',
        fontFamily: variant === 'mono' ? 'var(--mono, monospace)' : 'inherit',
        wordBreak: 'break-all'
      }
    }, value || '\u2014')
  );
}
