// EA-Commander JARVIS — Production app.jsx
// Babel-standalone React 18, no ES module imports
// All React hooks via destructuring from global React

const {
  useState, useEffect, useMemo, useRef, useCallback, useReducer
} = React;

/* ─────────────────────────────────────────────
   API UTILITIES
───────────────────────────────────────────── */
const API_BASE = "";

async function apiFetch(path, opts = {}) {
  const token = localStorage.getItem("jwt");
  const headers = { "Content-Type": "application/json", ...(opts.headers || {}) };
  if (token) headers["Authorization"] = "Bearer " + token;
  const res = await fetch(API_BASE + path, { ...opts, headers });
  if (res.status === 401) {
    localStorage.removeItem("jwt");
    window.location.reload();
    return null;
  }
  if (!res.ok) {
    let msg = "Request failed";
    try { const d = await res.json(); msg = d.detail || d.message || msg; } catch (_) {}
    throw new Error(msg);
  }
  if (res.status === 204) return null;
  return res.json();
}

/* ─────────────────────────────────────────────
   TOAST SYSTEM
───────────────────────────────────────────── */
let _toastSetState = null;

function toast(msg, type = "info") {
  if (_toastSetState) _toastSetState(p => [...p, { id: Date.now() + Math.random(), msg, type }]);
}

function ToastContainer() {
  const [toasts, setToasts] = useState([]);
  _toastSetState = setToasts;

  useEffect(() => {
    if (toasts.length === 0) return;
    const t = setTimeout(() => {
      setToasts(p => p.slice(1));
    }, 3000);
    return () => clearTimeout(t);
  }, [toasts]);

  const colorMap = { info: "#5ee0ff", success: "#5cf2a0", error: "#ff4d6d", warn: "#ffb547" };

  return (
    <div style={{
      position: "fixed", top: 16, right: 16, zIndex: 9999,
      display: "flex", flexDirection: "column", gap: 8, pointerEvents: "none"
    }}>
      {toasts.map(t => (
        <div key={t.id} style={{
          background: "#0e1826",
          border: `1px solid ${colorMap[t.type] || "#5ee0ff"}`,
          borderRadius: 8, padding: "10px 16px",
          color: "#d8ecff", fontFamily: "var(--mono)", fontSize: 13,
          boxShadow: `0 0 16px ${colorMap[t.type] || "#5ee0ff"}33`,
          animation: "slideInToast 0.3s ease",
          pointerEvents: "auto", maxWidth: 340
        }}>
          {t.msg}
        </div>
      ))}
    </div>
  );
}

/* ─────────────────────────────────────────────
   FORMAT HELPERS
───────────────────────────────────────────── */
function fmtMoney(n, sign = false) {
  if (n == null || isNaN(n)) return "—";
  const v = Math.abs(n).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
  const prefix = sign ? (n >= 0 ? "+" : "-") : (n < 0 ? "-" : "");
  return prefix + "$" + v;
}

function relTime(ts) {
  if (!ts) return "—";
  const d = new Date(ts);
  const diff = (Date.now() - d.getTime()) / 1000;
  if (diff < 60) return Math.round(diff) + "s ago";
  if (diff < 3600) return Math.round(diff / 60) + "m ago";
  if (diff < 86400) return Math.round(diff / 3600) + "h ago";
  return Math.round(diff / 86400) + "d ago";
}

/* ─────────────────────────────────────────────
   TICKER DATA (decorative)
───────────────────────────────────────────── */
const TICKER_DATA = [
  { sym: "XAU/USD", px: "4,476.20", ch: "+0.84%", up: true },
  { sym: "EUR/USD", px: "1.0842",   ch: "-0.12%", up: false },
  { sym: "GBP/JPY", px: "192.41",   ch: "+0.42%", up: true },
  { sym: "NAS100",  px: "20,418.5", ch: "+0.92%", up: true },
  { sym: "GER40",   px: "21,402.8", ch: "+0.18%", up: true },
  { sym: "BTC/USD", px: "98,420",   ch: "-1.20%", up: false },
  { sym: "USD/JPY", px: "152.18",   ch: "+0.05%", up: true },
  { sym: "OIL",     px: "72.40",    ch: "-0.62%", up: false },
];

/* ─────────────────────────────────────────────
   SPARKLINE
───────────────────────────────────────────── */
function Sparkline({ data, color, area = true }) {
  if (!data || data.length < 2) return null;
  const W = 200, H = 38;
  const min = Math.min(...data), max = Math.max(...data);
  const x = i => (i / (data.length - 1)) * W;
  const y = v => H - ((v - min) / (max - min || 1)) * (H - 4) - 2;
  const path = data.map((v, i) => `${i === 0 ? "M" : "L"} ${x(i).toFixed(1)} ${y(v).toFixed(1)}`).join(" ");
  const areaPath = path + ` L ${W} ${H} L 0 ${H} Z`;
  const uid = color.replace(/[^a-z0-9]/gi, "");
  return (
    <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none" style={{ width: "100%", height: "100%" }}>
      {area && (
        <>
          <defs>
            <linearGradient id={`sp-${uid}`} x1="0" y1="0" x2="0" y2="1">
              <stop offset="0%" stopColor={color} stopOpacity="0.4" />
              <stop offset="100%" stopColor={color} stopOpacity="0" />
            </linearGradient>
          </defs>
          <path d={areaPath} fill={`url(#sp-${uid})`} />
        </>
      )}
      <path d={path} fill="none" stroke={color} strokeWidth="1.3" />
    </svg>
  );
}

/* ─────────────────────────────────────────────
   EQUITY CHART
───────────────────────────────────────────── */
function EquityChart({ data, accent, currentEquity }) {
  // Convert daily-pnl data [{day, pnl}] to cumulative equity curve
  const points = useMemo(() => {
    if (data && data.length >= 2) {
      // Work backwards: current equity minus sum of all pnl = starting equity
      const totalPnl = data.reduce((s, d) => s + (d.pnl || 0), 0);
      const baseEquity = Math.max(0, (currentEquity || 100000) - totalPnl);
      let cum = baseEquity;
      return data.map(d => { cum += (d.pnl || 0); return cum; });
    }
    // No real trade data yet — flat line at current equity, no oscillation
    if (currentEquity && currentEquity > 0) {
      return [currentEquity * 0.9995, currentEquity];
    }
    return null;
  }, [data, currentEquity]);

  const W = 800, H = 260, PAD = 28;

  if (!points || points.length < 2) {
    return (
      <div className="equity-chart-wrap" style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>
        <div style={{ color: "rgba(94,224,255,0.3)", fontFamily: "var(--mono)", fontSize: 12, letterSpacing: "0.1em" }}>
          KEINE HANDELSDATEN
        </div>
      </div>
    );
  }

  const rawMin = Math.min(...points);
  const rawMax = Math.max(...points);
  const pad = (rawMax - rawMin) * 0.1 || rawMax * 0.01 || 100;
  const min = rawMin - pad;
  const max = rawMax + pad;
  const px = i => PAD + (i / (points.length - 1)) * (W - PAD * 2);
  const py = v => H - PAD - ((v - min) / (max - min || 1)) * (H - PAD * 2);

  const linePath = points.map((v, i) => `${i === 0 ? "M" : "L"} ${px(i).toFixed(1)} ${py(v).toFixed(1)}`).join(" ");
  const areaPath = linePath + ` L ${px(points.length - 1).toFixed(1)} ${H - PAD} L ${px(0)} ${H - PAD} Z`;
  const last = points[points.length - 1];
  const lx = px(points.length - 1), ly = py(last);

  const gridY = [];
  for (let i = 0; i < 5; i++) {
    const yy = PAD + (i / 4) * (H - PAD * 2);
    const val = max - (i / 4) * (max - min);
    gridY.push({ y: yy, v: val });
  }

  const xLabels = data && data.length >= 2
    ? (() => {
        const idxs = [0, Math.floor(data.length / 4), Math.floor(data.length / 2), Math.floor(3 * data.length / 4), data.length - 1];
        return idxs.map(i => (data[i].day || "").slice(5)); // "MM-DD" from "YYYY-MM-DD"
      })()
    : [];

  return (
    <div className="equity-chart-wrap">
      <svg viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="none">
        <defs>
          <linearGradient id="eq-fill" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={accent} stopOpacity="0.35" />
            <stop offset="100%" stopColor={accent} stopOpacity="0" />
          </linearGradient>
          <linearGradient id="eq-line" x1="0" y1="0" x2="1" y2="0">
            <stop offset="0%" stopColor={accent} stopOpacity="0.4" />
            <stop offset="100%" stopColor={accent} stopOpacity="1" />
          </linearGradient>
          <filter id="glow"><feGaussianBlur stdDeviation="3" /></filter>
        </defs>

        {gridY.map((g, i) => (
          <g key={i}>
            <line x1={PAD} x2={W - PAD} y1={g.y} y2={g.y} stroke="rgba(120,200,255,0.07)" strokeDasharray="2 4" />
            <text x={W - PAD + 4} y={g.y + 3} style={{ fontSize: 9, fontFamily: "var(--mono)", fill: "rgba(147,179,205,0.6)" }}>{Math.round(g.v / 1000)}k</text>
          </g>
        ))}

        {xLabels.map((l, i) => {
          const xx = PAD + (i / (xLabels.length - 1)) * (W - PAD * 2);
          return <text key={i} x={xx} y={H - 6} textAnchor="middle" style={{ fontSize: 9, fontFamily: "var(--mono)", fill: "rgba(147,179,205,0.5)" }}>{l}</text>;
        })}

        <path d={areaPath} fill="url(#eq-fill)" />
        <path d={linePath} fill="none" stroke={accent} strokeWidth="2" strokeLinejoin="round" filter="url(#glow)" opacity="0.6" />
        <path d={linePath} fill="none" stroke="url(#eq-line)" strokeWidth="1.6" strokeLinejoin="round" />

        {[Math.floor(points.length * 0.1), Math.floor(points.length * 0.25), Math.floor(points.length * 0.4), Math.floor(points.length * 0.57), Math.floor(points.length * 0.75), Math.floor(points.length * 0.88)].map(idx => (
          <g key={idx}>
            <circle cx={px(idx)} cy={py(points[idx])} r="2.5" fill={accent} />
            <line x1={px(idx)} x2={px(idx)} y1={py(points[idx])} y2={H - PAD} stroke={accent} strokeOpacity="0.15" strokeDasharray="2 3" />
          </g>
        ))}

        <line x1={lx} x2={lx} y1={PAD} y2={H - PAD} stroke={accent} strokeOpacity="0.4" strokeDasharray="3 3" />
        <circle cx={lx} cy={ly} r="10" fill={accent} fillOpacity="0.15" />
        <circle cx={lx} cy={ly} r="5" fill={accent} fillOpacity="0.4" />
        <circle cx={lx} cy={ly} r="2.5" fill="#fff" />

        <g transform={`translate(${Math.min(lx + 10, W - 110)}, ${Math.max(ly - 14, PAD)})`}>
          <rect width="88" height="22" rx="3" fill="#0a121c" stroke={accent} strokeOpacity="0.5" />
          <text x="8" y="14" style={{ fontSize: 11, fontFamily: "var(--mono)", fill: "#d8ecff" }}>
            ${last.toLocaleString("en-US", { maximumFractionDigits: 0 })}
          </text>
        </g>

        <path d={`M ${PAD} ${PAD + 12} L ${PAD} ${PAD} L ${PAD + 12} ${PAD}`} fill="none" stroke={accent} strokeOpacity="0.5" />
        <path d={`M ${W - PAD - 12} ${PAD} L ${W - PAD} ${PAD} L ${W - PAD} ${PAD + 12}`} fill="none" stroke={accent} strokeOpacity="0.5" />
        <path d={`M ${PAD} ${H - PAD - 12} L ${PAD} ${H - PAD} L ${PAD + 12} ${H - PAD}`} fill="none" stroke={accent} strokeOpacity="0.5" />
        <path d={`M ${W - PAD - 12} ${H - PAD} L ${W - PAD} ${H - PAD} L ${W - PAD} ${H - PAD - 12}`} fill="none" stroke={accent} strokeOpacity="0.5" />
      </svg>
    </div>
  );
}

