<!DOCTYPE html>
<html lang="de">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>AdPlatform Dashboard</title>

  <!-- React + Babel direkt aus CDN – kein npm nötig -->
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.23.2/babel.min.js"></script>

  <!-- Google Fonts -->
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">

  <style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { background: #fff; font-family: 'Space Grotesk', system-ui, sans-serif; }
    #root { min-height: 100vh; }

    /* Login-Screen */
    .login-wrap {
      min-height: 100vh;
      display: flex;
      align-items: center;
      justify-content: center;
      background: #f4f4f5;
    }
    .login-box {
      background: white;
      border: 1px solid #e2e2e5;
      border-radius: 16px;
      padding: 40px;
      width: 100%;
      max-width: 400px;
      box-shadow: 0 4px 24px rgba(0,0,0,0.07);
    }
    .login-logo {
      display: flex;
      align-items: center;
      gap: 12px;
      margin-bottom: 28px;
    }
    .login-logo-icon {
      width: 42px; height: 42px;
      background: #18181b;
      border-radius: 10px;
      display: flex;
      align-items: center;
      justify-content: center;
    }
    .login-title { font-size: 20px; font-weight: 700; }
    .login-sub   { font-size: 13px; color: #84848c; }
    .login-field { margin-bottom: 14px; }
    .login-field label { display: block; font-size: 12px; font-weight: 600; color: #84848c; text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 5px; }
    .login-field input {
      width: 100%; padding: 10px 12px;
      border: 1px solid #e2e2e5; border-radius: 8px;
      font-size: 14px; font-family: inherit;
      outline: none; transition: border-color 0.15s;
    }
    .login-field input:focus { border-color: #18181b; }
    .login-btn {
      width: 100%; padding: 12px;
      background: #18181b; color: white;
      border: none; border-radius: 8px;
      font-size: 14px; font-weight: 600;
      cursor: pointer; font-family: inherit;
      margin-top: 8px;
    }
    .login-btn:hover { background: #000; }
    .login-error {
      background: #fef2f2; border: 1px solid #fca5a5;
      color: #b91c1c; padding: 10px 12px;
      border-radius: 8px; font-size: 13px;
      margin-bottom: 14px;
    }
    .login-loading {
      text-align: center; color: #84848c;
      font-size: 13px; padding: 20px;
    }
  </style>
</head>
<body>
<div id="root">
  <div class="login-loading">Dashboard wird geladen…</div>
</div>

<script type="text/babel">
const { useState, useEffect, useRef } = React;

const API_BASE = "https://derl.ink/api/index.php";
const AD_BASE  = "https://derl.ink";
const getToken = () => localStorage.getItem("adp_token") || "";
const setToken = (t) => localStorage.setItem("adp_token", t);
const clearToken = () => localStorage.removeItem("adp_token");
async function api(action, method="GET", body=null) {
  const opts={method,headers:{"Content-Type":"application/json","Authorization":"Bearer "+getToken()}};
  if(body) opts.body=JSON.stringify(body);
  const res=await fetch(API_BASE+"?action="+action,opts);
  return res.json();
}

// ── Icon set ───────────────────────────────────────────────────
// Leichte Outline-Icons (Linear-Style). "active" schaltet auf eine
// dünn gefüllte Variante um (Outline + leichte solide Füllung),
// damit der aktive Nav-Punkt sich klar abhebt ohne brachial zu wirken.
function Icon({ name, size = 19, active = false, color }) {
  const stroke = color || "currentColor";
  const fill = active ? stroke : "none";
  const fillOpacity = active ? 0.12 : 0;
  const sw = active ? 2 : 1.6;
  const common = { width: size, height: size, viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" };
  const paths = {
    dashboard: <>
      <rect x="3.5" y="3.5" width="7.5" height="7.5" rx="1.6" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <rect x="13" y="3.5" width="7.5" height="4.5" rx="1.6" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <rect x="13" y="10" width="7.5" height="10.5" rx="1.6" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <rect x="3.5" y="13" width="7.5" height="7.5" rx="1.6" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
    </>,
    campaign: <>
      <path d="M3.5 9.5v5a1.5 1.5 0 0 0 1.5 1.5h1l1.2 4.5h2l-1-4.5h2.8l6 3.5v-14l-6 3.5H5a1.5 1.5 0 0 0-1.5 1.5Z" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
      <path d="M19.5 9.5a4.5 4.5 0 0 1 0 5" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    tracking: <>
      <path d="M4 19.5V4" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
      <path d="M4 19.5h16" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
      <path d="M6.5 16l3.5-4.5 3 2.5L18 8" fill="none" stroke={stroke} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round"/>
      {active && <path d="M6.5 16l3.5-4.5 3 2.5L18 8V18.2H6.5Z" fill={stroke} fillOpacity={0.12} stroke="none"/>}
    </>,
    publisher: <>
      <circle cx="12" cy="12" r="8.5" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M3.5 12h17M12 3.5c2.2 2.2 3.3 5.4 3.3 8.5s-1.1 6.3-3.3 8.5c-2.2-2.2-3.3-5.4-3.3-8.5S9.8 5.7 12 3.5Z" stroke={stroke} strokeWidth={sw*0.85}/>
    </>,
    link: <>
      <path d="M9.5 14.5l5-5" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
      <path d="M11 6.5l1-1a3.5 3.5 0 0 1 5 5l-1 1" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
      <path d="M13 17.5l-1 1a3.5 3.5 0 0 1-5-5l1-1" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    settings: <>
      <circle cx="12" cy="12" r="3" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M12 3.5v2.2M12 18.3v2.2M20.5 12h-2.2M5.7 12H3.5M18 6l-1.6 1.6M7.6 16.4 6 18M18 18l-1.6-1.6M7.6 7.6 6 6" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    qr: <>
      <rect x="3.5" y="3.5" width="6" height="6" rx="1" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <rect x="14.5" y="3.5" width="6" height="6" rx="1" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <rect x="3.5" y="14.5" width="6" height="6" rx="1" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <rect x="15.5" y="15.5" width="2" height="2" fill={stroke}/>
      <rect x="19" y="15.5" width="1.5" height="1.5" fill={stroke}/>
      <rect x="15.5" y="19" width="1.5" height="1.5" fill={stroke}/>
      <rect x="18.5" y="18.5" width="2" height="2" fill={stroke}/>
    </>,
    rotate: <>
      <path d="M4 12a8 8 0 0 1 13.6-5.7M20 12a8 8 0 0 1-13.6 5.7" stroke={stroke} strokeWidth={sw} strokeLinecap="round" fill={fill} fillOpacity={fillOpacity}/>
      <path d="M17.6 3.2v3.6h-3.6M6.4 20.8v-3.6H10" stroke={stroke} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round"/>
    </>,
    domain: <>
      <rect x="3.5" y="4" width="17" height="6" rx="1.6" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <rect x="3.5" y="14" width="17" height="6" rx="1.6" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <circle cx="7" cy="7" r="0.9" fill={stroke}/>
      <circle cx="7" cy="17" r="0.9" fill={stroke}/>
    </>,
    plus: <path d="M12 5v14M5 12h14" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>,
    edit: <path d="M15.5 4.5l4 4L8 20H4v-4Z" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinejoin="round" strokeLinecap="round"/>,
    copy: <>
      <rect x="8.5" y="8.5" width="11" height="11" rx="1.6" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M15.5 8.5V6a1.5 1.5 0 0 0-1.5-1.5H6A1.5 1.5 0 0 0 4.5 6v8a1.5 1.5 0 0 0 1.5 1.5h2.5" stroke={stroke} strokeWidth={sw}/>
    </>,
    play: <path d="M6 4.5v15l13-7.5Z" fill={fill || stroke} fillOpacity={active?1:0.9} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>,
    pause: <>
      <rect x="6" y="4.5" width="4" height="15" rx="1" fill={stroke}/>
      <rect x="14" y="4.5" width="4" height="15" rx="1" fill={stroke}/>
    </>,
    trash: <>
      <path d="M5 7.5h14M9.5 7.5V5a1 1 0 0 1 1-1h3a1 1 0 0 1 1 1v2.5M7 7.5l1 12a1.5 1.5 0 0 0 1.5 1.4h5a1.5 1.5 0 0 0 1.5-1.4l1-12" stroke={stroke} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round"/>
    </>,
    close: <path d="M5.5 5.5l13 13M18.5 5.5l-13 13" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>,
    bell: <>
      <path d="M6 9.5a6 6 0 0 1 12 0c0 3 1 4.5 1.5 5.5H4.5C5 14 6 12.5 6 9.5Z" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
      <path d="M10 18.5a2 2 0 0 0 4 0" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    search: <>
      <circle cx="10.5" cy="10.5" r="6.5" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M15.5 15.5L20 20" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    server: <>
      <rect x="4" y="4" width="16" height="6" rx="1.4" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <rect x="4" y="14" width="16" height="6" rx="1.4" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <circle cx="7.2" cy="7" r="0.8" fill={stroke}/>
      <circle cx="7.2" cy="17" r="0.8" fill={stroke}/>
    </>,
    chevronDown: <path d="M6 9l6 6 6-6" stroke={stroke} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round"/>,
    socialProof: <>
      <circle cx="8" cy="8" r="2.8" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M2.5 19c0-3 2.5-5 5.5-5s5.5 2 5.5 5" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
      <path d="M16 5l1.5 1.5L21 3" stroke={stroke} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round"/>
      <circle cx="17.5" cy="10" r="2.5" stroke={stroke} strokeWidth={sw}/>
      <path d="M13.5 19c0-2.5 1.8-4.5 4-4.5s4 2 4 4.5" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    sparkle: <>
      <path d="M12 3v2M12 19v2M3 12h2M19 12h2M5.6 5.6l1.4 1.4M17 17l1.4 1.4M5.6 18.4l1.4-1.4M17 7l1.4-1.4" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
      <circle cx="12" cy="12" r="3.5" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
    </>,
    shieldAlert: <>
      <path d="M12 3.5l7 2.8v5.4c0 5-3 8.2-7 9.8-4-1.6-7-4.8-7-9.8V6.3Z" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
      <path d="M12 8.5v3.5" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
      <circle cx="12" cy="15" r="0.8" fill={stroke}/>
    </>,
    fire: <>
      <path d="M12 21c-4.4 0-8-3.1-8-7 0-2.5 1.2-4.3 2.5-5.8C7.8 10 9 11.5 9 13c0-3 1-6 3-8.5C13.5 7 15 10 15 13c0-1.5 1.2-3 2.5-4.8C18.8 9.7 20 11.5 20 14c0 3.9-3.6 7-8 7Z" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
    </>,
    bellRing: <>
      <path d="M6 9.5a6 6 0 0 1 12 0c0 3 1 4.5 1.5 5.5H4.5C5 14 6 12.5 6 9.5Z" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
      <path d="M10 18.5a2 2 0 0 0 4 0" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
      <path d="M3.5 5.5a9 9 0 0 1 2-2M20.5 5.5a9 9 0 0 0-2-2" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    cursor: <>
      <path d="M5 3.5l14 8.5-6.5 1.5-3.5 6Z" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
    </>,
    mapPin: <>
      <path d="M12 21s-7-6.8-7-11a7 7 0 1 1 14 0c0 4.2-7 11-7 11Z" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
      <circle cx="12" cy="10" r="2" stroke={stroke} strokeWidth={sw}/>
    </>,
    newspaper: <>
      <rect x="4" y="4" width="16" height="16" rx="1.5" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M8 8.5h8M8 12h8M8 15.5h5" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
      <rect x="8" y="8.5" width="3.5" height="3" rx="0.5" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw*0.7}/>
    </>,
    person: <>
      <circle cx="12" cy="8" r="3.5" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M4.5 20c0-4.1 3.4-7.5 7.5-7.5s7.5 3.4 7.5 7.5" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    users: <>
      <circle cx="9" cy="8" r="3" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M3 20c0-3.3 2.7-6 6-6s6 2.7 6 6" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
      <circle cx="17" cy="8" r="2.5" stroke={stroke} strokeWidth={sw}/>
      <path d="M21 20c0-2.8-1.8-5.1-4-5.8" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    eye: <>
      <path d="M2.5 12s3.5-7 9.5-7 9.5 7 9.5 7-3.5 7-9.5 7-9.5-7-9.5-7Z" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
      <circle cx="12" cy="12" r="2.5" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
    </>,
    invoice: <>
      <path d="M6.5 3.5h11a1 1 0 0 1 1 1v15.7l-2.5-1.5-2.2 1.5-2.3-1.5-2.3 1.5-2.2-1.5-2.5 1.5V4.5a1 1 0 0 1 1-1Z" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
      <path d="M9 8.5h6M9 12h6M9 15.5h3.5" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    coin: <>
      <circle cx="12" cy="12" r="8.5" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M12 7.5v9M9.5 9.5c0-1.2 1-2 2.5-2s2.5.8 2.5 2-1 1.5-2.5 2-2.5.8-2.5 2 1 2 2.5 2 2.5-.8 2.5-2" stroke={stroke} strokeWidth={sw*0.85} strokeLinecap="round"/>
    </>,
    flask: <>
      <path d="M9 3.5h6M10 3.5v6.2L5.8 17a2 2 0 0 0 1.7 3h9a2 2 0 0 0 1.7-3L14 9.7V3.5" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
      <path d="M8 15h8" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    layout: <>
      <rect x="3.5" y="3.5" width="17" height="17" rx="1.8" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M3.5 9h17M9 9v11.5" stroke={stroke} strokeWidth={sw}/>
    </>,
    trophy: <>
      <path d="M7 4.5h10v6a5 5 0 0 1-10 0Z" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
      <path d="M7 6.5H4.5v1a3 3 0 0 0 2.6 3M17 6.5h2.5v1a3 3 0 0 1-2.6 3" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
      <path d="M12 15.5v2.5M9 20.5h6" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    shield: <>
      <path d="M12 3.5l7 2.8v5.4c0 5-3 8.2-7 9.8-4-1.6-7-4.8-7-9.8V6.3Z" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw} strokeLinejoin="round"/>
      <path d="M9 12l2 2 4-4.5" stroke={stroke} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round"/>
    </>,
    clock: <>
      <circle cx="12" cy="12" r="8.5" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M12 7.5V12l3.2 2" stroke={stroke} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round"/>
    </>,
    desktop: <>
      <rect x="3.5" y="4.5" width="17" height="11" rx="1.4" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M9 19.5h6M12 15.5v4" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    mobile: <>
      <rect x="7" y="2.5" width="10" height="19" rx="2" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M11 18.5h2" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    tablet: <>
      <rect x="5" y="3" width="14" height="18" rx="1.8" fill={fill} fillOpacity={fillOpacity} stroke={stroke} strokeWidth={sw}/>
      <path d="M11 18h2" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
    external: <>
      <path d="M9 6H6a1.5 1.5 0 0 0-1.5 1.5v10A1.5 1.5 0 0 0 6 19h10a1.5 1.5 0 0 0 1.5-1.5V14" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
      <path d="M14 5h5v5M19 5l-8.5 8.5" stroke={stroke} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round"/>
    </>,
    download: <>
      <path d="M12 4v11" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
      <path d="M7.5 11.5L12 16l4.5-4.5" stroke={stroke} strokeWidth={sw} strokeLinecap="round" strokeLinejoin="round"/>
      <path d="M5 18.5h14" stroke={stroke} strokeWidth={sw} strokeLinecap="round"/>
    </>,
  };
  return <svg {...common}>{paths[name] || null}</svg>;
}

// ── Design tokens ──────────────────────────────────────────────
// Palette: helles, ruhiges Schwarz-Weiß-Theme. Weißer Hintergrund,
// dunkles Anthrazit/Schwarz für Text & Akzente, Grautöne für Struktur.
// Status-Farben (grün/gelb/rot) bleiben dezent für Lesbarkeit erhalten.
const T = {
  bg:       "#FFFFFF",
  surface:  "#FFFFFF",
  surfaceHi:"#F4F4F5",
  border:   "#E2E2E5",
  accent:   "#18181B",
  accentHi: "#000000",
  coral:    "#B5443B",
  green:    "#3F7A5C",
  yellow:   "#A98328",
  text:     "#18181B",
  muted:    "#84848C",
  white:    "#18181B",
};

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

  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

  body {
    background: ${T.bg};
    color: ${T.text};
    font-family: 'Space Grotesk', sans-serif;
    font-size: 14px;
    line-height: 1.6;
    min-height: 100vh;
  }

  ::-webkit-scrollbar { width: 6px; }
  ::-webkit-scrollbar-track { background: ${T.bg}; }
  ::-webkit-scrollbar-thumb { background: ${T.border}; border-radius: 3px; }

  .mono { font-family: 'JetBrains Mono', monospace; }

  /* Layout */
  .shell { display: flex; min-height: 100vh; }

  /* Sidebar */
  .sidebar {
    width: 220px;
    min-width: 220px;
    background: ${T.surface};
    border-right: 1px solid ${T.border};
    display: flex;
    flex-direction: column;
    padding: 24px 0;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
  }
  .sidebar-logo {
    padding: 0 20px 28px;
    border-bottom: 1px solid ${T.border};
    margin-bottom: 16px;
  }
  .logo-mark {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 18px;
    font-weight: 700;
    color: ${T.white};
    letter-spacing: -0.5px;
  }
  .logo-icon {
    width: 32px; height: 32px;
    background: linear-gradient(135deg, ${T.accent}, ${T.accentHi});
    border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
    font-size: 16px;
  }
  .logo-sub { font-size: 10px; color: ${T.muted}; font-weight: 400; letter-spacing: 1px; text-transform: uppercase; margin-top: 2px; }
  .nav-section { padding: 0 12px; margin-bottom: 8px; }
  .nav-label { font-size: 10px; color: ${T.muted}; text-transform: uppercase; letter-spacing: 1.5px; padding: 8px 8px 4px; font-weight: 600; }
  .nav-item {
    display: flex; align-items: center; gap: 10px;
    padding: 9px 10px;
    border-radius: 8px;
    cursor: pointer;
    color: ${T.muted};
    font-size: 13.5px;
    font-weight: 500;
    transition: all 0.15s;
    border: 1px solid transparent;
    margin-bottom: 2px;
  }
  .nav-item:hover { background: ${T.surfaceHi}; color: ${T.text}; }
  .nav-item.active { background: ${T.surfaceHi}; color: ${T.accentHi}; border-color: ${T.border}; font-weight: 700; }
  .nav-item .nav-icon { width: 18px; text-align: center; font-size: 15px; }
  .nav-badge {
    margin-left: auto;
    background: ${T.accent};
    color: white;
    font-size: 10px;
    padding: 1px 6px;
    border-radius: 10px;
    font-weight: 600;
  }
  .sidebar-footer { margin-top: auto; padding: 16px 20px 0; border-top: 1px solid ${T.border}; }
  .status-dot { width: 8px; height: 8px; background: ${T.green}; border-radius: 50%; display: inline-block; margin-right: 6px; animation: pulse 2s infinite; }
  @keyframes pulse { 0%,100%{opacity:1} 50%{opacity:0.4} }

  /* Main */
  .main { flex: 1; overflow-x: hidden; }
  .topbar {
    background: ${T.surface};
    border-bottom: 1px solid ${T.border};
    padding: 16px 32px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    position: sticky;
    top: 0;
    z-index: 10;
  }
  .topbar-title { font-size: 18px; font-weight: 700; color: ${T.white}; }
  .topbar-sub { font-size: 12px; color: ${T.muted}; margin-top: 1px; }
  .topbar-actions { display: flex; align-items: center; gap: 12px; }

  .btn {
    padding: 8px 16px;
    border-radius: 8px;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    border: none;
    transition: all 0.15s;
    font-family: 'Space Grotesk', sans-serif;
    display: inline-flex;
    align-items: center;
    gap: 6px;
  }
  .btn-primary { background: ${T.accent}; color: white; }
  .btn-primary:hover { background: ${T.accentHi}; transform: translateY(-1px); }
  .btn-ghost { background: transparent; color: ${T.muted}; border: 1px solid ${T.border}; }
  .btn-ghost:hover { background: ${T.surfaceHi}; color: ${T.text}; }
  .btn-danger { background: #F7ECEA; color: ${T.coral}; border: 1px solid #E8D2CD; }
  .btn-danger:hover { background: #F0DCD7; }
  .btn-sm { padding: 5px 10px; font-size: 12px; }
  .btn-success { background: #EAF2EC; color: ${T.green}; border: 1px solid #D2E3D8; }

  /* Page */
  .page { padding: 28px 32px; }

  /* KPI Cards */
  .kpi-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 28px; }
  .kpi-card {
    background: ${T.surface};
    border: 1px solid ${T.border};
    border-radius: 12px;
    padding: 20px;
    position: relative;
    overflow: hidden;
    box-shadow: 0 1px 3px rgba(0,0,0,0.04);
  }
  .kpi-card::before {
    content: '';
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 2px;
  }
  .kpi-card.blue::before { background: ${T.accentHi}; }
  .kpi-card.green::before { background: ${T.green}; }
  .kpi-card.coral::before { background: ${T.coral}; }
  .kpi-card.yellow::before { background: ${T.yellow}; }
  .kpi-label { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: ${T.muted}; font-weight: 600; }
  .kpi-value { font-size: 28px; font-weight: 700; color: ${T.white}; margin: 6px 0 4px; font-family: 'JetBrains Mono', monospace; }
  .kpi-change { font-size: 12px; display: flex; align-items: center; gap: 4px; }
  .kpi-change.up { color: ${T.green}; }
  .kpi-change.down { color: ${T.coral}; }
  .kpi-icon { position: absolute; right: 16px; top: 16px; font-size: 22px; opacity: 0.3; }

  /* Charts area */
  .charts-row { display: grid; grid-template-columns: 2fr 1fr; gap: 16px; margin-bottom: 28px; }

  .card {
    background: ${T.surface};
    border: 1px solid ${T.border};
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 1px 3px rgba(0,0,0,0.04);
  }
  .card-header {
    padding: 16px 20px;
    border-bottom: 1px solid ${T.border};
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
  .card-title { font-size: 14px; font-weight: 600; color: ${T.white}; }
  .card-body { padding: 20px; }

  /* Mini chart bars */
  .mini-chart { display: flex; align-items: flex-end; gap: 4px; height: 80px; }
  .bar-wrap { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px; }
  .bar {
    width: 100%;
    background: ${T.accent};
    border-radius: 3px 3px 0 0;
    opacity: 0.7;
    transition: opacity 0.2s;
    cursor: pointer;
  }
  .bar:hover { opacity: 1; }
  .bar.highlight { opacity: 1; background: ${T.accentHi}; }
  .bar-label { font-size: 9px; color: ${T.muted}; }

  /* Line chart SVG */
  .chart-svg { width: 100%; overflow: visible; }

  /* Campaigns table */
  .table-wrap { overflow-x: auto; }
  table { width: 100%; border-collapse: collapse; }
  th {
    text-align: left;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1px;
    color: ${T.muted};
    font-weight: 600;
    padding: 10px 16px;
    border-bottom: 1px solid ${T.border};
    white-space: nowrap;
  }
  td {
    padding: 12px 16px;
    border-bottom: 1px solid ${T.border};
    font-size: 13px;
    vertical-align: middle;
  }
  tr:last-child td { border-bottom: none; }
  tr:hover td { background: ${T.surfaceHi}; }

  .badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    border-radius: 6px;
    font-size: 11px;
    font-weight: 600;
  }
  .badge-active { background: #EAF2EC; color: ${T.green}; }
  .badge-paused { background: #F6F0E1; color: ${T.yellow}; }
  .badge-draft { background: ${T.surfaceHi}; color: ${T.muted}; }
  .badge-ended { background: #F7ECEA; color: ${T.coral}; }

  /* Format badges */
  .format-tag {
    display: inline-block;
    padding: 2px 7px;
    border-radius: 4px;
    font-size: 10px;
    font-weight: 600;
    background: ${T.surfaceHi};
    color: ${T.text};
    border: 1px solid ${T.border};
  }

  /* Progress bar */
  .prog-wrap { background: ${T.border}; border-radius: 3px; height: 5px; min-width: 80px; }
  .prog-fill { height: 100%; border-radius: 3px; background: ${T.accentHi}; }

  /* Modal */
  .modal-overlay {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.4);
    backdrop-filter: blur(4px);
    z-index: 100;
    display: flex; align-items: center; justify-content: center;
    padding: 20px;
  }
  .modal {
    background: ${T.surface};
    border: 1px solid ${T.border};
    border-radius: 16px;
    width: 100%;
    max-width: 560px;
    max-height: 85vh;
    overflow-y: auto;
    animation: slideUp 0.2s ease;
    box-shadow: 0 16px 48px rgba(0,0,0,0.18);
  }
  @keyframes slideUp { from { opacity:0; transform:translateY(16px); } to { opacity:1; transform:translateY(0); } }
  .modal-header {
    padding: 20px 24px;
    border-bottom: 1px solid ${T.border};
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
  .modal-title { font-size: 16px; font-weight: 700; color: ${T.white}; }
  .modal-body { padding: 24px; }
  .modal-footer { padding: 16px 24px; border-top: 1px solid ${T.border}; display: flex; justify-content: flex-end; gap: 10px; }

  /* Form */
  .form-row { margin-bottom: 16px; }
  .form-row-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 16px; }
  label { display: block; font-size: 12px; font-weight: 600; color: ${T.muted}; margin-bottom: 6px; text-transform: uppercase; letter-spacing: 0.5px; }
  input, select, textarea {
    width: 100%;
    background: ${T.surfaceHi};
    border: 1px solid ${T.border};
    border-radius: 8px;
    color: ${T.text};
    padding: 10px 12px;
    font-size: 13px;
    font-family: 'Space Grotesk', sans-serif;
    outline: none;
    transition: border-color 0.15s;
  }
  input:focus, select:focus, textarea:focus { border-color: ${T.accentHi}; background: #FFFFFF; }
  select option { background: ${T.surface}; }
  textarea { resize: vertical; min-height: 70px; }

  /* Snippet box */
  .snippet {
    background: #18181B;
    border: 1px solid ${T.border};
    border-radius: 8px;
    padding: 14px;
    font-family: 'JetBrains Mono', monospace;
    font-size: 11.5px;
    color: #E4E4E7;
    white-space: pre;
    overflow-x: auto;
    line-height: 1.7;
  }

  /* QR placeholder */
  .qr-box {
    width: 120px; height: 120px;
    background: white;
    border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
    font-size: 48px;
    margin: 0 auto 12px;
    border: 1.5px solid ${T.text};
    box-shadow: 0 0 0 4px ${T.surfaceHi};
  }

  /* Tabs */
  .tabs { display: flex; gap: 4px; margin-bottom: 20px; background: ${T.surfaceHi}; padding: 4px; border-radius: 10px; border: 1px solid ${T.border}; width: fit-content; }
  .tab {
    padding: 7px 16px;
    border-radius: 7px;
    cursor: pointer;
    font-size: 13px;
    font-weight: 500;
    color: ${T.muted};
    transition: all 0.15s;
  }
  .tab.active { background: ${T.accent}; color: white; font-weight: 600; }
  .tab:hover:not(.active) { color: ${T.text}; }

  /* Tracking live */
  .live-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 0; border-bottom: 1px solid ${T.border}; }
  .live-row:last-child { border-bottom: none; }
  .live-site { font-size: 13px; font-weight: 500; color: ${T.text}; }
  .live-url { font-size: 11px; color: ${T.muted}; }
  .live-stat { font-family: 'JetBrains Mono', monospace; font-size: 13px; font-weight: 600; color: ${T.accentHi}; }

  /* Empty state */
  .empty { text-align: center; padding: 48px 20px; color: ${T.muted}; }
  .empty-icon { font-size: 40px; margin-bottom: 12px; }
  .empty-title { font-size: 15px; font-weight: 600; color: ${T.text}; margin-bottom: 6px; }

  /* Notification toast */
  .toast {
    position: fixed;
    bottom: 24px; right: 24px;
    background: ${T.accent};
    color: #FFFFFF;
    padding: 12px 20px;
    border-radius: 10px;
    font-weight: 600;
    font-size: 13px;
    z-index: 200;
    box-shadow: 0 8px 24px rgba(0,0,0,0.15);
    animation: slideIn 0.3s ease, fadeOut 0.3s ease 2.5s forwards;
  }
  @keyframes slideIn { from { opacity:0; transform:translateY(16px); } to { opacity:1; transform:translateY(0); } }
  @keyframes fadeOut { to { opacity:0; transform:translateY(8px); } }

  /* Preview mockups */
  .preview-frame {
    background: ${T.surfaceHi};
    border: 1px solid ${T.border};
    border-radius: 12px;
    position: relative;
    overflow: hidden;
    height: 360px;
  }
  .preview-page {
    position: absolute; inset: 0;
    padding: 16px;
  }
  .preview-page-line { height: 8px; background: ${T.border}; border-radius: 4px; margin-bottom: 10px; }
  .mock-popup {
    position: absolute;
    top: 50%; left: 50%;
    transform: translate(-50%,-50%);
    background: ${T.surface};
    border: 1px solid ${T.border};
    border-radius: 12px;
    box-shadow: 0 16px 40px rgba(0,0,0,0.18);
    width: 240px;
    padding: 20px;
    text-align: center;
  }
  .mock-popup-close {
    position: absolute; top: 8px; right: 8px;
    width: 22px; height: 22px;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: ${T.surfaceHi};
    cursor: pointer;
  }
  .mock-interstitial {
    position: absolute; inset: 8px;
    background: ${T.surface};
    border: 1px solid ${T.border};
    border-radius: 10px;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    text-align: center;
    padding: 24px;
  }
  .mock-skip {
    position: absolute; top: 14px; right: 14px;
    font-size: 11px; color: ${T.muted};
    border: 1px solid ${T.border};
    border-radius: 14px;
    padding: 4px 10px;
  }
  .mock-sticky {
    position: absolute; left: 12px; right: 12px; bottom: 12px;
    background: ${T.surface};
    border: 1px solid ${T.border};
    border-radius: 10px;
    box-shadow: 0 8px 20px rgba(0,0,0,0.1);
    padding: 12px 16px;
    display: flex; align-items: center; justify-content: space-between;
  }
  .mock-floating {
    position: absolute; right: 16px; bottom: 16px;
    width: 64px; height: 64px;
    border-radius: 50%;
    background: ${T.accentHi};
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 8px 20px rgba(0,0,0,0.18);
  }
  .mock-native {
    position: absolute; inset: 16px;
    background: ${T.surface};
    border: 1px solid ${T.border};
    border-radius: 10px;
    padding: 14px;
  }
  .mock-native-tag {
    display: inline-block;
    font-size: 9px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: ${T.muted};
    border: 1px solid ${T.border};
    border-radius: 4px;
    padding: 1px 6px;
    margin-bottom: 8px;
  }
  .format-picker { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 20px; }
  .format-pill {
    display: flex; align-items: center; gap: 6px;
    padding: 8px 14px;
    border-radius: 20px;
    border: 1px solid ${T.border};
    cursor: pointer;
    font-size: 13px;
    font-weight: 500;
    color: ${T.muted};
    transition: all 0.15s;
  }
  .format-pill:hover { background: ${T.surfaceHi}; color: ${T.text}; }
  .format-pill.active { background: ${T.accentHi}; color: #fff; border-color: ${T.accentHi}; }

  /* A/B testing */
  .variant-card {
    border: 1px solid ${T.border};
    border-radius: 10px;
    padding: 14px;
    background: ${T.surfaceHi};
    position: relative;
  }
  .variant-card.winner { border-color: ${T.green}; background: #EAF2EC; }
  .winner-tag {
    position: absolute; top: -10px; right: 12px;
    background: ${T.green};
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 10px;
    display: flex; align-items: center; gap: 4px;
  }
  .split-bar { display: flex; height: 8px; border-radius: 4px; overflow: hidden; margin: 10px 0; }
  .split-seg { height: 100%; }

  /* Role tabs */
  .role-tabs {
    display: flex;
    gap: 2px;
    background: ${T.surfaceHi};
    border: 1px solid ${T.border};
    border-radius: 10px;
    padding: 3px;
  }
  .role-tab {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 7px 16px;
    border-radius: 8px;
    cursor: pointer;
    font-size: 13px;
    font-weight: 500;
    color: ${T.muted};
    transition: all 0.15s;
    white-space: nowrap;
  }
  .role-tab:hover { color: ${T.text}; }
  .role-tab.active { background: ${T.surface}; color: ${T.text}; font-weight: 600; box-shadow: 0 1px 3px rgba(0,0,0,0.08); }

  /* Customer cards */
  .customer-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 24px; }
  .customer-card {
    background: ${T.surface};
    border: 1px solid ${T.border};
    border-radius: 12px;
    padding: 18px;
    box-shadow: 0 1px 3px rgba(0,0,0,0.04);
    position: relative;
  }
  .customer-card:hover { border-color: ${T.accentHi}; }
  .customer-avatar {
    width: 38px; height: 38px;
    border-radius: 10px;
    background: ${T.surfaceHi};
    border: 1px solid ${T.border};
    display: flex; align-items: center; justify-content: center;
    font-weight: 700;
    font-size: 14px;
    color: ${T.text};
    margin-bottom: 10px;
  }
  .customer-name { font-size: 14px; font-weight: 700; color: ${T.text}; }
  .customer-meta { font-size: 12px; color: ${T.muted}; margin-top: 2px; }
  .customer-stats { display: flex; gap: 16px; margin-top: 12px; padding-top: 12px; border-top: 1px solid ${T.border}; }
  .customer-stat-label { font-size: 10px; color: ${T.muted}; text-transform: uppercase; letter-spacing: 0.5px; }
  .customer-stat-value { font-size: 13px; font-weight: 700; color: ${T.text}; font-family: 'JetBrains Mono', monospace; }

  /* Phase 5 */
  .fraud-score {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 3px 9px; border-radius: 6px;
    font-size: 11px; font-weight: 700; font-family: 'JetBrains Mono', monospace;
  }
  .fraud-safe    { background:#EAF2EC; color:${T.green}; }
  .fraud-warning { background:#F6F0E1; color:${T.yellow}; }
  .fraud-danger  { background:#F7ECEA; color:${T.coral}; }

  .heatmap-wrap {
    position: relative;
    border-radius: 10px;
    overflow: hidden;
    background: ${T.surfaceHi};
    border: 1px solid ${T.border};
  }
  .heatmap-legend {
    display: flex; align-items: center; gap: 8px;
    font-size: 11px; color: ${T.muted};
    margin-top: 8px;
  }
  .legend-bar {
    width: 80px; height: 8px; border-radius: 4px;
    background: linear-gradient(to right, rgba(24,24,27,0.05), rgba(24,24,27,0.9));
  }

  .push-sub-bar {
    display: flex; align-items: center; justify-content: space-between;
    padding: 11px 14px;
    border-bottom: 1px solid ${T.border};
    font-size: 13px;
  }
  .push-sub-bar:last-child { border-bottom: none; }

  .native-preview {
    border: 1px solid ${T.border};
    border-radius: 10px;
    overflow: hidden;
    background: ${T.surface};
    max-width: 340px;
  }
  .native-preview-img {
    width: 100%; height: 140px;
    background: ${T.surfaceHi};
    display: flex; align-items: center; justify-content: center;
    color: ${T.muted};
    font-size: 13px;
    overflow: hidden;
  }
  .native-preview-body { padding: 14px; }
  .native-preview-sponsor {
    font-size: 9px; text-transform: uppercase; letter-spacing: 1px;
    color: ${T.muted}; margin-bottom: 5px;
  }
  .native-preview-title { font-size: 15px; font-weight: 700; line-height: 1.35; margin-bottom: 6px; }
  .native-preview-desc  { font-size: 12.5px; color: ${T.muted}; line-height: 1.5; margin-bottom: 10px; }
  .native-preview-cta   { font-size: 12px; font-weight: 600; color: ${T.accentHi}; }
  .native-preview-source { font-size: 11px; color: ${T.muted}; margin-top: 6px; }

  /* Social Proof */
  .sp-popup-preview {
    background: white;
    border: 1px solid ${T.border};
    border-radius: 12px;
    box-shadow: 0 8px 32px rgba(0,0,0,0.12);
    padding: 12px 16px;
    display: flex;
    align-items: center;
    gap: 12px;
    max-width: 300px;
    position: relative;
  }
  .sp-avatar {
    width: 38px; height: 38px;
    border-radius: 50%;
    background: ${T.surfaceHi};
    border: 1.5px solid ${T.border};
    display: flex; align-items: center; justify-content: center;
    font-size: 13px; font-weight: 700;
    flex-shrink: 0;
  }
  .sp-popup-name  { font-size: 13px; font-weight: 700; color: ${T.text}; }
  .sp-popup-action{ font-size: 12px; color: ${T.muted}; }
  .sp-popup-time  { font-size: 11px; color: ${T.muted}; margin-top: 2px; }
  .sp-type-pill {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 6px 14px; border-radius: 20px;
    border: 1px solid ${T.border};
    cursor: pointer; font-size: 12.5px; font-weight: 500;
    color: ${T.muted}; transition: all 0.15s;
  }
  .sp-type-pill:hover { background: ${T.surfaceHi}; color: ${T.text}; }
  .sp-type-pill.active { background: ${T.accentHi}; color: white; border-color: ${T.accentHi}; }
  .sp-feed-item {
    display: flex; align-items: center; gap: 12px;
    padding: 11px 16px;
    border-bottom: 1px solid ${T.border};
    font-size: 13px;
  }
  .sp-feed-item:last-child { border-bottom: none; }

  /* Responsive */
  @media (max-width: 900px) {
    .kpi-grid { grid-template-columns: repeat(2, 1fr); }
    .charts-row { grid-template-columns: 1fr; }
  }
  @media (max-width: 600px) {
    .sidebar { display: none; }
    .page { padding: 16px; }
    .topbar { padding: 12px 16px; }
    .kpi-grid { grid-template-columns: 1fr 1fr; }
  }
`;

// ── Mock Data ──────────────────────────────────────────────────
// Globale Standardpreise – greifen, wenn eine Kampagne keinen eigenen Override hat
const DEFAULT_PRICING = { cpm: 3.0, cpc: 0.15, currency: "€" };

const INIT_CAMPAIGNS = [];

// Berechnet die laufenden Kosten einer Kampagne abhängig vom Preismodell.
// CPM/CPC nutzen den Override, falls gesetzt, sonst den globalen Standardpreis.
function computeCost(c, pricing = DEFAULT_PRICING) {
  if (c.pricingModel === "flat") return Number(c.flatAmount || 0);
  if (c.pricingModel === "cpc") {
    const rate = Number(c.cpcOverride || pricing.cpc);
    return c.clicks * rate;
  }
  // default: cpm
  const rate = Number(c.cpmOverride || pricing.cpm);
  return (c.impressions / 1000) * rate;
}

const PRICING_LABELS = { cpm: "CPM · pro 1000 Impr.", cpc: "CPC · pro Klick", flat: "Flatrate · monatlich" };

const DAILY = [12, 18, 14, 22, 19, 28, 31, 25, 33, 29, 38, 42, 36, 45];
const FORMATS = ["Banner 728×90", "Banner 300×250", "Banner 300×600", "Mobile 320×50", "Popup", "Interstitial", "Sticky", "Textlink", "Native Ad", "Floating"];

function rand(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }
function fmt(n) { return n >= 1000000 ? (n/1000000).toFixed(1)+"M" : n >= 1000 ? (n/1000).toFixed(1)+"K" : n; }
function ctr(imp, clk) { return imp > 0 ? ((clk/imp)*100).toFixed(2) : "0.00"; }

// ── Subcomponents ──────────────────────────────────────────────
function Toast({ msg, onDone }) {
  useEffect(() => { const t = setTimeout(onDone, 2900); return () => clearTimeout(t); }, []);
  return <div className="toast">✓ {msg}</div>;
}

function KpiCard({ label, value, change, up, icon, color }) {
  return (
    <div className={`kpi-card ${color}`}>
      <span className="kpi-icon"><Icon name={icon} size={22} /></span>
      <div className="kpi-label">{label}</div>
      <div className="kpi-value">{value}</div>
      <div className={`kpi-change ${up ? "up" : "down"}`}>{up ? "▲" : "▼"} {change}</div>
    </div>
  );
}

function MiniChart({ data }) {
  const max = Math.max(...data);
  const days = ["M","D","M","D","F","S","S","M","D","M","D","F","S","S"];
  return (
    <div className="mini-chart">
      {data.map((v,i) => (
        <div className="bar-wrap" key={i}>
          <div className="bar" style={{ height: `${(v/max)*72}px` }} title={`${v}k Impressions`} />
          <span className="bar-label">{days[i]}</span>
        </div>
      ))}
    </div>
  );
}

function LineChart({ data }) {
  const w = 300, h = 80;
  const max = Math.max(...data), min = Math.min(...data);
  const pts = data.map((v,i) => {
    const x = (i/(data.length-1))*w;
    const y = h - ((v-min)/(max-min||1))*(h-8);
    return `${x},${y}`;
  }).join(" ");
  return (
    <svg viewBox={`0 0 ${w} ${h}`} className="chart-svg" style={{height:80}}>
      <polyline fill="none" stroke={T.accent} strokeWidth="2" strokeLinejoin="round" points={pts} />
      {data.map((v,i) => {
        const x = (i/(data.length-1))*w;
        const y = h - ((v-min)/(max-min||1))*(h-8);
        return <circle key={i} cx={x} cy={y} r="3" fill={T.accentHi} />;
      })}
    </svg>
  );
}

function StatusBadge({ status }) {
  const map = { active:"badge-active", paused:"badge-paused", draft:"badge-draft", ended:"badge-ended" };
  const icons = { active:"●", paused:"⏸", draft:"✎", ended:"■" };
  return <span className={`badge ${map[status]||"badge-draft"}`}>{icons[status]} {status}</span>;
}

function CampaignModal({ campaign, onClose, onSave }) {
  const isNew = !campaign;
  const [form, setForm] = useState(campaign || {
    name:"", format: FORMATS[0], url:"", budget: "", status:"draft",
    bounceUrl:"", bounceTime: 8, freqCap: 3, geo:"", device:"all",
    pricingModel:"cpm", cpmOverride:"", cpcOverride:"", flatAmount:"", flatStart:"", flatEnd:"",
    bannerUrl:"", bannerFile:null
  });
  const set = k => e => setForm(p => ({ ...p, [k]: e.target.value }));

  return (
    <div className="modal-overlay" onClick={e => e.target===e.currentTarget && onClose()}>
      <div className="modal">
        <div className="modal-header">
          <span className="modal-title" style={{display:"flex", alignItems:"center", gap:8}}>
            <Icon name={isNew ? "plus" : "edit"} size={17} /> {isNew ? "Neue Kampagne" : "Kampagne bearbeiten"}
          </span>
          <button className="btn btn-ghost btn-sm" onClick={onClose}><Icon name="close" size={14} /></button>
        </div>
        <div className="modal-body">
          <div className="form-row">
            <label>Kampagnenname</label>
            <input value={form.name} onChange={set("name")} placeholder="z.B. Sommer Sale 2025" />
          </div>
          <div className="form-row-2">
            <div>
              <label>Werbeformat</label>
              <select value={form.format} onChange={set("format")}>
                {FORMATS.map(f => <option key={f}>{f}</option>)}
              </select>
            </div>
            <div>
              <label>Status</label>
              <select value={form.status} onChange={set("status")}>
                <option value="draft">Draft</option>
                <option value="active">Aktiv</option>
                <option value="paused">Pausiert</option>
              </select>
            </div>
          </div>
          <div className="form-row">
            <label>Ziel-URL</label>
            <input value={form.url} onChange={set("url")} placeholder="https://example.com/landingpage" />
          </div>
          <div className="form-row-2">
            <div>
              <label>Budget (€)</label>
              <input type="number" value={form.budget} onChange={set("budget")} placeholder="500" />
            </div>
            <div>
              <label>Gerät-Targeting</label>
              <select value={form.device} onChange={set("device")}>
                <option value="all">Alle Geräte</option>
                <option value="desktop">Nur Desktop</option>
                <option value="mobile">Nur Mobile</option>
                <option value="tablet">Nur Tablet</option>
              </select>
            </div>
          </div>
          <div className="form-row">
            <label>Geo-Targeting</label>
            <input value={form.geo} onChange={set("geo")} placeholder="z.B. DE, AT, CH (leer = weltweit)" />
          </div>
          <div style={{background:T.surfaceHi, border:`1px solid ${T.border}`, borderRadius:10, padding:16, marginBottom:16}}>
            <div style={{fontWeight:700, color:T.text, marginBottom:12, fontSize:13, display:"flex", alignItems:"center", gap:6}}><Icon name="rotate" size={15} /> Bounce-Back System</div>
            <div className="form-row-2">
              <div>
                <label>Bounce-Back URL</label>
                <input value={form.bounceUrl} onChange={set("bounceUrl")} placeholder="https://example.com/angebot" />
              </div>
              <div>
                <label>Bounce-Zeit (Sek.)</label>
                <input type="number" value={form.bounceTime} onChange={set("bounceTime")} min={3} max={60} />
              </div>
            </div>
          </div>
          <div style={{background:T.surfaceHi, border:`1px solid ${T.border}`, borderRadius:10, padding:16, marginBottom:16}}>
            <div style={{fontWeight:700, color:T.text, marginBottom:12, fontSize:13, display:"flex", alignItems:"center", gap:6}}><Icon name="coin" size={15} /> Abrechnung</div>
            <div className="form-row">
              <label>Preismodell</label>
              <select value={form.pricingModel} onChange={set("pricingModel")}>
                <option value="cpm">CPM – pro 1000 Impressions</option>
                <option value="cpc">CPC – pro Klick</option>
                <option value="flat">Flatrate – monatliche Buchung</option>
              </select>
            </div>

            {form.pricingModel === "cpm" && (
              <div className="form-row">
                <label>CPM-Preis (€) — leer = Standard ({DEFAULT_PRICING.cpm.toFixed(2)} €)</label>
                <input type="number" step="0.01" value={form.cpmOverride} onChange={set("cpmOverride")} placeholder={`${DEFAULT_PRICING.cpm.toFixed(2)}`} />
              </div>
            )}

            {form.pricingModel === "cpc" && (
              <div className="form-row">
                <label>CPC-Preis (€) — leer = Standard ({DEFAULT_PRICING.cpc.toFixed(2)} €)</label>
                <input type="number" step="0.01" value={form.cpcOverride} onChange={set("cpcOverride")} placeholder={`${DEFAULT_PRICING.cpc.toFixed(2)}`} />
              </div>
            )}

            {form.pricingModel === "flat" && (
              <>
                <div className="form-row">
                  <label>Monatlicher Betrag (€)</label>
                  <input type="number" value={form.flatAmount} onChange={set("flatAmount")} placeholder="z.B. 300" />
                </div>
                <div className="form-row-2">
                  <div>
                    <label>Laufzeit von</label>
                    <input type="date" value={form.flatStart} onChange={set("flatStart")} />
                  </div>
                  <div>
                    <label>Laufzeit bis</label>
                    <input type="date" value={form.flatEnd} onChange={set("flatEnd")} />
                  </div>
                </div>
              </>
            )}
          </div>
          <div className="form-row">
            <label>Frequenz-Cap (Max. Anzeigen/User/Tag)</label>
            <input type="number" value={form.freqCap} onChange={set("freqCap")} min={1} max={20} />
          </div>
        </div>
        <div className="modal-footer">
          <button className="btn btn-ghost" onClick={onClose}>Abbrechen</button>
          <button className="btn btn-primary" onClick={() => onSave(form)}>
            {isNew ? "Kampagne erstellen" : "Speichern"}
          </button>
        </div>
      </div>
    </div>
  );
}

function SnippetModal({ campaign, onClose }) {
  const qrCanvasRef = useRef(null);
  const [qrReady, setQrReady] = useState(false);
  const shortUrl = `https://ad.ly/${campaign.id.toLowerCase()}`;

  const snippet = `<!-- AdPlatform | Kampagne: ${campaign.name} -->
<script>
  (function(w,d,s,id){
    w.AdPlatformQ=w.AdPlatformQ||[];
    var js=d.createElement(s);
    js.src=AD_BASE+'/public/js/loader.js';
    js.onload=function(){
      AdPlatform.init({
        campaign: '${campaign.id}',
        format:   '${campaign.format}',
        bounce:   { url:'${campaign.bounceUrl||""}', time:${campaign.bounceTime||8} }
      });
    };
    d.head.appendChild(js);
  })(window,document,'script','adp');
<\/script>
<div id="ad-slot-${campaign.id}"></div>`;

  useEffect(() => {
    let cancelled = false;
    function draw() {
      if (cancelled || !qrCanvasRef.current || !window.QRCode) return;
      window.QRCode.toCanvas(qrCanvasRef.current, shortUrl, {
        width: 132,
        margin: 1,
        color: { dark: "#18181B", light: "#FFFFFF" }
      }, (err) => { if (!err) setQrReady(true); });
    }
    if (window.QRCode) {
      draw();
    } else {
      const existing = document.getElementById("qrcodejs-lib");
      if (!existing) {
        const script = document.createElement("script");
        script.id = "qrcodejs-lib";
        script.src = "https://cdn.jsdelivr.net/npm/qrcode@1.5.3/build/qrcode.min.js";
        script.onload = draw;
        document.head.appendChild(script);
      } else {
        existing.addEventListener("load", draw);
      }
    }
    return () => { cancelled = true; };
  }, [shortUrl]);

  const downloadQr = () => {
    const canvas = qrCanvasRef.current;
    if (!canvas) return;
    const link = document.createElement("a");
    link.download = `qr-${campaign.id}.png`;
    link.href = canvas.toDataURL("image/png");
    link.click();
  };

  return (
    <div className="modal-overlay" onClick={e => e.target===e.currentTarget && onClose()}>
      <div className="modal">
        <div className="modal-header">
          <span className="modal-title" style={{display:"flex", alignItems:"center", gap:8}}><Icon name="qr" size={17} /> Einbindungs-Code</span>
          <button className="btn btn-ghost btn-sm" onClick={onClose}><Icon name="close" size={14} /></button>
        </div>
        <div className="modal-body">
          <p style={{color:T.muted, marginBottom:16, fontSize:13}}>Füge diesen Code auf deiner Webseite ein, wo die Werbung erscheinen soll.</p>
          <div className="snippet">{snippet}</div>
          <div style={{marginTop:16, textAlign:"center"}}>
            <div className="qr-box" style={{padding: qrReady ? 0 : undefined}}>
              <canvas ref={qrCanvasRef} style={{display: qrReady ? "block" : "none", width:120, height:120}} />
              {!qrReady && <Icon name="qr" size={40} color={T.muted} />}
            </div>
            <div style={{color:T.muted, fontSize:12}} className="mono">{shortUrl}</div>
            <div style={{color:T.muted, fontSize:11, marginTop:4}}>Dynamisch – Ziel-URL jederzeit änderbar</div>
            <button className="btn btn-ghost btn-sm" style={{marginTop:10}} onClick={downloadQr} disabled={!qrReady}>
              <Icon name="download" size={13} /> QR-Code herunterladen
            </button>
          </div>
        </div>
        <div className="modal-footer">
          <button className="btn btn-ghost" onClick={onClose}>Schließen</button>
          <button className="btn btn-primary" onClick={() => { navigator.clipboard?.writeText(snippet); }}><Icon name="copy" size={14} /> Code kopieren</button>
        </div>
      </div>
    </div>
  );
}

// ── Views ──────────────────────────────────────────────────────
function Dashboard({ campaigns }) {
  const [stats, setStats]           = useState(null);
  const [liveEvents, setLiveEvents] = useState([]);
  const [dailyData, setDailyData]   = useState(DAILY);

  useEffect(() => {
    api("dashboard").then(d => {
      if (d.kpi) setStats(d.kpi);
      if (d.live) setLiveEvents(d.live);
      if (d.daily && d.daily.length > 0) {
        setDailyData(d.daily.map(x => parseInt(x.impressions) || 0));
      }
    }).catch(() => {});
  }, []);

  const totalImp   = stats ? stats.impressions   : campaigns.reduce((s,c) => s+c.impressions, 0);
  const totalClk   = stats ? stats.clicks        : campaigns.reduce((s,c) => s+c.clicks, 0);
  const totalSpent = stats ? stats.estimated_cost: campaigns.reduce((s,c) => s+(c.spent||0), 0);
  const active     = stats ? stats.active_campaigns : campaigns.filter(c => c.status==="active").length;
  const clicks2    = [8,12,9,17,14,22,25,19,28,23,32,35,29,38];

  return (
    <div className="page">
      <div className="kpi-grid">
        <KpiCard label="Impressions (heute)" value={fmt(totalImp)} change="12.4% vs. gestern" up color="blue" icon="search" />
        <KpiCard label="Klicks" value={fmt(totalClk)} change="8.1% vs. gestern" up color="green" icon="link" />
        <KpiCard label="Ausgaben (€)" value={`€ ${totalSpent}`} change="3.2% vs. gestern" up={false} color="coral" icon="domain" />
        <KpiCard label="Aktive Kampagnen" value={active} change={`von ${campaigns.length} gesamt`} up color="yellow" icon="campaign" />
      </div>

      <div className="charts-row">
        <div className="card">
          <div className="card-header">
            <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="dashboard" size={15} /> Impressions – letzte 14 Tage</span>
          </div>
          <div className="card-body">
            <MiniChart data={dailyData.length > 0 ? dailyData : DAILY} />
          </div>
        </div>
        <div className="card">
          <div className="card-header">
            <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="tracking" size={15} /> Klick-Verlauf</span>
          </div>
          <div className="card-body">
            <LineChart data={clicks2} />
            <div style={{marginTop:12, display:"flex", justifyContent:"space-between"}}>
              <span style={{color:T.muted, fontSize:12}}>CTR gesamt</span>
              <span className="mono" style={{color:T.accentHi, fontWeight:700}}>{ctr(totalImp, totalClk)}%</span>
            </div>
          </div>
        </div>
      </div>

      <div className="card">
        <div className="card-header">
          <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><span className="status-dot" style={{position:"static"}} /> Live Tracking</span>
          <span style={{fontSize:12, color:T.green}}><span className="status-dot" /> Live</span>
        </div>
        <div className="card-body">
          {liveEvents && liveEvents.length > 0 ? liveEvents.map((r,i) => (
            <div className="live-row" key={i}>
              <div>
                <div className="live-site">{r.campaign_name || "—"}</div>
                <div className="live-url">{r.event_type} · {r.device_type} · {r.timestamp?.slice(0,16)}</div>
              </div>
              <div style={{display:"flex", gap:24}}>
                <div style={{textAlign:"right"}}>
                  <div className="live-stat" style={{color: r.event_type==="click" ? T.green : T.accentHi}}>
                    {r.event_type === "click" ? "Klick" : "Impression"}
                  </div>
                  <div className="live-url">{r.ip}</div>
                </div>
              </div>
            </div>
          )) : (
            <div className="empty" style={{padding:"20px 0"}}>
              <div className="empty-icon"><Icon name="tracking" size={24} color={T.muted}/></div>
              <div className="empty-title" style={{fontSize:13}}>Noch keine Tracking-Daten</div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function CampaignsView({ campaigns, setCampaigns, setToast }) {
  const [modal, setModal] = useState(null); // null | "new" | campaign obj
  const [snippet, setSnippet] = useState(null);
  const [search, setSearch] = useState("");
  const [filter, setFilter] = useState("all");

  const filtered = campaigns.filter(c => {
    const matchSearch = c.name.toLowerCase().includes(search.toLowerCase());
    const matchFilter = filter === "all" || c.status === filter;
    return matchSearch && matchFilter;
  });

  const save = (form) => {
    if (modal === "new") {
      const newC = { ...form, id:`C${String(campaigns.length+1).padStart(3,"0")}`, impressions:0, clicks:0, spent:0, created: new Date().toISOString().slice(0,10) };
      setCampaigns(p => [...p, newC]);
      setToast("Kampagne erstellt!");
    } else {
      setCampaigns(p => p.map(c => c.id===form.id ? form : c));
      setToast("Kampagne gespeichert!");
    }
    setModal(null);
  };

  const del = (id) => {
    if (window.confirm("Kampagne wirklich löschen?")) {
      setCampaigns(p => p.filter(c => c.id !== id));
      setToast("Kampagne gelöscht.");
    }
  };

  const toggle = (camp) => {
    const next = camp.status === "active" ? "paused" : "active";
    setCampaigns(p => p.map(c => c.id===camp.id ? {...c, status:next} : c));
    setToast(`Kampagne ${next === "active" ? "aktiviert" : "pausiert"}.`);
  };

  return (
    <div className="page">
      {modal && <CampaignModal campaign={modal==="new"?null:modal} onClose={() => setModal(null)} onSave={save} />}
      {snippet && <SnippetModal campaign={snippet} onClose={() => setSnippet(null)} />}

      <div style={{display:"flex", gap:12, marginBottom:20, flexWrap:"wrap"}}>
        <input
          style={{maxWidth:260}}
          placeholder="Kampagne suchen..."
          value={search}
          onChange={e => setSearch(e.target.value)}
        />
        <select value={filter} onChange={e => setFilter(e.target.value)} style={{width:"auto"}}>
          <option value="all">Alle Status</option>
          <option value="active">Aktiv</option>
          <option value="paused">Pausiert</option>
          <option value="draft">Draft</option>
          <option value="ended">Beendet</option>
        </select>
        <button className="btn btn-primary" style={{marginLeft:"auto"}} onClick={() => setModal("new")}>
          <Icon name="plus" size={15} /> Neue Kampagne
        </button>
      </div>

      <div className="card">
        <div className="table-wrap">
          <table>
            <thead>
              <tr>
                <th>Kampagne</th>
                <th>Format</th>
                <th>Status</th>
                <th>Modell</th>
                <th>Impressions</th>
                <th>Klicks</th>
                <th>CTR</th>
                <th>Budget</th>
                <th>Fortschritt</th>
                <th>Aktionen</th>
              </tr>
            </thead>
            <tbody>
              {filtered.length === 0 && (
                <tr><td colSpan={10}>
                  <div className="empty">
                    <div className="empty-icon"><Icon name="search" size={32} color={T.muted} /></div>
                    <div className="empty-title">Keine Kampagnen gefunden</div>
                  </div>
                </td></tr>
              )}
              {filtered.map(c => {
                const cost = computeCost(c);
                return (
                <tr key={c.id}>
                  <td>
                    <div style={{fontWeight:600, color:T.white}}>{c.name}</div>
                    <div style={{fontSize:11, color:T.muted}} className="mono">{c.id} · {c.created}</div>
                  </td>
                  <td><span className="format-tag">{c.format}</span></td>
                  <td><StatusBadge status={c.status} /></td>
                  <td>
                    <span className="format-tag" style={{background: c.pricingModel==="flat" ? "#EAF2EC" : T.surfaceHi, color: c.pricingModel==="flat" ? T.green : T.text}}>
                      {c.pricingModel === "cpm" ? "CPM" : c.pricingModel === "cpc" ? "CPC" : "Flatrate"}
                    </span>
                  </td>
                  <td><span className="mono">{fmt(c.impressions)}</span></td>
                  <td><span className="mono" style={{color:T.accentHi}}>{fmt(c.clicks)}</span></td>
                  <td><span className="mono" style={{color: parseFloat(ctr(c.impressions,c.clicks))>2?T.green:T.muted}}>{ctr(c.impressions,c.clicks)}%</span></td>
                  <td><span className="mono">€{c.budget || "—"}</span></td>
                  <td>
                    {c.pricingModel === "flat" ? (
                      <div style={{fontSize:11, color:T.muted}} className="mono">€{cost.toFixed(0)} / Monat</div>
                    ) : (
                      <>
                        <div className="prog-wrap" title={`€${cost.toFixed(2)} von €${c.budget||0} ausgegeben`}>
                          <div className="prog-fill" style={{width:`${c.budget>0?Math.min(100,(cost/c.budget)*100):0}%`}} />
                        </div>
                        <div style={{fontSize:10, color:T.muted, marginTop:2}}>€{cost.toFixed(2)} / €{c.budget || "—"}</div>
                      </>
                    )}
                  </td>
                  <td>
                    <div style={{display:"flex", gap:4}}>
                      <button className="btn btn-ghost btn-sm" onClick={() => setModal(c)} title="Bearbeiten"><Icon name="edit" size={14} /></button>
                      <button className="btn btn-ghost btn-sm" onClick={() => setSnippet(c)} title="Code & QR"><Icon name="qr" size={14} /></button>
                      <button className="btn btn-ghost btn-sm" onClick={() => toggle(c)} title={c.status==="active"?"Pausieren":"Aktivieren"}>
                        <Icon name={c.status==="active"?"pause":"play"} size={14} />
                      </button>
                      <button className="btn btn-danger btn-sm" onClick={() => del(c.id)} title="Löschen"><Icon name="trash" size={14} /></button>
                    </div>
                  </td>
                </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

function TrackingView({ campaigns }) {
  const cardClasses = ["blue","coral","green","yellow"];
  return (
    <div className="page">
      <div className="kpi-grid">
        {["Banner","Popup","Mobile","Textlink"].map((f,i) => {
          const vals = [78420,12340,45600,23100];
          const clks = [1203,892,2341,445];
          return (
            <div className={`kpi-card ${cardClasses[i]}`} key={f}>
              <div className="kpi-label">{f}</div>
              <div className="kpi-value mono">{fmt(vals[i])}</div>
              <div style={{fontSize:12, color:T.muted}}>{fmt(clks[i])} Klicks · CTR {ctr(vals[i],clks[i])}%</div>
            </div>
          );
        })}
      </div>

      <div className="charts-row">
        <div className="card">
          <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="rotate" size={15} /> Bounce-Back Auswertung</span></div>
          <div className="card-body">
            {campaigns.filter(c=>c.bounceUrl).map(c => (
              <div className="live-row" key={c.id}>
                <div>
                  <div className="live-site">{c.name}</div>
                  <div className="live-url">Bounce → {c.bounceUrl||"—"}</div>
                </div>
                <div style={{display:"flex", gap:20, alignItems:"center"}}>
                  <div style={{textAlign:"right"}}>
                    <div className="live-stat" style={{color:T.yellow}}>{rand(5,22)}%</div>
                    <div className="live-url">Bounce-Rate</div>
                  </div>
                  <div style={{textAlign:"right"}}>
                    <div className="live-stat" style={{color:T.green}}>{rand(10,40)}%</div>
                    <div className="live-url">Recovery</div>
                  </div>
                </div>
              </div>
            ))}
            {campaigns.filter(c=>c.bounceUrl).length===0 && (
              <div className="empty">
                <div className="empty-icon"><Icon name="rotate" size={32} color={T.muted} /></div>
                <div className="empty-title">Noch kein Bounce-Back eingerichtet</div>
                <p style={{color:T.muted, fontSize:13}}>Füge eine Bounce-Back URL in einer Kampagne hinzu.</p>
              </div>
            )}
          </div>
        </div>
        <div className="card">
          <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="mobile" size={15} /> Geräte-Split</span></div>
          <div className="card-body">
            {[["Desktop","desktop",58],["Mobile","mobile",34],["Tablet","tablet",8]].map(([lbl,ico,pct]) => (
              <div key={lbl} style={{marginBottom:14}}>
                <div style={{display:"flex", justifyContent:"space-between", marginBottom:4}}>
                  <span style={{fontSize:13, display:"flex", alignItems:"center", gap:6}}><Icon name={ico} size={15} color={T.muted} /> {lbl}</span>
                  <span className="mono" style={{color:T.accentHi, fontSize:13}}>{pct}%</span>
                </div>
                <div className="prog-wrap">
                  <div className="prog-fill" style={{width:`${pct}%`, background: lbl==="Mobile"?T.green:lbl==="Tablet"?T.yellow:undefined}} />
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>

      <div className="card">
        <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="clock" size={15} /> Stündliche Verteilung</span></div>
        <div className="card-body">
          <div className="mini-chart" style={{height:60}}>
            {Array.from({length:24},(_,i)=>{
              const v = i>=6&&i<=22 ? rand(20,100) : rand(2,15);
              return (
                <div className="bar-wrap" key={i}>
                  <div className="bar" style={{height:`${v}%`, opacity: i>=9&&i<=18?1:0.5}} title={`${i}:00 – ${v}%`} />
                  <span className="bar-label">{i%4===0?`${i}h`:""}</span>
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </div>
  );
}

function BillingView({ campaigns, setToast }) {
  const now = new Date();
  const monthLabel = now.toLocaleDateString("de-DE", { month:"long", year:"numeric" });

  const rows = campaigns.map(c => ({ ...c, cost: computeCost(c) }));
  const totalCost = rows.reduce((s,c) => s + c.cost, 0);
  const byModel = {
    cpm:  rows.filter(c => c.pricingModel === "cpm"),
    cpc:  rows.filter(c => c.pricingModel === "cpc"),
    flat: rows.filter(c => c.pricingModel === "flat"),
  };
  const sumModel = list => list.reduce((s,c) => s + c.cost, 0);

  return (
    <div className="page">
      <div className="kpi-grid">
        <KpiCard label={`Kosten · ${monthLabel}`} value={`€ ${totalCost.toFixed(2)}`} change="laufender Monat" up color="blue" icon="coin" />
        <KpiCard label="CPM-Kampagnen" value={`€ ${sumModel(byModel.cpm).toFixed(2)}`} change={`${byModel.cpm.length} Kampagne(n)`} up color="green" icon="dashboard" />
        <KpiCard label="CPC-Kampagnen" value={`€ ${sumModel(byModel.cpc).toFixed(2)}`} change={`${byModel.cpc.length} Kampagne(n)`} up color="yellow" icon="link" />
        <KpiCard label="Flatrate-Buchungen" value={`€ ${sumModel(byModel.flat).toFixed(2)}`} change={`${byModel.flat.length} Buchung(en)`} up color="coral" icon="invoice" />
      </div>

      <div className="card" style={{marginBottom:20}}>
        <div className="card-header">
          <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="coin" size={15} /> Globale Standardpreise</span>
        </div>
        <div className="card-body">
          <div style={{display:"flex", gap:24}}>
            <div>
              <div style={{fontSize:11, color:T.muted, textTransform:"uppercase", letterSpacing:0.5}}>CPM Standard</div>
              <div style={{fontSize:18, fontWeight:700}} className="mono">€{DEFAULT_PRICING.cpm.toFixed(2)} <span style={{fontSize:11, fontWeight:400, color:T.muted}}>/ 1000 Impr.</span></div>
            </div>
            <div>
              <div style={{fontSize:11, color:T.muted, textTransform:"uppercase", letterSpacing:0.5}}>CPC Standard</div>
              <div style={{fontSize:18, fontWeight:700}} className="mono">€{DEFAULT_PRICING.cpc.toFixed(2)} <span style={{fontSize:11, fontWeight:400, color:T.muted}}>/ Klick</span></div>
            </div>
          </div>
          <p style={{fontSize:11.5, color:T.muted, marginTop:12}}>
            Anpassbar unter Einstellungen. Einzelne Kampagnen können davon abweichende Preise nutzen (Override in der Kampagne).
          </p>
        </div>
      </div>

      <div className="card">
        <div className="card-header">
          <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="invoice" size={15} /> Kostenübersicht · {monthLabel}</span>
          <button className="btn btn-ghost btn-sm" onClick={() => setToast("Abrechnungsexport vorbereitet.")}><Icon name="download" size={13} /> Als CSV exportieren</button>
        </div>
        <div className="table-wrap">
          <table>
            <thead>
              <tr>
                <th>Kampagne</th>
                <th>Modell</th>
                <th>Menge</th>
                <th>Preis</th>
                <th>Kosten</th>
                <th>Zeitraum</th>
              </tr>
            </thead>
            <tbody>
              {rows.map(c => (
                <tr key={c.id}>
                  <td style={{fontWeight:600, color:T.text}}>{c.name}</td>
                  <td>
                    <span className="format-tag" style={{background: c.pricingModel==="flat" ? "#EAF2EC" : T.surfaceHi, color: c.pricingModel==="flat" ? T.green : T.text}}>
                      {c.pricingModel === "cpm" ? "CPM" : c.pricingModel === "cpc" ? "CPC" : "Flatrate"}
                    </span>
                  </td>
                  <td className="mono" style={{fontSize:12}}>
                    {c.pricingModel === "cpm" && `${fmt(c.impressions)} Impr.`}
                    {c.pricingModel === "cpc" && `${fmt(c.clicks)} Klicks`}
                    {c.pricingModel === "flat" && (c.flatStart ? `${c.flatStart} – ${c.flatEnd}` : "—")}
                  </td>
                  <td className="mono" style={{fontSize:12, color:T.muted}}>
                    {c.pricingModel === "cpm" && `€${Number(c.cpmOverride || DEFAULT_PRICING.cpm).toFixed(2)} / 1000`}
                    {c.pricingModel === "cpc" && `€${Number(c.cpcOverride || DEFAULT_PRICING.cpc).toFixed(2)} / Klick`}
                    {c.pricingModel === "flat" && "Fixpreis"}
                  </td>
                  <td className="mono" style={{fontWeight:700, color:T.accentHi}}>€{c.cost.toFixed(2)}</td>
                  <td style={{fontSize:12, color:T.muted}}>{monthLabel}</td>
                </tr>
              ))}
            </tbody>
            <tfoot>
              <tr>
                <td colSpan={4} style={{textAlign:"right", fontWeight:700, fontSize:13, borderTop:`1px solid ${T.border}`, padding:"12px 16px"}}>Gesamt</td>
                <td className="mono" style={{fontWeight:700, fontSize:14, borderTop:`1px solid ${T.border}`}}>€{totalCost.toFixed(2)}</td>
                <td style={{borderTop:`1px solid ${T.border}`}}></td>
              </tr>
            </tfoot>
          </table>
        </div>
      </div>
    </div>
  );
}

function PublisherView({ setToast }) {
  const pubs = [];
  return (
    <div className="page">
      <div style={{display:"flex", justifyContent:"flex-end", marginBottom:20}}>
        <button className="btn btn-primary" onClick={() => setToast("Publisher eingeladen!")}><Icon name="plus" size={15} /> Publisher einladen</button>
      </div>
      <div className="card">
        <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="publisher" size={15} /> Publisher-Übersicht</span></div>
        <div className="table-wrap">
          <table>
            <thead>
              <tr>
                <th>Publisher</th>
                <th>Ad-Slots</th>
                <th>Impressions</th>
                <th>Einnahmen (€)</th>
                <th>Status</th>
                <th>Aktionen</th>
              </tr>
            </thead>
            <tbody>
              {pubs.map(p => (
                <tr key={p.id}>
                  <td>
                    <div style={{fontWeight:600, color:T.white}}>{p.name}</div>
                    <div style={{fontSize:11, color:T.muted}} className="mono">{p.id}</div>
                  </td>
                  <td className="mono">{p.slots}</td>
                  <td className="mono">{fmt(p.imp)}</td>
                  <td className="mono" style={{color:T.green}}>€ {p.earn}</td>
                  <td><StatusBadge status={p.status==="pending"?"draft":p.status} /></td>
                  <td>
                    <button className="btn btn-ghost btn-sm" onClick={() => setToast("Snippet kopiert!")}><Icon name="copy" size={13} /> Snippet</button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

const PREVIEW_FORMATS = [
  { id:"popup",        label:"Popup",        icon:"layout" },
  { id:"interstitial",  label:"Interstitial", icon:"layout" },
  { id:"sticky",        label:"Sticky Ad",    icon:"layout" },
  { id:"floating",      label:"Floating Ad",  icon:"layout" },
  { id:"native",        label:"Native Ad",    icon:"layout" },
];

function PreviewView({ campaigns }) {
  const [format, setFormat] = useState("popup");
  const [trigger, setTrigger] = useState("delay");
  const [headline, setHeadline] = useState("20% Rabatt nur heute");
  const [cta, setCta] = useState("Jetzt sichern");

  return (
    <div className="page">
      <div className="format-picker">
        {PREVIEW_FORMATS.map(f => (
          <div key={f.id} className={`format-pill ${format===f.id?"active":""}`} onClick={() => setFormat(f.id)}>
            <Icon name={f.icon} size={14} />
            {f.label}
          </div>
        ))}
      </div>

      <div className="charts-row" style={{gridTemplateColumns:"1fr 320px"}}>
        <div className="card">
          <div className="card-header"><span className="card-title">Live-Vorschau · {PREVIEW_FORMATS.find(f=>f.id===format)?.label}</span></div>
          <div className="card-body">
            <div className="preview-frame">
              <div className="preview-page">
                <div className="preview-page-line" style={{width:"60%"}} />
                <div className="preview-page-line" style={{width:"85%"}} />
                <div className="preview-page-line" style={{width:"40%"}} />
                <div className="preview-page-line" style={{width:"70%"}} />
                <div className="preview-page-line" style={{width:"55%"}} />
              </div>

              {format === "popup" && (
                <div className="mock-popup">
                  <div className="mock-popup-close"><Icon name="close" size={11} /></div>
                  <div style={{fontWeight:700, fontSize:15, marginBottom:8}}>{headline}</div>
                  <div style={{fontSize:12, color:T.muted, marginBottom:14}}>Nur für kurze Zeit verfügbar.</div>
                  <button className="btn btn-primary" style={{width:"100%", justifyContent:"center"}}>{cta}</button>
                </div>
              )}

              {format === "interstitial" && (
                <div className="mock-interstitial">
                  <div className="mock-skip">Überspringen in 4s</div>
                  <div style={{fontWeight:700, fontSize:18, marginBottom:10}}>{headline}</div>
                  <div style={{fontSize:13, color:T.muted, marginBottom:18}}>Vollbild-Werbung zwischen Seitenaufrufen</div>
                  <button className="btn btn-primary">{cta}</button>
                </div>
              )}

              {format === "sticky" && (
                <div className="mock-sticky">
                  <div>
                    <div style={{fontWeight:700, fontSize:13}}>{headline}</div>
                    <div style={{fontSize:11, color:T.muted}}>Klebt am unteren Bildschirmrand</div>
                  </div>
                  <button className="btn btn-primary btn-sm">{cta}</button>
                </div>
              )}

              {format === "floating" && (
                <div className="mock-floating" title={headline}>
                  <Icon name="campaign" size={26} color="#fff" />
                </div>
              )}

              {format === "native" && (
                <div className="mock-native">
                  <div className="mock-native-tag">Sponsored</div>
                  <div style={{fontWeight:700, fontSize:14, marginBottom:6}}>{headline}</div>
                  <div style={{fontSize:12, color:T.muted, marginBottom:10}}>Sieht aus wie redaktioneller Inhalt, klar als Anzeige gekennzeichnet.</div>
                  <span style={{fontSize:12, color:T.accentHi, fontWeight:600}}>{cta} →</span>
                </div>
              )}
            </div>
          </div>
        </div>

        <div className="card">
          <div className="card-header"><span className="card-title">Inhalt anpassen</span></div>
          <div className="card-body">
            <div className="form-row">
              <label>Überschrift</label>
              <input value={headline} onChange={e => setHeadline(e.target.value)} />
            </div>
            <div className="form-row">
              <label>Button-Text</label>
              <input value={cta} onChange={e => setCta(e.target.value)} />
            </div>
            {(format==="popup") && (
              <div className="form-row">
                <label>Auslöser</label>
                <select value={trigger} onChange={e => setTrigger(e.target.value)}>
                  <option value="delay">Nach X Sekunden</option>
                  <option value="exit">Exit-Intent</option>
                  <option value="scroll">Scroll-Tiefe</option>
                  <option value="click">Klick irgendwo</option>
                </select>
              </div>
            )}
            <div style={{fontSize:11.5, color:T.muted, marginTop:8, lineHeight:1.6}}>
              Diese Vorschau zeigt, wie das Format auf einer echten Seite wirkt. Die finalen Inhalte werden pro Kampagne festgelegt.
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function ABTestView({ campaigns, setToast }) {
  const [tests, setTests] = useState([]);
  const [modal, setModal] = useState(null);

  const ctrOf = v => v.impressions>0 ? (v.clicks/v.impressions)*100 : 0;
  const winnerOf = test => test.variants.reduce((best,v) => ctrOf(v) > ctrOf(best) ? v : best, test.variants[0]);

  const save = (form) => {
    if (modal === "new") {
      setTests(p => [...p, { ...form, id:`AB${String(p.length+1).padStart(3,"0")}` }]);
      setToast("A/B-Test erstellt!");
    } else {
      setTests(p => p.map(t => t.id===form.id ? form : t));
      setToast("A/B-Test gespeichert!");
    }
    setModal(null);
  };

  return (
    <div className="page">
      {modal && <ABTestModal test={modal==="new"?null:modal} campaigns={campaigns} onClose={() => setModal(null)} onSave={save} />}

      <div style={{display:"flex", justifyContent:"space-between", alignItems:"center", marginBottom:20}}>
        <p style={{color:T.muted, fontSize:13, maxWidth:480}}>
          Teste mehrere Varianten gegeneinander — Text oder Banner-Bilder. Traffic wird gemäß Split verteilt, der Gewinner anhand der CTR automatisch markiert.
        </p>
        <button className="btn btn-primary" onClick={() => setModal("new")}>
          <Icon name="plus" size={15} /> Neuer A/B-Test
        </button>
      </div>

      {tests.map(test => {
        const winner = winnerOf(test);
        const colors = [T.accentHi, T.green, T.yellow, T.coral];
        const isBanner = test.testType === "banner";
        return (
          <div className="card" key={test.id} style={{marginBottom:16}}>
            <div className="card-header">
              <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}>
                <Icon name={isBanner ? "layout" : "flask"} size={15} /> {test.name}
                <span className="format-tag" style={{marginLeft:4}}>{isBanner ? "Banner" : "Text"}</span>
              </span>
              <div style={{display:"flex", alignItems:"center", gap:10}}>
                <span style={{fontSize:12, color:T.muted}}>{test.campaign}</span>
                <StatusBadge status={test.status} />
                <button className="btn btn-ghost btn-sm" onClick={() => setModal(test)} title="Bearbeiten"><Icon name="edit" size={13} /></button>
              </div>
            </div>
            <div className="card-body">
              <div className="split-bar">
                {test.variants.map((v,i) => (
                  <div key={v.id} className="split-seg" style={{width:`${v.split}%`, background:colors[i%colors.length]}} title={`${v.name}: ${v.split}%`} />
                ))}
              </div>
              <div style={{display:"grid", gridTemplateColumns:`repeat(${test.variants.length}, 1fr)`, gap:12}}>
                {test.variants.map((v,i) => {
                  const isWinner = v.id === winner.id && ctrOf(v) > 0;
                  return (
                    <div key={v.id} className={`variant-card ${isWinner?"winner":""}`}>
                      {isWinner && <span className="winner-tag"><Icon name="trophy" size={11} /> Gewinner</span>}
                      <div style={{fontSize:11, color:T.muted, marginBottom:4}}>{v.name} · {v.split}% Traffic</div>
                      {isBanner ? (
                        v.imageUrl ? (
                          <img src={v.imageUrl} alt={v.name} style={{width:"100%", maxHeight:90, objectFit:"contain", borderRadius:6, border:`1px solid ${T.border}`, background:T.surface, marginBottom:10}} />
                        ) : (
                          <div style={{width:"100%", height:70, display:"flex", alignItems:"center", justifyContent:"center", borderRadius:6, border:`1px dashed ${T.border}`, color:T.muted, fontSize:11, marginBottom:10}}>
                            Kein Bild hinterlegt
                          </div>
                        )
                      ) : (
                        <div style={{fontWeight:600, fontSize:13, marginBottom:10}}>{v.headline}</div>
                      )}
                      <div style={{display:"flex", justifyContent:"space-between", fontSize:12}}>
                        <span className="mono" style={{color:T.muted}}>{fmt(v.impressions)} Impr.</span>
                        <span className="mono" style={{color: isWinner?T.green:T.accentHi, fontWeight:700}}>{ctrOf(v).toFixed(2)}% CTR</span>
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

function ABTestModal({ test, campaigns, onClose, onSave }) {
  const isNew = !test;
  const [form, setForm] = useState(test || {
    name:"", campaign: campaigns[0]?.name || "", status:"active", testType:"text",
    variants:[
      { id:"V1", name:"Variante A", headline:"", imageUrl:"", split:34, impressions:0, clicks:0 },
      { id:"V2", name:"Variante B", headline:"", imageUrl:"", split:33, impressions:0, clicks:0 },
      { id:"V3", name:"Variante C", headline:"", imageUrl:"", split:33, impressions:0, clicks:0 },
    ]
  });

  const setVariant = (i, key, val) => setForm(p => ({ ...p, variants: p.variants.map((v,idx) => idx===i ? {...v,[key]:val} : v) }));
  const addVariant = () => setForm(p => ({ ...p, variants: [...p.variants, { id:`V${p.variants.length+1}`, name: form.testType==="banner" ? `Banner ${String.fromCharCode(65+p.variants.length)}` : `Variante ${String.fromCharCode(65+p.variants.length)}`, headline:"", imageUrl:"", split:0, impressions:0, clicks:0 }] }));
  const removeVariant = (i) => setForm(p => ({ ...p, variants: p.variants.filter((_,idx) => idx!==i) }));
  const setType = (t) => setForm(p => ({
    ...p,
    testType: t,
    variants: p.variants.map((v,i) => ({ ...v, name: t==="banner" ? `Banner ${String.fromCharCode(65+i)}` : `Variante ${String.fromCharCode(65+i)}` }))
  }));

  const totalSplit = form.variants.reduce((s,v) => s + Number(v.split||0), 0);
  const distributeEvenly = () => {
    const n = form.variants.length;
    const base = Math.floor(100/n);
    const rest = 100 - base*n;
    setForm(p => ({ ...p, variants: p.variants.map((v,i) => ({ ...v, split: base + (i < rest ? 1 : 0) })) }));
  };

  const isBanner = form.testType === "banner";

  return (
    <div className="modal-overlay" onClick={e => e.target===e.currentTarget && onClose()}>
      <div className="modal" style={{maxWidth:660}}>
        <div className="modal-header">
          <span className="modal-title" style={{display:"flex", alignItems:"center", gap:8}}>
            <Icon name="flask" size={17} /> {isNew ? "Neuer A/B-Test" : "A/B-Test bearbeiten"}
          </span>
          <button className="btn btn-ghost btn-sm" onClick={onClose}><Icon name="close" size={14} /></button>
        </div>
        <div className="modal-body">
          <div className="form-row-2">
            <div>
              <label>Testname</label>
              <input value={form.name} onChange={e => setForm(p=>({...p,name:e.target.value}))} placeholder="z.B. Headline-Test" />
            </div>
            <div>
              <label>Kampagne</label>
              <select value={form.campaign} onChange={e => setForm(p=>({...p,campaign:e.target.value}))}>
                {campaigns.map(c => <option key={c.id}>{c.name}</option>)}
              </select>
            </div>
          </div>

          <div className="form-row">
            <label>Was wird getestet?</label>
            <div className="format-picker" style={{marginBottom:0}}>
              <div className={`format-pill ${!isBanner?"active":""}`} onClick={() => setType("text")}>
                <Icon name="flask" size={13} /> Text / Headline
              </div>
              <div className={`format-pill ${isBanner?"active":""}`} onClick={() => setType("banner")}>
                <Icon name="layout" size={13} /> Banner-Bild
              </div>
            </div>
          </div>

          <div style={{display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom:10, marginTop:6}}>
            <span style={{fontWeight:700, fontSize:13}}>Varianten</span>
            <span style={{fontSize:11, color: totalSplit===100 ? T.green : T.coral}} className="mono">{totalSplit}% verteilt</span>
          </div>

          {form.variants.map((v,i) => (
            <div key={v.id} style={{display:"flex", gap:8, marginBottom:10, alignItems:"flex-end"}}>
              <div style={{width:90}}>
                {i===0 && <label>Name</label>}
                <input value={v.name} onChange={e => setVariant(i,"name",e.target.value)} />
              </div>
              {isBanner ? (
                <div style={{flex:1}}>
                  {i===0 && <label>Banner-Bild URL (PNG/JPG)</label>}
                  <input value={v.imageUrl} onChange={e => setVariant(i,"imageUrl",e.target.value)} placeholder="https://.../banner-a.png" />
                </div>
              ) : (
                <div style={{flex:1}}>
                  {i===0 && <label>Headline / Inhalt</label>}
                  <input value={v.headline} onChange={e => setVariant(i,"headline",e.target.value)} placeholder="Textvariante..." />
                </div>
              )}
              <div style={{width:70}}>
                {i===0 && <label>Split %</label>}
                <input type="number" min={0} max={100} value={v.split} onChange={e => setVariant(i,"split",e.target.value)} />
              </div>
              {form.variants.length > 2 && (
                <button className="btn btn-danger btn-sm" style={{height:38}} onClick={() => removeVariant(i)}><Icon name="trash" size={13} /></button>
              )}
            </div>
          ))}

          {isBanner && (
            <div style={{display:"grid", gridTemplateColumns:`repeat(${form.variants.length}, 1fr)`, gap:8, marginBottom:14}}>
              {form.variants.map(v => (
                <div key={v.id} style={{textAlign:"center"}}>
                  {v.imageUrl ? (
                    <img src={v.imageUrl} alt={v.name} style={{width:"100%", maxHeight:70, objectFit:"contain", borderRadius:6, border:`1px solid ${T.border}`, background:T.surfaceHi}} />
                  ) : (
                    <div style={{height:50, display:"flex", alignItems:"center", justifyContent:"center", borderRadius:6, border:`1px dashed ${T.border}`, color:T.muted, fontSize:10}}>
                      Vorschau
                    </div>
                  )}
                </div>
              ))}
            </div>
          )}

          <div style={{display:"flex", gap:8}}>
            <button className="btn btn-ghost btn-sm" onClick={addVariant}><Icon name="plus" size={13} /> Weitere Variante</button>
            <button className="btn btn-ghost btn-sm" onClick={distributeEvenly}><Icon name="rotate" size={13} /> Gleich verteilen</button>
          </div>
        </div>
        <div className="modal-footer">
          <button className="btn btn-ghost" onClick={onClose}>Abbrechen</button>
          <button className="btn btn-primary" onClick={() => onSave(form)}>{isNew ? "Test starten" : "Speichern"}</button>
        </div>
      </div>
    </div>
  );
}

function LinksView({ setToast }) {
  const [domains, setDomains] = useState(["derl.ink"]);
  const [links, setLinks]     = useState([]);
  const [loading, setLoading] = useState(true);
  const [modal, setModal]     = useState(null);

  useEffect(() => {
    Promise.all([api("domains"), api("links")]).then(([dd, ld]) => {
      if (dd.domains?.length) setDomains(dd.domains.filter(d => d.status === "active").map(d => d.domain));
      if (ld.links) setLinks(ld.links);
      setLoading(false);
    }).catch(() => setLoading(false));
  }, []);

  const del = async (id) => {
    try { await api("link_delete","POST",{id}); setLinks(p=>p.filter(l=>l.id!==id)); setToast("Link gelöscht."); } catch {}
  };

  const saveLink = async (form) => {
    try {
      if (modal === "new") {
        const data = await api("link_create","POST",{slug:form.slug,domain:form.domain,campaign_name:form.campaign,targets:form.targets,bounce_url:form.bounceUrl||null,bounce_time:form.bounceTime,bounce_max:form.bounceMaxAttempts});
        if (data.error) { setToast("Fehler: "+data.error); return; }
        setLinks(p=>[...p,data.link]); setToast("Short-Link erstellt!");
      } else {
        const data = await api("link_update","POST",{id:form.id,targets:form.targets,bounce_url:form.bounceUrl||null,bounce_time:form.bounceTime,bounce_max:form.bounceMaxAttempts});
        if (data.error) { setToast("Fehler: "+data.error); return; }
        setLinks(p=>p.map(l=>l.id===form.id?data.link:l)); setToast("Gespeichert!");
      }
    } catch { setToast("Fehler beim Speichern."); }
    setModal(null);
  };

  if (loading) return <div className="page"><div className="empty"><div className="empty-icon"><Icon name="link" size={32} color={T.muted}/></div><div className="empty-title">Wird geladen…</div></div></div>;

  return (
    <div className="page">
      {modal && <LinkModal link={modal==="new"?null:modal} domains={domains} onClose={()=>setModal(null)} onSave={saveLink}/>}
      <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:20}}>
        <p style={{color:T.muted,fontSize:13}}>Kurze Links mit URL-Rotation und Bounce-Back.</p>
        <button className="btn btn-primary" onClick={()=>setModal("new")}><Icon name="plus" size={15}/> Neuer Short-Link</button>
      </div>
      <div className="card"><div className="table-wrap"><table>
        <thead><tr><th>Short-Link</th><th>Kampagne</th><th>Rotation</th><th>Bounce-Back</th><th>Klicks</th><th>Aktionen</th></tr></thead>
        <tbody>
          {links.length===0 && <tr><td colSpan={6}><div className="empty"><div className="empty-icon"><Icon name="link" size={28} color={T.muted}/></div><div className="empty-title">Noch keine Links</div></div></td></tr>}
          {links.map(l => {
            const targets = Array.isArray(l.targets)?l.targets:(typeof l.targets==="string"?JSON.parse(l.targets||"[]"):[]);
            return <tr key={l.id}>
              <td><div style={{fontWeight:600}} className="mono">{l.domain}/{l.slug}</div><div style={{fontSize:11,color:T.muted}} className="mono">{l.id}</div></td>
              <td style={{fontSize:13}}>{l.campaign_name||"—"}</td>
              <td>{targets.length===1?<span className="format-tag">1 URL</span>:<span className="format-tag"><Icon name="rotate" size={11}/> {targets.length}× Rotation</span>}</td>
              <td>{l.bounce_url?<span className="badge badge-active" style={{fontSize:10}}><Icon name="rotate" size={10}/> {l.bounce_time}s</span>:<span style={{color:T.muted,fontSize:12}}>—</span>}</td>
              <td className="mono" style={{color:T.accentHi}}>{fmt(l.clicks||0)}</td>
              <td><div style={{display:"flex",gap:4}}>
                <button className="btn btn-ghost btn-sm" onClick={()=>setModal({...l,targets,bounceUrl:l.bounce_url,bounceTime:l.bounce_time,bounceMaxAttempts:l.bounce_max})}><Icon name="edit" size={14}/></button>
                <button className="btn btn-ghost btn-sm" onClick={()=>{navigator.clipboard?.writeText("https://"+l.domain+"/"+l.slug);setToast("Kopiert!");}}><Icon name="copy" size={14}/></button>
                <button className="btn btn-danger btn-sm" onClick={()=>del(l.id)}><Icon name="trash" size={14}/></button>
              </div></td>
            </tr>;
          })}
        </tbody>
      </table></div></div>
    </div>
  );
}
function LinkModal({ link, domains, onClose, onSave }) {
  const isNew = !link;
  const [form, setForm] = useState(link || {
    slug:"", domain:domains[0], campaign:"",
    targets:[{url:"", weight:100}],
    bounceUrl:"", bounceTime:8, bounceMaxAttempts:2,
  });
  const set = k => e => setForm(p => ({ ...p, [k]: e.target.value }));

  const setTarget = (i, key, val) => setForm(p => ({ ...p, targets: p.targets.map((t,idx) => idx===i ? {...t, [key]:val} : t) }));
  const addTarget = () => setForm(p => ({ ...p, targets: [...p.targets, { url:"", weight:0 }] }));
  const removeTarget = (i) => setForm(p => ({ ...p, targets: p.targets.filter((_,idx) => idx!==i) }));

  const totalWeight = form.targets.reduce((s,t) => s + Number(t.weight||0), 0);
  const bounceActive = !!form.bounceUrl?.trim();

  return (
    <div className="modal-overlay" onClick={e => e.target===e.currentTarget && onClose()}>
      <div className="modal" style={{maxWidth:580}}>
        <div className="modal-header">
          <span className="modal-title" style={{display:"flex", alignItems:"center", gap:8}}>
            <Icon name="link" size={18}/> {isNew ? "Neuer Short-Link" : "Short-Link bearbeiten"}
          </span>
          <button className="btn btn-ghost btn-sm" onClick={onClose}><Icon name="close" size={14}/></button>
        </div>
        <div className="modal-body">
          <div className="form-row-2">
            <div>
              <label>Domain</label>
              <select value={form.domain} onChange={set("domain")}>
                {domains.map(d => <option key={d}>{d}</option>)}
              </select>
            </div>
            <div>
              <label>Slug (Kurz-Pfad)</label>
              <input value={form.slug} onChange={set("slug")} placeholder="z.B. sale24"/>
            </div>
          </div>
          <div className="form-row">
            <label>Kampagne</label>
            <input value={form.campaign} onChange={set("campaign")} placeholder="Verknüpfte Kampagne"/>
          </div>

          {/* URL-Rotation */}
          <div style={{background:T.surfaceHi, border:`1px solid ${T.border}`, borderRadius:10, padding:16, marginBottom:14}}>
            <div style={{display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom:12}}>
              <span style={{fontWeight:700, fontSize:13, display:"flex", alignItems:"center", gap:6}}>
                <Icon name="rotate" size={15}/> URL-Rotation
              </span>
              <span style={{fontSize:11, color: totalWeight===100 ? T.green : T.coral}} className="mono">
                {totalWeight}% verteilt
              </span>
            </div>
            {form.targets.map((t, i) => (
              <div key={i} style={{display:"flex", gap:8, marginBottom:10, alignItems:"flex-end"}}>
                <div style={{flex:1}}>
                  {i===0 && <label>Ziel-URL</label>}
                  <input value={t.url} onChange={e => setTarget(i,"url",e.target.value)} placeholder="https://example.com/ziel"/>
                </div>
                <div style={{width:80}}>
                  {i===0 && <label>Gewicht %</label>}
                  <input type="number" min={0} max={100} value={t.weight} onChange={e => setTarget(i,"weight",e.target.value)}/>
                </div>
                {form.targets.length > 1 && (
                  <button className="btn btn-danger btn-sm" style={{height:38}} onClick={() => removeTarget(i)}><Icon name="trash" size={13}/></button>
                )}
              </div>
            ))}
            <button className="btn btn-ghost btn-sm" onClick={addTarget}><Icon name="plus" size={13}/> Weitere Ziel-URL</button>
            <p style={{fontSize:11.5, color:T.muted, marginTop:10}}>
              Traffic wird gemäß Gewichtung zufällig verteilt. Bei einer URL: 100% Weiterleitung ohne Rotation.
            </p>
          </div>

          {/* Bounce-Back */}
          <div style={{background: bounceActive ? "#EAF2EC" : T.surfaceHi, border:`1.5px solid ${bounceActive ? T.green : T.border}`, borderRadius:10, padding:16}}>
            <div style={{display:"flex", alignItems:"center", justifyContent:"space-between", marginBottom:12}}>
              <span style={{fontWeight:700, fontSize:13, display:"flex", alignItems:"center", gap:6, color: bounceActive ? T.green : T.text}}>
                <Icon name="rotate" size={15} color={bounceActive ? T.green : T.text}/> Bounce-Back
                {bounceActive && <span style={{fontSize:10, background:T.green, color:"white", padding:"2px 7px", borderRadius:10, fontWeight:700}}>aktiv</span>}
              </span>
              {bounceActive && (
                <button className="btn btn-ghost btn-sm" style={{fontSize:11}} onClick={() => setForm(p=>({...p, bounceUrl:""}))}>
                  Deaktivieren
                </button>
              )}
            </div>

            <div style={{fontSize:12, color:T.muted, marginBottom:12, lineHeight:1.6}}>
              Verlässt ein Besucher die Zielseite innerhalb der eingestellten Zeit (z.B. durch Klick auf "Zurück"),
              wird er automatisch auf die Bounce-Back URL weitergeleitet — statt zurück zur vorherigen Seite.
            </div>

            <div className="form-row">
              <label>Bounce-Back URL <span style={{fontWeight:400, color:T.muted}}>(leer = deaktiviert)</span></label>
              <input
                value={form.bounceUrl}
                onChange={set("bounceUrl")}
                placeholder="https://example.com/zweite-chance"
                style={{borderColor: bounceActive ? T.green : undefined}}
              />
            </div>

            {bounceActive && (
              <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:10}}>
                <div>
                  <label>Bounce-Zeitfenster (Sek.)</label>
                  <input type="number" value={form.bounceTime} onChange={set("bounceTime")} min={3} max={60}/>
                  <div style={{fontSize:11, color:T.muted, marginTop:4}}>
                    Verlässt der Besucher die Seite innerhalb von {form.bounceTime}s → Bounce-Back wird ausgelöst
                  </div>
                </div>
                <div>
                  <label>Max. Versuche / Besucher</label>
                  <input type="number" value={form.bounceMaxAttempts} onChange={set("bounceMaxAttempts")} min={1} max={5}/>
                  <div style={{fontSize:11, color:T.muted, marginTop:4}}>
                    Wie oft der gleiche Besucher maximal umgeleitet wird
                  </div>
                </div>
              </div>
            )}

            {bounceActive && (
              <div style={{marginTop:12, background:"white", border:`1px solid ${T.border}`, borderRadius:8, padding:12}}>
                <div style={{fontSize:11, fontWeight:600, color:T.muted, marginBottom:6}}>So funktioniert es:</div>
                <div style={{fontSize:12, color:T.muted, display:"flex", flexDirection:"column", gap:4}}>
                  <span>① Besucher klickt auf Short-Link <span className="mono" style={{color:T.text}}>{form.domain||"ad.ly"}/{form.slug||"…"}</span></span>
                  <span>② Landet auf Ziel-URL (gemäß Rotation)</span>
                  <span>③ Verlässt die Seite innerhalb von {form.bounceTime}s</span>
                  <span>④ Wird weitergeleitet zu: <span className="mono" style={{color:T.green, wordBreak:"break-all"}}>{form.bounceUrl}</span></span>
                </div>
              </div>
            )}
          </div>
        </div>
        <div className="modal-footer">
          <button className="btn btn-ghost" onClick={onClose}>Abbrechen</button>
          <button className="btn btn-primary" onClick={() => onSave(form)}>{isNew ? "Link erstellen" : "Speichern"}</button>
        </div>
      </div>
    </div>
  );
}

function DomainsView({ setToast }) {
  const [domains, setDomains]   = useState([]);
  const [loading, setLoading]   = useState(true);
  const [newDomain, setNewDomain] = useState("");
  const [checking, setChecking] = useState({});
  const [dnsResult, setDnsResult] = useState({});

  useEffect(() => {
    api("domains").then(d => { if(d.domains) setDomains(d.domains); setLoading(false); }).catch(() => setLoading(false));
  }, []);

  const add = async () => {
    const d = newDomain.trim().toLowerCase();
    if (!d) return;
    if (domains.find(x => x.domain===d)) { setToast("Domain bereits vorhanden."); return; }
    setNewDomain(""); setToast("Domain wird hinzugefügt & DNS geprüft…");
    try {
      const data = await api("domain_add","POST",{domain:d});
      if (data.error) { setToast("Fehler: "+data.error); return; }
      if (data.domain) { setDomains(p=>[...p,{...data.domain,link_count:0}]); setDnsResult(p=>({...p,[data.domain.id]:data.dns})); setToast(data.dns?.points_to_server?"✅ Verifiziert!":"⚠️ DNS noch nicht korrekt."); }
    } catch { setToast("Verbindungsfehler."); }
  };

  const verify = async (domain) => {
    setChecking(p=>({...p,[domain.id]:true})); setToast("Wird geprüft…");
    try {
      const data = await api("domain_verify","POST",{id:domain.id});
      if (data.domain) { setDomains(p=>p.map(x=>x.id===domain.id?{...x,...data.domain}:x)); setDnsResult(p=>({...p,[domain.id]:data.dns})); setToast(data.dns?.points_to_server?"✅ Verifiziert!":"⚠️ Noch nicht korrekt."); }
    } catch { setToast("Fehler bei DNS-Prüfung."); }
    setChecking(p=>({...p,[domain.id]:false}));
  };

  const makeDefault = async (id) => {
    if (domains.find(x=>x.id===id)?.status!=="active") { setToast("Nur verifizierte Domains können Standard sein."); return; }
    try { await api("domain_set_default","POST",{id}); setDomains(p=>p.map(x=>({...x,is_default:x.id===id?1:0}))); setToast("Standard-Domain gesetzt."); } catch {}
  };

  const remove = async (id) => {
    if (domains.find(x=>x.id===id)?.is_default) { setToast("Standard-Domain kann nicht gelöscht werden."); return; }
    try { await api("domain_delete","POST",{id}); setDomains(p=>p.filter(x=>x.id!==id)); setToast("Domain entfernt."); } catch {}
  };

  if (loading) return <div className="page"><div className="empty"><div className="empty-icon"><Icon name="domain" size={32} color={T.muted}/></div><div className="empty-title">Domains werden geladen…</div></div></div>;

  return (
    <div className="page">
      <div className="card" style={{marginBottom:20}}>
        <div className="card-header"><span className="card-title" style={{display:"flex",alignItems:"center",gap:8}}><Icon name="domain" size={16}/> Neue Domain hinzufügen</span></div>
        <div className="card-body">
          <div style={{display:"flex",gap:10}}>
            <input value={newDomain} onChange={e=>setNewDomain(e.target.value)} onKeyDown={e=>e.key==="Enter"&&add()} placeholder="z.B. meine-kurzdomain.de" style={{flex:1}}/>
            <button className="btn btn-primary" onClick={add}><Icon name="plus" size={15}/> Hinzufügen & prüfen</button>
          </div>
          <div style={{marginTop:12,background:T.surfaceHi,borderRadius:8,padding:12,fontSize:12,color:T.muted}}>
            <strong style={{color:T.text}}>A-Record bei Namecheap:</strong> Type=A, Host=@, Value=IP deines Servers (allincal Kundenbereich), TTL=Auto
          </div>
        </div>
      </div>
      <div className="card">
        <div className="card-header"><span className="card-title" style={{display:"flex",alignItems:"center",gap:7}}><Icon name="domain" size={15}/> Deine Domains</span><span style={{fontSize:12,color:T.muted}}>{domains.filter(d=>d.status==="active").length}/{domains.length} verifiziert</span></div>
        {domains.length===0 ? (
          <div className="empty" style={{padding:40}}><div className="empty-icon"><Icon name="domain" size={32} color={T.muted}/></div><div className="empty-title">Noch keine Domains</div><p style={{color:T.muted,fontSize:13}}>Füge oben deine erste Domain hinzu.</p></div>
        ) : (
          <div className="table-wrap"><table>
            <thead><tr><th>Domain</th><th>Status</th><th>IP</th><th>Verifiziert</th><th>Links</th><th>Standard</th><th>Aktionen</th></tr></thead>
            <tbody>
              {domains.map(d => {
                const dns=dnsResult[d.id]; const isChk=checking[d.id];
                return <tr key={d.id}>
                  <td><span style={{fontWeight:600}} className="mono">{d.domain}</span></td>
                  <td>
                    {isChk?<span style={{fontSize:12,color:T.muted}}>⏳ Prüft…</span>:d.status==="active"?<span className="badge badge-active" style={{gap:4}}><Icon name="shield" size={11}/> Verifiziert</span>:<span className="badge badge-draft" style={{gap:4}}><Icon name="clock" size={11}/> Ausstehend</span>}
                    {dns&&<div style={{fontSize:10,color:dns.points_to_server?T.green:T.coral,marginTop:3}}>{dns.message}</div>}
                  </td>
                  <td className="mono" style={{fontSize:11,color:T.muted}}>{d.resolved_ip||"—"}</td>
                  <td style={{fontSize:11,color:T.muted}}>{d.verified_at?d.verified_at.slice(0,10):"—"}</td>
                  <td className="mono">{d.link_count||0}</td>
                  <td>{d.is_default?<span className="badge badge-active">★ Standard</span>:<button className="btn btn-ghost btn-sm" onClick={()=>makeDefault(d.id)} style={{opacity:d.status!=="active"?0.4:1}}>Standard</button>}</td>
                  <td><div style={{display:"flex",gap:4}}>
                    <button className="btn btn-ghost btn-sm" onClick={()=>verify(d)} disabled={isChk}><Icon name="rotate" size={13}/> Prüfen</button>
                    <button className="btn btn-danger btn-sm" onClick={()=>remove(d.id)} disabled={!!d.is_default} style={{opacity:d.is_default?0.4:1}}><Icon name="trash" size={13}/></button>
                  </div></td>
                </tr>;
              })}
            </tbody>
          </table></div>
        )}
      </div>
    </div>
  );
}
function CustomersView({ setToast }) {
  const [customers, setCustomers] = useState([]);
  const [filter, setFilter] = useState("all"); // all | advertiser | publisher
  const [modal, setModal] = useState(null);

  const filtered = customers.filter(c => filter === "all" || c.role === filter);
  const advertisers = customers.filter(c => c.role === "advertiser");
  const publishers  = customers.filter(c => c.role === "publisher");

  const save = (form) => {
    if (modal === "new") {
      setCustomers(p => [...p, { ...form, id:`${form.role==="advertiser"?"ADV":"PUB"}${String(p.length+1).padStart(3,"0")}`, joined: new Date().toISOString().slice(0,10), spent:0, campaigns:0, impressions:0, earnings:0, slots:0 }]);
      setToast("Kunde angelegt!");
    } else {
      setCustomers(p => p.map(c => c.id===form.id ? form : c));
      setToast("Kunde gespeichert!");
    }
    setModal(null);
  };

  const del = (id) => {
    if (window.confirm("Kunden wirklich löschen?")) {
      setCustomers(p => p.filter(c => c.id !== id));
      setToast("Kunde gelöscht.");
    }
  };

  const initials = (name) => name.split(" ").map(w=>w[0]).join("").slice(0,2).toUpperCase();

  return (
    <div className="page">
      {modal && <CustomerModal customer={modal==="new"?null:modal} onClose={() => setModal(null)} onSave={save} />}

      <div className="kpi-grid" style={{gridTemplateColumns:"repeat(3,1fr)", marginBottom:20}}>
        <KpiCard label="Advertiser gesamt" value={advertisers.length} change={`${advertisers.filter(a=>a.status==="active").length} aktiv`} up color="blue" icon="users" />
        <KpiCard label="Publisher gesamt"  value={publishers.length}  change={`${publishers.filter(p=>p.status==="active").length} aktiv`} up color="green" icon="publisher" />
        <KpiCard label="Offenes Budget"    value={`€ ${advertisers.reduce((s,a)=>s+(a.budget-a.spent),0).toFixed(0)}`} change="verfügbar gesamt" up color="yellow" icon="coin" />
      </div>

      <div style={{display:"flex", gap:10, marginBottom:20, alignItems:"center"}}>
        <div className="tabs" style={{marginBottom:0}}>
          {[["all","Alle"],["advertiser","Advertiser"],["publisher","Publisher"]].map(([v,l]) => (
            <div key={v} className={`tab ${filter===v?"active":""}`} onClick={() => setFilter(v)}>{l}</div>
          ))}
        </div>
        <button className="btn btn-primary" style={{marginLeft:"auto"}} onClick={() => setModal("new")}>
          <Icon name="plus" size={15} /> Kunde anlegen
        </button>
      </div>

      <div className="customer-grid">
        {filtered.map(c => (
          <div className="customer-card" key={c.id}>
            <div style={{display:"flex", justifyContent:"space-between", alignItems:"flex-start"}}>
              <div className="customer-avatar">{initials(c.name)}</div>
              <StatusBadge status={c.status} />
            </div>
            <div className="customer-name">{c.name}</div>
            <div className="customer-meta">{c.company} · {c.email}</div>
            <div className="customer-meta" style={{marginTop:4}}>
              <span className="format-tag">{c.role === "advertiser" ? "Advertiser" : "Publisher"}</span>
              <span style={{marginLeft:6}} className="mono" style={{fontSize:10, color:T.muted}}>{c.id}</span>
            </div>

            {c.role === "advertiser" ? (
              <div className="customer-stats">
                <div>
                  <div className="customer-stat-label">Budget</div>
                  <div className="customer-stat-value">€{c.budget}</div>
                </div>
                <div>
                  <div className="customer-stat-label">Ausgaben</div>
                  <div className="customer-stat-value">€{c.spent}</div>
                </div>
                <div>
                  <div className="customer-stat-label">Kampagnen</div>
                  <div className="customer-stat-value">{c.campaigns}</div>
                </div>
              </div>
            ) : (
              <div className="customer-stats">
                <div>
                  <div className="customer-stat-label">Slots</div>
                  <div className="customer-stat-value">{c.slots}</div>
                </div>
                <div>
                  <div className="customer-stat-label">Impressions</div>
                  <div className="customer-stat-value">{fmt(c.impressions)}</div>
                </div>
                <div>
                  <div className="customer-stat-label">Einnahmen</div>
                  <div className="customer-stat-value">€{(c.earnings||0).toFixed(0)}</div>
                </div>
              </div>
            )}

            <div style={{display:"flex", gap:6, marginTop:14}}>
              <button className="btn btn-ghost btn-sm" style={{flex:1}} onClick={() => setModal(c)}><Icon name="edit" size={13} /> Bearbeiten</button>
              <button className="btn btn-danger btn-sm" onClick={() => del(c.id)}><Icon name="trash" size={13} /></button>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

function CustomerModal({ customer, onClose, onSave }) {
  const isNew = !customer;
  const [form, setForm] = useState(customer || {
    role:"advertiser", name:"", company:"", email:"", status:"active", budget:0
  });
  const set = k => e => setForm(p => ({ ...p, [k]: e.target.value }));

  return (
    <div className="modal-overlay" onClick={e => e.target===e.currentTarget && onClose()}>
      <div className="modal">
        <div className="modal-header">
          <span className="modal-title" style={{display:"flex", alignItems:"center", gap:8}}>
            <Icon name="person" size={17} /> {isNew ? "Neuer Kunde" : "Kunde bearbeiten"}
          </span>
          <button className="btn btn-ghost btn-sm" onClick={onClose}><Icon name="close" size={14} /></button>
        </div>
        <div className="modal-body">
          <div className="form-row">
            <label>Rolle</label>
            <div className="format-picker" style={{marginBottom:0}}>
              <div className={`format-pill ${form.role==="advertiser"?"active":""}`} onClick={() => setForm(p=>({...p,role:"advertiser"}))}><Icon name="users" size={13} /> Advertiser</div>
              <div className={`format-pill ${form.role==="publisher"?"active":""}`}  onClick={() => setForm(p=>({...p,role:"publisher"}))}><Icon name="publisher" size={13} /> Publisher</div>
            </div>
          </div>
          <div className="form-row-2">
            <div><label>Name</label><input value={form.name} onChange={set("name")} placeholder="Vor- und Nachname" /></div>
            <div><label>Status</label>
              <select value={form.status} onChange={set("status")}>
                <option value="active">Aktiv</option>
                <option value="paused">Pausiert</option>
                <option value="draft">Ausstehend</option>
              </select>
            </div>
          </div>
          <div className="form-row">
            <label>Unternehmen / Domain</label>
            <input value={form.company} onChange={set("company")} placeholder={form.role==="publisher" ? "z.B. meine-seite.de" : "z.B. Berger GmbH"} />
          </div>
          <div className="form-row">
            <label>E-Mail</label>
            <input type="email" value={form.email} onChange={set("email")} placeholder="kunde@example.com" />
          </div>
          {form.role === "advertiser" && (
            <div className="form-row">
              <label>Budget (€)</label>
              <input type="number" value={form.budget} onChange={set("budget")} placeholder="z.B. 500" />
            </div>
          )}
          <p style={{fontSize:11.5, color:T.muted, marginTop:4}}>
            {form.role === "advertiser"
              ? "Der Advertiser kann sich später einloggen und eigene Kampagnen verwalten."
              : "Der Publisher erhält automatisch einen Snippet-Code für seine Webseite."}
          </p>
        </div>
        <div className="modal-footer">
          <button className="btn btn-ghost" onClick={onClose}>Abbrechen</button>
          <button className="btn btn-primary" onClick={() => onSave(form)}>{isNew ? "Anlegen" : "Speichern"}</button>
        </div>
      </div>
    </div>
  );
}

// Advertiser-Portal: vereinfachte Ansicht für einen eingeloggten Advertiser-Kunden
function AdvertiserPortal({ campaigns }) {
  const myCampaigns = campaigns.slice(0, 3); // simuliert "eigene" Kampagnen
  const totalImpr = myCampaigns.reduce((s,c)=>s+c.impressions,0);
  const totalClks = myCampaigns.reduce((s,c)=>s+c.clicks,0);
  const totalSpent = myCampaigns.reduce((s,c)=>s+computeCost(c),0);
  const budget = 1200;

  return (
    <div className="page">
      <div style={{background:T.surfaceHi, border:`1px solid ${T.border}`, borderRadius:12, padding:"14px 20px", marginBottom:20, display:"flex", alignItems:"center", gap:10}}>
        <Icon name="person" size={18} color={T.muted} />
        <span style={{fontSize:13, color:T.muted}}>Eingeloggt als <strong style={{color:T.text}}>{user?.name || "Advertiser"}</strong></span>
        <span style={{marginLeft:"auto", fontSize:12, color:T.muted}}>Verbleibend: <strong className="mono" style={{color:T.green}}>€{(budget-totalSpent).toFixed(0)}</strong> von €{budget}</span>
      </div>

      <div className="kpi-grid" style={{gridTemplateColumns:"repeat(4,1fr)"}}>
        <KpiCard label="Impressions" value={fmt(totalImpr)} change="laufender Monat" up color="blue" icon="eye" />
        <KpiCard label="Klicks" value={fmt(totalClks)} change="laufender Monat" up color="green" icon="link" />
        <KpiCard label="Ausgaben" value={`€${totalSpent.toFixed(0)}`} change={`von €${budget} Budget`} up={false} color="coral" icon="coin" />
        <KpiCard label="Kampagnen" value={myCampaigns.length} change={`${myCampaigns.filter(c=>c.status==="active").length} aktiv`} up color="yellow" icon="campaign" />
      </div>

      <div className="card">
        <div className="card-header">
          <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="campaign" size={15} /> Meine Kampagnen</span>
          <button className="btn btn-primary btn-sm"><Icon name="plus" size={13} /> Neue Kampagne anfragen</button>
        </div>
        <div className="table-wrap">
          <table>
            <thead>
              <tr><th>Kampagne</th><th>Format</th><th>Status</th><th>Modell</th><th>Impressions</th><th>CTR</th><th>Kosten</th></tr>
            </thead>
            <tbody>
              {myCampaigns.map(c => (
                <tr key={c.id}>
                  <td style={{fontWeight:600}}>{c.name}</td>
                  <td><span className="format-tag">{c.format}</span></td>
                  <td><StatusBadge status={c.status} /></td>
                  <td><span className="format-tag">{c.pricingModel.toUpperCase()}</span></td>
                  <td className="mono">{fmt(c.impressions)}</td>
                  <td className="mono">{ctr(c.impressions,c.clicks)}%</td>
                  <td className="mono" style={{color:T.accentHi}}>€{computeCost(c).toFixed(2)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

// Publisher-Portal: vereinfachte Ansicht für einen eingeloggten Publisher
function PublisherPortal({ setToast }) {
  const stats = { impressions:89200, clicks:1203, earnings:178.20, slots:1, domain:"mein-shop.com" };
  const snippet = `<!-- AdPlatform | Publisher: mein-shop.com -->
<script src="'+AD_BASE+'/public/js/loader.js"
  data-pub="PUB002"
  data-slot="banner-top">
<\/script>`;

  const monthly = [
    { month:"März", earnings:98.40 },
    { month:"April", earnings:134.20 },
    { month:"Mai", earnings:156.80 },
    { month:"Juni", earnings:178.20 },
  ];

  return (
    <div className="page">
      <div style={{background:T.surfaceHi, border:`1px solid ${T.border}`, borderRadius:12, padding:"14px 20px", marginBottom:20, display:"flex", alignItems:"center", gap:10}}>
        <Icon name="publisher" size={18} color={T.muted} />
        <span style={{fontSize:13, color:T.muted}}>Publisher: <strong style={{color:T.text}}>mein-shop.com</strong></span>
        <span className="badge badge-active" style={{marginLeft:8}}>Verifiziert</span>
      </div>

      <div className="kpi-grid" style={{gridTemplateColumns:"repeat(4,1fr)"}}>
        <KpiCard label="Impressions" value={fmt(stats.impressions)} change="laufender Monat" up color="blue" icon="eye" />
        <KpiCard label="Klicks" value={fmt(stats.clicks)} change="laufender Monat" up color="green" icon="link" />
        <KpiCard label="Einnahmen" value={`€${stats.earnings.toFixed(2)}`} change="laufender Monat" up color="yellow" icon="coin" />
        <KpiCard label="Ad-Slots" value={stats.slots} change="aktiv" up color="coral" icon="layout" />
      </div>

      <div className="charts-row">
        <div className="card">
          <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="tracking" size={15} /> Einnahmen-Verlauf</span></div>
          <div className="card-body">
            <div style={{display:"flex", alignItems:"flex-end", gap:12, height:80}}>
              {monthly.map(m => {
                const max = Math.max(...monthly.map(x=>x.earnings));
                return (
                  <div key={m.month} style={{flex:1, display:"flex", flexDirection:"column", alignItems:"center", gap:4}}>
                    <div style={{width:"100%", height:`${(m.earnings/max)*70}px`, background:T.accentHi, borderRadius:"3px 3px 0 0", opacity:0.7}} />
                    <span style={{fontSize:10, color:T.muted}}>{m.month}</span>
                    <span style={{fontSize:10, fontWeight:700}} className="mono">€{m.earnings.toFixed(0)}</span>
                  </div>
                );
              })}
            </div>
          </div>
        </div>
        <div className="card">
          <div className="card-header">
            <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="qr" size={15} /> Mein Einbindungs-Code</span>
          </div>
          <div className="card-body">
            <div className="snippet" style={{fontSize:11}}>{snippet}</div>
            <button className="btn btn-ghost btn-sm" style={{marginTop:10}} onClick={() => { navigator.clipboard?.writeText(snippet); setToast("Snippet kopiert!"); }}>
              <Icon name="copy" size={13} /> Kopieren
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Phase 5 ───────────────────────────────────────────────────

// ── Fraud Detection ──────────────────────────────────────────
const FRAUD_RULES = {
  ctrThreshold:    0.15,   // > 15% CTR → verdächtig
  burstWindow:     60,     // Sekunden-Fenster für Klick-Bursts
  burstLimit:      8,      // Klicks in burstWindow → Burst-Flag
  ipRepeatLimit:   5,      // gleiche IP > N Klicks → Flag
  unknownAgentScore: 20,   // Headless-Browser / fehlender UA
};

function fraudScore(event) {
  let score = 0;
  const reasons = [];
  if (event.ctr > FRAUD_RULES.ctrThreshold) {
    score += Math.round((event.ctr - FRAUD_RULES.ctrThreshold) * 400);
    reasons.push(`CTR ${(event.ctr*100).toFixed(1)}% (Schwelle: ${FRAUD_RULES.ctrThreshold*100}%)`);
  }
  if (event.ipClicks >= FRAUD_RULES.ipRepeatLimit) {
    score += (event.ipClicks - FRAUD_RULES.ipRepeatLimit + 1) * 12;
    reasons.push(`IP ${event.ip}: ${event.ipClicks}× Klicks`);
  }
  if (event.burstClicks >= FRAUD_RULES.burstLimit) {
    score += (event.burstClicks - FRAUD_RULES.burstLimit + 1) * 10;
    reasons.push(`${event.burstClicks} Klicks in ${FRAUD_RULES.burstWindow}s`);
  }
  if (event.unknownAgent) {
    score += FRAUD_RULES.unknownAgentScore;
    reasons.push("Unbekannter User-Agent / Bot-Verdacht");
  }
  if (event.geo === "blacklisted") {
    score += 30;
    reasons.push("IP-Region auf Blacklist");
  }
  const level = score >= 50 ? "danger" : score >= 20 ? "warning" : "safe";
  return { score: Math.min(score, 100), level, reasons };
}

const FRAUD_EVENTS_INIT = [];
function FraudView({ setToast }) {
  const [events, setEvents] = useState(FRAUD_EVENTS_INIT.map(e => ({ ...e, fraud: fraudScore(e) })));
  const [ipBlacklist, setIpBlacklist] = useState(["91.108.4.120"]);
  const [newIp, setNewIp] = useState("");
  const [filter, setFilter] = useState("all");

  const block = (id) => {
    setEvents(p => p.map(e => e.id===id ? {...e, blocked:true} : e));
    setToast("Event blockiert & IP gemeldet.");
  };
  const addBlacklist = () => {
    if (!newIp.trim()) return;
    setIpBlacklist(p => [...p, newIp.trim()]);
    setNewIp("");
    setToast("IP auf Blacklist gesetzt.");
  };

  const filtered = events.filter(e =>
    filter === "all" ? true : e.fraud.level === filter
  );
  const counts = { danger: events.filter(e=>e.fraud.level==="danger").length, warning: events.filter(e=>e.fraud.level==="warning").length, safe: events.filter(e=>e.fraud.level==="safe").length };

  return (
    <div className="page">
      <div className="kpi-grid">
        <KpiCard label="Gefährlich" value={counts.danger}  change="sofort prüfen" up={false} color="coral"  icon="shieldAlert" />
        <KpiCard label="Verdächtig" value={counts.warning} change="beobachten"    up={false} color="yellow" icon="fire" />
        <KpiCard label="Unauffällig" value={counts.safe}   change="OK"            up        color="green"   icon="shield" />
        <KpiCard label="Blacklist-IPs" value={ipBlacklist.length} change="blockiert" up={false} color="blue" icon="server" />
      </div>

      <div className="charts-row" style={{gridTemplateColumns:"2fr 1fr"}}>
        <div className="card">
          <div className="card-header">
            <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="shieldAlert" size={15}/> Live Event-Monitor</span>
            <div className="tabs" style={{marginBottom:0}}>
              {[["all","Alle"],["danger","🔴"],["warning","🟡"],["safe","🟢"]].map(([v,l]) => (
                <div key={v} className={`tab ${filter===v?"active":""}`} onClick={() => setFilter(v)} style={{padding:"5px 10px"}}>{l}</div>
              ))}
            </div>
          </div>
          <div className="table-wrap">
            <table>
              <thead><tr><th>Zeit</th><th>IP</th><th>Kampagne</th><th>Klicks</th><th>CTR</th><th>Score</th><th>Gründe</th><th>Aktion</th></tr></thead>
              <tbody>
                {filtered.map(e => (
                  <tr key={e.id} style={{opacity: e.blocked ? 0.4 : 1}}>
                    <td className="mono" style={{fontSize:11}}>{e.time}</td>
                    <td className="mono" style={{fontSize:11}}>{e.ip} <span style={{fontSize:10, color:T.muted}}>({e.geo})</span></td>
                    <td style={{fontSize:12}}>{e.campaign}</td>
                    <td className="mono">{e.clicks}</td>
                    <td className="mono">{(e.ctr*100).toFixed(1)}%</td>
                    <td>
                      <span className={`fraud-score fraud-${e.fraud.level}`}>
                        {e.fraud.level === "danger" ? "⚠" : e.fraud.level === "warning" ? "~" : "✓"} {e.fraud.score}
                      </span>
                    </td>
                    <td style={{fontSize:11, color:T.muted, maxWidth:180}}>{e.fraud.reasons.join(", ") || "—"}</td>
                    <td>
                      {!e.blocked ? (
                        <button className="btn btn-danger btn-sm" onClick={() => block(e.id)}>Blockieren</button>
                      ) : (
                        <span style={{fontSize:11, color:T.muted}}>Blockiert</span>
                      )}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>

        <div style={{display:"flex", flexDirection:"column", gap:16}}>
          <div className="card">
            <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="fire" size={15}/> Erkennungs-Schwellen</span></div>
            <div className="card-body" style={{fontSize:12}}>
              {[
                ["CTR-Schwelle", `> ${FRAUD_RULES.ctrThreshold*100}%`],
                ["IP-Wiederholung", `> ${FRAUD_RULES.ipRepeatLimit}× Klicks`],
                ["Burst-Limit", `${FRAUD_RULES.burstLimit} Klicks / ${FRAUD_RULES.burstWindow}s`],
                ["Bot-Score", `+${FRAUD_RULES.unknownAgentScore} Punkte`],
                ["Blacklist-Geo", `+30 Punkte`],
              ].map(([k,v]) => (
                <div key={k} style={{display:"flex", justifyContent:"space-between", padding:"6px 0", borderBottom:`1px solid ${T.border}`}}>
                  <span style={{color:T.muted}}>{k}</span>
                  <span className="mono" style={{fontWeight:700}}>{v}</span>
                </div>
              ))}
            </div>
          </div>
          <div className="card">
            <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="server" size={15}/> IP-Blacklist</span></div>
            <div className="card-body">
              <div style={{display:"flex", gap:6, marginBottom:10}}>
                <input value={newIp} onChange={e=>setNewIp(e.target.value)} placeholder="IP hinzufügen" style={{flex:1, fontSize:12}} />
                <button className="btn btn-danger btn-sm" onClick={addBlacklist}><Icon name="plus" size={12}/></button>
              </div>
              {ipBlacklist.map(ip => (
                <div key={ip} style={{display:"flex", justifyContent:"space-between", alignItems:"center", padding:"5px 0", borderBottom:`1px solid ${T.border}`, fontSize:12}}>
                  <span className="mono">{ip}</span>
                  <button className="btn btn-ghost btn-sm" onClick={() => { setIpBlacklist(p=>p.filter(x=>x!==ip)); setToast("IP entfernt."); }}><Icon name="trash" size={12}/></button>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Heatmap ───────────────────────────────────────────────────
function HeatmapView({ campaigns }) {
  const [selected, setSelected] = useState(campaigns[0]?.id || "");
  const [mode, setMode] = useState("clicks"); // clicks | impressions

  // Generiert reproduzierbare Heatmap-Punkte aus Kampagnen-ID als Seed
  function heatPoints(campaignId, n=40) {
    const seed = campaignId.split("").reduce((s,c)=>s+c.charCodeAt(0),0);
    const pts = [];
    for (let i=0; i<n; i++) {
      const sx = Math.sin(seed * (i+1) * 127.1) * 43758.5453;
      const sy = Math.sin(seed * (i+1) * 311.7) * 43758.5453;
      const si = Math.sin(seed * (i+1) * 74.3) * 43758.5453;
      pts.push({
        x: ((sx - Math.floor(sx)) * 0.8 + 0.1),
        y: ((sy - Math.floor(sy)) * 0.8 + 0.1),
        intensity: (si - Math.floor(si)) * 0.85 + 0.15,
      });
    }
    return pts;
  }

  const camp = campaigns.find(c=>c.id===selected) || campaigns[0];
  const points = camp ? heatPoints(camp.id, 50) : [];

  // Zonen-Analyse
  const zones = [
    { label:"Oben links",   x1:0,   y1:0,   x2:0.5, y2:0.4 },
    { label:"Oben rechts",  x1:0.5, y1:0,   x2:1,   y2:0.4 },
    { label:"Mitte",        x1:0.2, y1:0.3, x2:0.8, y2:0.7 },
    { label:"Unten links",  x1:0,   y1:0.6, x2:0.5, y2:1   },
    { label:"Unten rechts", x1:0.5, y1:0.6, x2:1,   y2:1   },
  ];
  const zoneHits = zones.map(z => ({
    ...z,
    count: points.filter(p => p.x>=z.x1 && p.x<z.x2 && p.y>=z.y1 && p.y<z.y2).length
  }));
  const maxZone = Math.max(...zoneHits.map(z=>z.count));

  const W = 560, H = 320;

  return (
    <div className="page">
      <div style={{display:"flex", gap:12, marginBottom:20, alignItems:"center", flexWrap:"wrap"}}>
        <select value={selected} onChange={e=>setSelected(e.target.value)} style={{maxWidth:280}}>
          {campaigns.map(c=><option key={c.id} value={c.id}>{c.name}</option>)}
        </select>
        <div className="tabs" style={{marginBottom:0}}>
          <div className={`tab ${mode==="clicks"?"active":""}`} onClick={()=>setMode("clicks")}>Klicks</div>
          <div className={`tab ${mode==="impressions"?"active":""}`} onClick={()=>setMode("impressions")}>Impressions</div>
        </div>
        {camp && <span style={{fontSize:12, color:T.muted}}>{fmt(mode==="clicks"?camp.clicks:camp.impressions)} Events visualisiert</span>}
      </div>

      <div className="charts-row" style={{gridTemplateColumns:"2fr 1fr"}}>
        <div className="card">
          <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="cursor" size={15}/> Klick-Verteilung · {camp?.name}</span></div>
          <div className="card-body">
            <div className="heatmap-wrap">
              <svg viewBox={`0 0 ${W} ${H}`} style={{width:"100%", display:"block"}}>
                {/* Seiten-Mockup Hintergrund */}
                <rect x="0" y="0" width={W} height={H} fill="#F4F4F5"/>
                {/* Header-Mockup */}
                <rect x="0" y="0" width={W} height={44} fill="#E2E2E5"/>
                <rect x="20" y="14" width="60" height="16" rx="4" fill="#C8C8CC"/>
                <rect x="100" y="16" width="40" height="12" rx="3" fill="#DDDDE0"/>
                <rect x="150" y="16" width="40" height="12" rx="3" fill="#DDDDE0"/>
                <rect x="200" y="16" width="40" height="12" rx="3" fill="#DDDDE0"/>
                {/* Content-Mockup */}
                <rect x="20" y="62" width={W-40} height="12" rx="3" fill="#E2E2E5"/>
                <rect x="20" y="82" width={W-100} height="12" rx="3" fill="#E2E2E5"/>
                <rect x="20" y="102" width={W-60} height="12" rx="3" fill="#E2E2E5"/>
                <rect x="20" y="130" width="200" height="120" rx="6" fill="#E2E2E5"/>
                <rect x="240" y="130" width={W-260} height="12" rx="3" fill="#E2E2E5"/>
                <rect x="240" y="150" width={W-280} height="12" rx="3" fill="#E2E2E5"/>
                <rect x="240" y="170" width={W-300} height="12" rx="3" fill="#E2E2E5"/>
                <rect x="20" y="270" width={W-40} height="12" rx="3" fill="#E2E2E5"/>
                <rect x="20" y="290" width={W-80} height="12" rx="3" fill="#E2E2E5"/>
                {/* Heatmap-Dots */}
                {points.map((p,i) => (
                  <circle
                    key={i}
                    cx={p.x * W}
                    cy={p.y * H}
                    r={14 + p.intensity * 18}
                    fill={`rgba(24,24,27,${p.intensity * 0.18})`}
                  />
                ))}
                {/* Hot-spots: engere Intensität */}
                {points.filter(p=>p.intensity>0.6).map((p,i) => (
                  <circle key={`h${i}`} cx={p.x*W} cy={p.y*H} r={6+p.intensity*8} fill={`rgba(24,24,27,${p.intensity*0.35})`}/>
                ))}
                {/* Einzelklick-Dots */}
                {points.filter(p=>p.intensity>0.7).map((p,i) => (
                  <circle key={`d${i}`} cx={p.x*W} cy={p.y*H} r={3} fill="rgba(24,24,27,0.7)"/>
                ))}
              </svg>
            </div>
            <div className="heatmap-legend">
              <span>Wenig</span>
              <div className="legend-bar"/>
              <span>Viel</span>
            </div>
          </div>
        </div>

        <div className="card">
          <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="mapPin" size={15}/> Zonen-Analyse</span></div>
          <div className="card-body">
            {zoneHits.map(z => (
              <div key={z.label} style={{marginBottom:14}}>
                <div style={{display:"flex", justifyContent:"space-between", marginBottom:4}}>
                  <span style={{fontSize:12}}>{z.label}</span>
                  <span className="mono" style={{fontSize:12, fontWeight:700}}>{z.count} Klicks</span>
                </div>
                <div className="prog-wrap">
                  <div className="prog-fill" style={{width:`${maxZone>0?(z.count/maxZone)*100:0}%`}}/>
                </div>
              </div>
            ))}
            <div style={{fontSize:11, color:T.muted, marginTop:12}}>
              Klickreichste Zone: <strong style={{color:T.text}}>{zoneHits.reduce((a,b)=>a.count>b.count?a:b).label}</strong>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Push Notifications ────────────────────────────────────────
const INIT_PUSH_CAMPAIGNS = [];

function PushView({ setToast }) {
  const [subscribers] = useState({ total:8420, optIn:6120, optOut:2300, devices:{ desktop:4210, mobile:3680, tablet:530 } });
  const [campaigns, setCampaigns] = useState(INIT_PUSH_CAMPAIGNS);
  const [modal, setModal] = useState(null);
  const [form, setForm] = useState({ title:"", body:"", url:"" });

  const sendPush = () => {
    const newCamp = { id:`PN${String(campaigns.length+1).padStart(3,"0")}`, title:form.title, body:form.body, sent:subscribers.optIn, opened:0, ctr:0, status:"active", sent_at:new Date().toLocaleString("de-DE") };
    setCampaigns(p => [newCamp, ...p]);
    setModal(null);
    setForm({ title:"", body:"", url:"" });
    setToast("Push-Notification gesendet!");
  };

  return (
    <div className="page">
      {modal === "new" && (
        <div className="modal-overlay" onClick={e=>e.target===e.currentTarget&&setModal(null)}>
          <div className="modal">
            <div className="modal-header">
              <span className="modal-title" style={{display:"flex", alignItems:"center", gap:8}}><Icon name="bellRing" size={17}/> Neue Push-Notification</span>
              <button className="btn btn-ghost btn-sm" onClick={()=>setModal(null)}><Icon name="close" size={14}/></button>
            </div>
            <div className="modal-body">
              <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:20}}>
                <div>
                  <div className="form-row"><label>Titel</label><input value={form.title} onChange={e=>setForm(p=>({...p,title:e.target.value}))} placeholder="z.B. Flash Sale heute"/></div>
                  <div className="form-row"><label>Nachricht</label><textarea value={form.body} onChange={e=>setForm(p=>({...p,body:e.target.value}))} placeholder="Kurztext..." style={{height:70}}/></div>
                  <div className="form-row"><label>Ziel-URL (optional)</label><input value={form.url} onChange={e=>setForm(p=>({...p,url:e.target.value}))} placeholder="https://..."/></div>
                  <p style={{fontSize:11.5, color:T.muted}}>Wird an <strong>{subscribers.optIn.toLocaleString()}</strong> aktive Subscriber gesendet.</p>
                </div>
                <div>
                  <label>Vorschau</label>
                  <div style={{background:T.surfaceHi, border:`1px solid ${T.border}`, borderRadius:10, padding:14}}>
                    <div style={{fontSize:10, color:T.muted, marginBottom:6}}>Browser-Notification</div>
                    <div style={{background:"white", borderRadius:8, padding:"10px 14px", boxShadow:"0 2px 12px rgba(0,0,0,0.1)"}}>
                      <div style={{fontWeight:700, fontSize:13, marginBottom:3}}>{form.title || "Titel..."}</div>
                      <div style={{fontSize:12, color:T.muted}}>{form.body || "Nachrichtentext..."}</div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
            <div className="modal-footer">
              <button className="btn btn-ghost" onClick={()=>setModal(null)}>Abbrechen</button>
              <button className="btn btn-primary" onClick={sendPush} disabled={!form.title||!form.body}><Icon name="bellRing" size={14}/> Jetzt senden</button>
            </div>
          </div>
        </div>
      )}

      <div className="kpi-grid">
        <KpiCard label="Subscriber gesamt"  value={subscribers.total.toLocaleString()}  change="registriert"  up color="blue"   icon="bellRing"/>
        <KpiCard label="Aktive Opt-ins"     value={subscribers.optIn.toLocaleString()}  change="empfangen Push" up color="green"  icon="bell"/>
        <KpiCard label="Opt-outs"           value={subscribers.optOut.toLocaleString()} change="abgemeldet"   up={false} color="coral"  icon="close"/>
        <KpiCard label="Ø Öffnungsrate"     value={`${(campaigns.filter(c=>c.sent>0).reduce((s,c)=>s+c.ctr,0)/Math.max(1,campaigns.filter(c=>c.sent>0).length)*100).toFixed(1)}%`} change="aller Kampagnen" up color="yellow" icon="fire"/>
      </div>

      <div className="charts-row">
        <div className="card">
          <div className="card-header">
            <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="bellRing" size={15}/> Push-Kampagnen</span>
            <button className="btn btn-primary btn-sm" onClick={()=>setModal("new")}><Icon name="plus" size={13}/> Neue Notification</button>
          </div>
          <div className="table-wrap">
            <table>
              <thead><tr><th>Titel</th><th>Gesendet</th><th>Geöffnet</th><th>CTR</th><th>Status</th><th>Zeitpunkt</th></tr></thead>
              <tbody>
                {campaigns.map(c => (
                  <tr key={c.id}>
                    <td>
                      <div style={{fontWeight:600, fontSize:13}}>{c.title}</div>
                      <div style={{fontSize:11, color:T.muted}}>{c.body}</div>
                    </td>
                    <td className="mono">{c.sent > 0 ? c.sent.toLocaleString() : "—"}</td>
                    <td className="mono">{c.opened > 0 ? c.opened.toLocaleString() : "—"}</td>
                    <td className="mono" style={{color: c.ctr > 0.15 ? T.green : T.muted}}>{c.sent>0 ? `${(c.ctr*100).toFixed(1)}%` : "—"}</td>
                    <td><StatusBadge status={c.status}/></td>
                    <td style={{fontSize:11, color:T.muted}}>{c.sent_at}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
        <div className="card">
          <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="mobile" size={15}/> Subscriber nach Gerät</span></div>
          <div className="card-body">
            {[["Desktop","desktop",subscribers.devices.desktop],["Mobile","mobile",subscribers.devices.mobile],["Tablet","tablet",subscribers.devices.tablet]].map(([l,ico,n]) => (
              <div key={l} style={{marginBottom:14}}>
                <div style={{display:"flex", justifyContent:"space-between", marginBottom:4}}>
                  <span style={{fontSize:13, display:"flex", alignItems:"center", gap:6}}><Icon name={ico} size={14} color={T.muted}/> {l}</span>
                  <span className="mono" style={{fontSize:12, fontWeight:700}}>{n.toLocaleString()} <span style={{color:T.muted, fontWeight:400}}>({Math.round(n/subscribers.total*100)}%)</span></span>
                </div>
                <div className="prog-wrap"><div className="prog-fill" style={{width:`${n/subscribers.total*100}%`}}/></div>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Native Ads Editor ─────────────────────────────────────────
const NATIVE_SIZES = [
  { id:"feed",     label:"In-Feed",       desc:"300×400 · Im Content-Stream" },
  { id:"widget",   label:"Content Widget",desc:"300×250 · Sidebar / End of Article" },
  { id:"strip",    label:"Strip",         desc:"600×120 · Horizontal Banner" },
  { id:"story",    label:"Story-Format",  desc:"320×568 · Vollbild Mobile" },
];

function NativeAdsView({ campaigns, setToast }) {
  const [ads, setAds] = useState([]);
  const [selected, setSelected] = useState(ads[0]);
  const [editMode, setEditMode] = useState(false);
  const [form, setForm] = useState(ads[0]);

  const setF = k => e => setForm(p=>({...p,[k]:e.target.value}));
  const save = () => {
    if (selected.id === form.id) {
      setAds(p => p.map(a => a.id===form.id ? form : a));
      setSelected(form);
    } else {
      const newAd = { ...form, id:`NA${String(ads.length+1).padStart(3,"0")}` };
      setAds(p => [...p, newAd]);
      setSelected(newAd);
    }
    setEditMode(false);
    setToast("Native Ad gespeichert!");
  };
  const newAd = () => {
    const blank = { id:"__new__", campaign: campaigns[0]?.name||"", title:"", description:"", imageUrl:"", cta:"Mehr erfahren", source:"", size:"feed", status:"draft" };
    setForm(blank);
    setSelected(blank);
    setEditMode(true);
  };

  const currentSize = NATIVE_SIZES.find(s=>s.id===(editMode?form.size:selected?.size)) || NATIVE_SIZES[0];

  return (
    <div className="page">
      <div style={{display:"flex", justifyContent:"space-between", alignItems:"center", marginBottom:20}}>
        <p style={{fontSize:13, color:T.muted, maxWidth:500}}>Erstelle und verwalte Native Ads – Werbemittel, die wie redaktioneller Inhalt aussehen und höhere Klickraten erzielen.</p>
        <button className="btn btn-primary" onClick={newAd}><Icon name="plus" size={15}/> Neue Native Ad</button>
      </div>

      <div style={{display:"grid", gridTemplateColumns:"260px 1fr 280px", gap:16}}>
        {/* Liste */}
        <div className="card" style={{overflow:"hidden"}}>
          <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="newspaper" size={14}/> Native Ads</span></div>
          <div>
            {ads.map(a => (
              <div key={a.id} onClick={() => { setSelected(a); setForm(a); setEditMode(false); }}
                style={{padding:"12px 16px", cursor:"pointer", borderBottom:`1px solid ${T.border}`, background: selected?.id===a.id ? T.surfaceHi : "transparent"}}>
                <div style={{fontWeight:600, fontSize:13}}>{a.title || "Unbenannt"}</div>
                <div style={{fontSize:11, color:T.muted}}>{a.campaign} · {NATIVE_SIZES.find(s=>s.id===a.size)?.label}</div>
                <StatusBadge status={a.status}/>
              </div>
            ))}
          </div>
        </div>

        {/* Editor */}
        <div className="card">
          <div className="card-header">
            <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="edit" size={14}/> {editMode ? "Bearbeiten" : "Details"}</span>
            {!editMode && selected && <button className="btn btn-ghost btn-sm" onClick={() => setEditMode(true)}><Icon name="edit" size={13}/> Bearbeiten</button>}
          </div>
          <div className="card-body">
            {editMode ? (
              <>
                <div className="form-row-2">
                  <div><label>Kampagne</label>
                    <select value={form.campaign} onChange={setF("campaign")}>
                      {campaigns.map(c=><option key={c.id}>{c.name}</option>)}
                    </select>
                  </div>
                  <div><label>Format-Größe</label>
                    <select value={form.size} onChange={setF("size")}>
                      {NATIVE_SIZES.map(s=><option key={s.id} value={s.id}>{s.label} – {s.desc}</option>)}
                    </select>
                  </div>
                </div>
                <div className="form-row"><label>Titel</label><input value={form.title} onChange={setF("title")} placeholder="Anzeigen-Überschrift"/></div>
                <div className="form-row"><label>Beschreibung</label><textarea value={form.description} onChange={setF("description")} placeholder="Kurzbeschreibung..." style={{height:70}}/></div>
                <div className="form-row"><label>Bild-URL (PNG/JPG)</label><input value={form.imageUrl} onChange={setF("imageUrl")} placeholder="https://.../bild.jpg"/></div>
                <div className="form-row-2">
                  <div><label>CTA-Text</label><input value={form.cta} onChange={setF("cta")} placeholder="z.B. Mehr erfahren"/></div>
                  <div><label>Quellen-Label</label><input value={form.source} onChange={setF("source")} placeholder="z.B. mein-blog.de"/></div>
                </div>
                <div className="form-row"><label>Status</label>
                  <select value={form.status} onChange={setF("status")}>
                    <option value="draft">Draft</option><option value="active">Aktiv</option><option value="paused">Pausiert</option>
                  </select>
                </div>
                <div style={{display:"flex", gap:8, marginTop:4}}>
                  <button className="btn btn-ghost" onClick={()=>setEditMode(false)}>Abbrechen</button>
                  <button className="btn btn-primary" onClick={save}>Speichern</button>
                </div>
              </>
            ) : selected ? (
              <div style={{fontSize:13}}>
                {[["Kampagne",selected.campaign],["Format",NATIVE_SIZES.find(s=>s.id===selected.size)?.label+" – "+NATIVE_SIZES.find(s=>s.id===selected.size)?.desc],["Titel",selected.title],["Beschreibung",selected.description],["CTA",selected.cta],["Quelle",selected.source]].map(([k,v])=>(
                  <div key={k} style={{display:"flex", gap:12, padding:"8px 0", borderBottom:`1px solid ${T.border}`}}>
                    <span style={{color:T.muted, minWidth:100}}>{k}</span>
                    <span style={{fontWeight:v===selected.title?700:400}}>{v||"—"}</span>
                  </div>
                ))}
              </div>
            ) : <div className="empty"><div className="empty-icon"><Icon name="newspaper" size={28} color={T.muted}/></div><div className="empty-title">Keine Ad ausgewählt</div></div>}
          </div>
        </div>

        {/* Vorschau */}
        <div>
          <div style={{fontSize:12, color:T.muted, marginBottom:8, fontWeight:600, display:"flex", alignItems:"center", gap:6}}><Icon name="eye" size={14}/> Live-Vorschau · {currentSize.label}</div>
          <div className="native-preview">
            <div className="native-preview-img">
              {(editMode?form.imageUrl:selected?.imageUrl) ? (
                <img src={editMode?form.imageUrl:selected?.imageUrl} alt="" style={{width:"100%", height:"100%", objectFit:"cover"}}/>
              ) : (
                <Icon name="layout" size={32} color={T.muted}/>
              )}
            </div>
            <div className="native-preview-body">
              <div className="native-preview-sponsor">Anzeige · {(editMode?form.source:selected?.source)||"Quelle"}</div>
              <div className="native-preview-title">{(editMode?form.title:selected?.title)||"Anzeigen-Titel erscheint hier"}</div>
              <div className="native-preview-desc">{(editMode?form.description:selected?.description)||"Kurzbeschreibung des Inhalts..."}</div>
              <div className="native-preview-cta">{(editMode?form.cta:selected?.cta)||"Mehr erfahren"} →</div>
            </div>
          </div>
          <div style={{marginTop:10, fontSize:11, color:T.muted}}>{currentSize.desc}</div>
          <div style={{marginTop:16, display:"flex", flexDirection:"column", gap:6}}>
            {NATIVE_SIZES.map(s=>(
              <div key={s.id} onClick={()=>setForm(p=>({...p,size:s.id}))} style={{padding:"8px 12px", borderRadius:8, border:`1px solid ${(editMode?form.size:selected?.size)===s.id?T.accentHi:T.border}`, cursor:editMode?"pointer":"default", fontSize:12, fontWeight:(editMode?form.size:selected?.size)===s.id?700:400}}>
                {s.label} <span style={{color:T.muted, fontWeight:400}}>· {s.desc}</span>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

// ── Social Proof Notifications ────────────────────────────────
const SP_TYPES = [
  { id:"purchase", label:"Kauf",         icon:"coin",       template:"[Name] aus [Stadt] hat gerade gekauft" },
  { id:"viewing",  label:"Zuschauer",    icon:"eye",        template:"[N] Personen schauen sich das gerade an" },
  { id:"review",   label:"Bewertung",    icon:"sparkle",    template:"[Name] hat [Sterne]★ bewertet" },
  { id:"stock",    label:"Low Stock",    icon:"fire",       template:"Nur noch [N] verfügbar!" },
  { id:"signup",   label:"Anmeldung",    icon:"person",     template:"[Name] hat sich gerade angemeldet" },
  { id:"custom",   label:"Eigener Text", icon:"newspaper",  template:"" },
];

const SP_NAMES  = ["Markus B.","Sarah K.","Tom W.","Julia M.","Felix S.","Anna L.","David H.","Lisa R.","Max N.","Nina P."];
const SP_CITIES = ["Berlin","Hamburg","München","Wien","Zürich","Köln","Frankfurt","Stuttgart","Bremen","Leipzig"];
const SP_TIMES  = ["gerade eben","vor 1 Min.","vor 2 Min.","vor 4 Min.","vor 7 Min.","vor 12 Min."];
const WEEKDAYS  = ["Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag","Sonntag"];

function emptySchedule() {
  return WEEKDAYS.map((day, i) => ({ day, dayIndex: i, events: [] }));
}
function todayIndex() {
  const d = new Date().getDay();
  return d === 0 ? 6 : d - 1;
}

const INIT_SP_CAMPAIGNS = [];
function SocialProofView({ setToast }) {
  const [campaigns, setCampaigns] = useState(INIT_SP_CAMPAIGNS);
  const [selected, setSelected]   = useState(null);
  const [editMode, setEditMode]   = useState(false);
  const [form, setForm]           = useState(null);
  const today                     = todayIndex();
  const [activeDay, setActiveDay] = useState(today);
  const [previewIdx, setPreviewIdx] = useState(0);
  const [newName, setNewName]     = useState("");
  const [newCity, setNewCity]     = useState("");
  const [newStars, setNewStars]   = useState(5);

  const activeCamp     = editMode ? form : selected;
  const currentSchedule = activeCamp?.schedule || emptySchedule();
  const daySlot         = currentSchedule[activeDay] || { events:[] };
  const previewEvents   = daySlot.events;

  useEffect(() => {
    if (previewEvents.length < 2) return;
    const t = setInterval(() => setPreviewIdx(i => (i+1) % previewEvents.length), 2500);
    return () => clearInterval(t);
  }, [activeDay, previewEvents.length, selected?.id, form?.id]);

  const previewEvent = previewEvents[previewIdx % Math.max(1, previewEvents.length)];
  const setF = k => e => setForm(p => ({...p, [k]: e.target.value}));

  const setDayEvents = (dayIdx, events) =>
    setForm(p => ({...p, schedule: p.schedule.map((s,i) => i===dayIdx ? {...s, events} : s)}));

  const addEvent = () => {
    if (!newName.trim()) return;
    setDayEvents(activeDay, [...daySlot.events, {name:newName, city:newCity, time:"gerade eben", stars:Number(newStars)}]);
    setNewName(""); setNewCity(""); setNewStars(5);
  };

  const removeEvent = i => setDayEvents(activeDay, daySlot.events.filter((_,idx)=>idx!==i));

  const randomize = () => {
    const n = SP_NAMES[Math.floor(Math.random()*SP_NAMES.length)];
    const c = SP_CITIES[Math.floor(Math.random()*SP_CITIES.length)];
    const t = SP_TIMES[Math.floor(Math.random()*SP_TIMES.length)];
    setDayEvents(activeDay, [...daySlot.events, {name:n, city:c, time:t, stars:Math.ceil(Math.random()*2)+3}]);
  };

  const copyToAll = () => {
    const evs = daySlot.events;
    setForm(p => ({...p, schedule: p.schedule.map(s => ({...s, events:[...evs]}))}));
    setToast("Auf alle Tage kopiert!");
  };

  const save = () => {
    if (form.id === "__new__") {
      const nc = {...form, id:`SP${String(campaigns.length+1).padStart(3,"0")}`};
      setCampaigns(p => [...p, nc]);
      setSelected(nc);
    } else {
      setCampaigns(p => p.map(c => c.id===form.id ? form : c));
      setSelected(form);
    }
    setEditMode(false);
    setToast("Social Proof Kampagne gespeichert!");
  };

  const newCampaign = () => {
    const blank = {id:"__new__", name:"", status:"draft", type:"purchase", product:"", domain:"", delay:4, duration:6, interval:12, position:"bottom-left", schedule:emptySchedule()};
    setForm(blank); setSelected(blank); setEditMode(true); setActiveDay(today);
  };

  const renderPopup = (ev, type, product) => {
    if (!ev) return <div style={{color:T.muted, fontSize:12, textAlign:"center", padding:20}}>Kein Eintrag für {WEEKDAYS[activeDay]}</div>;
    const initials = ev.name.split(" ").map(w=>w[0]).join("").slice(0,2).toUpperCase();
    let actionLine = "";
    if      (type==="purchase") actionLine = `hat "${product||"Produkt"}" gekauft`;
    else if (type==="signup")   actionLine = "hat sich gerade angemeldet";
    else if (type==="review")   actionLine = `hat bewertet ${"★".repeat(ev.stars||5)}`;
    else if (type==="viewing")  actionLine = "schaut sich das gerade an";
    else if (type==="stock")    actionLine = "Nur noch wenige verfügbar!";
    else                        actionLine = product || "hat interagiert";
    return (
      <div className="sp-popup-preview">
        <div className="sp-avatar">
          {type==="viewing"?"👥":type==="stock"?"🔥":type==="review"?"⭐":initials}
        </div>
        <div>
          <div className="sp-popup-name">
            {type==="viewing" ? `${Math.floor(Math.random()*40)+8} Personen` : ev.name}
            {ev.city ? <span style={{fontWeight:400, color:T.muted}}> aus {ev.city}</span> : null}
          </div>
          <div className="sp-popup-action">{actionLine}</div>
          <div className="sp-popup-time">{ev.time} · verifiziert ✓</div>
        </div>
      </div>
    );
  };

  const snippet = activeCamp ? `<!-- AdPlatform Social Proof | ${activeCamp.name} -->
<script>
  (function(){
    var s=document.createElement('script');
    s.src=AD_BASE+'/public/js/loader.js';
    s.onload=function(){
      AdPlatform.socialProof({
        campaign:'${activeCamp.id}',
        type:'${activeCamp.type}',
        delay:${activeCamp.delay},
        duration:${activeCamp.duration},
        interval:${activeCamp.interval},
        position:'${activeCamp.position}',
        schedule:'weekly',
      });
    };
    document.head.appendChild(s);
  })();
<\/script>` : "";

  return (
    <div className="page">
      <div style={{display:"flex", justifyContent:"space-between", alignItems:"center", marginBottom:20}}>
        <p style={{fontSize:13, color:T.muted, maxWidth:520}}>
          Social Proof Notifications mit Wochenplan — für jeden Tag eigene Namen & Städte.
          Nach 7 Tagen wiederholt sich der Zyklus automatisch.
        </p>
        <button className="btn btn-primary" onClick={newCampaign}><Icon name="plus" size={15}/> Neue Kampagne</button>
      </div>

      <div style={{display:"grid", gridTemplateColumns:"230px 1fr 300px", gap:16}}>

        {/* Kampagnen-Liste */}
        <div className="card" style={{overflow:"hidden", alignSelf:"start"}}>
          <div className="card-header">
            <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="socialProof" size={14}/> Kampagnen</span>
          </div>
          {campaigns.map(c => (
            <div key={c.id} onClick={() => {setSelected(c); setForm(c); setEditMode(false); setPreviewIdx(0); setActiveDay(today);}}
              style={{padding:"12px 16px", cursor:"pointer", borderBottom:`1px solid ${T.border}`, background:selected?.id===c.id?T.surfaceHi:"transparent"}}>
              <div style={{display:"flex", justifyContent:"space-between", alignItems:"flex-start"}}>
                <div style={{fontWeight:600, fontSize:13}}>{c.name||"Unbenannt"}</div>
                <StatusBadge status={c.status}/>
              </div>
              <div style={{fontSize:11, color:T.muted, marginTop:2}}>{SP_TYPES.find(t=>t.id===c.type)?.label} · {c.domain||"—"}</div>
            </div>
          ))}
        </div>

        {/* Editor / Details */}
        <div className="card">
          <div className="card-header">
            <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}>
              <Icon name={editMode?"edit":"eye"} size={14}/> {editMode ? "Bearbeiten" : "Details"}
            </span>
            {!editMode && selected && (
              <button className="btn btn-ghost btn-sm" onClick={() => setEditMode(true)}><Icon name="edit" size={13}/> Bearbeiten</button>
            )}
          </div>
          <div className="card-body">

            {/* Wochenplan-Tage-Auswahl — immer sichtbar */}
            <div style={{marginBottom:16}}>
              <div style={{fontSize:12, fontWeight:600, color:T.muted, marginBottom:8, display:"flex", alignItems:"center", gap:6}}>
                <Icon name="clock" size={13}/> Wochenplan — wähle einen Tag
              </div>
              <div style={{display:"flex", gap:4, flexWrap:"wrap"}}>
                {WEEKDAYS.map((day, i) => {
                  const dayEvs = currentSchedule[i]?.events || [];
                  const isToday  = i === today;
                  const isActive = i === activeDay;
                  return (
                    <div key={day} onClick={() => {setActiveDay(i); setPreviewIdx(0);}}
                      style={{padding:"6px 10px", borderRadius:8, cursor:"pointer", fontSize:12,
                        fontWeight:isActive?700:500, textAlign:"center",
                        background:isActive?T.accentHi:T.surfaceHi,
                        color:isActive?"#fff":T.text,
                        border:`1.5px solid ${isActive?T.accentHi:isToday?T.text:T.border}`,
                        position:"relative"}}>
                      {day.slice(0,2)}
                      {isToday && (
                        <span style={{position:"absolute", top:-4, right:-4, width:8, height:8, background:T.green, borderRadius:"50%", border:"1.5px solid white"}}/>
                      )}
                      <div style={{fontSize:9, color:isActive?"rgba(255,255,255,0.7)":T.muted, marginTop:2}}>
                        {dayEvs.length} Eintr.
                      </div>
                    </div>
                  );
                })}
              </div>
              <div style={{fontSize:11, color:T.muted, marginTop:6, display:"flex", alignItems:"center", gap:4}}>
                <span style={{width:8, height:8, background:T.green, borderRadius:"50%", display:"inline-block"}}/> = heute ({WEEKDAYS[today]})
              </div>
            </div>

            {editMode ? (
              <>
                <div className="form-row-2">
                  <div><label>Kampagnenname</label><input value={form.name} onChange={setF("name")} placeholder="z.B. Shop Social Proof"/></div>
                  <div><label>Domain</label><input value={form.domain} onChange={setF("domain")} placeholder="mein-shop.de"/></div>
                </div>
                <div className="form-row">
                  <label>Popup-Typ</label>
                  <div style={{display:"flex", gap:6, flexWrap:"wrap"}}>
                    {SP_TYPES.map(t => (
                      <div key={t.id} className={`sp-type-pill ${form.type===t.id?"active":""}`} onClick={() => setForm(p=>({...p,type:t.id}))}>
                        <Icon name={t.icon} size={12}/> {t.label}
                      </div>
                    ))}
                  </div>
                </div>
                {["purchase","review","signup","custom"].includes(form.type) && (
                  <div className="form-row"><label>Produkt / Text</label><input value={form.product} onChange={setF("product")} placeholder="z.B. Premium-Mitgliedschaft"/></div>
                )}
                <div style={{display:"grid", gridTemplateColumns:"1fr 1fr 1fr", gap:10, marginBottom:16}}>
                  <div><label>Verzögerung (s)</label><input type="number" value={form.delay} onChange={setF("delay")} min={0} max={30}/></div>
                  <div><label>Anzeigedauer (s)</label><input type="number" value={form.duration} onChange={setF("duration")} min={2} max={20}/></div>
                  <div><label>Intervall (s)</label><input type="number" value={form.interval} onChange={setF("interval")} min={5} max={60}/></div>
                </div>
                <div className="form-row-2">
                  <div><label>Position</label>
                    <select value={form.position} onChange={setF("position")}>
                      <option value="bottom-left">Unten links</option>
                      <option value="bottom-right">Unten rechts</option>
                      <option value="top-left">Oben links</option>
                      <option value="top-right">Oben rechts</option>
                    </select>
                  </div>
                  <div><label>Status</label>
                    <select value={form.status} onChange={setF("status")}>
                      <option value="active">Aktiv</option>
                      <option value="paused">Pausiert</option>
                      <option value="draft">Draft</option>
                    </select>
                  </div>
                </div>

                {/* Tages-Events Editor */}
                <div style={{background:T.surfaceHi, border:`1px solid ${T.border}`, borderRadius:10, padding:14, marginBottom:14}}>
                  <div style={{fontWeight:700, fontSize:13, marginBottom:10, display:"flex", alignItems:"center", justifyContent:"space-between"}}>
                    <span style={{display:"flex", alignItems:"center", gap:6}}>
                      <Icon name="users" size={14}/> {WEEKDAYS[activeDay]} – Einträge
                    </span>
                    <div style={{display:"flex", gap:6}}>
                      <button className="btn btn-ghost btn-sm" onClick={randomize}><Icon name="rotate" size={12}/> Zufällig</button>
                      <button className="btn btn-ghost btn-sm" onClick={copyToAll} title="Einträge auf alle Tage kopieren">
                        <Icon name="copy" size={12}/> → Alle Tage
                      </button>
                    </div>
                  </div>
                  {daySlot.events.length === 0 && (
                    <div style={{fontSize:12, color:T.muted, padding:"8px 0", textAlign:"center"}}>Noch keine Einträge für {WEEKDAYS[activeDay]}</div>
                  )}
                  {daySlot.events.map((ev,i) => (
                    <div key={i} style={{display:"flex", alignItems:"center", gap:8, padding:"6px 0", borderBottom:`1px solid ${T.border}`}}>
                      <div style={{flex:1, fontSize:12}}>
                        <strong>{ev.name}</strong>{ev.city ? ` aus ${ev.city}` : ""}{ev.stars>0 ? " " + "★".repeat(ev.stars) : ""}
                      </div>
                      <button className="btn btn-danger btn-sm" onClick={() => removeEvent(i)}><Icon name="trash" size={11}/></button>
                    </div>
                  ))}
                  <div style={{display:"grid", gridTemplateColumns:"1fr 1fr auto auto", gap:6, marginTop:10, alignItems:"flex-end"}}>
                    <div><label>Name</label><input value={newName} onChange={e=>setNewName(e.target.value)} placeholder="Markus B."/></div>
                    <div><label>Stadt</label><input value={newCity} onChange={e=>setNewCity(e.target.value)} placeholder="Berlin"/></div>
                    {form.type==="review" && (
                      <div><label>★</label><input type="number" min={1} max={5} value={newStars} onChange={e=>setNewStars(e.target.value)} style={{width:52}}/></div>
                    )}
                    <button className="btn btn-ghost btn-sm" style={{height:38, marginTop:"auto"}} onClick={addEvent}><Icon name="plus" size={13}/></button>
                  </div>
                  <p style={{fontSize:11, color:T.muted, marginTop:8}}>
                    Jeder Tag hat seine eigene Liste. Mit "→ Alle Tage" kopierst du den aktuellen Tag auf alle anderen.
                  </p>
                </div>

                <div style={{display:"flex", gap:8}}>
                  <button className="btn btn-ghost" onClick={() => setEditMode(false)}>Abbrechen</button>
                  <button className="btn btn-primary" onClick={save}>Speichern</button>
                </div>
              </>
            ) : selected ? (
              <div>
                {[
                  ["Domain",      selected.domain||"—"],
                  ["Typ",         SP_TYPES.find(t=>t.id===selected.type)?.label||"—"],
                  ["Produkt",     selected.product||"—"],
                  ["Position",    selected.position],
                  ["Verzögerung", `${selected.delay}s`],
                  ["Anzeige",     `${selected.duration}s`],
                  ["Intervall",   `${selected.interval}s`],
                ].map(([k,v]) => (
                  <div key={k} style={{display:"flex", gap:12, padding:"8px 0", borderBottom:`1px solid ${T.border}`, fontSize:13}}>
                    <span style={{color:T.muted, minWidth:110}}>{k}</span>
                    <span style={{fontWeight:500}}>{v}</span>
                  </div>
                ))}
                <div style={{marginTop:12, fontSize:12}}>
                  <div style={{fontWeight:600, marginBottom:6, color:T.muted, display:"flex", alignItems:"center", gap:6}}>
                    <Icon name="clock" size={13}/> Einträge pro Wochentag
                  </div>
                  {selected.schedule.map((s,i) => (
                    <div key={i} style={{display:"flex", justifyContent:"space-between", padding:"5px 0", borderBottom:`1px solid ${T.border}`, alignItems:"center"}}>
                      <span style={{display:"flex", alignItems:"center", gap:6, fontWeight:i===today?700:400, fontSize:12}}>
                        {i===today && <span style={{width:7, height:7, background:T.green, borderRadius:"50%", display:"inline-block"}}/>}
                        {s.day}
                      </span>
                      <span className="mono" style={{color:s.events.length===0?T.muted:T.text, fontSize:12}}>
                        {s.events.length} Einträge
                        {s.events.length>0 ? ` · ${s.events.map(e=>e.name).join(", ")}` : ""}
                      </span>
                    </div>
                  ))}
                </div>
                <div style={{marginTop:16}}>
                  <label>Einbindungs-Code</label>
                  <div className="snippet" style={{fontSize:11, marginTop:6}}>{snippet}</div>
                  <button className="btn btn-ghost btn-sm" style={{marginTop:8}} onClick={() => {navigator.clipboard?.writeText(snippet); setToast("Code kopiert!");}}>
                    <Icon name="copy" size={12}/> Kopieren
                  </button>
                </div>
              </div>
            ) : null}
          </div>
        </div>

        {/* Rechte Spalte: Live-Vorschau + Feed */}
        <div style={{display:"flex", flexDirection:"column", gap:16}}>
          <div className="card">
            <div className="card-header">
              <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="sparkle" size={14}/> Vorschau · {WEEKDAYS[activeDay]}</span>
              {activeDay===today && <span className="badge badge-active" style={{fontSize:10}}>Heute</span>}
            </div>
            <div className="card-body">
              <div style={{background:T.surfaceHi, borderRadius:10, padding:20, minHeight:120, position:"relative", overflow:"hidden"}}>
                {[80,60,70,55,65].map((w,i) => (
                  <div key={i} style={{height:8, borderRadius:4, background:T.border, marginBottom:8, width:`${w}%`}}/>
                ))}
                <div style={{
                  position:"absolute",
                  bottom: activeCamp?.position?.startsWith("bottom") ? 10 : "auto",
                  top:    activeCamp?.position?.startsWith("top")    ? 10 : "auto",
                  left:   activeCamp?.position?.endsWith("left")     ? 10 : "auto",
                  right:  activeCamp?.position?.endsWith("right")    ? 10 : "auto",
                  maxWidth:220,
                }}>
                  {renderPopup(previewEvent, activeCamp?.type, activeCamp?.product)}
                </div>
              </div>
              <p style={{fontSize:11, color:T.muted, marginTop:10, textAlign:"center"}}>
                {previewEvents.length>0 ? `Rotiert alle 2.5s · ${previewEvents.length} Einträge` : "Keine Einträge für diesen Tag"}
              </p>
            </div>
          </div>

          <div className="card">
            <div className="card-header">
              <span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="fire" size={14}/> {WEEKDAYS[activeDay]}</span>
            </div>
            <div>
              {previewEvents.length===0 ? (
                <div className="empty" style={{padding:"20px 16px"}}>
                  <div className="empty-icon"><Icon name="users" size={22} color={T.muted}/></div>
                  <div className="empty-title" style={{fontSize:13}}>Keine Einträge</div>
                </div>
              ) : previewEvents.map((ev,i) => (
                <div key={i} className="sp-feed-item">
                  <div className="sp-avatar" style={{width:30, height:30, fontSize:11}}>
                    {ev.name.split(" ").map(w=>w[0]).join("").slice(0,2)}
                  </div>
                  <div style={{flex:1}}>
                    <div style={{fontSize:12, fontWeight:600}}>{ev.name}{ev.city?` · ${ev.city}`:""}</div>
                    <div style={{fontSize:11, color:T.muted}}>{ev.time}{ev.stars>0?` · ${"★".repeat(ev.stars)}`:""}</div>
                  </div>
                  {i===previewIdx%previewEvents.length && (
                    <span style={{fontSize:10, background:T.accentHi, color:"white", padding:"2px 6px", borderRadius:4, fontWeight:700}}>aktiv</span>
                  )}
                </div>
              ))}
            </div>
          </div>
        </div>

      </div>
    </div>
  );
}


function SettingsView({ setToast }) {
  const [cpm, setCpm] = useState(DEFAULT_PRICING.cpm);
  const [cpc, setCpc] = useState(DEFAULT_PRICING.cpc);

  const savePricing = () => {
    DEFAULT_PRICING.cpm = Number(cpm) || DEFAULT_PRICING.cpm;
    DEFAULT_PRICING.cpc = Number(cpc) || DEFAULT_PRICING.cpc;
    setToast && setToast("Standardpreise aktualisiert.");
  };

  return (

    <div className="page">
      <div style={{display:"grid", gridTemplateColumns:"1fr 1fr", gap:16}}>
        <div className="card">
          <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="settings" size={15} /> Allgemein</span></div>
          <div className="card-body">
            <div className="form-row"><label>Plattform-Name</label><input defaultValue="MyAdPlatform" /></div>
            <div className="form-row"><label>Admin-E-Mail</label><input defaultValue="admin@example.com" /></div>
            <div className="form-row"><label>Zeitzone</label>
              <select defaultValue="Europe/Berlin"><option>Europe/Berlin</option><option>Europe/Vienna</option><option>UTC</option></select>
            </div>
            <button className="btn btn-primary btn-sm">Speichern</button>
          </div>
        </div>
        <div className="card">
          <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="coin" size={15} /> Standardpreise (Abrechnung)</span></div>
          <div className="card-body">
            <div className="form-row-2">
              <div>
                <label>CPM (€ / 1000 Impr.)</label>
                <input type="number" step="0.01" value={cpm} onChange={e => setCpm(e.target.value)} />
              </div>
              <div>
                <label>CPC (€ / Klick)</label>
                <input type="number" step="0.01" value={cpc} onChange={e => setCpc(e.target.value)} />
              </div>
            </div>
            <p style={{fontSize:11.5, color:T.muted, marginBottom:12}}>
              Gilt für alle Kampagnen ohne individuellen Preis-Override.
            </p>
            <button className="btn btn-primary btn-sm" onClick={savePricing}>Speichern</button>
          </div>
        </div>
        <div className="card">
          <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="link" size={15} /> API & Integration</span></div>
          <div className="card-body">
            <div className="form-row"><label>API Key</label>
              <div className="snippet" style={{fontSize:12, padding:"8px 12px"}}>ak_live_••••••••••••••••••••••</div>
            </div>
            <button className="btn btn-ghost btn-sm"><Icon name="rotate" size={13} /> Key regenerieren</button>
          </div>
        </div>
        <div className="card">
          <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="rotate" size={15} /> Bounce-Back Defaults</span></div>
          <div className="card-body">
            <div className="form-row"><label>Standard Bounce-Zeit (Sek.)</label><input type="number" defaultValue={8} /></div>
            <div className="form-row"><label>Max. Recovery-Versuche / User</label><input type="number" defaultValue={2} /></div>
            <button className="btn btn-primary btn-sm">Speichern</button>
          </div>
        </div>
        <div className="card">
          <div className="card-header"><span className="card-title" style={{display:"flex", alignItems:"center", gap:7}}><Icon name="shield" size={15} /> DSGVO</span></div>
          <div className="card-body">
            <div className="form-row"><label>Cookie-Consent Modus</label>
              <select><option>Opt-In (DSGVO konform)</option><option>Opt-Out</option></select>
            </div>
            <div className="form-row"><label>Datenlöschung nach (Tage)</label><input type="number" defaultValue={90} /></div>
            <button className="btn btn-primary btn-sm">Speichern</button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ── App Shell ──────────────────────────────────────────────────
const NAV = [
  { id:"dashboard", icon:"dashboard",  label:"Dashboard" },
  { id:"campaigns", icon:"campaign",   label:"Kampagnen" },
  { id:"preview",   icon:"layout",     label:"Vorschau" },
  { id:"abtests",   icon:"flask",      label:"A/B-Tests" },
  { id:"native",    icon:"newspaper",  label:"Native Ads" },
  { id:"tracking",  icon:"tracking",   label:"Tracking & Stats" },
  { id:"heatmap",   icon:"cursor",     label:"Heatmap" },
  { id:"fraud",     icon:"shieldAlert",label:"Fraud Detection" },
  { id:"push",      icon:"bellRing",    label:"Push Notifications" },
  { id:"social",    icon:"socialProof", label:"Social Proof" },
  { id:"billing",   icon:"invoice",    label:"Abrechnung" },
  { id:"customers", icon:"users",      label:"Kunden" },
  { id:"links",     icon:"link",       label:"Short Links" },
  { id:"publisher", icon:"publisher",  label:"Publisher" },
  { id:"domains",   icon:"domain",     label:"Domains" },
  { id:"settings",  icon:"settings",   label:"Einstellungen" },
];

const ROLES = [
  { id:"admin",      icon:"settings", label:"Admin" },
  { id:"advertiser", icon:"users",    label:"Advertiser" },
  { id:"publisher",  icon:"publisher",label:"Publisher" },
];

function App({ user, onLogout }) {
  const [view, setView] = useState("dashboard");
  const [role, setRole] = useState("admin");
  const [campaigns, setCampaigns] = useState(INIT_CAMPAIGNS);
  const [toast, setToast] = useState(null);
  const active = campaigns.filter(c => c.status==="active").length;

  // Wenn Rolle wechselt, Startview setzen
  const switchRole = (r) => {
    setRole(r);
    setView("dashboard");
  };

  const navForRole = role === "admin" ? NAV : [];

  return (
    <>
      <style>{css}</style>
      {toast && <Toast msg={toast} onDone={() => setToast(null)} />}
      <div className="shell">

        {/* Sidebar – nur für Admin */}
        {role === "admin" && (
          <aside className="sidebar">
            <div className="sidebar-logo">
              <div className="logo-mark">
                <div className="logo-icon"><Icon name="dashboard" size={17} color="#FFFFFF" active /></div>
                <div>
                  <div>AdPlatform</div>
                  <div className="logo-sub">v1.0 · Phase 4</div>
                </div>
              </div>
            </div>
            <nav className="nav-section">
              <div className="nav-label">Navigation</div>
              {NAV.map(n => (
                <div
                  key={n.id}
                  className={`nav-item ${view===n.id?"active":""}`}
                  onClick={() => setView(n.id)}
                >
                  <span className="nav-icon"><Icon name={n.icon} size={18} active={view===n.id} /></span>
                  {n.label}
                  {n.id==="campaigns" && <span className="nav-badge">{active}</span>}
                </div>
              ))}
            </nav>
            <div className="sidebar-footer">
              <div style={{fontSize:12, color:T.muted}}>
                <span className="status-dot" />
                Ad-Server online
              </div>
              <div style={{fontSize:11, color:T.muted, marginTop:4}}>
                {campaigns.length} Kampagnen total
              </div>
            </div>
          </aside>
        )}

        <div className="main">
          {/* Topbar */}
          <div className="topbar">
            <div>
              <div className="topbar-title" style={{display:"flex", alignItems:"center", gap:8}}>
                {role === "admin" && <>
                  <Icon name={NAV.find(n=>n.id===view)?.icon || "dashboard"} size={20} active />
                  {NAV.find(n=>n.id===view)?.label || "Dashboard"}
                </>}
                {role === "advertiser" && <><Icon name="users" size={20} active /> Mein Portal · Advertiser</>}
                {role === "publisher"  && <><Icon name="publisher" size={20} active /> Mein Portal · Publisher</>}
              </div>
              <div className="topbar-sub">
                {new Date().toLocaleDateString("de-DE", {weekday:"long", year:"numeric", month:"long", day:"numeric"})}
              </div>
            </div>
            <div className="topbar-actions">
              {/* Rollen-Tabs */}
              <div className="role-tabs">
                {ROLES.map(r => (
                  <div key={r.id} className={`role-tab ${role===r.id?"active":""}`} onClick={() => switchRole(r.id)}>
                    <Icon name={r.icon} size={14} active={role===r.id} />
                    {r.label}
                  </div>
                ))}
              </div>
              {role === "admin" && (
                <span style={{fontSize:12, color:T.muted}} className="mono">
                  {campaigns.reduce((s,c)=>s+c.impressions,0).toLocaleString()} Impr.
                </span>
              )}
              <button className="btn btn-ghost btn-sm"><Icon name="bell" size={16} /></button>
              <button className="btn btn-ghost btn-sm" onClick={onLogout} style={{display:"flex",alignItems:"center",gap:5}}><Icon name="close" size={14}/> Logout</button>
            </div>
          </div>

          {/* Admin Views */}
          {role === "admin" && <>
            {view === "dashboard"  && <Dashboard campaigns={campaigns} />}
            {view === "campaigns"  && <CampaignsView campaigns={campaigns} setCampaigns={setCampaigns} setToast={setToast} />}
            {view === "preview"    && <PreviewView campaigns={campaigns} />}
            {view === "abtests"    && <ABTestView campaigns={campaigns} setToast={setToast} />}
            {view === "native"     && <NativeAdsView campaigns={campaigns} setToast={setToast} />}
            {view === "tracking"   && <TrackingView campaigns={campaigns} />}
            {view === "heatmap"    && <HeatmapView campaigns={campaigns} />}
            {view === "fraud"      && <FraudView setToast={setToast} />}
            {view === "push"       && <PushView setToast={setToast} />}
            {view === "social"     && <SocialProofView setToast={setToast} />}
            {view === "billing"    && <BillingView campaigns={campaigns} setToast={setToast} />}
            {view === "customers"  && <CustomersView setToast={setToast} />}
            {view === "links"      && <LinksView setToast={setToast} />}
            {view === "publisher"  && <PublisherView setToast={setToast} />}
            {view === "domains"    && <DomainsView setToast={setToast} />}
            {view === "settings"   && <SettingsView setToast={setToast} />}
          </>}

          {/* Advertiser Portal */}
          {role === "advertiser" && <AdvertiserPortal campaigns={campaigns} />}

          {/* Publisher Portal */}
          {role === "publisher" && <PublisherPortal setToast={setToast} />}
        </div>
      </div>
    </>
  );
}

// ── Login-Komponente ───────────────────────────────────────────
function LoginScreen({ onLogin }) {
  const [email, setEmail]       = useState("");
  const [password, setPassword] = useState("");
  const [error, setError]       = useState("");
  const [loading, setLoading]   = useState(false);

  const login = async () => {
    if (!email || !password) { setError("Bitte Email und Passwort eingeben."); return; }
    setLoading(true); setError("");
    try {
      const data = await api("login", "POST", { email, password });
      if (data.token) {
        setToken(data.token);
        onLogin(data.user);
      } else {
        setError(data.error || "Ungültige Zugangsdaten");
      }
    } catch {
      setError("Server nicht erreichbar. API_BASE in index.html prüfen.");
    }
    setLoading(false);
  };

  const handleKey = (e) => { if (e.key === "Enter") login(); };

  return (
    <div className="login-wrap">
      <div className="login-box">
        <div className="login-logo">
          <div className="login-logo-icon">
            <Icon name="dashboard" size={22} color="#fff" active />
          </div>
          <div>
            <div className="login-title">AdPlatform</div>
            <div className="login-sub">Dashboard</div>
          </div>
        </div>
        {error && <div className="login-error">{error}</div>}
        <div className="login-field">
          <label>E-Mail</label>
          <input type="email" value={email} onChange={e=>setEmail(e.target.value)} onKeyDown={handleKey} placeholder="admin@deine-domain.de" autoFocus />
        </div>
        <div className="login-field">
          <label>Passwort</label>
          <input type="password" value={password} onChange={e=>setPassword(e.target.value)} onKeyDown={handleKey} placeholder="••••••••" />
        </div>
        <button className="login-btn" onClick={login} disabled={loading}>
          {loading ? "Wird eingeloggt…" : "Einloggen"}
        </button>
      </div>
    </div>
  );
}

// ── App-Wrapper mit Login-Gate ─────────────────────────────────
function AppWithAuth() {
  const [user, setUser] = useState(null);
  const [checking, setChecking] = useState(true);

  useEffect(() => {
    // Prüfen ob bereits eingeloggt (Token im localStorage)
    const token = getToken();
    if (!token) { setChecking(false); return; }
    api("me").then(data => {
      if (data.user) setUser(data.user);
      else clearToken();
      setChecking(false);
    }).catch(() => { clearToken(); setChecking(false); });
  }, []);

  const logout = () => { clearToken(); setUser(null); };

  if (checking) return <div className="login-loading">Wird geladen…</div>;
  if (!user)    return <LoginScreen onLogin={setUser} />;
  return <App user={user} onLogout={logout} />;
}

// ── React mounten ─────────────────────────────────────────────
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<AppWithAuth />);
</script>
</body>
</html>
