import type { CSSProperties } from 'react';
import { useEffect, useMemo, useRef, useState } from 'react';
import { useLocalStorageState } from './app/hooks/useLocalStorageState';
import AppShell from './layout/AppShell';
import ChartPanel from './features/chart/ChartPanel';
import { useChartData } from './features/chart/useChartData';
import TickerBar from './features/tickerbar/TickerBar';
import Card from './ui/Card';
import Tabs from './ui/Tabs';
import MarketHeader from './features/market/MarketHeader';
import Button from './ui/Button';
import TopNav from './layout/TopNav';
import AuthStatus from './layout/AuthStatus';
import LoginScreen from './layout/LoginScreen';
import { useDlobStats } from './features/market/useDlobStats';
import { useDlobL2 } from './features/market/useDlobL2';
import { useDlobSlippage } from './features/market/useDlobSlippage';
import { useDlobDepthBands } from './features/market/useDlobDepthBands';
import DlobDashboard from './features/market/DlobDashboard';
import ContractCostsPanel from './features/contracts/ContractCostsPanel';

type PaneId = 'chart' | 'dlob' | 'costsActive' | 'costsNew';

// Order matters: missing panes are appended in this order; last is default "top".
const ALL_PANES: PaneId[] = ['chart', 'dlob', 'costsActive', 'costsNew'];

function makePaneRecord<T>(factory: (id: PaneId) => T): Record<PaneId, T> {
  const out: any = {};
  for (const id of ALL_PANES) out[id] = factory(id);
  return out as Record<PaneId, T>;
}

function normalizePaneOrder(raw: unknown): PaneId[] {
  const out: PaneId[] = [];
  const arr = Array.isArray(raw) ? raw : [];
  for (const v of arr) {
    if (v === 'chart' || v === 'dlob' || v === 'costsActive' || v === 'costsNew') {
      if (!out.includes(v)) out.push(v);
    }
  }
  for (const id of ALL_PANES) {
    if (!out.includes(id)) out.push(id);
  }
  return out;
}

function normalizeLayerOpacity(raw: unknown): Record<PaneId, number> {
  const input = (raw && typeof raw === 'object' ? (raw as any) : {}) as Partial<Record<PaneId, unknown>>;
  const clamp = (v: unknown, fallback: number) => {
    const n = typeof v === 'number' ? v : typeof v === 'string' ? Number(v) : NaN;
    if (!Number.isFinite(n)) return fallback;
    return Math.min(1, Math.max(0, n));
  };
  return makePaneRecord((id) => clamp((input as any)[id], 1));
}

function normalizeLayerToggle(raw: unknown, fallback: boolean): Record<PaneId, boolean> {
  const input = (raw && typeof raw === 'object' ? (raw as any) : {}) as Partial<Record<PaneId, unknown>>;
  const toBool = (v: unknown) => (typeof v === 'boolean' ? v : fallback);
  return makePaneRecord((id) => toBool((input as any)[id]));
}

function normalizeLayerFactor(raw: unknown, fallback: number, min: number, max: number): Record<PaneId, number> {
  const input = (raw && typeof raw === 'object' ? (raw as any) : {}) as Partial<Record<PaneId, unknown>>;
  const clamp = (v: unknown) => {
    const n = typeof v === 'number' ? v : typeof v === 'string' ? Number(v) : NaN;
    if (!Number.isFinite(n)) return fallback;
    return Math.min(max, Math.max(min, n));
  };
  return makePaneRecord((id) => clamp((input as any)[id]));
}

function reorderList<T>(items: T[], from: T, to: T): T[] {
  if (from === to) return items.slice();
  const next = items.filter((x) => x !== from);
  const idx = next.indexOf(to);
  if (idx < 0) return next.concat(from);
  next.splice(idx, 0, from);
  return next;
}

function clampNumber(v: number, min: number, max: number): number {
  if (!Number.isFinite(v)) return min;
  return Math.min(max, Math.max(min, v));
}

function stepByWheel(e: React.WheelEvent, step: number): number {
  // Wheel up => increase, wheel down => decrease
  if (e.deltaY === 0) return 0;
  return e.deltaY < 0 ? step : -step;
}

function envNumber(name: string, fallback: number): number {
  const v = (import.meta as any).env?.[name];
  if (v == null) return fallback;
  const n = Number(v);
  return Number.isFinite(n) ? n : fallback;
}

function envString(name: string, fallback: string): string {
  const v = (import.meta as any).env?.[name];
  return v == null ? fallback : String(v);
}

function formatUsd(v: number | null | undefined): string {
  if (v == null || !Number.isFinite(v)) return '—';
  if (v >= 1_000_000) return `$${(v / 1_000_000).toFixed(2)}M`;
  if (v >= 1000) return `$${(v / 1000).toFixed(0)}K`;
  if (v >= 1) return `$${v.toFixed(2)}`;
  return `$${v.toPrecision(4)}`;
}