/* ─────────────────────────────────────────────
   RADIAL DIAL
───────────────────────────────────────────── */
function Dial({ value, max = 100, label, color = "var(--accent)", suffix = "%" }) {
  const R = 42, C = 2 * Math.PI * R;
  const pct = Math.min((value || 0) / max, 1);
  const off = C * (1 - pct);
  return (
    <div className="dial">
      <svg viewBox="0 0 100 100">
        <circle cx="50" cy="50" r={R} fill="none" stroke="rgba(94,224,255,0.08)" strokeWidth="3" />
        <circle cx="50" cy="50" r={R} fill="none" stroke={color} strokeWidth="3"
          strokeDasharray={C} strokeDashoffset={off}
          strokeLinecap="round"
          transform="rotate(-90 50 50)"
          style={{ filter: `drop-shadow(0 0 6px ${color})`, transition: "stroke-dashoffset 0.6s ease" }}
        />
        {Array.from({ length: 24 }).map((_, i) => {
          const a = (i / 24) * Math.PI * 2 - Math.PI / 2;
          const r1 = 47, r2 = 49;
          return <line key={i} x1={50 + Math.cos(a) * r1} y1={50 + Math.sin(a) * r1}
            x2={50 + Math.cos(a) * r2} y2={50 + Math.sin(a) * r2}
            stroke="rgba(120,200,255,0.2)" strokeWidth="0.5" />;
        })}
      </svg>
      <div className="v">{(value || 0).toFixed(value < 10 ? 1 : 0)}<span style={{ fontSize: 11, color: "var(--ink-3)" }}>{suffix}</span></div>
      <div className="l">{label}</div>
    </div>
  );
}

/* ─────────────────────────────────────────────
   NAV ICON
───────────────────────────────────────────── */
function NavIcon({ name }) {
  const map = {
    grid:    <><rect x="3" y="3" width="7" height="7" /><rect x="14" y="3" width="7" height="7" /><rect x="3" y="14" width="7" height="7" /><rect x="14" y="14" width="7" height="7" /></>,
    cpu:     <><rect x="6" y="6" width="12" height="12" rx="1" /><path d="M9 9h6v6H9z" /><path d="M3 9h3M3 12h3M3 15h3M18 9h3M18 12h3M18 15h3M9 3v3M12 3v3M15 3v3M9 18v3M12 18v3M15 18v3" /></>,
    pulse:   <><path d="M3 12h4l2-7 4 14 2-7h6" /></>,
    users:   <><circle cx="9" cy="8" r="3" /><path d="M3 20c0-3 3-5 6-5s6 2 6 5" /><circle cx="17" cy="9" r="2.5" /><path d="M14 20c0-2 2-4 4-4s4 1 4 4" /></>,
    wallet:  <><rect x="3" y="6" width="18" height="14" rx="2" /><path d="M3 10h18" /><circle cx="17" cy="15" r="1.5" /></>,
    stack:   <><path d="M12 3l9 4-9 4-9-4 9-4z" /><path d="M3 12l9 4 9-4" /><path d="M3 17l9 4 9-4" /></>,
    server:  <><rect x="3" y="4" width="18" height="6" rx="1" /><rect x="3" y="14" width="18" height="6" rx="1" /><circle cx="7" cy="7" r="0.5" fill="currentColor" /><circle cx="7" cy="17" r="0.5" fill="currentColor" /></>,
    log:     <><path d="M5 4h11l3 3v13H5z" /><path d="M9 9h6M9 12h6M9 15h4" /></>,
    tag:     <><path d="M20.59 13.41l-7.17 7.17a2 2 0 01-2.83 0L2 12V2h10l8.59 8.59a2 2 0 010 2.82z" /><line x1="7" y1="7" x2="7.01" y2="7" /></>,
  };
  return (
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"
      strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round">
      {map[name] || null}
    </svg>
  );
}

/* ─────────────────────────────────────────────
   HUD OVERLAY
───────────────────────────────────────────── */
function HudOverlay() {
  return (
    <div className="hud-overlay">
      <svg viewBox="0 0 1920 1080" preserveAspectRatio="none">
        <g stroke="var(--accent)" strokeOpacity="0.35" fill="none" strokeWidth="1">
          <path d="M 16 16 L 16 56 M 16 16 L 56 16" />
          <path d="M 1904 16 L 1904 56 M 1904 16 L 1864 16" />
          <path d="M 16 1064 L 16 1024 M 16 1064 L 56 1064" />
          <path d="M 1904 1064 L 1904 1024 M 1904 1064 L 1864 1064" />
        </g>
        <g stroke="var(--accent)" strokeOpacity="0.25" fill="none">
          <circle cx="960" cy="20" r="3" />
          <line x1="960" y1="0" x2="960" y2="14" />
          <line x1="940" y1="20" x2="956" y2="20" />
          <line x1="964" y1="20" x2="980" y2="20" />
        </g>
        {Array.from({ length: 30 }).map((_, i) => (
          <line key={i} x1="0" x2={i % 5 === 0 ? 8 : 4} y1={i * 36 + 20} y2={i * 36 + 20}
            stroke="var(--accent)" strokeOpacity="0.15" />
        ))}
      </svg>
    </div>
  );
}

/* ─────────────────────────────────────────────
   TICKER
───────────────────────────────────────────── */
function Ticker() {
  const items = [...TICKER_DATA, ...TICKER_DATA, ...TICKER_DATA];
  return (
    <div className="ticker">
      <span className="lbl">▸ Markets</span>
      <div className="ticker-track">
        {items.map((t, i) => (
          <span key={i} className="item">
            <span className="sym">{t.sym}</span>
            <span className="px">{t.px}</span>
            <span className={"ch " + (t.up ? "pos" : "neg")}>{t.ch}</span>
          </span>
        ))}
      </div>
    </div>
  );
}

/* ─────────────────────────────────────────────
   EA CARD
───────────────────────────────────────────── */
function EACard({ bot, accent }) {
  const name = bot.name || "Unknown EA";
  const pl = bot.today_pl || 0;
  const dd = bot.drawdown || 0;
  const data = useMemo(() => Array.from({ length: 32 }, (_, i) =>
    50 + Math.sin(i / 3 + name.length) * 12 + Math.cos(i / 1.5) * 8 + (pl > 0 ? i * 0.4 : -i * 0.2)
  ), [name, pl]);

  return (
    <div className="card ea-card card-corners">
      <span className="corner-tr"></span><span className="corner-bl"></span>
      <div className="top">
        <div>
          <div className="name"><span className="live"></span>{name}</div>
          <div className="sub">{bot.symbol || "—"} {bot.timeframe || ""}</div>
        </div>
        <div className={"pl" + (pl < 0 ? " neg" : "")}>{fmtMoney(pl, true)}</div>
      </div>
      <div className="bar"><Sparkline data={data} color={pl >= 0 ? "#5cf2a0" : "#ff4d6d"} /></div>
      <div className="meta">
        <div className="it"><div className="l">Symbol</div><div className="v">{bot.symbol || "—"}</div></div>
        <div className="it"><div className="l">DD</div><div className="v" style={{ color: dd > 3 ? "var(--bad)" : "var(--ink-0)" }}>{dd.toFixed(1)}%</div></div>
        <div className="it"><div className="l">TF</div><div className="v">{bot.timeframe || "—"}</div></div>
      </div>
    </div>
  );
}

/* ─────────────────────────────────────────────
   ACCOUNT ROW
───────────────────────────────────────────── */
function AcctRow({ account, onConfig }) {
  const a = account;
  const dd = a.max_dd_today || 0;
  const tone = dd > 4 ? "bad" : dd > 2.5 ? "warn" : "";
  const initials = (a.broker || a.account_name || "AC").substring(0, 3).toUpperCase();

  return (
    <div className={"acct-row " + tone}>
      <div className="ico">{initials}</div>
      <div className="nm">
        {a.broker || a.account_name || "Unknown"}
        <div className="sub">{a.login} · {a.server || ""}</div>
      </div>
      <div className="eq">
        <div className="l">Equity</div>
        {fmtMoney(a.equity)}
      </div>
      <div className="eq" style={{ minWidth: 110 }}>
        <div className="l">Daily P&L</div>
        <span style={{ color: (a.daily_pl || 0) >= 0 ? "var(--good)" : "var(--bad)" }}>
          {fmtMoney(a.daily_pl || 0, true)}
        </span>
      </div>
      <div className={"dd-pill" + (dd > 4 ? " bad" : dd > 2.5 ? " warn" : "")}>DD {dd.toFixed(1)}%</div>
      <div style={{ fontSize: 11, color: "var(--ink-2)", minWidth: 60 }}>{relTime(a.last_seen)}</div>
      {onConfig && a.vm_id && (
        <button className="cfg" onClick={() => onConfig(a.vm_id)}>Config</button>
      )}
    </div>
  );
}

/* ─────────────────────────────────────────────
   VM CARD
───────────────────────────────────────────── */
function VMCard({ vm, cust, onStop, onStart, onConnect, onDelete, isAdmin, killLocked }) {
  const isRun      = vm.status === "running";
  const isStarting = vm.status === "creating" || vm.status === "starting";
  const isGolden   = vm.vm_type === "golden";
  const custName   = cust ? cust.name : (vm.customer_id ? `#${vm.customer_id}` : "—");

  return (
    <div className="card vm-card card-corners" style={isGolden ? { borderColor: "rgba(255,181,71,0.4)", boxShadow: "0 0 24px rgba(255,181,71,0.08)" } : {}}>
      <span className="corner-tr"></span><span className="corner-bl"></span>
      <div className="top">
        <div>
          <div className="nm" style={{ display: "flex", alignItems: "center", gap: 6 }}>
            {vm.name}
            {isGolden && (
              <span style={{ fontSize: 11, fontFamily: "var(--mono)", color: "#ffb547", background: "rgba(255,181,71,0.12)", border: "1px solid rgba(255,181,71,0.3)", borderRadius: 4, padding: "1px 6px", letterSpacing: "0.06em" }}>
                ⭐ GOLDEN
              </span>
            )}
          </div>
          <div className="id">ID · {vm.short_id || vm.id}</div>
        </div>
        {isStarting ? (
          <div style={{ display: "flex", alignItems: "center", gap: 6, fontSize: 11, fontFamily: "var(--mono)", color: "var(--accent)" }}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" style={{ animation: "spin 1s linear infinite" }}>
              <path d="M21 12a9 9 0 1 1-6.219-8.56" />
            </svg>
            STARTING…
          </div>
        ) : (
          <div className={"stat-pill " + (isRun ? "run" : "stop")}>{isRun ? "● RUNNING" : "○ STOPPED"}</div>
        )}
      </div>
      <div className="meta">
        <div className="it"><div className="l">Customer</div><div className="v" style={{ fontSize: 11 }}>{(custName || "—").slice(0, 12)}</div></div>
        <div className="it"><div className="l">MT5</div><div className="v">{vm.mt5_login || "—"}</div></div>
        <div className="it"><div className="l">Server</div><div className="v" style={{ fontSize: 10 }}>{(vm.mt5_server || "—").slice(0, 12)}</div></div>
      </div>
      {!isStarting && (
        <div className="actions">
          {isRun
            ? <button className="btn danger" onClick={() => onStop && onStop(vm.id)}>Stop</button>
            : (
              <button
                className="btn"
                disabled={!!killLocked}
                title={killLocked ? "Kill Switch aktiv — Neustart erst um 00:00 Uhr" : undefined}
                onClick={() => !killLocked && onStart && onStart(vm.id)}
                style={killLocked ? { opacity: 0.4, cursor: "not-allowed" } : {}}
              >
                {killLocked ? "🔒 Gesperrt" : "Start"}
              </button>
            )
          }
          {isRun && vm.caddy_subdomain && (
            <button className="btn" onClick={() => onConnect && onConnect(vm)}>Connect</button>
          )}
          {isAdmin && (
            <button className="btn danger" onClick={() => onDelete && onDelete(vm.id)}>Delete</button>
          )}
        </div>
      )}
      {isStarting && (
        <div style={{ padding: "8px 0 4px", fontSize: 12, color: "var(--ink-2)", fontFamily: "var(--mono)" }}>
          VM wird eingerichtet, bitte warten…
        </div>
      )}
    </div>
  );
}

/* ─────────────────────────────────────────────
   GOLDEN VM PANEL (admin only)
───────────────────────────────────────────── */
function GoldenVMPanel({ onRefresh }) {
  const [status, setStatus] = useState(null); // null | "running" | "stopped"
  const [subdomain, setSubdomain] = useState(null);
  const [loading, setLoading] = useState(false);

  const fetchStatus = async () => {
    try {
      const d = await apiFetch("/api/vms/golden/status");
      setStatus(d.status);
      setSubdomain(d.subdomain);
    } catch (_) { setStatus("unknown"); }
  };

  useEffect(() => { fetchStatus(); }, []);

  const act = async (endpoint, msg) => {
    setLoading(true);
    try {
      await apiFetch(endpoint, { method: "POST" });
      toast(msg, "success");
      await fetchStatus();
      onRefresh && onRefresh();
    } catch (e) { toast("Fehler: " + e.message, "error"); }
    finally { setLoading(false); }
  };

  const isRunning = status === "running";

  return (
    <div style={{
      marginBottom: 24,
      padding: "18px 20px",
      border: "1px solid rgba(255,181,71,0.35)",
      borderRadius: 12,
      background: "rgba(255,181,71,0.04)",
      display: "flex", alignItems: "center", gap: 20, flexWrap: "wrap",
    }}>
      {/* Icon + info */}
      <div style={{ display: "flex", alignItems: "center", gap: 12, flex: 1 }}>
        <div style={{
          width: 40, height: 40, borderRadius: 10, fontSize: 20,
          background: "rgba(255,181,71,0.12)", border: "1px solid rgba(255,181,71,0.3)",
          display: "flex", alignItems: "center", justifyContent: "center",
        }}>⭐</div>
        <div>
          <div style={{ fontWeight: 600, color: "#ffb547", fontSize: 14, fontFamily: "var(--mono)", letterSpacing: "0.04em" }}>
            GOLDEN VM TEMPLATE
          </div>
          <div style={{ fontSize: 12, color: "var(--ink-2)", marginTop: 2 }}>
            {status === null ? "Laden…" : isRunning ? "Läuft — Änderungen werden übernommen wenn du speicherst" : "Gestoppt — Starten zum Bearbeiten"}
          </div>
        </div>
      </div>

      {/* Status pill */}
      <div className={"stat-pill " + (isRunning ? "run" : "stop")} style={{ fontSize: 11 }}>
        {status === null ? "…" : isRunning ? "● RUNNING" : "○ STOPPED"}
      </div>

      {/* Actions */}
      <div style={{ display: "flex", gap: 8 }}>
        {!isRunning ? (
          <button
            onClick={() => act("/api/vms/golden/start", "Golden VM wird gestartet…")}
            disabled={loading}
            style={{ ...modalBtn, opacity: loading ? 0.5 : 1, borderColor: "rgba(255,181,71,0.4)", color: "#ffb547" }}
          >
            {loading ? "…" : "▸ Starten"}
          </button>
        ) : (
          <>
            {subdomain && (
              <button
                onClick={() => window.open("https://" + subdomain, "_blank")}
                style={{ ...modalBtn, borderColor: "rgba(94,224,255,0.3)" }}
              >Connect</button>
            )}
            <button
              onClick={() => act("/api/vms/golden/capture", "Golden Image gespeichert!")}
              disabled={loading}
              style={{ ...modalBtn, opacity: loading ? 0.5 : 1, borderColor: "rgba(92,242,160,0.4)", color: "var(--good)" }}
            >
              {loading ? "…" : "💾 Speichern"}
            </button>
            <button
              onClick={async () => {
                if (!window.confirm("Änderungen wirklich verwerfen? Das Image bleibt unverändert.")) return;
                act("/api/vms/golden/stop", "Golden VM gestoppt. Änderungen verworfen.");
              }}
              disabled={loading}
              style={{ ...modalBtn, opacity: loading ? 0.5 : 1, borderColor: "rgba(255,77,109,0.4)", color: "var(--bad)" }}
            >
              {loading ? "…" : "✕ Verwerfen"}
            </button>
          </>
        )}
      </div>
    </div>
  );
}

/* ─────────────────────────────────────────────
   SIDEBAR
───────────────────────────────────────────── */
function Sidebar({ active, setActive, user }) {
  const isAdmin = user && user.is_admin;
  const initials = user && user.full_name ? user.full_name.split(" ").map(w => w[0]).join("").slice(0, 2).toUpperCase() : "??";

  const groups = [
    {
      group: "Übersicht", entries: [
        { id: "dash",     label: "Dashboard",       icon: "grid"   },
        { id: "bots",     label: "Expert Advisors",  icon: "cpu"    },
        { id: "accounts", label: "Accounts",         icon: "wallet" },
        { id: "vms",      label: "Virtual Machines", icon: "server" },
      ]
    },
    ...(isAdmin ? [{
      group: "Admin", entries: [
        { id: "customers", label: "Customers",    icon: "users" },
        { id: "trials",    label: "Free Trials",  icon: "tag"   },
        { id: "auditlog",  label: "Audit Log",    icon: "log"   },
      ]
    }] : []),
  ];

  return (
    <aside className="sidebar">
      <div className="brand">
        <div className="brand-mark">
          <svg viewBox="0 0 24 24" fill="none">
            <path d="M12 3 L4 19 L12 14 L20 19 Z" fill="currentColor" />
          </svg>
        </div>
        <div>
          <div className="brand-name">EA-Commander</div>
          <div className="brand-sub">JARVIS · v2</div>
        </div>
      </div>

      {groups.map(g => (
        <div key={g.group} className="nav-group">
          <div className="nav-label">▸ {g.group}</div>
          {g.entries.map(it => (
            <div key={it.id}
              className={"nav-item" + (active === it.id ? " active" : "")}
              onClick={() => setActive(it.id)}>
              <NavIcon name={it.icon} />
              <span>{it.label}</span>
            </div>
          ))}
        </div>
      ))}

      <div className="user-card" style={{ marginTop: "auto" }}>
        <div className="avatar">{initials}</div>
        <div>
          <div className="user-name">{user ? user.full_name : "Loading..."}</div>
          <div className="user-role">{isAdmin ? "ADMIN · CMDR" : "USER"}</div>
        </div>
      </div>
    </aside>
  );
}

/* ─────────────────────────────────────────────
   MODAL BASE
───────────────────────────────────────────── */
function Modal({ children, onClose, width = 660 }) {
  useEffect(() => {
    const handler = e => { if (e.key === "Escape") onClose(); };
    document.addEventListener("keydown", handler);
    return () => document.removeEventListener("keydown", handler);
  }, [onClose]);

  return (
    <div style={{
      position: "fixed", inset: 0, background: "rgba(0,0,0,0.75)",
      backdropFilter: "blur(8px)", zIndex: 1000,
      display: "flex", alignItems: "center", justifyContent: "center"
    }} onClick={e => { if (e.target === e.currentTarget) onClose(); }}>
      <div style={{
        background: "#0a121c",
        border: "1px solid rgba(94,224,255,0.2)",
        borderRadius: 12,
        width, maxWidth: "95vw",
        maxHeight: "85vh",
        overflow: "hidden",
        display: "flex",
        flexDirection: "column",
        boxShadow: "0 0 60px rgba(94,224,255,0.08)"
      }}>
        {children}
      </div>
    </div>
  );
}

const modalInput = {
  background: "#070b12",
  border: "1px solid rgba(94,224,255,0.15)",
  borderRadius: 6,
  color: "#d8ecff",
  padding: "8px 12px",
  fontSize: 13,
  fontFamily: "var(--mono)",
  width: "100%",
  outline: "none",
};

const modalLabel = {
  fontSize: 11,
  color: "var(--ink-2)",
  fontFamily: "var(--mono)",
  marginBottom: 4,
  display: "block",
  textTransform: "uppercase",
  letterSpacing: "0.06em",
};

const modalBtn = {
  background: "rgba(94,224,255,0.12)",
  border: "1px solid rgba(94,224,255,0.3)",
  borderRadius: 6,
  color: "var(--accent)",
  padding: "9px 20px",
  fontSize: 13,
  fontFamily: "var(--mono)",
  cursor: "pointer",
};

const modalBtnDanger = {
  ...modalBtn,
  background: "rgba(255,77,109,0.12)",
  border: "1px solid rgba(255,77,109,0.3)",
  color: "var(--bad)",
};