function formatQty(v: number | null | undefined, decimals: number): string {
  if (v == null || !Number.isFinite(v)) return '—';
  return v.toLocaleString(undefined, { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
}

function formatCompact(v: number | null | undefined): string {
  if (v == null || !Number.isFinite(v)) return '—';
  const abs = Math.abs(v);
  if (abs >= 1_000_000) return `${(v / 1_000_000).toFixed(2)}M`;
  if (abs >= 1000) return `${(v / 1000).toFixed(0)}K`;
  if (abs >= 1) return v.toFixed(2);
  return v.toPrecision(4);
}

function clamp01(scale: number): number {
  return Number.isFinite(scale) && scale > 0 ? Math.min(1, scale) : 0;
}

function barCurve(scale01: number): number {
  // Makes small rows visible without letting a single wall dominate.
  return Math.sqrt(clamp01(scale01));
}

function orderbookRowBarStyle(totalScale: number, levelScale: number): CSSProperties {
  return {
    ['--ob-total-scale' as any]: barCurve(totalScale),
    ['--ob-level-scale' as any]: barCurve(levelScale),
  } as CSSProperties;
}

function liquidityStyle(bid: number, ask: number): CSSProperties {
  const max = Math.max(1e-9, bid, ask);
  const b = Number.isFinite(bid) && bid > 0 ? Math.min(1, bid / max) : 0;
  const a = Number.isFinite(ask) && ask > 0 ? Math.min(1, ask / max) : 0;
  return { ['--liq-bid' as any]: b, ['--liq-ask' as any]: a } as CSSProperties;
}

type WhoamiResponse = {
  ok?: boolean;
  user?: string | null;
  mode?: string;
};

export default function App() {
  const [user, setUser] = useState<string | null>(null);
  const [authLoading, setAuthLoading] = useState(true);

  useEffect(() => {
    let cancelled = false;
    setAuthLoading(true);
    fetch('/whoami', { cache: 'no-store' })
      .then(async (res) => {
        const json = (await res.json().catch(() => null)) as WhoamiResponse | null;
        const u = typeof json?.user === 'string' ? json.user.trim() : '';
        return u || null;
      })
      .then((u) => {
        if (cancelled) return;
        setUser(u);
      })
      .catch(() => {
        if (cancelled) return;
        setUser(null);
      })
      .finally(() => {
        if (cancelled) return;
        setAuthLoading(false);
      });

    return () => {
      cancelled = true;
    };
  }, []);

  const logout = async () => {
    try {
      await fetch('/auth/logout', { method: 'POST' });
    } finally {
      setUser(null);
    }
  };

  if (authLoading) {
    return (
      <div className="loginScreen">
        <div className="loginCard" role="status" aria-label="Ładowanie">
          Ładowanie…
        </div>
      </div>
    );
  }

  if (!user) {
    return <LoginScreen onLoggedIn={setUser} />;
  }

  return <TradeApp user={user} onLogout={() => void logout()} />;
}

function TradeApp({ user, onLogout }: { user: string; onLogout: () => void }) {
  const markets = useMemo(() => ['PUMP-PERP', 'SOL-PERP', '1MBONK-PERP', 'BTC-PERP', 'ETH-PERP'], []);

  const normalizeTf = (raw: string): string => {
    const v = String(raw || '').trim();
    if (!v) return '1m';
    const lower = v.toLowerCase();
    // keep backwards compatibility with older saved values (e.g. "1D")
    if (lower === '1d') return '1d';
    return lower;
  };

  const [symbol, setSymbol] = useLocalStorageState('trade.symbol', envString('VITE_SYMBOL', 'SOL-PERP'));
  const [source, setSource] = useLocalStorageState('trade.source', envString('VITE_SOURCE', ''));
  const [tfRaw, setTfRaw] = useLocalStorageState('trade.tf', envString('VITE_TF', '1m'));
  const tf = useMemo(() => normalizeTf(tfRaw), [tfRaw]);
  const setTf = (next: string) => setTfRaw(normalizeTf(next));
  const [pollMs, setPollMs] = useLocalStorageState('trade.pollMs', envNumber('VITE_POLL_MS', 1000));
  const [limit, setLimit] = useLocalStorageState('trade.limit', envNumber('VITE_LIMIT', 300));
  const [showIndicators, setShowIndicators] = useLocalStorageState('trade.showIndicators', true);
  const [showBuild, setShowBuild] = useLocalStorageState('trade.showBuild', true);
  const [tab, setTab] = useLocalStorageState<'orderbook' | 'trades'>('trade.sidebarTab', 'orderbook');
  const [bottomTab, setBottomTab] = useLocalStorageState<
    'dlob' | 'costs' | 'positions' | 'orders' | 'balances' | 'orderHistory' | 'positionHistory'
  >('trade.bottomTab', envString('VITE_BOTTOM_TAB', 'dlob') as any);
  const [tradeSide, setTradeSide] = useLocalStorageState<'long' | 'short'>('trade.form.side', 'long');
  const [tradeOrderType, setTradeOrderType] = useLocalStorageState<'market' | 'limit' | 'other'>(
    'trade.form.type',
    'market'
  );
  const [tradePrice, setTradePrice] = useLocalStorageState<number>('trade.form.price', 0);
  const [tradeSize, setTradeSize] = useLocalStorageState<number>('trade.form.size', 0.1);

  const [layoutMode, setLayoutMode] = useLocalStorageState<'grid' | 'stack'>('trade.layoutMode', 'grid');
  const [stackOrderRaw, setStackOrder] = useLocalStorageState<PaneId[]>('trade.stackOrder', ALL_PANES);
  const stackOrder = useMemo(() => normalizePaneOrder(stackOrderRaw), [stackOrderRaw]);
  const activePane = stackOrder[stackOrder.length - 1] ?? 'chart';
  const [stackOrderManual, setStackOrderManual] = useLocalStorageState<boolean>('trade.stackOrderManual', false);
  const escRef = useRef<number>(0);
  const [stackPanelLocked, setStackPanelLocked] = useLocalStorageState<boolean>('trade.stackPanelLocked', false);
  const [stackPanelOpen, setStackPanelOpen] = useState(true);
  const stackPanelHideTimerRef = useRef<number | null>(null);
  const [stackDrawerOpacity, setStackDrawerOpacity] = useLocalStorageState<number>('trade.stackDrawerOpacity', 0.92);
  const [stackBackdropOpacity, setStackBackdropOpacity] = useLocalStorageState<number>('trade.stackBackdropOpacity', 0.55);
  const [layerOpacityRaw, setLayerOpacity] = useLocalStorageState<Record<PaneId, number>>('trade.layerOpacity', {
    chart: 1,
    dlob: 1,
    costsActive: 1,
    costsNew: 1,
  });
  const layerOpacity = useMemo(() => normalizeLayerOpacity(layerOpacityRaw), [layerOpacityRaw]);
  const [layerVisibleRaw, setLayerVisible] = useLocalStorageState<Record<PaneId, boolean>>('trade.layerVisible', {
    chart: true,
    dlob: true,
    costsActive: false,
    costsNew: true,
  });
  const layerVisible = useMemo(() => normalizeLayerToggle(layerVisibleRaw, true), [layerVisibleRaw]);
  const [layerLockedRaw, setLayerLocked] = useLocalStorageState<Record<PaneId, boolean>>('trade.layerLocked', {
    chart: false,
    dlob: false,
    costsActive: false,
    costsNew: false,
  });
  const layerLocked = useMemo(() => normalizeLayerToggle(layerLockedRaw, false), [layerLockedRaw]);
  const [layerBrightnessRaw, setLayerBrightness] = useLocalStorageState<Record<PaneId, number>>('trade.layerBrightness', {
    chart: 1,
    dlob: 1,
    costsActive: 1,
    costsNew: 1,
  });
  const layerBrightness = useMemo(() => normalizeLayerFactor(layerBrightnessRaw, 1, 0.6, 1.8), [layerBrightnessRaw]);
  const [activeContractIdSeen, setActiveContractIdSeen] = useLocalStorageState<string>('trade.activeContractIdSeen', '');
  const [activeContractId] = useLocalStorageState<string>('trade.contractId', '');
  const hasActiveContract = Boolean(activeContractId.trim());

  useEffect(() => {
    const normalized = normalizePaneOrder(stackOrderRaw);
    if (normalized.join('|') !== (Array.isArray(stackOrderRaw) ? stackOrderRaw.join('|') : '')) {
      setStackOrder(normalized);
    }
  }, [setStackOrder, stackOrderRaw]);

  useEffect(() => {
    const normalized = normalizeLayerOpacity(layerOpacityRaw);
    const raw = layerOpacityRaw as any;
    if (!raw || normalized.chart !== raw.chart || normalized.dlob !== raw.dlob) setLayerOpacity(normalized);
  }, [layerOpacityRaw, setLayerOpacity]);

  useEffect(() => {
    const normalized = normalizeLayerToggle(layerVisibleRaw, true);
    const raw = layerVisibleRaw as any;
    const needsFix = !raw || ALL_PANES.some((k) => normalized[k] !== raw[k]);
    if (needsFix) setLayerVisible(normalized);
  }, [layerVisibleRaw, setLayerVisible]);

  useEffect(() => {
    const normalized = normalizeLayerToggle(layerLockedRaw, false);
    const raw = layerLockedRaw as any;
    const needsFix = !raw || ALL_PANES.some((k) => normalized[k] !== raw[k]);
    if (needsFix) setLayerLocked(normalized);
  }, [layerLockedRaw, setLayerLocked]);

  useEffect(() => {
    const normalized = normalizeLayerFactor(layerBrightnessRaw, 1, 0.6, 1.8);
    const raw = layerBrightnessRaw as any;
    const needsFix = !raw || ALL_PANES.some((k) => normalized[k] !== raw[k]);
    if (needsFix) setLayerBrightness(normalized);
  }, [layerBrightnessRaw, setLayerBrightness]);

  // When a contract is "pushed" (contractId becomes non-empty), ensure Active layer is visible and placed
  // directly below Costs(New) (unless user reorders later). We do this once per contract id.
  useEffect(() => {
    const id = activeContractId.trim();
    if (!id) return;
    if (id === activeContractIdSeen) return;

    setLayerVisible((prev) => ({ ...normalizeLayerToggle(prev, true), costsActive: true }));

    if (!stackOrderManual) {
      setStackOrder((prev) => {
        const normalized = normalizePaneOrder(prev);
        const without = normalized.filter((p) => p !== 'costsActive');
        const idxNew = without.indexOf('costsNew');
        const insertAt = idxNew >= 0 ? idxNew : Math.max(0, without.length - 1);
        without.splice(insertAt, 0, 'costsActive');
        return without;
      });
    }

    setActiveContractIdSeen(id);
  }, [activeContractId, activeContractIdSeen, setActiveContractIdSeen, setLayerVisible, setStackOrder, stackOrderManual]);

  useEffect(() => {
    document.body.classList.toggle('stackMode', layoutMode === 'stack');
    return () => document.body.classList.remove('stackMode');
  }, [layoutMode]);

  useEffect(() => {
    const drawer = clampNumber(stackDrawerOpacity, 0.05, 1);
    const backdrop = clampNumber(stackBackdropOpacity, 0, 0.95);
    document.body.style.setProperty('--stack-drawer-opacity', String(drawer));
    document.body.style.setProperty('--stack-backdrop-opacity', String(backdrop));
    return () => {
      document.body.style.removeProperty('--stack-drawer-opacity');
      document.body.style.removeProperty('--stack-backdrop-opacity');
    };
  }, [stackBackdropOpacity, stackDrawerOpacity]);

  useEffect(() => {
    if (layoutMode !== 'stack') return;
    // Default focus order in stack mode unless the user manually reordered (DnD).
    if (!stackOrderManual) {
      setStackOrder(() => normalizePaneOrder(ALL_PANES));
    }
    setStackPanelOpen(true);
    if (stackPanelHideTimerRef.current != null) window.clearTimeout(stackPanelHideTimerRef.current);
    stackPanelHideTimerRef.current = null;
  }, [layoutMode, setStackOrder, stackOrderManual]);

  useEffect(() => {
    return () => {
      if (stackPanelHideTimerRef.current != null) window.clearTimeout(stackPanelHideTimerRef.current);
      stackPanelHideTimerRef.current = null;
    };
  }, []);

  useEffect(() => {
    if (layoutMode !== 'stack') return;
    const onKeyDown = (e: KeyboardEvent) => {
      if (e.key !== 'Escape') return;
      const now = Date.now();
      if (now - escRef.current < 800) {
        escRef.current = 0;
        setLayoutMode('grid');
        return;
      }
      escRef.current = now;
    };
    window.addEventListener('keydown', onKeyDown);
    return () => window.removeEventListener('keydown', onKeyDown);
  }, [layoutMode, setLayoutMode]);

  const openStackPanel = () => {
    if (layoutMode !== 'stack') return;
    if (stackPanelHideTimerRef.current != null) window.clearTimeout(stackPanelHideTimerRef.current);
    stackPanelHideTimerRef.current = null;
    setStackPanelOpen(true);
  };

  const scheduleHideStackPanel = () => {
    if (layoutMode !== 'stack') return;
    if (stackPanelLocked) return;
    if (stackPanelHideTimerRef.current != null) window.clearTimeout(stackPanelHideTimerRef.current);
    stackPanelHideTimerRef.current = window.setTimeout(() => {
      setStackPanelOpen(false);
      stackPanelHideTimerRef.current = null;
    }, 1000);
  };

  const enterStack = (pane: PaneId) => {
    if (pane === 'dlob') setBottomTab('dlob');
    setLayoutMode('stack');
    setStackOrder((prev) => {
      const normalized = normalizePaneOrder(prev);
      return normalized.filter((p) => p !== pane).concat(pane);
    });
    openStackPanel();
  };

  const exitStack = () => setLayoutMode('grid');

  const togglePaneFullscreen = (pane: PaneId) => {
    if (layoutMode === 'stack' && activePane === pane) {
      exitStack();
      return;
    }
    enterStack(pane);
  };

  const stackTopFirst = useMemo(() => stackOrder.slice().reverse(), [stackOrder]);
  const stackZ = useMemo(() => {
    const z: Record<PaneId, number> = makePaneRecord(() => 2600);
    const base = 2600;
    const step = 20;
    for (let i = 0; i < stackOrder.length; i++) {
      const id = stackOrder[i];
      z[id] = base + i * step;
    }
    return z;
  }, [stackOrder]);

  const effectiveLayerOpacity = useMemo(() => {
    const out: Record<PaneId, number> = makePaneRecord(() => 0);
    for (const id of ALL_PANES) {
      out[id] = layerVisible[id] ? clampNumber(layerOpacity[id] ?? 1, 0, 1) : 0;
    }
    return out;
  }, [layerOpacity, layerVisible]);

  useEffect(() => {
    if (symbol === 'BONK-PERP') {
      setSymbol('1MBONK-PERP');
      return;
    }
    if (!markets.includes(symbol)) {
      setSymbol('SOL-PERP');
    }
  }, [markets, setSymbol, symbol]);

  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const wanted = (params.get('bottomTab') || params.get('tab') || '').trim();
    const allowed = new Set(['dlob', 'costs', 'positions', 'orders', 'balances', 'orderHistory', 'positionHistory']);
    if (wanted && allowed.has(wanted)) setBottomTab(wanted as any);
  }, [setBottomTab]);

  const { candles, indicators, meta, loading, error, refresh } = useChartData({
    symbol,
    source: source.trim() ? source : undefined,
    tf,
    limit,
    pollMs,
  });

  const { stats: dlob, connected: dlobConnected, error: dlobError } = useDlobStats(symbol);
  const { l2: dlobL2, connected: dlobL2Connected, error: dlobL2Error } = useDlobL2(symbol, { levels: 10 });
  const { rows: slippageRows, connected: slippageConnected, error: slippageError } = useDlobSlippage(symbol);
  const { rows: depthBands, connected: depthBandsConnected, error: depthBandsError } = useDlobDepthBands(symbol);

  const latest = candles.length ? candles[candles.length - 1] : null;
  const first = candles.length ? candles[0] : null;
  const changePct =
    first && latest && first.close > 0 ? ((latest.close - first.close) / first.close) * 100 : null;

  const orderbook = useMemo(() => {
    if (dlobL2) {
      return {
        asks: dlobL2.asks,
        bids: dlobL2.bids,
        mid: dlobL2.mid as number | null,
        bestBid: dlobL2.bestBid,
        bestAsk: dlobL2.bestAsk,
      };
    }
    if (!latest) return { asks: [], bids: [], mid: null as number | null, bestBid: null as number | null, bestAsk: null as number | null };
    const mid = latest.close;
    const step = Math.max(mid * 0.00018, 0.0001);
    const levels = 10;

    const asksRaw = Array.from({ length: levels }, (_, i) => ({
      price: mid + (i + 1) * step,
      sizeBase: 0.1 + ((i * 7) % 15) * 0.1,
    }));
    const bidsRaw = Array.from({ length: levels }, (_, i) => ({
      price: mid - (i + 1) * step,
      sizeBase: 0.1 + ((i * 5) % 15) * 0.1,
    }));

    let askTotalBase = 0;
    let askTotalUsd = 0;
    const asks = asksRaw
      .slice()
      .reverse()
      .map((r) => {
        const sizeUsd = r.sizeBase * r.price;
        askTotalBase += r.sizeBase;
        askTotalUsd += sizeUsd;
        return { ...r, sizeUsd, totalBase: askTotalBase, totalUsd: askTotalUsd };
      });

    let bidTotalBase = 0;
    let bidTotalUsd = 0;
    const bids = bidsRaw.map((r) => {
      const sizeUsd = r.sizeBase * r.price;
      bidTotalBase += r.sizeBase;
      bidTotalUsd += sizeUsd;
      return { ...r, sizeUsd, totalBase: bidTotalBase, totalUsd: bidTotalUsd };
    });

    return { asks, bids, mid, bestBid: bidsRaw[0]?.price ?? null, bestAsk: asksRaw[0]?.price ?? null };
  }, [dlobL2, latest]);

  const maxAskTotal = useMemo(() => {
    let max = 0;
    for (const r of orderbook.asks) max = Math.max(max, (r as any).totalUsd || 0);
    return max;
  }, [orderbook.asks]);

  const maxBidTotal = useMemo(() => {
    let max = 0;
    for (const r of orderbook.bids) max = Math.max(max, (r as any).totalUsd || 0);
    return max;
  }, [orderbook.bids]);

  const maxAskSize = useMemo(() => {
    let max = 0;
    for (const r of orderbook.asks) max = Math.max(max, (r as any).sizeUsd || 0);
    return max;
  }, [orderbook.asks]);

  const maxBidSize = useMemo(() => {
    let max = 0;
    for (const r of orderbook.bids) max = Math.max(max, (r as any).sizeUsd || 0);
    return max;
  }, [orderbook.bids]);

  const liquidity = useMemo(() => {
    const bid = orderbook.bids.length ? (orderbook.bids[orderbook.bids.length - 1] as any).totalUsd || 0 : 0;
    const ask = orderbook.asks.length ? (orderbook.asks[0] as any).totalUsd || 0 : 0;
    const bestBid = orderbook.bestBid;
    const bestAsk = orderbook.bestAsk;
    const spreadAbs = bestBid != null && bestAsk != null ? bestAsk - bestBid : null;
    const spreadPct =
      spreadAbs != null && orderbook.mid != null && orderbook.mid > 0 ? (spreadAbs / orderbook.mid) * 100 : null;
    return { bidUsd: bid, askUsd: ask, spreadAbs, spreadPct };
  }, [orderbook.asks, orderbook.bids, orderbook.bestAsk, orderbook.bestBid, orderbook.mid]);

  const trades = useMemo(() => {
    const slice = candles.slice(-24).reverse();
    return slice.map((c) => {
      const isBuy = c.close >= c.open;
      return {
        time: c.time,
        price: c.close,
        size: c.volume ?? null,
        side: isBuy ? ('buy' as const) : ('sell' as const),
      };
    });
  }, [candles]);

  const effectiveTradePrice = useMemo(() => {
    if (tradeOrderType === 'limit') return tradePrice;
    return latest?.close ?? tradePrice;
  }, [latest?.close, tradeOrderType, tradePrice]);

  const orderValueUsd = useMemo(() => {
    if (!Number.isFinite(tradeSize) || tradeSize <= 0) return null;
    if (!Number.isFinite(effectiveTradePrice) || effectiveTradePrice <= 0) return null;
    const v = effectiveTradePrice * tradeSize;
    return Number.isFinite(v) && v > 0 ? v : null;
  }, [effectiveTradePrice, tradeSize]);

  const dynamicSlippage = useMemo(() => {
    if (orderValueUsd == null) return null;
    const side = tradeSide === 'short' ? 'sell' : 'buy';
    const rows = slippageRows.filter((r) => r.side === side).slice();
    rows.sort((a, b) => a.sizeUsd - b.sizeUsd);
    if (!rows.length) return null;
    const biggest = rows[rows.length - 1];
    const match = rows.find((r) => r.sizeUsd >= orderValueUsd) || biggest;
    return match;
  }, [orderValueUsd, slippageRows, tradeSide]);

  const topItems = useMemo(
    () => [
      { key: 'BTC', label: 'BTC', changePct: 1.28, active: false },
      { key: 'SOL', label: 'SOL', changePct: 1.89, active: false },
    ],
    []
  );

  const stats = useMemo(() => {
    return [
      {
        key: 'last',
        label: 'Last',
        value: formatUsd(latest?.close),
        sub:
          changePct == null ? (
            '—'
          ) : (
            <span className={changePct >= 0 ? 'pos' : 'neg'}>
              {changePct >= 0 ? '+' : ''}
              {changePct.toFixed(2)}%
            </span>
          ),
      },
      { key: 'oracle', label: 'Oracle', value: formatUsd(latest?.oracle ?? null) },
      { key: 'bid', label: 'Bid', value: formatUsd(dlob?.bestBid ?? null) },
      { key: 'ask', label: 'Ask', value: formatUsd(dlob?.bestAsk ?? null) },
      {
        key: 'spread',
        label: 'Spread',
        value: dlob?.spreadBps == null ? '—' : `${dlob.spreadBps.toFixed(1)} bps`,
        sub: formatUsd(dlob?.spreadAbs ?? null),
      },
      {
        key: 'dlob',
        label: 'DLOB',
        value: dlobConnected ? 'live' : '—',
        sub: dlobError ? <span className="neg">{dlobError}</span> : dlob?.updatedAt || '—',
      },
      {
        key: 'l2',
        label: 'L2',
        value: dlobL2Connected ? 'live' : '—',
        sub: dlobL2Error ? <span className="neg">{dlobL2Error}</span> : dlobL2?.updatedAt || '—',
      },
    ];
  }, [latest?.close, latest?.oracle, changePct, dlob, dlobConnected, dlobError, dlobL2, dlobL2Connected, dlobL2Error]);

  const seriesLabel = useMemo(() => `Candles: Mark (oracle overlay)`, []);
  const seriesKey = useMemo(() => `${symbol}|${source}|${tf}`, [symbol, source, tf]);
  const bucketSeconds = meta?.bucketSeconds ?? 60;

  return (
    <>
      <AppShell
        header={<TopNav active="trade" rightEndSlot={<AuthStatus user={user} onLogout={onLogout} />} />}
        top={<TickerBar items={topItems} />}
        main={
          <div className="tradeMain">
          <Card
            className="marketCard"
            title={
              <MarketHeader
                market={symbol}
                markets={markets}
                onMarketChange={setSymbol}
                leftSlot={
                  <label className="inlineField">
                    <span className="inlineField__label">Source</span>
                    <input
                      className="inlineField__input"
                      value={source}
                      onChange={(e) => setSource(e.target.value)}
                      placeholder="(any)"
                    />
                  </label>
                }
                stats={stats}
                rightSlot={
                  <div className="marketHeader__actions">
                    <label className="inlineField">
                      <span className="inlineField__label">Poll</span>
                      <input
                        className="inlineField__input"
                        value={pollMs}
                        type="number"
                        min={250}
                        step={250}
                        onChange={(e) => setPollMs(Number(e.target.value))}
                      />
                    </label>
                    <label className="inlineField">
                      <span className="inlineField__label">Limit</span>
                      <input
                        className="inlineField__input"
                        value={limit}
                        type="number"
                        min={50}
                        step={50}
                        onChange={(e) => setLimit(Number(e.target.value))}
                      />
                    </label>
                    <Button onClick={() => void refresh()} disabled={loading} type="button">
                      Refresh
                    </Button>
                  </div>
                }
              />
            }
          >
            {error ? <div className="uiError">{error}</div> : null}
          </Card>

          <ChartPanel
            candles={candles}
            indicators={indicators}
            timeframe={tf}
            bucketSeconds={bucketSeconds}
            seriesKey={seriesKey}
            onTimeframeChange={setTf}
            showIndicators={showIndicators}
            onToggleIndicators={() => setShowIndicators((v) => !v)}
            showBuild={showBuild}
            onToggleBuild={() => setShowBuild((v) => !v)}
            seriesLabel={seriesLabel}
            dlobQuotes={{ bid: dlob?.bestBid ?? null, ask: dlob?.bestAsk ?? null, mid: dlob?.mid ?? null }}
            fullscreenOverride={layoutMode === 'stack'}
            onToggleFullscreenOverride={() => togglePaneFullscreen('chart')}
            fullscreenStyle={
              layoutMode === 'stack'
                ? {
                    zIndex: stackZ.chart,
                    opacity: effectiveLayerOpacity.chart,
                    filter: `brightness(${layerBrightness.chart})`,
                    pointerEvents: activePane === 'chart' ? 'auto' : 'none',
                  }
                : undefined
            }
          />

          <Card className="bottomCard">
            <Tabs
              items={[
                {
                  id: 'dlob',
                  label: 'DLOB',
                  content: (
                    <DlobDashboard
                      market={symbol}
                      stats={dlob}
                      statsConnected={dlobConnected}
                      statsError={dlobError}
                      depthBands={depthBands}
                      depthBandsConnected={depthBandsConnected}
                      depthBandsError={depthBandsError}
                      slippageRows={slippageRows}
                      slippageConnected={slippageConnected}
                      slippageError={slippageError}
                      isFullscreen={layoutMode === 'stack' && activePane === 'dlob'}
                      onToggleFullscreen={() => togglePaneFullscreen('dlob')}
                    />
                  ),
                },
                {
                  id: 'costs',
                  label: 'Costs',
                  content: <ContractCostsPanel market={symbol} />,
                },
                { id: 'positions', label: 'Positions', content: <div className="placeholder">Positions (next)</div> },
                { id: 'orders', label: 'Orders', content: <div className="placeholder">Orders (next)</div> },
                { id: 'balances', label: 'Balances', content: <div className="placeholder">Balances (next)</div> },
                {
                  id: 'orderHistory',
                  label: 'Order History',
                  content: <div className="placeholder">Order history (next)</div>,
                },
                {
                  id: 'positionHistory',
                  label: 'Position History',
                  content: <div className="placeholder">Position history (next)</div>,
                },
              ]}
              activeId={bottomTab}
              onChange={setBottomTab}
            />
          </Card>
          </div>
        }
        sidebar={
        <Card
          className="orderbookCard"
          title={
            <div className="sideHead">
              <div className="sideHead__title">Orderbook</div>
              <div className="sideHead__subtitle">{loading ? 'loading…' : orderbook.mid != null ? formatUsd(orderbook.mid) : latest ? formatUsd(latest.close) : '—'}</div>
            </div>
          }
        >
          <Tabs
            items={[
              {
                id: 'orderbook',
                label: 'Orderbook',
                content: (
                  <div className="orderbook">
                    <div className="orderbook__header">
                      <span>Price</span>
                      <span className="orderbook__num">Size (USD)</span>
                      <span className="orderbook__num">Total (USD)</span>
                    </div>
                    <div className="orderbook__rows">
                      {orderbook.asks.map((r) => (
                        <div
                          key={`a-${r.price}`}
                          className="orderbookRow orderbookRow--ask"
                          style={orderbookRowBarStyle(
                            maxAskTotal > 0 ? (r as any).totalUsd / maxAskTotal : 0,
                            maxAskSize > 0 ? (r as any).sizeUsd / maxAskSize : 0
                          )}
                        >
                          <span className="orderbookRow__price">{formatQty(r.price, 3)}</span>
                          <span className="orderbookRow__num">{formatCompact((r as any).sizeUsd)}</span>
                          <span className="orderbookRow__num">{formatCompact((r as any).totalUsd)}</span>
                        </div>
                      ))}
                      <div className="orderbookMid">
                        <span className="orderbookMid__price">{formatQty(orderbook.mid, 3)}</span>
                        <span className="orderbookMid__label">mid</span>
                      </div>
                      {orderbook.bids.map((r) => (
                        <div
                          key={`b-${r.price}`}
                          className="orderbookRow orderbookRow--bid"
                          style={orderbookRowBarStyle(
                            maxBidTotal > 0 ? (r as any).totalUsd / maxBidTotal : 0,
                            maxBidSize > 0 ? (r as any).sizeUsd / maxBidSize : 0
                          )}
                        >
                          <span className="orderbookRow__price">{formatQty(r.price, 3)}</span>
                          <span className="orderbookRow__num">{formatCompact((r as any).sizeUsd)}</span>
                          <span className="orderbookRow__num">{formatCompact((r as any).totalUsd)}</span>
                        </div>
                      ))}
                      <div className="orderbookMeta">
                        <div className="orderbookMeta__row">
                          <span className="muted">Spread</span>
                          <span className="orderbookMeta__val">
                            {liquidity.spreadAbs == null || liquidity.spreadPct == null
                              ? '—'
                              : `${formatUsd(liquidity.spreadAbs)} (${liquidity.spreadPct.toFixed(3)}%)`}
                          </span>
                        </div>
                        <div className="orderbookMeta__row">
                          <span className="muted">Liquidity (L1–L10)</span>
                          <span className="orderbookMeta__val">
                            <span className="pos">{formatUsd(liquidity.bidUsd)}</span> <span className="muted">/</span>{' '}
                            <span className="neg">{formatUsd(liquidity.askUsd)}</span>
                          </span>
                        </div>
                        <div className="liquidityBar" style={liquidityStyle(liquidity.bidUsd, liquidity.askUsd)}>
                          <div className="liquidityBar__bid" />
                          <div className="liquidityBar__ask" />
                        </div>
                      </div>
                    </div>
                  </div>
                ),
              },
              {
                id: 'trades',
                label: 'Recent Trades',
                content: (
                  <div className="trades">
                    <div className="trades__header">
                      <span>Time</span>
                      <span className="trades__num">Price</span>
                      <span className="trades__num">Size</span>
                    </div>
                    <div className="trades__rows">
                      {trades.map((t) => (
                        <div key={`${t.time}-${t.price}`} className="tradeRow">
                          <span className="tradeRow__time">
                            {new Date(t.time * 1000).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' })}
                          </span>
                          <span className={['tradeRow__price', t.side === 'buy' ? 'pos' : 'neg'].join(' ')}>
                            {formatQty(t.price, 3)}
                          </span>
                          <span className="tradeRow__num">{t.size == null ? '—' : formatQty(t.size, 2)}</span>
                        </div>
                      ))}
                    </div>
                  </div>
                ),
              },
            ]}
            activeId={tab}
            onChange={setTab}
          />
        </Card>
        }
        rightbar={
        <Card
          className="tradeFormCard"
          title={
            <div className="tradeFormHead">
              <div className="tradeFormHead__left">
                <button className="chipBtn" type="button">
                  Cross
                </button>
                <button className="chipBtn" type="button">
                  20x
                </button>
              </div>
              <div className="tradeFormHead__right">{symbol}</div>
            </div>
          }
        >
          <div className="tradeForm">
            <div className="segmented">
              <button
                className={['segmented__btn', tradeSide === 'long' ? 'segmented__btn--activeLong' : ''].filter(Boolean).join(' ')}
                type="button"
                onClick={() => setTradeSide('long')}
              >
                Long
              </button>
              <button
                className={['segmented__btn', tradeSide === 'short' ? 'segmented__btn--activeShort' : ''].filter(Boolean).join(' ')}
                type="button"
                onClick={() => setTradeSide('short')}
              >
                Short
              </button>
            </div>

            <div className="tradeTabs">
              <button
                type="button"
                className={['tradeTabs__btn', tradeOrderType === 'market' ? 'tradeTabs__btn--active' : ''].filter(Boolean).join(' ')}
                onClick={() => setTradeOrderType('market')}
              >
                Market
              </button>
              <button
                type="button"
                className={['tradeTabs__btn', tradeOrderType === 'limit' ? 'tradeTabs__btn--active' : ''].filter(Boolean).join(' ')}
                onClick={() => setTradeOrderType('limit')}
              >
                Limit
              </button>
              <button
                type="button"
                className={['tradeTabs__btn', tradeOrderType === 'other' ? 'tradeTabs__btn--active' : ''].filter(Boolean).join(' ')}
                onClick={() => setTradeOrderType('other')}
              >
                Others
              </button>
            </div>

            <div className="tradeFields">
              <label className="formField">
                <span className="formField__label">Price</span>
                <input
                  className="formField__input"
                  value={tradeOrderType === 'market' ? '' : String(tradePrice)}
                  placeholder={tradeOrderType === 'market' ? formatQty(latest?.close ?? null, 3) : '0'}
                  disabled={tradeOrderType !== 'limit'}
                  onChange={(e) => setTradePrice(Number(e.target.value))}
                  inputMode="decimal"
                />
              </label>
              <label className="formField">
                <span className="formField__label">Size</span>
                <input
                  className="formField__input"
                  value={String(tradeSize)}
                  onChange={(e) => setTradeSize(Number(e.target.value))}
                  inputMode="decimal"
                />
              </label>
            </div>

            <Button className="tradeCta" type="button" disabled>
              Enable Trading
            </Button>

            <div className="tradeMeta">
              <div className="tradeMeta__row">
                <span className="tradeMeta__label">Order Value</span>
                <span className="tradeMeta__value">{effectiveTradePrice ? formatUsd(effectiveTradePrice * tradeSize) : '—'}</span>
              </div>
              <div className="tradeMeta__row">
                <span className="tradeMeta__label">Slippage (Dynamic)</span>
                <span className="tradeMeta__value">
                  {slippageError ? (
                    <span className="neg">{slippageError}</span>
                  ) : dynamicSlippage?.impactBps == null ? (
                    slippageConnected ? (
                      '—'
                    ) : (
                      'offline'
                    )
                  ) : (
                    <>
                      {dynamicSlippage.impactBps.toFixed(1)} bps{' '}
                      <span className="muted">
                        ({dynamicSlippage.sizeUsd.toLocaleString()} USD)
                        {dynamicSlippage.fillPct != null && dynamicSlippage.fillPct < 99.9
                          ? `, ${dynamicSlippage.fillPct.toFixed(0)}% fill`
                          : ''}
                      </span>
                    </>
                  )}
                </span>
              </div>
              <div className="tradeMeta__row">
                <span className="tradeMeta__label">Margin Required</span>
                <span className="tradeMeta__value">—</span>
              </div>
              <div className="tradeMeta__row">
                <span className="tradeMeta__label">Liq. Price</span>
                <span className="tradeMeta__value">—</span>
              </div>
            </div>
          </div>
        </Card>
        }
      />

      {layoutMode === 'stack' ? (
        <>
          <div className="stackDrawerHotspot" onMouseEnter={openStackPanel} aria-label="Layers hotspot" />
          <Card
            className={['stackDrawer', stackPanelOpen ? 'stackDrawer--open' : 'stackDrawer--closed'].join(' ')}
            title="Layers"
            right={
              <div className="stackPanel__actions">
                <span className="muted stackPanel__hint">Esc ×2</span>
                <Button
                  size="sm"
                  variant={stackPanelLocked ? 'primary' : 'ghost'}
                  onClick={() => {
                    setStackPanelLocked((v) => !v);
                    openStackPanel();
                  }}
                  type="button"
                  title={stackPanelLocked ? 'Auto-hide disabled' : 'Auto-hide enabled'}
                >
                  {stackPanelLocked ? 'Locked' : 'Auto'}
                </Button>
                <Button
                  size="sm"
                  variant="ghost"
                  onClick={() => {
                    setStackPanelOpen(false);
                    scheduleHideStackPanel();
                  }}
                  type="button"
                >
                  Hide
                </Button>
                <Button size="sm" variant="primary" onClick={exitStack} type="button">
                  Back
                </Button>
              </div>
            }
            onMouseEnter={openStackPanel}
            onMouseLeave={scheduleHideStackPanel}
          >
            <div className="stackPanel__sub muted">UI Opacity</div>
            <div className="stackPanel__sliders" style={{ marginBottom: 14 }}>
              <label className="stackPanel__sliderRow">
                <span className="stackPanel__sliderLabel muted">Backdrop</span>
                <input
                  className="stackPanel__slider"
                  type="range"
                  min={0}
                  max={95}
                  step={1}
                  value={Math.round(Math.min(0.95, Math.max(0, stackBackdropOpacity)) * 100)}
                  onChange={(e) => setStackBackdropOpacity(Number(e.target.value) / 100)}
                  onWheel={(e) => {
                    e.preventDefault();
                    const cur = Math.round(clampNumber(stackBackdropOpacity, 0, 0.95) * 100);
                    const step = e.shiftKey ? 5 : 1;
                    const next = clampNumber(cur + stepByWheel(e, step), 0, 95);
                    setStackBackdropOpacity(next / 100);
                  }}
                />
                <span className="stackPanel__sliderValue muted">
                  {Math.round(Math.min(0.95, Math.max(0, stackBackdropOpacity)) * 100)}%
                </span>
              </label>
              <label className="stackPanel__sliderRow">
                <span className="stackPanel__sliderLabel muted">Panel</span>
                <input
                  className="stackPanel__slider"
                  type="range"
                  min={5}
                  max={100}
                  step={1}
                  value={Math.round(Math.min(1, Math.max(0.05, stackDrawerOpacity)) * 100)}
                  onChange={(e) => setStackDrawerOpacity(Number(e.target.value) / 100)}
                  onWheel={(e) => {
                    e.preventDefault();
                    const cur = Math.round(clampNumber(stackDrawerOpacity, 0.05, 1) * 100);
                    const step = e.shiftKey ? 5 : 1;
                    const next = clampNumber(cur + stepByWheel(e, step), 5, 100);
                    setStackDrawerOpacity(next / 100);
                  }}
                />
                <span className="stackPanel__sliderValue muted">
                  {Math.round(Math.min(1, Math.max(0.05, stackDrawerOpacity)) * 100)}%
                </span>
              </label>
            </div>

            <div className="stackPanel__sub muted">
              Drag to reorder, click to focus (top = active).
            </div>
            <div className="stackPanel__list" role="list">
              {stackTopFirst.map((pane) => {
                const isActive = pane === activePane;
                const label =
                  pane === 'chart'
                    ? 'Chart'
                    : pane === 'dlob'
                      ? 'DLOB'
                      : pane === 'costsNew'
                        ? 'Costs (New)'
                        : 'Costs (Active)';
                const pct = Math.round(clampNumber(layerOpacity[pane] ?? 1, 0, 1) * 100);
                const isVisible = layerVisible[pane];
                const isLocked = layerLocked[pane];
                const brightPct = Math.round(clampNumber(layerBrightness[pane] ?? 1, 0.6, 1.8) * 100);
                return (
                  <div
                    key={pane}
                    role="listitem"
                    className={[
                      'stackPanel__item',
                      isActive ? 'stackPanel__item--active' : null,
                      isLocked ? 'stackPanel__item--locked' : null,
                      !isVisible ? 'stackPanel__item--hidden' : null,
                    ]
                      .filter(Boolean)
                      .join(' ')}
                    draggable={!isLocked}
                    onClick={() => {
                      if (isLocked) return;
                      enterStack(pane);
                    }}
                    onDragStart={(e) => {
                      if (isLocked) return;
                      e.dataTransfer.setData('text/plain', pane);
                      e.dataTransfer.effectAllowed = 'move';
                    }}
                    onDragOver={(e) => {
                      if (isLocked) return;
                      e.preventDefault();
                      e.dataTransfer.dropEffect = 'move';
                    }}
                    onDrop={(e) => {
                      e.preventDefault();
                      const dragged = e.dataTransfer.getData('text/plain') as PaneId;
                      if (!ALL_PANES.includes(dragged)) return;
                      if (layerLocked[dragged]) return;
                      if (isLocked) return;
                      const nextTop = reorderList(stackTopFirst, dragged, pane);
                      setStackOrder(nextTop.slice().reverse() as any);
                      setStackOrderManual(true);
                    }}
                  >
                    <span className="stackPanel__drag">⋮⋮</span>
                    <span className="stackPanel__label">{label}</span>
                    <button
                      type="button"
                      className="stackPanel__iconBtn"
                      title={isVisible ? 'Hide layer' : 'Show layer'}
                      onClick={(e) => {
                        e.stopPropagation();
                        setLayerVisible((prev) => ({ ...normalizeLayerToggle(prev, true), [pane]: !isVisible }));
                      }}
                    >
                      {isVisible ? '👁' : '🚫'}
                    </button>
                    <button
                      type="button"
                      className="stackPanel__iconBtn"
                      title={isLocked ? 'Unlock layer' : 'Lock layer'}
                      onClick={(e) => {
                        e.stopPropagation();
                        setLayerLocked((prev) => ({ ...normalizeLayerToggle(prev, false), [pane]: !isLocked }));
                      }}
                    >
                      {isLocked ? '🔒' : '🔓'}
                    </button>
                    <input
                      className="stackPanel__layerBrightness"
                      type="range"
                      min={60}
                      max={180}
                      step={1}
                      value={brightPct}
                      title={`${label} brightness`}
                      onClick={(e) => e.stopPropagation()}
                      onWheel={(e) => {
                        e.preventDefault();
                        const cur = Math.round(clampNumber(layerBrightness[pane] ?? 1, 0.6, 1.8) * 100);
                        const step = e.shiftKey ? 10 : 2;
                        const next = clampNumber(cur + stepByWheel(e, step), 60, 180);
                        setLayerBrightness((prev) => ({ ...normalizeLayerFactor(prev, 1, 0.6, 1.8), [pane]: next / 100 }));
                      }}
                      disabled={isLocked}
                      onChange={(e) =>
                        setLayerBrightness((prev) => ({
                          ...normalizeLayerFactor(prev, 1, 0.6, 1.8),
                          [pane]: Number(e.target.value) / 100,
                        }))
                      }
                    />
                    <span className="stackPanel__layerBrightnessValue muted">{brightPct}%</span>
                    <input
                      className="stackPanel__layerOpacity"
                      type="range"
                      min={0}
                      max={100}
                      step={1}
                      value={pct}
                      title={`${label} opacity`}
                      onClick={(e) => e.stopPropagation()}
                      onWheel={(e) => {
                        e.preventDefault();
                        const cur = Math.round(clampNumber(layerOpacity[pane] ?? 1, 0, 1) * 100);
                        const step = e.shiftKey ? 5 : 1;
                        const next = clampNumber(cur + stepByWheel(e, step), 0, 100);
                        setLayerOpacity((prev) => ({ ...normalizeLayerOpacity(prev), [pane]: next / 100 }));
                      }}
                      disabled={isLocked}
                      onChange={(e) =>
                        setLayerOpacity((prev) => ({
                          ...normalizeLayerOpacity(prev),
                          [pane]: Number(e.target.value) / 100,
                        }))
                      }
                    />
                    <span className="stackPanel__layerOpacityValue muted">{pct}%</span>
                    {isActive ? <span className="stackPanel__badge">active</span> : null}
                  </div>
                );
              })}
            </div>
          </Card>
        </>
      ) : null}

      {layoutMode === 'stack' ? <div className="stackBackdrop" aria-hidden="true" /> : null}

      {layoutMode === 'stack' && effectiveLayerOpacity.dlob > 0 ? (
        <div
          className="stackLayer stackLayer--dlob"
          role="dialog"
          aria-label="DLOB layer"
          style={{
            zIndex: stackZ.dlob,
            opacity: effectiveLayerOpacity.dlob,
            filter: `brightness(${layerBrightness.dlob})`,
            pointerEvents: activePane === 'dlob' ? 'auto' : 'none',
          }}
        >
          <div className="stackLayer__body">
            <Card className="stackLayer__card">
              <DlobDashboard
                market={symbol}
                stats={dlob}
                statsConnected={dlobConnected}
                statsError={dlobError}
                depthBands={depthBands}
                depthBandsConnected={depthBandsConnected}
                depthBandsError={depthBandsError}
                slippageRows={slippageRows}
                slippageConnected={slippageConnected}
                slippageError={slippageError}
                isFullscreen
                onToggleFullscreen={() => togglePaneFullscreen('dlob')}
              />
            </Card>
          </div>
        </div>
      ) : null}

      {layoutMode === 'stack' && effectiveLayerOpacity.costsActive > 0 && hasActiveContract ? (
        <div
          className="stackLayer stackLayer--costsActive"
          role="dialog"
          aria-label="Costs active layer"
          style={{
            zIndex: stackZ.costsActive,
            opacity: effectiveLayerOpacity.costsActive,
            filter: `brightness(${layerBrightness.costsActive})`,
            pointerEvents: activePane === 'costsActive' ? 'auto' : 'none',
          }}
        >
          <div className="stackLayer__body">
            <Card className="stackLayer__card">
              <ContractCostsPanel market={symbol} view="active" />
            </Card>
          </div>
        </div>
      ) : null}

      {layoutMode === 'stack' && effectiveLayerOpacity.costsNew > 0 ? (
        <div
          className="stackLayer stackLayer--costsNew"
          role="dialog"
          aria-label="Costs new layer"
          style={{
            zIndex: stackZ.costsNew,
            opacity: effectiveLayerOpacity.costsNew,
            filter: `brightness(${layerBrightness.costsNew})`,
            pointerEvents: activePane === 'costsNew' ? 'auto' : 'none',
          }}
        >
          <div className="stackLayer__body">
            <Card className="stackLayer__card">
              <ContractCostsPanel market={symbol} view="new" />
            </Card>
          </div>
        </div>
      ) : null}
    </>
  );
}