/* ─────────────────────────────────────────────
   EA CONFIG MODAL
───────────────────────────────────────────── */
function EAConfigModal({ vmId, onClose }) {
  const [tab, setTab] = useState("risiko");
  const [cfg, setCfg] = useState(null);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);

  useEffect(() => {
    setLoading(true);
    apiFetch(`/api/vms/${vmId}/ea-config`)
      .then(d => {
        if (d && d.ea_config) setCfg(d.ea_config);
        else if (d) setCfg(d);
      })
      .catch(e => toast("Config laden fehlgeschlagen: " + e.message, "error"))
      .finally(() => setLoading(false));
  }, [vmId]);

  const set = (k, v) => setCfg(p => ({ ...p, [k]: v }));

  const save = async () => {
    setSaving(true);
    try {
      await apiFetch(`/api/vms/${vmId}/ea-config`, {
        method: "PATCH",
        body: JSON.stringify({ ea_config: cfg }),
      });
      toast("Konfiguration gespeichert", "success");
      onClose();
    } catch (e) {
      toast("Fehler: " + e.message, "error");
    } finally {
      setSaving(false);
    }
  };

  const TABS = [
    { id: "risiko", label: "Risiko" },
    { id: "strategie", label: "Strategie" },
    { id: "zeiten", label: "Zeiten" },
    { id: "propfirm", label: "Prop Firm" },
  ];

  const WEEKDAYS = [
    { key: "allow_monday",    label: "Mo" },
    { key: "allow_tuesday",   label: "Di" },
    { key: "allow_wednesday", label: "Mi" },
    { key: "allow_thursday",  label: "Do" },
    { key: "allow_friday",    label: "Fr" },
  ];

  const TF_OPTIONS = ["M5", "M15", "M30", "H1", "H2", "H4", "D1", "W1"];
  const TF_OPTIONS2 = ["M1", "M2", "M3", "M4", "M5", "M15", "M30", "H1", "H4", "D1"];

  const FRow = ({ label, children }) => (
    <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
      <label style={modalLabel}>{label}</label>
      {children}
    </div>
  );

  const FNum = ({ k, step = 0.1, min }) => (
    <input type="number" style={modalInput} step={step} min={min}
      value={cfg[k] ?? ""} onChange={e => set(k, parseFloat(e.target.value) || 0)} />
  );

  const FToggle = ({ k, label }) => (
    <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "6px 0" }}>
      <span style={{ fontSize: 13, color: "var(--ink-1)" }}>{label}</span>
      <button type="button" style={{
        width: 36, height: 20, borderRadius: 10,
        background: cfg[k] ? "var(--accent)" : "rgba(94,224,255,0.1)",
        border: "1px solid rgba(94,224,255,0.3)",
        cursor: "pointer", position: "relative", transition: "background 0.2s"
      }} onClick={() => set(k, !cfg[k])}>
        <span style={{
          position: "absolute", top: 2, left: cfg[k] ? 18 : 2,
          width: 14, height: 14, borderRadius: "50%",
          background: cfg[k] ? "#0a121c" : "var(--ink-2)",
          transition: "left 0.2s"
        }} />
      </button>
    </div>
  );

  const grid2 = { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 };
  const grid3 = { display: "grid", gridTemplateColumns: "1fr 1fr 1fr", gap: 12 };

  return (
    <Modal onClose={onClose} width={700}>
      <div style={{ padding: "20px 24px 16px", borderBottom: "1px solid rgba(94,224,255,0.1)" }}>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
          <div>
            <div style={{ fontSize: 16, fontWeight: 600, color: "var(--ink-0)", fontFamily: "var(--mono)" }}>
              EA Konfiguration
            </div>
            <div style={{ fontSize: 12, color: "var(--ink-2)", marginTop: 2 }}>
              VM-ID: {vmId}{cfg && cfg.version ? ` · v${cfg.version}` : ""}
            </div>
          </div>
          <button onClick={onClose} style={{ background: "none", border: "none", color: "var(--ink-2)", fontSize: 18, cursor: "pointer" }}>✕</button>
        </div>
        <div style={{ display: "flex", gap: 4, marginTop: 16 }}>
          {TABS.map(t => (
            <button key={t.id} onClick={() => setTab(t.id)} style={{
              padding: "6px 16px", borderRadius: 6, fontSize: 12,
              fontFamily: "var(--mono)", cursor: "pointer",
              background: tab === t.id ? "rgba(94,224,255,0.15)" : "transparent",
              border: tab === t.id ? "1px solid rgba(94,224,255,0.4)" : "1px solid transparent",
              color: tab === t.id ? "var(--accent)" : "var(--ink-2)",
            }}>{t.label}</button>
          ))}
        </div>
      </div>

      <div style={{ padding: "20px 24px", overflowY: "auto", flex: 1 }}>
        {loading ? (
          <div style={{ textAlign: "center", padding: 40, color: "var(--ink-2)", fontFamily: "var(--mono)" }}>
            Laden...
          </div>
        ) : !cfg ? (
          <div style={{ textAlign: "center", padding: 40, color: "var(--bad)", fontFamily: "var(--mono)" }}>
            Konfiguration nicht verfügbar
          </div>
        ) : (
          <>
            {tab === "risiko" && (
              <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
                <div style={grid3}>
                  <FRow label="Risiko / Trade (%)"><FNum k="risk_per_trade" step={0.1} /></FRow>
                  <FRow label="Daily Loss Limit (%)"><FNum k="daily_loss_limit" step={0.1} /></FRow>
                  <FRow label="Weekly Loss Limit (%)"><FNum k="weekly_loss_limit" step={0.1} /></FRow>
                </div>
                <div style={grid3}>
                  <FRow label="Stop Loss (Pips)"><FNum k="stop_loss_pips" step={1} min={0} /></FRow>
                  <FRow label="TP1 RR"><FNum k="tp1_rr" step={0.1} /></FRow>
                  <FRow label="TP2 RR"><FNum k="tp2_rr" step={0.1} /></FRow>
                </div>
                <div style={grid3}>
                  <FRow label="TP3 RR"><FNum k="tp3_rr" step={0.1} /></FRow>
                  <FRow label="Buffer EMA"><FNum k="buffer_ema" step={1} min={0} /></FRow>
                  <div />
                </div>
                <div style={{ fontSize: 11, color: "var(--ink-2)", fontFamily: "var(--mono)", paddingTop: 4 }}>
                  ▸ Teilschließungen
                </div>
                <div style={grid2}>
                  <FRow label="Part 1 (%)"><FNum k="part1_pct" step={1} min={0} /></FRow>
                  <FRow label="Part 2 (%)"><FNum k="part2_pct" step={1} min={0} /></FRow>
                  <FRow label="Part 3 (%)"><FNum k="part3_pct" step={1} min={0} /></FRow>
                  <FRow label="Part 4 (%)"><FNum k="part4_pct" step={1} min={0} /></FRow>
                </div>
              </div>
            )}

            {tab === "strategie" && (
              <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
                <div style={grid3}>
                  <FRow label="MA Fast"><FNum k="ma_fast" step={1} min={1} /></FRow>
                  <FRow label="MA Slow"><FNum k="ma_slow" step={1} min={1} /></FRow>
                  <FRow label="ATR Periode"><FNum k="atr_period" step={1} min={1} /></FRow>
                </div>
                <div style={grid3}>
                  <FRow label="ATR Schwelle"><FNum k="atr_threshold" step={0.01} /></FRow>
                  <div />
                  <div />
                </div>
                <div style={{ borderTop: "1px solid rgba(94,224,255,0.08)", paddingTop: 12 }}>
                  <FToggle k="enable_htf" label="Higher Timeframe aktivieren" />
                  {cfg.enable_htf && (
                    <div style={{ ...grid3, marginTop: 12 }}>
                      <FRow label="HTF Timeframe">
                        <select style={modalInput} value={cfg.htf_timeframe || "H1"}
                          onChange={e => set("htf_timeframe", e.target.value)}>
                          {TF_OPTIONS.map(t => <option key={t} value={t}>{t}</option>)}
                        </select>
                      </FRow>
                      <FRow label="HTF Lookback"><FNum k="htf_lookback" step={1} min={1} /></FRow>
                      <FRow label="HTF Schwelle"><FNum k="htf_threshold" step={0.01} /></FRow>
                    </div>
                  )}
                </div>
                <div style={{ borderTop: "1px solid rgba(94,224,255,0.08)", paddingTop: 12 }}>
                  <FToggle k="use_robust_method" label="Robuste Methode verwenden" />
                  <FToggle k="allow_neutral_trend" label="Neutralen Trend erlauben" />
                </div>
              </div>
            )}

            {tab === "zeiten" && (
              <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
                <div style={grid3}>
                  <FRow label="Start Stunde"><FNum k="start_hour" step={1} min={0} /></FRow>
                  <FRow label="End Stunde"><FNum k="end_hour" step={1} min={0} /></FRow>
                  <div />
                </div>
                <div style={{ borderTop: "1px solid rgba(94,224,255,0.08)", paddingTop: 12 }}>
                  <FToggle k="friday_close" label="Freitag automatisch schließen" />
                  <FToggle k="avoid_news" label="News-Zeiten meiden" />
                </div>
                <div>
                  <div style={modalLabel}>Handelstage</div>
                  <div style={{ display: "flex", gap: 8, marginTop: 6 }}>
                    {WEEKDAYS.map(w => (
                      <button key={w.key} type="button" onClick={() => set(w.key, !cfg[w.key])} style={{
                        padding: "8px 16px", borderRadius: 6, fontSize: 13,
                        fontFamily: "var(--mono)", cursor: "pointer",
                        background: cfg[w.key] ? "rgba(94,224,255,0.18)" : "rgba(94,224,255,0.04)",
                        border: cfg[w.key] ? "1px solid rgba(94,224,255,0.5)" : "1px solid rgba(94,224,255,0.1)",
                        color: cfg[w.key] ? "var(--accent)" : "var(--ink-2)",
                        transition: "all 0.15s"
                      }}>{w.label}</button>
                    ))}
                  </div>
                </div>
              </div>
            )}

            {tab === "propfirm" && (
              <div style={{ display: "flex", flexDirection: "column", gap: 14 }}>
                <div>
                  <FToggle k="enable_random" label="Random-Faktor aktivieren" />
                  {cfg.enable_random && (
                    <div style={{ marginTop: 12 }}>
                      <FRow label="Random Faktor"><FNum k="random_factor" step={0.01} /></FRow>
                    </div>
                  )}
                </div>
                <div style={{ borderTop: "1px solid rgba(94,224,255,0.08)", paddingTop: 12 }}>
                  <div style={grid2}>
                    <FRow label="Target Equity">
                      <input type="number" style={modalInput} step={100} min={0}
                        value={cfg.target_equity ?? ""} onChange={e => set("target_equity", parseFloat(e.target.value) || 0)} />
                    </FRow>
                    <div />
                  </div>
                </div>
                <div style={{ borderTop: "1px solid rgba(94,224,255,0.08)", paddingTop: 12 }}>
                  <div style={grid2}>
                    <FRow label="Symbol">
                      <input type="text" style={modalInput}
                        value={cfg.symbol || ""} onChange={e => set("symbol", e.target.value)} />
                    </FRow>
                    <FRow label="Timeframe">
                      <select style={modalInput} value={cfg.timeframe || "M15"}
                        onChange={e => set("timeframe", e.target.value)}>
                        {TF_OPTIONS2.map(t => <option key={t} value={t}>{t}</option>)}
                      </select>
                    </FRow>
                  </div>
                </div>
              </div>
            )}
          </>
        )}
      </div>

      <div style={{ padding: "16px 24px", borderTop: "1px solid rgba(94,224,255,0.1)", display: "flex", justifyContent: "flex-end", gap: 10 }}>
        <button onClick={onClose} style={{ ...modalBtn, background: "transparent", color: "var(--ink-2)", border: "1px solid rgba(94,224,255,0.1)" }}>
          Abbrechen
        </button>
        <button onClick={save} disabled={saving || loading} style={{ ...modalBtn, opacity: (saving || loading) ? 0.5 : 1 }}>
          {saving ? "Speichern..." : "Speichern"}
        </button>
      </div>
    </Modal>
  );
}

/* ─────────────────────────────────────────────
   SPAWN VM MODAL
───────────────────────────────────────────── */
function SpawnVMModal({ customers, isAdmin, onClose, onSpawned }) {
  const [form, setForm] = useState({ customer_id: "", mt5_login: "", mt5_password: "", vm_type: "standard" });
  const [loading, setLoading] = useState(false);

  const set = (k, v) => setForm(p => ({ ...p, [k]: v }));

  const submit = async () => {
    if (!form.mt5_login || !form.mt5_password) {
      toast("MT5 Login und Passwort erforderlich", "warn");
      return;
    }
    setLoading(true);
    try {
      const body = { ...form };
      if (body.customer_id) body.customer_id = parseInt(body.customer_id);
      else delete body.customer_id;
      await apiFetch("/api/vms/spawn", { method: "POST", body: JSON.stringify(body) });
      toast("VM wird gestartet…", "success");
      onSpawned && onSpawned();
      onClose();
    } catch (e) {
      toast("Fehler: " + e.message, "error");
    } finally {
      setLoading(false);
    }
  };

  return (
    <Modal onClose={onClose} width={480}>
      <div style={{ padding: "20px 24px 16px", borderBottom: "1px solid rgba(94,224,255,0.1)" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
          <span style={{ fontSize: 16, fontWeight: 600, color: "var(--ink-0)", fontFamily: "var(--mono)" }}>VM Starten</span>
          <button onClick={onClose} style={{ background: "none", border: "none", color: "var(--ink-2)", fontSize: 18, cursor: "pointer" }}>✕</button>
        </div>
      </div>
      <div style={{ padding: "20px 24px", display: "flex", flexDirection: "column", gap: 14 }}>
        {isAdmin && customers && customers.length > 0 && (
          <div>
            <label style={modalLabel}>Customer</label>
            <select style={modalInput} value={form.customer_id} onChange={e => set("customer_id", e.target.value)}>
              <option value="">— Kein Customer —</option>
              {customers.map(c => <option key={c.id} value={c.id}>{c.name}</option>)}
            </select>
          </div>
        )}
        <div>
          <label style={modalLabel}>VM Typ</label>
          <div style={{ display: "flex", gap: 8 }}>
            {[
              { value: "standard", label: "Standard", icon: "🖥", desc: "1 Account" },
              { value: "golden",   label: "Golden",   icon: "⭐", desc: "Multi-Account" },
            ].map(opt => (
              <button
                key={opt.value}
                type="button"
                onClick={() => set("vm_type", opt.value)}
                style={{
                  flex: 1, padding: "10px 12px", cursor: "pointer", textAlign: "left",
                  border: `1px solid ${form.vm_type === opt.value ? "var(--accent)" : "rgba(94,224,255,0.15)"}`,
                  borderRadius: 8,
                  background: form.vm_type === opt.value ? "rgba(94,224,255,0.1)" : "rgba(94,224,255,0.03)",
                  color: form.vm_type === opt.value ? "var(--accent)" : "var(--ink-1)",
                  transition: "all 0.15s",
                }}
              >
                <div style={{ fontSize: 18, marginBottom: 4 }}>{opt.icon}</div>
                <div style={{ fontWeight: 600, fontSize: 13 }}>{opt.label}</div>
                <div style={{ fontSize: 11, color: "var(--ink-3)", fontFamily: "var(--mono)" }}>{opt.desc}</div>
              </button>
            ))}
          </div>
        </div>
        <div>
          <label style={modalLabel}>MT5 Login</label>
          <input type="text" style={modalInput} value={form.mt5_login} onChange={e => set("mt5_login", e.target.value)} placeholder="z.B. 12345678" />
        </div>
        <div>
          <label style={modalLabel}>MT5 Passwort</label>
          <input type="password" style={modalInput} value={form.mt5_password} onChange={e => set("mt5_password", e.target.value)} placeholder="••••••••" />
        </div>
      </div>
      <div style={{ padding: "16px 24px", borderTop: "1px solid rgba(94,224,255,0.1)", display: "flex", justifyContent: "flex-end", gap: 10 }}>
        <button onClick={onClose} style={{ ...modalBtn, background: "transparent", color: "var(--ink-2)", border: "1px solid rgba(94,224,255,0.1)" }}>Abbrechen</button>
        <button onClick={submit} disabled={loading} style={{ ...modalBtn, opacity: loading ? 0.5 : 1 }}>{loading ? "Starten..." : "VM Starten"}</button>
      </div>
    </Modal>
  );
}

/* ─────────────────────────────────────────────
   KILL SWITCH MODAL
───────────────────────────────────────────── */
function KillSwitchModal({ onClose, onDone }) {
  const [loading, setLoading] = useState(false);
  const [confirmed, setConfirmed] = useState(false);
  const [lockStatus, setLockStatus] = useState(null); // null | {locked, locked_until}

  useEffect(() => {
    apiFetch("/api/vms/kill-switch/status")
      .then(d => setLockStatus(d))
      .catch(() => {});
  }, []);

  const execute = async () => {
    setLoading(true);
    try {
      const res = await apiFetch("/api/vms/kill-switch", { method: "POST" });
      toast(`Kill Switch aktiviert — ${res.stopped} VM(s) gestoppt. Neustart ab 00:00 Uhr.`, "warn");
      onDone && onDone();
      onClose();
    } catch (e) {
      toast("Fehler: " + e.message, "error");
    } finally {
      setLoading(false);
    }
  };

  const isLocked = lockStatus && lockStatus.locked;
  const lockedUntil = lockStatus && lockStatus.locked_until
    ? new Date(lockStatus.locked_until).toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" })
    : "00:00";

  return (
    <Modal onClose={onClose} width={440}>
      <div style={{ padding: "28px 24px", textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center", gap: 18 }}>
        <div style={{
          width: 72, height: 72, borderRadius: "50%",
          background: "rgba(255,77,109,0.15)", border: "2px solid rgba(255,77,109,0.4)",
          display: "flex", alignItems: "center", justifyContent: "center", fontSize: 32,
          boxShadow: "0 0 40px rgba(255,77,109,0.2)",
        }}>⚡</div>

        <div>
          <div style={{ fontSize: 18, fontWeight: 700, color: "var(--bad)", fontFamily: "var(--mono)", letterSpacing: "0.06em" }}>
            KILL SWITCH
          </div>
          {isLocked ? (
            <div style={{ fontSize: 13, color: "var(--ink-1)", marginTop: 10, lineHeight: 1.7 }}>
              <div style={{ color: "var(--warn)", fontFamily: "var(--mono)", fontSize: 12, marginBottom: 8 }}>
                ⚠ Kill Switch ist aktiv
              </div>
              Deine VMs sind gesperrt bis<br />
              <strong style={{ color: "var(--accent)", fontSize: 18 }}>{lockedUntil} Uhr</strong>
            </div>
          ) : (
            <div style={{ fontSize: 13, color: "var(--ink-1)", marginTop: 10, lineHeight: 1.7 }}>
              Stoppt <strong>alle deine laufenden VMs</strong> sofort.<br />
              <span style={{ color: "var(--warn)" }}>VMs können erst wieder um <strong>00:00 Uhr</strong> gestartet werden.</span>
            </div>
          )}
        </div>

        {!isLocked && (
          <label style={{ display: "flex", alignItems: "center", gap: 10, fontSize: 13, color: "var(--ink-1)", cursor: "pointer" }}>
            <input type="checkbox" checked={confirmed} onChange={e => setConfirmed(e.target.checked)}
              style={{ accentColor: "var(--bad)", width: 16, height: 16 }} />
            Ich bestätige: alle VMs stoppen bis 00:00 Uhr
          </label>
        )}
      </div>

      <div style={{ padding: "16px 24px", borderTop: "1px solid rgba(255,77,109,0.15)", display: "flex", justifyContent: "center", gap: 10 }}>
        <button onClick={onClose} style={{ ...modalBtn, background: "transparent", color: "var(--ink-2)", border: "1px solid rgba(94,224,255,0.1)" }}>
          {isLocked ? "Schließen" : "Abbrechen"}
        </button>
        {!isLocked && (
          <button onClick={execute} disabled={!confirmed || loading} style={{
            ...modalBtnDanger,
            opacity: (!confirmed || loading) ? 0.4 : 1,
            cursor: (!confirmed || loading) ? "not-allowed" : "pointer",
          }}>
            {loading ? "Stoppe..." : "⚡ ALLE VMs STOPPEN"}
          </button>
        )}
      </div>
    </Modal>
  );
}

/* ─────────────────────────────────────────────
   CUSTOMER MODAL
───────────────────────────────────────────── */
function CustomerModal({ customer, onClose, onSaved }) {
  const isEdit = !!customer;
  const [form, setForm] = useState({
    name: customer?.name || "",
    license_key: customer?.license_key || "",
    email: customer?.email || "",
    max_accounts: customer?.max_accounts || 1,
    is_active: customer?.is_active !== false,
  });
  const [loading, setLoading] = useState(false);

  const set = (k, v) => setForm(p => ({ ...p, [k]: v }));

  const submit = async () => {
    if (!form.name) { toast("Name erforderlich", "warn"); return; }
    setLoading(true);
    try {
      if (isEdit) {
        await apiFetch(`/api/customers/${customer.id}`, { method: "PATCH", body: JSON.stringify(form) });
        toast("Customer aktualisiert", "success");
      } else {
        await apiFetch("/api/customers", { method: "POST", body: JSON.stringify(form) });
        toast("Customer erstellt", "success");
      }
      onSaved && onSaved();
      onClose();
    } catch (e) {
      toast("Fehler: " + e.message, "error");
    } finally {
      setLoading(false);
    }
  };

  return (
    <Modal onClose={onClose} width={480}>
      <div style={{ padding: "20px 24px 16px", borderBottom: "1px solid rgba(94,224,255,0.1)" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
          <span style={{ fontSize: 16, fontWeight: 600, color: "var(--ink-0)", fontFamily: "var(--mono)" }}>
            {isEdit ? "Customer bearbeiten" : "Neuer Customer"}
          </span>
          <button onClick={onClose} style={{ background: "none", border: "none", color: "var(--ink-2)", fontSize: 18, cursor: "pointer" }}>✕</button>
        </div>
      </div>
      <div style={{ padding: "20px 24px", display: "flex", flexDirection: "column", gap: 14 }}>
        <div>
          <label style={modalLabel}>Name</label>
          <input type="text" style={modalInput} value={form.name} onChange={e => set("name", e.target.value)} />
        </div>
        <div>
          <label style={modalLabel}>E-Mail</label>
          <input type="email" style={modalInput} value={form.email} onChange={e => set("email", e.target.value)} />
        </div>
        <div>
          <label style={modalLabel}>License Key</label>
          <input type="text" style={modalInput} value={form.license_key} onChange={e => set("license_key", e.target.value)} placeholder="Wird automatisch generiert wenn leer" />
        </div>
        <div>
          <label style={modalLabel}>Max Accounts</label>
          <input type="number" style={modalInput} min={1} value={form.max_accounts} onChange={e => set("max_accounts", parseInt(e.target.value) || 1)} />
        </div>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
          <span style={{ fontSize: 13, color: "var(--ink-1)", fontFamily: "var(--mono)" }}>Aktiv</span>
          <button type="button" onClick={() => set("is_active", !form.is_active)} style={{
            width: 36, height: 20, borderRadius: 10,
            background: form.is_active ? "var(--accent)" : "rgba(94,224,255,0.1)",
            border: "1px solid rgba(94,224,255,0.3)",
            cursor: "pointer", position: "relative", transition: "background 0.2s"
          }}>
            <span style={{
              position: "absolute", top: 2, left: form.is_active ? 18 : 2,
              width: 14, height: 14, borderRadius: "50%",
              background: form.is_active ? "#0a121c" : "var(--ink-2)",
              transition: "left 0.2s"
            }} />
          </button>
        </div>
      </div>
      <div style={{ padding: "16px 24px", borderTop: "1px solid rgba(94,224,255,0.1)", display: "flex", justifyContent: "flex-end", gap: 10 }}>
        <button onClick={onClose} style={{ ...modalBtn, background: "transparent", color: "var(--ink-2)", border: "1px solid rgba(94,224,255,0.1)" }}>Abbrechen</button>
        <button onClick={submit} disabled={loading} style={{ ...modalBtn, opacity: loading ? 0.5 : 1 }}>{loading ? "Speichern..." : "Speichern"}</button>
      </div>
    </Modal>
  );
}

/* ─────────────────────────────────────────────
   TRIAL CAMPAIGN MODAL
───────────────────────────────────────────── */
function TrialModal({ campaign, onClose, onSaved }) {
  const isEdit = !!campaign;
  const [form, setForm] = useState({
    name: campaign?.name || "",
    slots_total: campaign?.slots_total || 10,
    trial_days: campaign?.trial_days || 14,
    trial_max_accounts: campaign?.trial_max_accounts || 1,
    signup_deadline: campaign?.signup_deadline ? campaign.signup_deadline.slice(0, 10) : "",
    is_active: campaign?.is_active !== false,
  });
  const [loading, setLoading] = useState(false);
  const set = (k, v) => setForm(p => ({ ...p, [k]: v }));

  const submit = async () => {
    if (!form.name) { toast("Name erforderlich", "warn"); return; }
    setLoading(true);
    try {
      const body = { ...form, slots_total: parseInt(form.slots_total), trial_days: parseInt(form.trial_days), trial_max_accounts: parseInt(form.trial_max_accounts) };
      if (isEdit) {
        await apiFetch(`/api/admin/trial-campaigns/${campaign.id}`, { method: "PATCH", body: JSON.stringify(body) });
        toast("Kampagne aktualisiert", "success");
      } else {
        await apiFetch("/api/admin/trial-campaigns", { method: "POST", body: JSON.stringify(body) });
        toast("Kampagne erstellt", "success");
      }
      onSaved && onSaved();
      onClose();
    } catch (e) {
      toast("Fehler: " + e.message, "error");
    } finally {
      setLoading(false);
    }
  };

  return (
    <Modal onClose={onClose} width={480}>
      <div style={{ padding: "20px 24px 16px", borderBottom: "1px solid rgba(94,224,255,0.1)" }}>
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
          <span style={{ fontSize: 16, fontWeight: 600, color: "var(--ink-0)", fontFamily: "var(--mono)" }}>
            {isEdit ? "Kampagne bearbeiten" : "Neue Kampagne"}
          </span>
          <button onClick={onClose} style={{ background: "none", border: "none", color: "var(--ink-2)", fontSize: 18, cursor: "pointer" }}>✕</button>
        </div>
      </div>
      <div style={{ padding: "20px 24px", display: "flex", flexDirection: "column", gap: 14 }}>
        <div>
          <label style={modalLabel}>Kampagnenname</label>
          <input type="text" style={modalInput} value={form.name} onChange={e => set("name", e.target.value)} />
        </div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 12 }}>
          <div>
            <label style={modalLabel}>Slots gesamt</label>
            <input type="number" style={modalInput} min={1} value={form.slots_total} onChange={e => set("slots_total", e.target.value)} />
          </div>
          <div>
            <label style={modalLabel}>Trial Tage</label>
            <input type="number" style={modalInput} min={1} value={form.trial_days} onChange={e => set("trial_days", e.target.value)} />
          </div>
        </div>
        <div>
          <label style={modalLabel}>Max Accounts / Trial</label>
          <input type="number" style={modalInput} min={1} value={form.trial_max_accounts} onChange={e => set("trial_max_accounts", e.target.value)} />
        </div>
        <div>
          <label style={modalLabel}>Anmelde-Deadline</label>
          <input type="date" style={modalInput} value={form.signup_deadline} onChange={e => set("signup_deadline", e.target.value)} />
        </div>
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
          <span style={{ fontSize: 13, color: "var(--ink-1)", fontFamily: "var(--mono)" }}>Aktiv</span>
          <button type="button" onClick={() => set("is_active", !form.is_active)} style={{
            width: 36, height: 20, borderRadius: 10,
            background: form.is_active ? "var(--accent)" : "rgba(94,224,255,0.1)",
            border: "1px solid rgba(94,224,255,0.3)",
            cursor: "pointer", position: "relative", transition: "background 0.2s"
          }}>
            <span style={{
              position: "absolute", top: 2, left: form.is_active ? 18 : 2,
              width: 14, height: 14, borderRadius: "50%",
              background: form.is_active ? "#0a121c" : "var(--ink-2)",
              transition: "left 0.2s"
            }} />
          </button>
        </div>
      </div>
      <div style={{ padding: "16px 24px", borderTop: "1px solid rgba(94,224,255,0.1)", display: "flex", justifyContent: "flex-end", gap: 10 }}>
        <button onClick={onClose} style={{ ...modalBtn, background: "transparent", color: "var(--ink-2)", border: "1px solid rgba(94,224,255,0.1)" }}>Abbrechen</button>
        <button onClick={submit} disabled={loading} style={{ ...modalBtn, opacity: loading ? 0.5 : 1 }}>{loading ? "Speichern..." : "Speichern"}</button>
      </div>
    </Modal>
  );
}

/* ─────────────────────────────────────────────
   LOGIN PAGE
───────────────────────────────────────────── */
function LoginPage({ onLogin }) {
  const [telegramId, setTelegramId] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);
  const tgRef = useRef(null);

  // Inject Telegram Login Widget script once on mount
  useEffect(() => {
    window.onTelegramAuth = async (user) => {
      setLoading(true);
      setError("");
      try {
        const data = await apiFetch("/api/auth/telegram", {
          method: "POST",
          body: JSON.stringify(user),
        });
        if (data && data.access_token) {
          localStorage.setItem("jwt", data.access_token);
          onLogin(data.access_token);
        } else {
          setError("Telegram Login fehlgeschlagen.");
        }
      } catch (e) {
        setError(e.message || "Kein Zugang. Bitte abonniere EA Commander.");
      } finally {
        setLoading(false);
      }
    };

    if (tgRef.current && tgRef.current.childNodes.length === 0) {
      const s = document.createElement("script");
      s.src = "https://telegram.org/js/telegram-widget.js?22";
      s.setAttribute("data-telegram-login", "NQBladeBladebot");
      s.setAttribute("data-size", "large");
      s.setAttribute("data-radius", "8");
      s.setAttribute("data-onauth", "onTelegramAuth(user)");
      s.setAttribute("data-request-access", "write");
      s.async = true;
      tgRef.current.appendChild(s);
    }

    return () => { delete window.onTelegramAuth; };
  }, []);

  const submit = async e => {
    e.preventDefault();
    if (!telegramId || !password) { setError("Bitte alle Felder ausfüllen."); return; }
    setLoading(true);
    setError("");
    try {
      const data = await apiFetch("/api/auth/login", {
        method: "POST",
        body: JSON.stringify({ telegram_id: parseInt(telegramId), password }),
      });
      if (data && data.access_token) {
        localStorage.setItem("jwt", data.access_token);
        onLogin(data.access_token);
      } else {
        setError("Login fehlgeschlagen.");
      }
    } catch (e) {
      setError(e.message || "Login fehlgeschlagen.");
    } finally {
      setLoading(false);
    }
  };

  return (
    <div style={{
      minHeight: "100vh", display: "flex", alignItems: "center", justifyContent: "center",
      background: "radial-gradient(1200px 600px at 60% 30%, rgba(94,224,255,0.07), transparent 60%), var(--bg-0)",
      fontFamily: "var(--sans)"
    }}>
      <div style={{
        width: 380, padding: "40px 36px",
        background: "rgba(10,18,28,0.85)",
        border: "1px solid rgba(94,224,255,0.15)",
        borderRadius: 16,
        backdropFilter: "blur(16px)",
        boxShadow: "0 0 80px rgba(94,224,255,0.06)",
      }}>
        {/* Brand */}
        <div style={{ display: "flex", alignItems: "center", gap: 14, marginBottom: 36 }}>
          <div style={{
            width: 44, height: 44, borderRadius: 11,
            background: "radial-gradient(circle at 30% 30%, var(--accent) 0%, #00b4d8 50%, #0a3a4a 100%)",
            boxShadow: "0 0 24px rgba(94,224,255,0.4)",
            display: "flex", alignItems: "center", justifyContent: "center"
          }}>
            <svg viewBox="0 0 24 24" fill="none" width="22" height="22" style={{ color: "#0a121c" }}>
              <path d="M12 3 L4 19 L12 14 L20 19 Z" fill="currentColor" />
            </svg>
          </div>
          <div>
            <div style={{ fontSize: 18, fontWeight: 700, color: "var(--ink-0)", letterSpacing: "-0.02em" }}>EA-Commander</div>
            <div style={{ fontSize: 11, color: "var(--ink-2)", fontFamily: "var(--mono)", letterSpacing: "0.08em" }}>JARVIS · OPERATIONS</div>
          </div>
        </div>

        {/* Telegram Login Widget */}
        <div style={{ display: "flex", flexDirection: "column", alignItems: "center", marginBottom: 24 }}>
          <div ref={tgRef} style={{ display: "flex", justifyContent: "center" }} />
          <div style={{ fontSize: 11, color: "var(--ink-3)", fontFamily: "var(--mono)", marginTop: 10 }}>
            Direkt mit deinem Telegram-Account anmelden
          </div>
        </div>

        {/* Divider */}
        <div style={{ display: "flex", alignItems: "center", gap: 12, marginBottom: 20 }}>
          <div style={{ flex: 1, height: 1, background: "rgba(94,224,255,0.1)" }} />
          <span style={{ fontSize: 11, color: "var(--ink-3)", fontFamily: "var(--mono)", letterSpacing: "0.08em" }}>ODER</span>
          <div style={{ flex: 1, height: 1, background: "rgba(94,224,255,0.1)" }} />
        </div>

        {/* Password fallback form */}
        <form onSubmit={submit} style={{ display: "flex", flexDirection: "column", gap: 16 }}>
          <div>
            <label style={modalLabel}>Telegram ID</label>
            <input
              type="number"
              style={{ ...modalInput, fontSize: 14 }}
              placeholder="12345678"
              value={telegramId}
              onChange={e => setTelegramId(e.target.value)}
            />
          </div>
          <div>
            <label style={modalLabel}>Passwort</label>
            <input
              type="password"
              style={{ ...modalInput, fontSize: 14 }}
              placeholder="••••••••"
              value={password}
              onChange={e => setPassword(e.target.value)}
            />
          </div>

          {error && (
            <div style={{
              background: "rgba(255,77,109,0.1)", border: "1px solid rgba(255,77,109,0.3)",
              borderRadius: 6, padding: "10px 14px", fontSize: 13, color: "var(--bad)",
              fontFamily: "var(--mono)"
            }}>{error}</div>
          )}

          <button type="submit" disabled={loading} style={{
            marginTop: 4, padding: "12px 0",
            background: loading ? "rgba(94,224,255,0.08)" : "rgba(94,224,255,0.14)",
            border: "1px solid rgba(94,224,255,0.35)",
            borderRadius: 8, color: "var(--accent)",
            fontSize: 14, fontFamily: "var(--mono)",
            cursor: loading ? "not-allowed" : "pointer",
            letterSpacing: "0.06em",
            transition: "all 0.15s"
          }}>
            {loading ? "VERBINDEN..." : "▸ LOGIN"}
          </button>
        </form>

        <div style={{ marginTop: 24, textAlign: "center", fontSize: 11, color: "var(--ink-3)", fontFamily: "var(--mono)" }}>
          EA-Commander · Secure Operations Panel
        </div>
      </div>
    </div>
  );
}

/* ─────────────────────────────────────────────
   DASHBOARD PAGE
───────────────────────────────────────────── */
function DashboardPage({ accounts, kpis, bots, vms, dailyPnl, customers, accent, user, onShowKill, onEaConfig }) {
  const [range, setRange] = useState("30D");
  const isAdmin = user && user.is_admin;

  // KPI field names match the backend response exactly
  const totalEquity = kpis ? kpis.total_equity   : accounts.reduce((s, a) => s + (a.equity || 0), 0);
  const totalFloat  = kpis ? kpis.floating_pl    : accounts.reduce((s, a) => s + (a.floating_pl || 0), 0);
  const dailyPnlVal = kpis ? kpis.daily_pl       : accounts.reduce((s, a) => s + (a.daily_pl || 0), 0);
  const maxDD       = kpis ? kpis.max_dd_today   : 0;
  const runBots     = kpis ? kpis.bots_running   : bots.length;
  const pf          = kpis ? kpis.profit_factor  : 0;
  const wr          = kpis ? kpis.win_rate       : 0;

  // Sparklines from real daily-pnl data (or empty if no data yet)
  const sparkEquity = useMemo(() => {
    if (dailyPnl && dailyPnl.length >= 2) {
      let cum = totalEquity - dailyPnl.reduce((s, d) => s + (d.pnl || 0), 0);
      return dailyPnl.map(d => { cum += (d.pnl || 0); return cum; });
    }
    return accounts.length ? [totalEquity * 0.98, totalEquity * 0.99, totalEquity] : [];
  }, [dailyPnl, totalEquity, accounts]);

  const sparkPnl = useMemo(() => {
    if (dailyPnl && dailyPnl.length >= 2) return dailyPnl.map(d => d.pnl || 0);
    return [];
  }, [dailyPnl]);

  const sparkDD = useMemo(() => {
    if (accounts.length) return accounts.map(a => a.max_dd_today || 0);
    return [];
  }, [accounts]);

  // On the dashboard always show only the logged-in user's own accounts,
  // even if user is admin (admin can use the Accounts page for all accounts).
  const myCustomerId = user && user.customer ? user.customer.id : null;
  const myAccounts = myCustomerId
    ? accounts.filter(a => a.customer_id === myCustomerId)
    : accounts;

  const accountsForDD = myAccounts.slice().sort((a, b) => (b.max_dd_today || 0) - (a.max_dd_today || 0)).slice(0, 4);

  return (
    <>
      <div className="topbar">
        <div className="title-block">
          <div className="eyebrow">▸ Live Operations</div>
          <h1>
            Dashboard
            <span className="ts"><span className="dot"></span>{accounts.length} Accounts</span>
          </h1>
        </div>
        <div className="session">
          <div className="stat-mini"><span className="l">Bots</span><span className="v" style={{ color: "var(--good)" }}>{runBots}</span></div>
          <div className="sep"></div>
          <div className="stat-mini"><span className="l">Equity</span><span className="v">{fmtMoney(totalEquity)}</span></div>
          <div className="sep"></div>
          <div className="stat-mini"><span className="l">Today</span><span className="v" style={{ color: dailyPnlVal >= 0 ? "var(--good)" : "var(--bad)" }}>{fmtMoney(dailyPnlVal, true)}</span></div>
        </div>
        <button className="kill" onClick={onShowKill}>
          <span className="ico"></span>
          Kill Switch
        </button>
      </div>

      <Ticker />

      <div className="hero">
        <div className="card equity-card card-corners">
          <span className="corner-tr"></span><span className="corner-bl"></span>
          <div className="equity-head">
            <div className="equity-total">
              <div className="lbl">▸ Total Equity</div>
              <div className="v flicker">
                <span className="cur">$</span>
                {totalEquity.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
              </div>
              <div className="delta">
                <span className={totalFloat >= 0 ? "pos" : "neg"}>{fmtMoney(totalFloat, true)} floating</span>
                <span className={dailyPnlVal >= 0 ? "pos" : "neg"}>{fmtMoney(dailyPnlVal, true)} today</span>
              </div>
            </div>
            <div className="equity-stats">
              <div className="item"><div className="l">PF</div><div className="v pos">{(pf || 0).toFixed(2)}</div></div>
              <div className="item"><div className="l">Win</div><div className="v pos">{(wr || 0).toFixed(1)}%</div></div>
              <div className="item"><div className="l">MaxDD</div><div className="v" style={{ color: maxDD > 5 ? "var(--bad)" : maxDD > 2.5 ? "var(--warn)" : "var(--good)" }}>{(maxDD || 0).toFixed(1)}%</div></div>
            </div>
          </div>
          <EquityChart data={dailyPnl} accent={accent} currentEquity={totalEquity} />
          <div className="range-tabs">
            {["7D", "14D", "30D", "90D", "ALL"].map(r => (
              <div key={r} className={"range-tab" + (range === r ? " active" : "")}
                onClick={() => setRange(r)}>{r}</div>
            ))}
          </div>
        </div>

        <div className="card side-card card-corners">
          <span className="corner-tr"></span><span className="corner-bl"></span>
          <h3>▸ Risk Console</h3>
          <div className="dial-row">
            <Dial value={pf || 0} max={5} label="Profit Factor" suffix="" color="var(--accent)" />
            <Dial value={wr || 0} label="Win Rate" color="var(--good)" />
          </div>
          <div className="health-bar">
            {accountsForDD.length === 0 ? (
              <div style={{ fontSize: 12, color: "var(--ink-2)", fontFamily: "var(--mono)", padding: "8px 0" }}>Keine Accounts</div>
            ) : accountsForDD.map(a => {
              const dd = a.max_dd_today || 0;
              const cls = dd > 4 ? " bad" : dd > 2.5 ? " warn" : "";
              const name = (a.account_name || a.broker || "Account").slice(0, 10);
              return (
                <div key={a.id} className={"row" + cls}>
                  <div className="lbl">{name}</div>
                  <div className="meter"><span style={{ width: Math.min(dd * 12, 100) + "%" }}></span></div>
                  <div className="val">{dd.toFixed(1)}%</div>
                </div>
              );
            })}
            <div className="row">
              <div className="lbl">Gesamt MaxDD</div>
              <div className="meter"><span style={{ width: Math.min((maxDD || 0) * 12, 100) + "%" }}></span></div>
              <div className="val">{(maxDD || 0).toFixed(1)}%</div>
            </div>
          </div>
        </div>
      </div>

      <div className="kpi-grid">
        <div className="card kpi card-corners accent">
          <span className="corner-tr"></span><span className="corner-bl"></span>
          <div className="head"><div className="lbl">▸ Total Equity</div><div className="tag">LIVE</div></div>
          <div className="v" style={{ fontSize: 20 }}>{fmtMoney(totalEquity)}</div>
          <div className="delta pos">{fmtMoney(dailyPnlVal, true)} heute</div>
          <div className="spark"><Sparkline data={sparkEquity.length >= 2 ? sparkEquity : null} color={accent} /></div>
        </div>
        <div className="card kpi card-corners good">
          <span className="corner-tr"></span><span className="corner-bl"></span>
          <div className="head"><div className="lbl">▸ Daily P&L</div><div className="tag">24H</div></div>
          <div className="v" style={{ color: dailyPnlVal >= 0 ? "var(--good)" : "var(--bad)" }}>{fmtMoney(dailyPnlVal)}</div>
          <div className={"delta " + (dailyPnlVal >= 0 ? "pos" : "neg")}>{fmtMoney(totalFloat, true)} floating</div>
          <div className="spark"><Sparkline data={sparkPnl.length >= 2 ? sparkPnl : null} color="#5cf2a0" /></div>
        </div>
        <div className="card kpi card-corners warn">
          <span className="corner-tr"></span><span className="corner-bl"></span>
          <div className="head"><div className="lbl">▸ Max DD Today</div><div className="tag">24H</div></div>
          <div className="v">{(maxDD || 0).toFixed(1)}<span className="u">%</span></div>
          <div className="delta" style={{ color: maxDD > 4 ? "var(--bad)" : "var(--ink-2)" }}>
            {maxDD > 4 ? "⚠ Kritisch" : maxDD > 2 ? "Erhöht" : "Normal"}
          </div>
          <div className="spark"><Sparkline data={sparkDD.length >= 2 ? sparkDD : null} color="#ffb547" /></div>
        </div>
        <div className="card kpi card-corners">
          <span className="corner-tr"></span><span className="corner-bl"></span>
          <div className="head"><div className="lbl">▸ Win Rate</div><div className="tag">LIVE</div></div>
          <div className="v">{(wr || 0).toFixed(1)}<span className="u">%</span></div>
          <div className="delta pos">Profit Factor: {(pf || 0).toFixed(2)}</div>
          <div className="spark"><Sparkline data={sparkPnl.length >= 2 ? sparkPnl : null} color={accent} /></div>
        </div>
      </div>

      {bots.length > 0 && (
        <div className="section">
          <div className="section-head">
            <h2>Active Expert Advisors <span className="meta">· {runBots} live</span></h2>
          </div>
          <div className="ea-grid">
            {bots.slice(0, 6).map(bot => <EACard key={bot.id} bot={bot} accent={accent} />)}
          </div>
        </div>
      )}

      {myAccounts.length > 0 && (
        <div className="section">
          <div className="section-head">
            <h2>Meine Accounts <span className="meta">· {myAccounts.length} total</span></h2>
          </div>
          <div className="acct-grid">
            {myAccounts.map(a => <AcctRow key={a.id} account={a} onConfig={onEaConfig} />)}
          </div>
        </div>
      )}

    </>
  );
}

/* ─────────────────────────────────────────────
   VMs PAGE
───────────────────────────────────────────── */
function VMsPage({ vms, customers, user, onRefresh, onEaConfig }) {
  const [showSpawn, setShowSpawn] = useState(false);
  const [killLocked, setKillLocked] = useState(false);
  const [killUntil, setKillUntil] = useState(null);

  useEffect(() => {
    apiFetch("/api/vms/kill-switch/status")
      .then(d => { setKillLocked(d.locked); setKillUntil(d.locked_until || null); })
      .catch(() => {});
  }, [vms]);

  const custMap = useMemo(() => {
    const m = {};
    if (customers) customers.forEach(c => { m[c.id] = c; });
    return m;
  }, [customers]);

  const handleStop = async id => {
    try {
      await apiFetch(`/api/vms/${id}/stop`, { method: "POST" });
      toast("VM gestoppt", "success");
      onRefresh && onRefresh();
    } catch (e) { toast("Fehler: " + e.message, "error"); }
  };

  const handleStart = async id => {
    try {
      await apiFetch(`/api/vms/${id}/start`, { method: "POST" });
      toast("VM gestartet", "success");
      onRefresh && onRefresh();
    } catch (e) { toast("Fehler: " + e.message, "error"); }
  };

  const handleDelete = async id => {
    if (!window.confirm("VM wirklich löschen?")) return;
    try {
      await apiFetch(`/api/vms/${id}`, { method: "DELETE" });
      toast("VM gelöscht", "success");
      onRefresh && onRefresh();
    } catch (e) { toast("Fehler: " + e.message, "error"); }
  };

  const isAdmin = user && user.is_admin;

  return (
    <>
      <div className="topbar">
        <div className="title-block">
          <div className="eyebrow">▸ Infrastruktur</div>
          <h1>Virtual Machines <span className="ts">{vms.length} total · {vms.filter(v => v.status === "running").length} running</span></h1>
        </div>
        <button onClick={() => setShowSpawn(true)} style={{ ...modalBtn, marginLeft: "auto" }}>+ VM Starten</button>
      </div>

      <div className="section" style={{ paddingTop: 16 }}>
        {isAdmin && <GoldenVMPanel onRefresh={onRefresh} />}

        {killLocked && (
          <div style={{
            marginBottom: 20, padding: "14px 18px",
            background: "rgba(255,77,109,0.07)", border: "1px solid rgba(255,77,109,0.3)",
            borderRadius: 10, display: "flex", alignItems: "center", gap: 12,
          }}>
            <span style={{ fontSize: 20 }}>⚡</span>
            <div>
              <div style={{ fontWeight: 600, color: "var(--bad)", fontFamily: "var(--mono)", fontSize: 13 }}>
                KILL SWITCH AKTIV
              </div>
              <div style={{ fontSize: 12, color: "var(--ink-2)", marginTop: 2 }}>
                VM-Start gesperrt bis{" "}
                <strong style={{ color: "var(--ink-0)" }}>
                  {killUntil ? new Date(killUntil).toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" }) : "00:00"} Uhr
                </strong>
              </div>
            </div>
          </div>
        )}

        <div className="vm-grid">
          {vms.length === 0 ? (
            <div style={{ color: "var(--ink-2)", fontFamily: "var(--mono)", padding: 32 }}>Keine VMs vorhanden.</div>
          ) : vms.map(vm => (
            <VMCard key={vm.id} vm={vm}
              cust={custMap[vm.customer_id]}
              isAdmin={isAdmin}
              onStop={handleStop}
              onStart={handleStart}
              onDelete={handleDelete}
              killLocked={killLocked}
              onConnect={v => v.caddy_subdomain && window.open("https://" + v.caddy_subdomain, "_blank")}
            />
          ))}
        </div>
      </div>

      {showSpawn && (
        <SpawnVMModal
          customers={customers}
          isAdmin={isAdmin}
          onClose={() => setShowSpawn(false)}
          onSpawned={onRefresh}
        />
      )}
    </>
  );
}

/* ─────────────────────────────────────────────
   ACCOUNTS PAGE
───────────────────────────────────────────── */
function AccountsPage({ accounts, onEaConfig }) {
  return (
    <>
      <div className="topbar">
        <div className="title-block">
          <div className="eyebrow">▸ Trading</div>
          <h1>Accounts <span className="ts">{accounts.length} verbunden</span></h1>
        </div>
      </div>
      <div className="section" style={{ paddingTop: 16 }}>
        <div className="acct-grid">
          {accounts.length === 0 ? (
            <div style={{ color: "var(--ink-2)", fontFamily: "var(--mono)", padding: 32 }}>Keine Accounts.</div>
          ) : accounts.map(a => (
            <AcctRow key={a.id} account={a} onConfig={onEaConfig} />
          ))}
        </div>
      </div>
    </>
  );
}

/* ─────────────────────────────────────────────
   BOTS PAGE
───────────────────────────────────────────── */
function BotsPage({ bots, accent }) {
  return (
    <>
      <div className="topbar">
        <div className="title-block">
          <div className="eyebrow">▸ Automation</div>
          <h1>Expert Advisors <span className="ts">{bots.length} bots</span></h1>
        </div>
      </div>
      <div className="section" style={{ paddingTop: 16 }}>
        {bots.length === 0 ? (
          <div style={{ color: "var(--ink-2)", fontFamily: "var(--mono)", padding: 32 }}>Keine Bots aktiv.</div>
        ) : (
          <div className="ea-grid">
            {bots.map(bot => <EACard key={bot.id} bot={bot} accent={accent} />)}
          </div>
        )}
      </div>

      {bots.length > 0 && (
        <div className="section">
          <div className="section-head"><h2>Statistiken</h2></div>
          <div className="kpi-grid">
            <div className="card kpi card-corners">
              <span className="corner-tr"></span><span className="corner-bl"></span>
              <div className="head"><div className="lbl">▸ Total Today P&L</div><div className="tag">24H</div></div>
              <div className="v" style={{ fontSize: 20, color: bots.reduce((s, b) => s + (b.today_pl || 0), 0) >= 0 ? "var(--good)" : "var(--bad)" }}>
                {fmtMoney(bots.reduce((s, b) => s + (b.today_pl || 0), 0))}
              </div>
            </div>
            <div className="card kpi card-corners">
              <span className="corner-tr"></span><span className="corner-bl"></span>
              <div className="head"><div className="lbl">▸ Aktive Bots</div><div className="tag">LIVE</div></div>
              <div className="v">{bots.length}</div>
            </div>
            <div className="card kpi card-corners warn">
              <span className="corner-tr"></span><span className="corner-bl"></span>
              <div className="head"><div className="lbl">▸ Max Drawdown</div><div className="tag">24H</div></div>
              <div className="v">{Math.max(...bots.map(b => b.drawdown || 0)).toFixed(1)}<span className="u">%</span></div>
            </div>
          </div>
        </div>
      )}
    </>
  );
}

/* ─────────────────────────────────────────────
   CUSTOMERS PAGE (admin)
───────────────────────────────────────────── */
function CustomersPage({ customers, onRefresh }) {
  const [showModal, setShowModal] = useState(false);
  const [editCustomer, setEditCustomer] = useState(null);

  const openCreate = () => { setEditCustomer(null); setShowModal(true); };
  const openEdit = c => { setEditCustomer(c); setShowModal(true); };

  const thStyle = { padding: "10px 14px", textAlign: "left", fontSize: 11, color: "var(--ink-2)", fontFamily: "var(--mono)", borderBottom: "1px solid rgba(94,224,255,0.08)", whiteSpace: "nowrap" };
  const tdStyle = { padding: "10px 14px", fontSize: 13, color: "var(--ink-1)", fontFamily: "var(--mono)", borderBottom: "1px solid rgba(94,224,255,0.05)" };

  return (
    <>
      <div className="topbar">
        <div className="title-block">
          <div className="eyebrow">▸ Admin</div>
          <h1>Customers <span className="ts">{customers.length} registriert</span></h1>
        </div>
        <button onClick={openCreate} style={{ ...modalBtn, marginLeft: "auto" }}>+ Customer</button>
      </div>

      <div className="section" style={{ paddingTop: 16 }}>
        <div className="card" style={{ overflow: "auto" }}>
          <table style={{ width: "100%", borderCollapse: "collapse" }}>
            <thead>
              <tr>
                <th style={thStyle}>Name</th>
                <th style={thStyle}>E-Mail</th>
                <th style={thStyle}>License Key</th>
                <th style={thStyle}>Max Accts</th>
                <th style={thStyle}>VMs</th>
                <th style={thStyle}>Accounts</th>
                <th style={thStyle}>Status</th>
                <th style={thStyle}>Aktionen</th>
              </tr>
            </thead>
            <tbody>
              {customers.length === 0 ? (
                <tr><td colSpan={8} style={{ ...tdStyle, textAlign: "center", padding: 32, color: "var(--ink-3)" }}>Keine Customers vorhanden.</td></tr>
              ) : customers.map(c => (
                <tr key={c.id}>
                  <td style={{ ...tdStyle, color: "var(--ink-0)", fontWeight: 500 }}>{c.name}</td>
                  <td style={tdStyle}>{c.email || "—"}</td>
                  <td style={{ ...tdStyle, fontSize: 11 }}>{(c.license_key || "—").slice(0, 20)}{c.license_key && c.license_key.length > 20 ? "…" : ""}</td>
                  <td style={{ ...tdStyle, textAlign: "center" }}>{c.max_accounts}</td>
                  <td style={{ ...tdStyle, textAlign: "center" }}>{c.vm_count || 0}</td>
                  <td style={{ ...tdStyle, textAlign: "center" }}>{c.registered_accounts || 0}</td>
                  <td style={tdStyle}>
                    <span style={{
                      padding: "3px 10px", borderRadius: 4, fontSize: 11,
                      background: c.is_active ? "rgba(92,242,160,0.12)" : "rgba(255,77,109,0.12)",
                      color: c.is_active ? "var(--good)" : "var(--bad)",
                      border: c.is_active ? "1px solid rgba(92,242,160,0.3)" : "1px solid rgba(255,77,109,0.3)"
                    }}>{c.is_active ? "AKTIV" : "INAKTIV"}</span>
                  </td>
                  <td style={tdStyle}>
                    <button onClick={() => openEdit(c)} style={{ ...modalBtn, padding: "5px 12px", fontSize: 11 }}>Bearbeiten</button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>

      {showModal && (
        <CustomerModal
          customer={editCustomer}
          onClose={() => setShowModal(false)}
          onSaved={onRefresh}
        />
      )}
    </>
  );
}

/* ─────────────────────────────────────────────
   TRIALS PAGE (admin)
───────────────────────────────────────────── */
function TrialsPage() {
  const [campaigns, setCampaigns] = useState([]);
  const [loading, setLoading] = useState(true);
  const [showModal, setShowModal] = useState(false);
  const [editCampaign, setEditCampaign] = useState(null);

  const load = useCallback(async () => {
    setLoading(true);
    try {
      const data = await apiFetch("/api/admin/trial-campaigns");
      setCampaigns(data || []);
    } catch (e) {
      toast("Fehler beim Laden: " + e.message, "error");
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => { load(); }, [load]);

  const openCreate = () => { setEditCampaign(null); setShowModal(true); };
  const openEdit = c => { setEditCampaign(c); setShowModal(true); };

  const handleDelete = async id => {
    if (!window.confirm("Kampagne löschen?")) return;
    try {
      await apiFetch(`/api/admin/trial-campaigns/${id}`, { method: "DELETE" });
      toast("Kampagne gelöscht", "success");
      load();
    } catch (e) { toast("Fehler: " + e.message, "error"); }
  };

  const thStyle = { padding: "10px 14px", textAlign: "left", fontSize: 11, color: "var(--ink-2)", fontFamily: "var(--mono)", borderBottom: "1px solid rgba(94,224,255,0.08)" };
  const tdStyle = { padding: "10px 14px", fontSize: 13, color: "var(--ink-1)", fontFamily: "var(--mono)", borderBottom: "1px solid rgba(94,224,255,0.05)" };

  return (
    <>
      <div className="topbar">
        <div className="title-block">
          <div className="eyebrow">▸ Admin</div>
          <h1>Trial Campaigns <span className="ts">{campaigns.length} gesamt</span></h1>
        </div>
        <button onClick={openCreate} style={{ ...modalBtn, marginLeft: "auto" }}>+ Kampagne</button>
      </div>

      <div className="section" style={{ paddingTop: 16 }}>
        {loading ? (
          <div style={{ color: "var(--ink-2)", fontFamily: "var(--mono)", padding: 32 }}>Laden...</div>
        ) : (
          <div className="card" style={{ overflow: "auto" }}>
            <table style={{ width: "100%", borderCollapse: "collapse" }}>
              <thead>
                <tr>
                  <th style={thStyle}>Name</th>
                  <th style={thStyle}>Slots</th>
                  <th style={thStyle}>Tage</th>
                  <th style={thStyle}>Max Accts</th>
                  <th style={thStyle}>Deadline</th>
                  <th style={thStyle}>Status</th>
                  <th style={thStyle}>Erstellt</th>
                  <th style={thStyle}>Aktionen</th>
                </tr>
              </thead>
              <tbody>
                {campaigns.length === 0 ? (
                  <tr><td colSpan={8} style={{ ...tdStyle, textAlign: "center", padding: 32, color: "var(--ink-3)" }}>Keine Kampagnen vorhanden.</td></tr>
                ) : campaigns.map(c => (
                  <tr key={c.id}>
                    <td style={{ ...tdStyle, color: "var(--ink-0)", fontWeight: 500 }}>{c.name}</td>
                    <td style={tdStyle}>{c.slots_used || 0} / {c.slots_total}</td>
                    <td style={tdStyle}>{c.trial_days}</td>
                    <td style={tdStyle}>{c.trial_max_accounts}</td>
                    <td style={tdStyle}>{c.signup_deadline ? c.signup_deadline.slice(0, 10) : "—"}</td>
                    <td style={tdStyle}>
                      <span style={{
                        padding: "3px 10px", borderRadius: 4, fontSize: 11,
                        background: c.is_active ? "rgba(92,242,160,0.12)" : "rgba(255,77,109,0.12)",
                        color: c.is_active ? "var(--good)" : "var(--bad)",
                        border: c.is_active ? "1px solid rgba(92,242,160,0.3)" : "1px solid rgba(255,77,109,0.3)"
                      }}>{c.is_active ? "AKTIV" : "INAKTIV"}</span>
                    </td>
                    <td style={{ ...tdStyle, fontSize: 11 }}>{c.created_at ? c.created_at.slice(0, 10) : "—"}</td>
                    <td style={tdStyle}>
                      <div style={{ display: "flex", gap: 6 }}>
                        <button onClick={() => openEdit(c)} style={{ ...modalBtn, padding: "5px 10px", fontSize: 11 }}>Edit</button>
                        <button onClick={() => handleDelete(c.id)} style={{ ...modalBtnDanger, padding: "5px 10px", fontSize: 11 }}>Löschen</button>
                      </div>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </div>

      {showModal && (
        <TrialModal
          campaign={editCampaign}
          onClose={() => setShowModal(false)}
          onSaved={load}
        />
      )}
    </>
  );
}

/* ─────────────────────────────────────────────
   AUDIT LOG PAGE
───────────────────────────────────────────── */
function AuditLogPage() {
  return (
    <>
      <div className="topbar">
        <div className="title-block">
          <div className="eyebrow">▸ Admin</div>
          <h1>Audit Log</h1>
        </div>
      </div>
      <div className="section" style={{ paddingTop: 40, textAlign: "center" }}>
        <div style={{ color: "var(--ink-2)", fontFamily: "var(--mono)", fontSize: 14 }}>
          <div style={{ fontSize: 40, marginBottom: 16, opacity: 0.3 }}>⌛</div>
          Audit log coming soon
        </div>
      </div>
    </>
  );
}

/* ─────────────────────────────────────────────
   MAIN APP
───────────────────────────────────────────── */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#5ee0ff",
  "hud": true,
  "density": "comfortable"
}/*EDITMODE-END*/;

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [authed, setAuthed] = useState(false);
  const [user, setUser] = useState(null);
  const [authChecked, setAuthChecked] = useState(false);

  // Data state
  const [accounts, setAccounts] = useState([]);
  const [vms, setVms] = useState([]);
  const [bots, setBots] = useState([]);
  const [kpis, setKpis] = useState(null);
  const [dailyPnl, setDailyPnl] = useState(null);
  const [customers, setCustomers] = useState([]);

  // UI state
  const [active, setActive] = useState("dash");
  const [showKill, setShowKill] = useState(false);
  const [eaConfigVmId, setEaConfigVmId] = useState(null);
  const [showTweaks, setShowTweaks] = useState(false);

  // Auth check on mount
  useEffect(() => {
    const token = localStorage.getItem("jwt");
    if (!token) { setAuthChecked(true); return; }
    apiFetch("/api/auth/me")
      .then(u => {
        if (u) { setUser(u); setAuthed(true); }
        else { localStorage.removeItem("jwt"); }
      })
      .catch(() => { localStorage.removeItem("jwt"); })
      .finally(() => setAuthChecked(false));
    setAuthChecked(true);
  }, []);

  // Apply accent CSS var
  useEffect(() => {
    document.documentElement.style.setProperty("--accent", t.accent);
    document.documentElement.style.setProperty("--accent-2", t.accent);
  }, [t.accent]);

  // Keyboard shortcut Ctrl+Shift+T to open TweaksPanel
  useEffect(() => {
    const handler = e => {
      if (e.ctrlKey && e.shiftKey && e.key === "T") {
        e.preventDefault();
        window.parent.postMessage({ type: "__activate_edit_mode" }, "*");
      }
    };
    document.addEventListener("keydown", handler);
    return () => document.removeEventListener("keydown", handler);
  }, []);

  // Data loading
  const loadData = useCallback(async () => {
    if (!authed) return;
    try {
      const [acctData, vmData, botData, kpiData, pnlData] = await Promise.all([
        apiFetch("/api/accounts").catch(() => []),
        apiFetch("/api/vms").catch(() => []),
        apiFetch("/api/bots?status=running").catch(() => []),
        apiFetch("/api/dashboard/kpis").catch(() => null),
        apiFetch("/api/dashboard/daily-pnl?days=30").catch(() => null),
      ]);
      setAccounts(acctData || []);
      setVms(vmData || []);
      setBots(botData || []);
      if (kpiData) setKpis(kpiData);
      if (pnlData) setDailyPnl(pnlData);
    } catch (e) {
      // silent — individual catches handle per-endpoint
    }
  }, [authed]);

  const loadCustomers = useCallback(async () => {
    if (!authed || !user?.is_admin) return;
    try {
      const data = await apiFetch("/api/customers");
      setCustomers(data || []);
    } catch (_) {}
  }, [authed, user]);

  useEffect(() => {
    if (authed) {
      loadData();
      loadCustomers();
    }
  }, [authed, loadData, loadCustomers]);

  // Auto-refresh every 30s
  useEffect(() => {
    if (!authed) return;
    const interval = setInterval(() => {
      loadData();
    }, 30000);
    return () => clearInterval(interval);
  }, [authed, loadData]);

  const handleLogin = useCallback(async token => {
    try {
      const u = await apiFetch("/api/auth/me");
      if (u) { setUser(u); setAuthed(true); }
    } catch (_) { localStorage.removeItem("jwt"); }
  }, []);

  const handleEaConfig = useCallback(vmId => {
    setEaConfigVmId(vmId);
  }, []);

  if (!authChecked && !authed) {
    return (
      <div style={{ minHeight: "100vh", display: "flex", alignItems: "center", justifyContent: "center", background: "var(--bg-0)" }}>
        <div style={{ color: "var(--ink-2)", fontFamily: "var(--mono)", fontSize: 14 }}>Verbinde...</div>
      </div>
    );
  }

  if (!authed) {
    return (
      <>
        <LoginPage onLogin={handleLogin} />
        <ToastContainer />
      </>
    );
  }

  const isAdmin = user && user.is_admin;

  const renderPage = () => {
    switch (active) {
      case "dash":
        return (
          <DashboardPage
            accounts={accounts} kpis={kpis} bots={bots} vms={vms}
            dailyPnl={dailyPnl} customers={customers}
            accent={t.accent} user={user}
            onShowKill={() => setShowKill(true)}
            onEaConfig={handleEaConfig}
          />
        );
      case "bots":
        return <BotsPage bots={bots} accent={t.accent} />;
      case "accounts":
        return <AccountsPage accounts={accounts} onEaConfig={handleEaConfig} />;
      case "vms":
        return <VMsPage vms={vms} customers={customers} user={user} onRefresh={loadData} onEaConfig={handleEaConfig} />;
      case "customers":
        return isAdmin ? <CustomersPage customers={customers} onRefresh={loadCustomers} /> : null;
      case "trials":
        return isAdmin ? <TrialsPage /> : null;
      case "auditlog":
        return <AuditLogPage />;
      default:
        return <div style={{ padding: 40, color: "var(--ink-2)", fontFamily: "var(--mono)" }}>Seite nicht gefunden.</div>;
    }
  };

  return (
    <div className={"app bg-grid scanline" + (t.density === "dense" ? " dense" : "")}>
      <Sidebar active={active} setActive={setActive} user={user} />

      <main className="main">
        {renderPage()}
      </main>

      {t.hud && <HudOverlay />}

      {showKill && <KillSwitchModal onClose={() => setShowKill(false)} onDone={loadData} />}
      {eaConfigVmId && <EAConfigModal vmId={eaConfigVmId} onClose={() => setEaConfigVmId(null)} />}

      <TweaksPanel title="JARVIS Tweaks">
        <TweakSection label="Farbe" />
        <TweakColor
          label="Accent"
          value={t.accent}
          options={["#5ee0ff", "#7cffb1", "#ffb547", "#a78bfa", "#ff6b9d"]}
          onChange={v => setTweak("accent", v)}
        />
        <TweakSection label="Display" />
        <TweakToggle label="HUD Overlay" value={t.hud} onChange={v => setTweak("hud", v)} />
        <TweakRadio
          label="Dichte"
          value={t.density}
          options={["comfortable", "dense"]}
          onChange={v => setTweak("density", v)}
        />
      </TweaksPanel>

      <ToastContainer />
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);

// Hide boot screen once React has painted its first frame.
// (onload on type="text/babel" fires at network-fetch time, not after Babel
//  transpiles — so we do it here instead.)
requestAnimationFrame(() => {
  requestAnimationFrame(() => {
    const boot = document.getElementById("boot-screen");
    if (boot) boot.classList.add("hidden");
  });
});
