// app.jsx — Techweise · Partner advertenties (Board 1)
const { useState, useRef, useEffect } = React;

/* ----------------------------------------------------------------- icons */
const Ic = {
  layers: (p) => (<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 3 3 8l9 5 9-5-9-5Z"/><path d="m3 13 9 5 9-5"/></svg>),
  spark: (p) => (<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 3v3m0 12v3m9-9h-3M6 12H3m13.5-6.5-2 2m-7 7-2 2m11 0-2-2m-7-7-2-2"/><circle cx="12" cy="12" r="2.5"/></svg>),
  trophy: (p) => (<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M7 4h10v4a5 5 0 0 1-10 0V4Z"/><path d="M17 5h3v2a3 3 0 0 1-3 3M7 5H4v2a3 3 0 0 0 3 3M9 18h6M10 14.5V18M14 14.5V18M8 21h8"/></svg>),
  gear: (p) => (<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.5 1.5 0 0 0 .3 1.7l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.5 1.5 0 0 0-2.5.6 1.5 1.5 0 0 0-1 1.4V22a2 2 0 0 1-4 0v-.1a1.5 1.5 0 0 0-2.6-1 1.5 1.5 0 0 0-1.7.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.5 1.5 0 0 0-.6-2.5 1.5 1.5 0 0 0-1.4-1H2a2 2 0 0 1 0-4h.1a1.5 1.5 0 0 0 1-2.6 1.5 1.5 0 0 0-.3-1.7l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.5 1.5 0 0 0 1.7.3H8a1.5 1.5 0 0 0 1-1.4V2a2 2 0 0 1 4 0v.1a1.5 1.5 0 0 0 1 1.4 1.5 1.5 0 0 0 1.7-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.5 1.5 0 0 0-.3 1.7V8a1.5 1.5 0 0 0 1.4 1H22a2 2 0 0 1 0 4h-.1a1.5 1.5 0 0 0-1.4 1Z"/></svg>),
  chevron: (p) => (<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m6 9 6 6 6-6"/></svg>),
  calendar: (p) => (<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="3" y="4.5" width="18" height="16" rx="2.5"/><path d="M3 9h18M8 2.5v4M16 2.5v4"/></svg>),
  pencil: (p) => (<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 20h9"/><path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4 12.5-12.5Z"/></svg>),
  ext: (p) => (<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M7 17 17 7M9 7h8v8"/></svg>),
  sort: (p) => (<svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m8 9 4-4 4 4M8 15l4 4 4-4"/></svg>),
  search: (p) => (<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="11" cy="11" r="7"/><path d="m20 20-3-3"/></svg>),
  filter: (p) => (<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M3 5h18l-7 8v5l-4 2v-7L3 5Z"/></svg>),
  check: (p) => (<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="m20 6-11 11-5-5"/></svg>),
};

/* ----------------------------------------------------------------- sidebar */
function Sidebar({ view, setView }) {
  const nav = [
    { id: 'partner', label: 'Partner advertenties', icon: Ic.layers },
    { id: 'creative', label: 'Creative Strategist', icon: Ic.spark },
    { id: 'leaderboard', label: 'Editor leaderboard', icon: Ic.trophy, soon: true },
    { id: 'settings', label: 'Instellingen', icon: Ic.gear },
  ];
  return (
    <aside style={SB.aside}>
      <div style={SB.brand}>
        <div style={SB.logo}>T</div>
        <div>
          <div style={SB.brandName}>Techweise</div>
          <div style={SB.brandSub}>Agency workspace</div>
        </div>
      </div>

      <nav style={{ display: 'flex', flexDirection: 'column', gap: 2, marginTop: 8 }}>
        {nav.map((n) => {
          const active = view === n.id;
          return (
            <div key={n.id}
              onClick={() => { if (!n.soon) setView(n.id); }}
              style={{
                ...SB.item,
                ...(active ? SB.itemActive : null),
                ...(n.soon ? SB.itemSoon : null),
              }}>
              {active && <span style={SB.activeBar} />}
              <n.icon style={{ color: active ? 'var(--accent)' : (n.soon ? 'var(--muted-2)' : 'var(--ink-2)'), flexShrink: 0 }} />
              <span style={{ flex: 1 }}>{n.label}</span>
              {n.soon && <span style={SB.soonPill}>Binnenkort</span>}
            </div>
          );
        })}
      </nav>

      <div style={{ flex: 1 }} />

      <div style={SB.user}>
        <div style={SB.avatar}>IP</div>
        <div style={{ minWidth: 0 }}>
          <div style={SB.userName}>Ivo Peeters</div>
          <div style={SB.userSub}>ivo@techweise.nl</div>
        </div>
        <Ic.chevron style={{ color: 'var(--muted-2)', transform: 'rotate(-90deg)', marginLeft: 'auto' }} />
      </div>
    </aside>
  );
}
const SB = {
  aside: { position: 'fixed', top: 0, left: 0, bottom: 0, width: 240, background: 'var(--surface)', borderRight: '1px solid var(--hairline)', display: 'flex', flexDirection: 'column', padding: '20px 14px 16px', zIndex: 20 },
  brand: { display: 'flex', alignItems: 'center', gap: 11, padding: '4px 8px 16px' },
  logo: { width: 34, height: 34, borderRadius: 9, background: 'var(--ink)', color: '#fff', display: 'grid', placeItems: 'center', fontWeight: 600, fontSize: 17, letterSpacing: '-0.02em' },
  brandName: { fontWeight: 600, fontSize: 14.5, letterSpacing: '-0.01em' },
  brandSub: { fontSize: 11.5, color: 'var(--muted)' },
  item: { position: 'relative', display: 'flex', alignItems: 'center', gap: 11, padding: '9px 10px', borderRadius: 9, fontSize: 13.5, fontWeight: 450, color: 'var(--ink-2)', cursor: 'pointer' },
  itemActive: { background: 'color-mix(in srgb, var(--accent) 9%, white)', color: 'var(--accent-ink)', fontWeight: 500 },
  itemSoon: { color: 'var(--muted-2)', cursor: 'default' },
  activeBar: { position: 'absolute', left: -14, top: 8, bottom: 8, width: 3, borderRadius: 99, background: 'var(--accent)' },
  soonPill: { fontSize: 9.5, fontWeight: 500, letterSpacing: '0.01em', color: 'var(--muted)', background: '#F4F4F3', border: '1px solid var(--hairline)', borderRadius: 99, padding: '2px 7px' },
  user: { display: 'flex', alignItems: 'center', gap: 10, padding: '9px 8px', borderRadius: 10, border: '1px solid var(--hairline)', cursor: 'pointer' },
  avatar: { width: 30, height: 30, borderRadius: 99, background: 'linear-gradient(135deg,#1f1f1f,#3a3a3a)', color: '#fff', display: 'grid', placeItems: 'center', fontSize: 11.5, fontWeight: 600, flexShrink: 0 },
  userName: { fontSize: 13, fontWeight: 500, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' },
  userSub: { fontSize: 11, color: 'var(--muted)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' },
};

/* ----------------------------------------------------------------- dropdown */
function Dropdown({ trigger, children, align = 'right', width = 220 }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    function onDoc(e) { if (ref.current && !ref.current.contains(e.target)) setOpen(false); }
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, []);
  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <div onClick={() => setOpen((o) => !o)}>{trigger(open)}</div>
      {open && (
        <div style={{ position: 'absolute', top: 'calc(100% + 8px)', [align]: 0, width, background: 'var(--surface)', border: '1px solid var(--hairline)', borderRadius: 12, boxShadow: '0 12px 32px -8px rgba(0,0,0,.12), 0 2px 6px rgba(0,0,0,.04)', padding: 6, zIndex: 40 }}>
          {children(() => setOpen(false))}
        </div>
      )}
    </div>
  );
}
function MenuItem({ label, hint, active, onClick }) {
  return (
    <div onClick={onClick} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '8px 9px', borderRadius: 8, fontSize: 13, cursor: 'pointer', color: 'var(--ink)' }}
      onMouseEnter={(e) => e.currentTarget.style.background = 'var(--row-hover)'}
      onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}>
      <span style={{ flex: 1 }}>{label}</span>
      {hint && <span style={{ fontSize: 11, color: 'var(--muted)' }}>{hint}</span>}
      {active && <Ic.check style={{ color: 'var(--accent)' }} />}
    </div>
  );
}

/* ----------------------------------------------------------------- top bar */
function TopBar({ title = 'Partner advertenties', subtitle = 'Collab ads · live uit Meta', products = ['Alle producten', 'Stoomreiniger', 'Luchtreiniger', 'Proteïne shaker', 'Messenset'] }) {
  const [product, setProduct] = useState('Alle producten');
  const [period, setPeriod] = useState('Mei 2026');
  const presets = [
    { label: 'Per maand', hint: 'Mei 2026' },
    { label: 'Laatste 7 dagen', hint: '22–28 mei' },
    { label: 'Lifetime', hint: 'sinds jan ’25' },
    { label: 'Aangepaste periode', hint: '' },
  ];
  return (
    <header style={TB.bar}>
      <div style={{ minWidth: 0 }}>
        <h1 style={TB.title}>{title}</h1>
        <div style={TB.sub}>
          <span style={TB.live}><span style={TB.liveDot} />{subtitle}</span>
        </div>
      </div>

      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <Dropdown width={210} trigger={(open) => (
          <button style={{ ...TB.ctrl, ...(open ? TB.ctrlOpen : null) }}>
            <Ic.filter style={{ color: 'var(--muted)' }} />
            <span>{product}</span>
            <Ic.chevron style={{ color: 'var(--muted)', transform: open ? 'rotate(180deg)' : 'none', transition: 'transform .15s' }} />
          </button>
        )}>
          {(close) => products.map((p) => (
            <MenuItem key={p} label={p} active={p === product} onClick={() => { setProduct(p); close(); }} />
          ))}
        </Dropdown>

        <Dropdown width={246} trigger={(open) => (
          <button style={{ ...TB.ctrl, ...(open ? TB.ctrlOpen : null) }}>
            <Ic.calendar style={{ color: 'var(--accent)' }} />
            <span>{period}</span>
            <Ic.chevron style={{ color: 'var(--muted)', transform: open ? 'rotate(180deg)' : 'none', transition: 'transform .15s' }} />
          </button>
        )}>
          {(close) => (
            <React.Fragment>
              <div style={TB.menuHead}>Periode</div>
              {presets.map((p, i) => (
                <MenuItem key={p.label} label={p.label} hint={p.hint} active={i === 0} onClick={() => { if (p.hint && i === 0) setPeriod(p.hint); close(); }} />
              ))}
            </React.Fragment>
          )}
        </Dropdown>
      </div>
    </header>
  );
}
const TB = {
  bar: { position: 'sticky', top: 0, background: 'rgba(255,255,255,0.86)', backdropFilter: 'saturate(180%) blur(10px)', WebkitBackdropFilter: 'saturate(180%) blur(10px)', borderBottom: '1px solid var(--hairline)', padding: '16px 32px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, zIndex: 15 },
  title: { margin: 0, fontSize: 20, fontWeight: 600, letterSpacing: '-0.02em' },
  sub: { marginTop: 3, fontSize: 12.5, color: 'var(--muted)' },
  live: { display: 'inline-flex', alignItems: 'center', gap: 6 },
  liveDot: { width: 6, height: 6, borderRadius: 99, background: 'var(--accent)', boxShadow: '0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent)' },
  ctrl: { display: 'inline-flex', alignItems: 'center', gap: 8, height: 36, padding: '0 12px', background: 'var(--surface)', border: '1px solid var(--hairline-strong)', borderRadius: 9, fontSize: 13, fontWeight: 450, color: 'var(--ink)', cursor: 'pointer', whiteSpace: 'nowrap' },
  ctrlOpen: { borderColor: 'var(--accent)', boxShadow: '0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent)' },
  menuHead: { fontSize: 10.5, fontWeight: 600, letterSpacing: '0.05em', textTransform: 'uppercase', color: 'var(--muted-2)', padding: '6px 9px 4px' },
};

/* ----------------------------------------------------------------- KPI row */
function Kpi({ label, value, delta, dir }) {
  const color = dir === 'up' ? 'var(--pos)' : 'var(--neg)';
  const arrow = dir === 'up' ? '▲' : '▼';
  return (
    <div style={KP.card}>
      <div style={KP.label}>{label}</div>
      <div style={KP.value} className="tnum">{value}</div>
      <div style={{ ...KP.delta, color }}>
        <span style={{ fontSize: 9 }}>{arrow}</span>
        <span className="tnum">{delta}</span>
        <span style={KP.deltaNote}>vs vorige periode</span>
      </div>
    </div>
  );
}
const KP = {
  card: { background: 'var(--surface)', border: '1px solid var(--hairline)', borderRadius: 14, padding: '16px 18px 15px' },
  label: { fontSize: 12, color: 'var(--muted)', fontWeight: 450 },
  value: { fontSize: 30, fontWeight: 600, letterSpacing: '-0.025em', margin: '7px 0 8px', lineHeight: 1 },
  delta: { display: 'flex', alignItems: 'center', gap: 5, fontSize: 12, fontWeight: 500 },
  deltaNote: { color: 'var(--muted-2)', fontWeight: 450, fontSize: 11.5, marginLeft: 2 },
};

/* ----------------------------------------------------------------- bar chart */
const BARS = [
  { handle: '@lisa_huishouden', roas: 3.8 },
  { handle: '@sophievlogt', roas: 4.5, nieuw: true, spend: '€1.940', date: '21 mei', hook: 'stoffige kamer' },
  { handle: '@mark.fitt', roas: 2.9 },
  { handle: '@gymwithtom', roas: 4.0, nieuw: true },
  { handle: '@beautybyfemke', roas: 2.4 },
  { handle: '@thuiskoknl', roas: 3.2 },
  { handle: '@koenkookt', roas: 3.5 },
  { handle: '@fitfemke', roas: 2.7 },
];
function BarChartCard({ bars = BARS, title = 'ROAS per advertentie' }) {
  const [hover, setHover] = useState(1); // default hover 2nd bar
  const max = 5;
  const H = 188;
  return (
    <div style={{ ...CARD, padding: '18px 22px 16px' }}>
      <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 6 }}>
        <h2 style={CARD_TITLE}>{title}</h2>
        <span style={{ fontSize: 12, color: 'var(--muted)' }}>Mei 2026 · {bars.length} advertenties</span>
      </div>
      <div style={{ display: 'flex', alignItems: 'flex-end', gap: 0, height: 318, paddingTop: 36, position: 'relative' }}>
        {/* gridlines */}
        {[0,1,2,3,4,5].map((g) => (
          <div key={g} style={{ position: 'absolute', left: 0, right: 0, bottom: 46 + (g/max)*H, borderTop: '1px dashed #F0F0EE', height: 0 }}>
            <span style={{ position: 'absolute', left: -2, top: -8, fontSize: 10, color: 'var(--muted-2)' }} className="tnum">{g}</span>
          </div>
        ))}
        <div style={{ width: 18 }} />
        {bars.map((b, i) => {
          const h = (b.roas / max) * H;
          const isH = hover === i;
          const lbl = b.label || b.handle;
          return (
            <div key={lbl} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'flex-end', position: 'relative', height: '100%' }}
              onMouseEnter={() => setHover(i)}>
              {b.nieuw && <span style={BC.nieuw}>Nieuw</span>}
              {isH && (
                <div style={{ ...BC.tip, bottom: h + 48 }}>
                  <div style={BC.tipHead}>{lbl} · {b.date || 'mei 2026'}</div>
                  <div style={BC.tipRow}><span>Ad spend</span><b className="tnum">{b.spend || '€' + (1200 + i*90)}</b></div>
                  <div style={BC.tipRow}><span>ROAS</span><b className="tnum">{b.roas.toFixed(1).replace('.', ',')}</b></div>
                  {b.hook && <div style={BC.tipRow}><span>Visual hook</span><b>{b.hook}</b></div>}
                  <div style={BC.tipArrow} />
                </div>
              )}
              <span style={{ fontSize: 11, fontWeight: 500, color: isH ? 'var(--accent-ink)' : 'var(--ink-2)', marginBottom: 5 }} className="tnum">{b.roas.toFixed(1).replace('.', ',')}</span>
              <div style={{
                width: 30, height: h, borderRadius: '6px 6px 0 0',
                background: isH ? 'var(--accent)' : 'color-mix(in srgb, var(--accent) 30%, white)',
                border: isH ? 'none' : '1px solid color-mix(in srgb, var(--accent) 38%, white)',
                borderBottom: 'none', transition: 'background .14s, height .2s',
              }} />
              <div style={{ height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center', marginTop: 6, width: '100%' }}>
                <span style={{ fontSize: 10.5, color: isH ? 'var(--ink)' : 'var(--muted)', fontWeight: isH ? 500 : 450, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: '100%' }}>{lbl}</span>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}
const BC = {
  nieuw: { position: 'absolute', top: 8, fontSize: 9, fontWeight: 600, letterSpacing: '0.03em', textTransform: 'uppercase', color: 'var(--accent-ink)', background: 'color-mix(in srgb, var(--accent) 12%, white)', border: '1px solid color-mix(in srgb, var(--accent) 30%, white)', borderRadius: 99, padding: '2px 7px', zIndex: 3 },
  tip: { position: 'absolute', left: '50%', transform: 'translateX(-50%)', background: '#1A1A1A', color: '#fff', borderRadius: 10, padding: '9px 11px', width: 196, boxShadow: '0 12px 28px -6px rgba(0,0,0,.35)', zIndex: 10 },
  tipHead: { fontSize: 12, fontWeight: 600, marginBottom: 6, whiteSpace: 'nowrap' },
  tipRow: { display: 'flex', justifyContent: 'space-between', gap: 12, fontSize: 11.5, color: '#C9C9C9', padding: '1.5px 0', whiteSpace: 'nowrap' },
  tipArrow: { position: 'absolute', top: '100%', left: '50%', transform: 'translateX(-50%)', width: 0, height: 0, borderLeft: '6px solid transparent', borderRight: '6px solid transparent', borderTop: '6px solid #1A1A1A' },
};

const CARD = { background: 'var(--surface)', border: '1px solid var(--hairline)', borderRadius: 16 };
const CARD_TITLE = { margin: 0, fontSize: 15, fontWeight: 600, letterSpacing: '-0.01em' };

/* ----------------------------------------------------------------- table */
const COLS = [
  { key: 'product', label: 'Product', origin: 'manual', editable: true, w: 156 },
  { key: 'creator', label: 'Creator · datum', origin: 'live', type: 'creator', w: 188 },
  { key: 'aankopen', label: 'Aankopen', origin: 'live', num: true, w: 96 },
  { key: 'cpa', label: 'CPA', origin: 'live', num: true, w: 84 },
  { key: 'spend', label: 'Ad spend', origin: 'live', num: true, w: 96 },
  { key: 'roas', label: 'ROAS', origin: 'live', num: true, w: 78 },
  { key: 'cvr', label: 'CVR', origin: 'live', num: true, w: 72 },
  { key: 'hook', label: 'Hook rate', origin: 'live', num: true, w: 92 },
  { key: 'kijktijd', label: 'Gem. kijktijd', origin: 'live', num: true, w: 104 },
  { key: 'ctr', label: 'CTR', origin: 'live', num: true, w: 72 },
  { key: 'cpm', label: 'CPM', origin: 'live', num: true, w: 80 },
  { key: 'cpc', label: 'CPC', origin: 'live', num: true, w: 80 },
  { key: 'intent', label: 'Intent framing', origin: 'manual', editable: true, w: 158 },
  { key: 'muziek', label: 'Muziek/Voice-over', origin: 'manual', editable: true, w: 138 },
  { key: 'visual', label: 'Visual hook', origin: 'manual', editable: true, w: 168 },
];
const ROWS = [
  { product: 'Stoomreiniger', creator: '@lisa_huishouden', date: '12 mei', aankopen: '142', cpa: '€18,40', spend: '€2.612', roas: '3,8', cvr: '2,1%', hook: '31%', kijktijd: '6,2s', ctr: '1,4%', cpm: '€9,20', cpc: '€0,74', intent: 'Probleem→oplossing', muziek: 'Voice-over', visual: 'Vuile vloer close-up' },
  { product: 'Luchtreiniger', creator: '@sophievlogt', date: '21 mei', nieuw: true, aankopen: '118', cpa: '€16,44', spend: '€1.940', roas: '4,5', cvr: '2,6%', hook: '38%', kijktijd: '7,1s', ctr: '1,7%', cpm: '€8,10', cpc: '€0,61', intent: 'Demo/bewijs', muziek: 'Voice-over', visual: 'Stoffige kamer' },
  { product: 'Proteïne shaker', creator: '@mark.fitt', date: '03 mei', aankopen: '84', cpa: '€15,60', spend: '€1.310', roas: '2,9', cvr: '1,8%', hook: '27%', kijktijd: '5,4s', ctr: '1,2%', cpm: '€10,40', cpc: '€0,82', intent: 'Lifestyle', muziek: 'Muziek', visual: 'Shaker schudden' },
  { product: 'Stoomreiniger', creator: '@gymwithtom', date: '19 mei', nieuw: true, aankopen: '101', cpa: '€16,04', spend: '€1.620', roas: '4,0', cvr: '2,3%', hook: '34%', kijktijd: '6,8s', ctr: '1,5%', cpm: '€8,70', cpc: '€0,68', intent: 'Voor/na', muziek: 'Voice-over', visual: 'Voor/na opname' },
  { product: 'Luchtreiniger', creator: '@beautybyfemke', date: '09 mei', aankopen: '58', cpa: '€18,62', spend: '€1.080', roas: '2,4', cvr: '1,5%', hook: '22%', kijktijd: '4,9s', ctr: '1,0%', cpm: '€11,80', cpc: '€0,95', intent: 'Lifestyle', muziek: 'Muziek', visual: 'Ochtendroutine' },
  { product: 'Messenset', creator: '@thuiskoknl', date: '28 apr', aankopen: '62', cpa: '€14,84', spend: '€920', roas: '3,2', cvr: '2,0%', hook: '29%', kijktijd: '5,8s', ctr: '1,3%', cpm: '€9,60', cpc: '€0,71', intent: 'Demo/bewijs', muziek: 'Voice-over', visual: 'Snijdemo' },
];

function EditableCell({ value, onChange }) {
  const [editing, setEditing] = useState(false);
  const [v, setV] = useState(value);
  const ref = useRef(null);
  useEffect(() => { if (editing && ref.current) { ref.current.focus(); ref.current.select(); } }, [editing]);
  if (editing) {
    return (
      <input ref={ref} value={v} className="edit-input"
        onChange={(e) => setV(e.target.value)}
        onBlur={() => { setEditing(false); onChange(v); }}
        onKeyDown={(e) => { if (e.key === 'Enter') { setEditing(false); onChange(v); } if (e.key === 'Escape') { setV(value); setEditing(false); } }}
        style={{ width: '100%', font: 'inherit', fontSize: 13, color: 'var(--ink)', border: '1px solid var(--accent)', borderRadius: 6, padding: '3px 6px', outline: 'none', boxShadow: '0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent)', background: '#fff' }} />
    );
  }
  return (
    <span className="editable-cell" onClick={() => setEditing(true)}
      style={{ display: 'inline-flex', alignItems: 'center', gap: 5, cursor: 'text', borderBottom: '1px dashed transparent', paddingBottom: 1, maxWidth: '100%' }}>
      <span style={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{v}</span>
      <span className="edit-pencil" style={{ color: 'var(--violet)', opacity: 0, transition: 'opacity .12s', flexShrink: 0 }}><Ic.pencil /></span>
    </span>
  );
}

function OriginDot({ origin }) {
  return <span style={{ width: 6, height: 6, borderRadius: 99, background: origin === 'live' ? 'var(--accent)' : 'var(--violet)', flexShrink: 0, display: 'inline-block' }} />;
}

function DataTable({ cols = COLS, rows: rowsProp = ROWS, title = 'Advertentie-overzicht', countLabel = '6 advertenties · mei 2026' }) {
  const [rows, setRows] = useState(rowsProp);
  const [sort, setSort] = useState({ key: null, dir: 'desc' });

  function toggleSort(key) {
    setSort((s) => s.key === key ? { key, dir: s.dir === 'desc' ? 'asc' : 'desc' } : { key, dir: 'desc' });
  }
  function parseNum(s) { return parseFloat(String(s).replace(/[^0-9,.-]/g, '').replace(/\./g, '').replace(',', '.')) || 0; }
  let display = rows.map((r, i) => ({ r, i }));
  if (sort.key) {
    display.sort((a, b) => { const d = parseNum(a.r[sort.key]) - parseNum(b.r[sort.key]); return sort.dir === 'asc' ? d : -d; });
  }
  function updateCell(rowIdx, key, val) {
    setRows((rs) => rs.map((r, i) => i === rowIdx ? { ...r, [key]: val } : r));
  }

  return (
    <div style={{ ...CARD, overflow: 'hidden' }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '16px 22px 12px', flexWrap: 'wrap', gap: 12 }}>
        <div>
          <h2 style={CARD_TITLE}>{title}</h2>
          <div style={{ fontSize: 12, color: 'var(--muted)', marginTop: 3 }}>{countLabel}</div>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
          <div style={TBL.legend}><OriginDot origin="live" /><span>live uit Meta</span></div>
          <div style={TBL.legend}><OriginDot origin="manual" /><span>handmatig ingevuld in dashboard</span></div>
        </div>
      </div>

      <div className="scroll-x" style={{ overflowX: 'auto' }}>
        <table style={{ borderCollapse: 'collapse', width: '100%', minWidth: 1640 }}>
          <thead>
            <tr>
              {cols.map((c) => (
                <th key={c.key} onClick={() => c.num && toggleSort(c.key)}
                  style={{ ...TBL.th, textAlign: c.num ? 'right' : 'left', cursor: c.num ? 'pointer' : 'default', minWidth: c.w, color: sort.key === c.key ? 'var(--ink)' : 'var(--ink-2)' }}>
                  <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, flexDirection: c.num ? 'row-reverse' : 'row' }}>
                    <OriginDot origin={c.origin} />
                    <span>{c.label}</span>
                    {c.num && <Ic.sort style={{ color: sort.key === c.key ? 'var(--accent)' : 'var(--muted-2)' }} />}
                  </span>
                </th>
              ))}
              <th style={{ ...TBL.th, minWidth: 130 }}></th>
            </tr>
          </thead>
          <tbody>
            {display.map(({ r, i }) => (
              <tr key={i} className="data-row" style={{ borderTop: '1px solid var(--hairline)' }}>
                {cols.map((c) => {
                  if (c.editable) {
                    return <td key={c.key} style={{ ...TBL.td, fontWeight: c.key === 'product' ? 500 : 450 }}><EditableCell value={r[c.key]} onChange={(v) => updateCell(i, c.key, v)} /></td>;
                  }
                  if (c.type === 'creator') {
                    return (
                      <td key={c.key} style={TBL.td}>
                        <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                          <span style={TBL.avatar}>{r.creator.replace('@', '').slice(0, 2).toUpperCase()}</span>
                          <span style={{ minWidth: 0 }}>
                            <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                              <span style={{ fontWeight: 450 }}>{r.creator}</span>
                              {r.nieuw && <span style={TBL.nieuw}>Nieuw</span>}
                            </span>
                            <span style={{ fontSize: 11.5, color: 'var(--muted)' }} className="tnum">{r.date}</span>
                          </span>
                        </div>
                      </td>
                    );
                  }
                  if (c.type === 'title') {
                    return (
                      <td key={c.key} style={TBL.td}>
                        <span style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                          <span style={{ fontWeight: 500, color: 'var(--ink)' }}>{r[c.key]}</span>
                          {r.nieuw && <span style={TBL.nieuw}>Nieuw</span>}
                        </span>
                        <span style={{ fontSize: 11.5, color: 'var(--muted)' }} className="tnum">{r.date}</span>
                      </td>
                    );
                  }
                  const strong = c.key === 'roas';
                  return <td key={c.key} className="tnum" style={{ ...TBL.td, textAlign: 'right', fontWeight: strong ? 600 : 450, color: strong ? 'var(--ink)' : 'var(--ink-2)' }}>{r[c.key]}</td>;
                })}
                <td style={{ ...TBL.td, textAlign: 'right' }}>
                  <button className="vid-pill" style={TBL.pill}>Bekijk video <Ic.ext /></button>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}
const TBL = {
  legend: { display: 'flex', alignItems: 'center', gap: 6, fontSize: 11.5, color: 'var(--muted)' },
  th: { padding: '9px 14px', fontSize: 11, fontWeight: 500, letterSpacing: '0.01em', whiteSpace: 'nowrap', background: 'var(--header-bg)', position: 'sticky', top: 0, userSelect: 'none', borderBottom: '1px solid var(--hairline)' },
  td: { padding: '11px 14px', fontSize: 13, color: 'var(--ink-2)', whiteSpace: 'nowrap', verticalAlign: 'middle' },
  avatar: { width: 24, height: 24, borderRadius: 99, background: '#F0F0EE', border: '1px solid var(--hairline)', display: 'grid', placeItems: 'center', fontSize: 9.5, fontWeight: 600, color: 'var(--ink-2)', flexShrink: 0 },
  nieuw: { fontSize: 8.5, fontWeight: 600, letterSpacing: '0.03em', textTransform: 'uppercase', color: 'var(--accent-ink)', background: 'color-mix(in srgb, var(--accent) 12%, white)', border: '1px solid color-mix(in srgb, var(--accent) 28%, white)', borderRadius: 99, padding: '1px 6px' },
  pill: { display: 'inline-flex', alignItems: 'center', gap: 5, height: 28, padding: '0 11px', fontSize: 12, fontWeight: 500, color: 'var(--accent-ink)', background: 'color-mix(in srgb, var(--accent) 9%, white)', border: '1px solid color-mix(in srgb, var(--accent) 24%, white)', borderRadius: 8, cursor: 'pointer', whiteSpace: 'nowrap' },
};

/* ----------------------------------------------------------------- creative data */
const CREATIVE_BARS = [
  { label: 'Stoom — demo A', roas: 3.4, nieuw: true, date: '14 mei', spend: '€3.010', hook: 'vuile vloer' },
  { label: 'Lucht — UGC', roas: 3.0, nieuw: true, date: '06 mei', spend: '€2.530', hook: 'frisse lucht' },
  { label: 'Mes — unboxing', roas: 2.8, date: '27 apr', spend: '€2.050', hook: 'doos openen' },
  { label: 'Stoom — voor/na', roas: 3.6, nieuw: true, date: '19 mei', spend: '€2.790', hook: 'voor/na opname' },
  { label: 'Lucht — testimonial', roas: 2.5, date: '02 mei', spend: '€1.760', hook: 'klant aan het woord' },
  { label: 'Mes — recept', roas: 3.2, date: '24 apr', spend: '€2.180', hook: 'snijdemo recept' },
];
const CREATIVE_COLS = [
  { key: 'title', label: 'Video · datum', origin: 'live', type: 'title', w: 210 },
  { key: 'aankopen', label: 'Aankopen', origin: 'live', num: true, w: 96 },
  { key: 'cpa', label: 'CPA', origin: 'live', num: true, w: 84 },
  { key: 'spend', label: 'Ad spend', origin: 'live', num: true, w: 96 },
  { key: 'roas', label: 'ROAS', origin: 'live', num: true, w: 78 },
  { key: 'cvr', label: 'CVR', origin: 'live', num: true, w: 72 },
  { key: 'hook', label: 'Hook rate', origin: 'live', num: true, w: 92 },
  { key: 'kijktijd', label: 'Gem. kijktijd', origin: 'live', num: true, w: 104 },
  { key: 'ctr', label: 'CTR', origin: 'live', num: true, w: 72 },
  { key: 'cpm', label: 'CPM', origin: 'live', num: true, w: 80 },
  { key: 'cpc', label: 'CPC', origin: 'live', num: true, w: 80 },
  { key: 'product', label: 'Product', origin: 'manual', editable: true, w: 142 },
  { key: 'angle', label: 'Angle', origin: 'manual', editable: true, w: 170 },
  { key: 'face', label: 'Face', origin: 'manual', editable: true, w: 110 },
  { key: 'style', label: 'Style', origin: 'manual', editable: true, w: 138 },
  { key: 'audio', label: 'Audio', origin: 'manual', editable: true, w: 120 },
  { key: 'visual', label: 'Visual hook', origin: 'manual', editable: true, w: 168 },
];
const CREATIVE_ROWS = [
  { title: 'Stoomreiniger demo A', date: '14 mei', nieuw: true, aankopen: '168', cpa: '€17,90', spend: '€3.010', roas: '3,4', cvr: '2,2%', hook: '33%', kijktijd: '6,5s', ctr: '1,5%', cpm: '€9,00', cpc: '€0,70', product: 'Stoomreiniger', angle: 'Probleem→oplossing', face: 'Sanne', style: 'UGC handheld', audio: 'Voice-over', visual: 'Vuile vloer' },
  { title: 'Luchtreiniger UGC', date: '06 mei', nieuw: true, aankopen: '132', cpa: '€19,20', spend: '€2.530', roas: '3,0', cvr: '1,9%', hook: '29%', kijktijd: '5,9s', ctr: '1,3%', cpm: '€9,80', cpc: '€0,76', product: 'Luchtreiniger', angle: 'Lifestyle', face: 'Mila', style: 'UGC handheld', audio: 'Muziek', visual: 'Frisse lucht' },
  { title: 'Messenset unboxing', date: '27 apr', aankopen: '96', cpa: '€21,40', spend: '€2.050', roas: '2,8', cvr: '1,7%', hook: '25%', kijktijd: '5,2s', ctr: '1,1%', cpm: '€10,90', cpc: '€0,88', product: 'Messenset', angle: 'Curiosity', face: 'Tom', style: 'Studio', audio: 'Muziek', visual: 'Doos openen' },
  { title: 'Stoomreiniger voor/na', date: '19 mei', nieuw: true, aankopen: '154', cpa: '€18,10', spend: '€2.790', roas: '3,6', cvr: '2,3%', hook: '35%', kijktijd: '6,8s', ctr: '1,6%', cpm: '€8,90', cpc: '€0,69', product: 'Stoomreiniger', angle: 'Voor/na', face: 'Sanne', style: 'UGC handheld', audio: 'Voice-over', visual: 'Voor/na opname' },
  { title: 'Luchtreiniger testimonial', date: '02 mei', nieuw: true, aankopen: '78', cpa: '€22,60', spend: '€1.760', roas: '2,5', cvr: '1,5%', hook: '23%', kijktijd: '4,8s', ctr: '1,0%', cpm: '€11,40', cpc: '€0,92', product: 'Luchtreiniger', angle: 'Sociaal bewijs', face: 'Rik', style: 'Talking head', audio: 'Voice-over', visual: 'Klant aan het woord' },
  { title: 'Messenset recept', date: '24 apr', aankopen: '110', cpa: '€19,80', spend: '€2.180', roas: '3,2', cvr: '2,0%', hook: '30%', kijktijd: '6,1s', ctr: '1,4%', cpm: '€9,40', cpc: '€0,73', product: 'Messenset', angle: 'Demo/bewijs', face: 'Lotte', style: 'Studio', audio: 'Muziek', visual: 'Snijdemo recept' },
];

const CONTENT = { padding: '24px 32px 56px', maxWidth: 1400, margin: '0 auto' };
const KPI_GRID = { display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 14, marginBottom: 16 };

/* ----------------------------------------------------------------- boards */
function PartnerBoard() {
  return (
    <React.Fragment>
      <TopBar title="Partner advertenties" subtitle="Collab ads · live uit Meta"
        products={['Alle producten', 'Stoomreiniger', 'Luchtreiniger', 'Proteïne shaker', 'Messenset']} />
      <div style={CONTENT}>
        <div style={KPI_GRID}>
          <Kpi label="Ad spend" value="€11.480" delta="8%" dir="up" />
          <Kpi label="ROAS" value="3,6" delta="0,4" dir="up" />
          <Kpi label="Aankopen" value="612" delta="12%" dir="up" />
          <Kpi label="CPA" value="€18,76" delta="3%" dir="down" />
        </div>
        <div style={{ marginBottom: 16 }}><BarChartCard bars={BARS} title="ROAS per advertentie" /></div>
        <DataTable cols={COLS} rows={ROWS} title="Advertentie-overzicht" countLabel="6 advertenties · mei 2026" />
      </div>
    </React.Fragment>
  );
}

function CreativeBoard() {
  return (
    <React.Fragment>
      <TopBar title="Creative Strategist" subtitle="Eigen video-ads · live uit Meta"
        products={['Alle producten', 'Stoomreiniger', 'Luchtreiniger', 'Messenset']} />
      <div style={CONTENT}>
        <div style={KPI_GRID}>
          <Kpi label="Ad spend" value="€18.240" delta="6%" dir="up" />
          <Kpi label="ROAS" value="3,1" delta="0,2" dir="up" />
          <Kpi label="Aankopen" value="884" delta="9%" dir="up" />
          <Kpi label="CPA" value="€20,63" delta="2%" dir="down" />
        </div>
        <div style={{ marginBottom: 16 }}><BarChartCard bars={CREATIVE_BARS} title="ROAS per advertentie" /></div>
        <DataTable cols={CREATIVE_COLS} rows={CREATIVE_ROWS} title="Video-overzicht" countLabel="6 video-ads · mei 2026" />
      </div>
    </React.Fragment>
  );
}

/* ----------------------------------------------------------------- settings */
function Toggle({ on, onChange }) {
  return (
    <button onClick={() => onChange(!on)} style={{
      width: 40, height: 23, borderRadius: 99, border: 'none', cursor: 'pointer', padding: 2,
      background: on ? 'var(--accent)' : '#D8D8D6', transition: 'background .16s', position: 'relative',
    }}>
      <span style={{ display: 'block', width: 19, height: 19, borderRadius: 99, background: '#fff', boxShadow: '0 1px 2px rgba(0,0,0,.2)', transform: on ? 'translateX(17px)' : 'translateX(0)', transition: 'transform .16s' }} />
    </button>
  );
}

function SettingsView({ t, setTweak }) {
  const [dailySync, setDailySync] = useState(true);
  const accents = ['#0EA5A4', '#2A6FDB', '#7A5AE0', '#E0556B', '#1F8A5B', '#E0822A'];
  return (
    <React.Fragment>
      <header style={TB.bar}>
        <div style={{ minWidth: 0 }}>
          <h1 style={TB.title}>Instellingen</h1>
          <div style={TB.sub}>Workspace · Techweise</div>
        </div>
      </header>
      <div style={{ ...CONTENT, maxWidth: 760, display: 'flex', flexDirection: 'column', gap: 16 }}>

        {/* Meta-koppeling */}
        <div style={{ ...CARD, padding: '20px 22px' }}>
          <h2 style={CARD_TITLE}>Meta-koppeling</h2>
          <div style={{ marginTop: 16, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16 }}>
            <div>
              <div style={ST.rowLabel}>Ad account</div>
              <div style={{ fontSize: 14, fontWeight: 500 }} className="tnum">223198489775680</div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 7, marginTop: 8, fontSize: 12.5, color: 'var(--ink-2)' }}>
                <span style={{ width: 7, height: 7, borderRadius: 99, background: 'var(--pos)', boxShadow: '0 0 0 3px color-mix(in srgb, var(--pos) 18%, transparent)' }} />
                Verbonden · laatste sync <span className="tnum" style={{ color: 'var(--muted)' }}>vandaag 06:00</span>
              </div>
            </div>
            <button style={ST.btnSec}>Nu synchroniseren</button>
          </div>
        </div>

        {/* Synchronisatie */}
        <div style={{ ...CARD, padding: '20px 22px' }}>
          <h2 style={CARD_TITLE}>Synchronisatie</h2>
          <div style={{ marginTop: 14, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, paddingBottom: 14, borderBottom: '1px solid var(--hairline)' }}>
            <div>
              <div style={{ fontSize: 13.5, fontWeight: 500 }}>Dagelijkse sync</div>
              <div style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 2 }} className="tnum">06:00 (CEST)</div>
            </div>
            <Toggle on={dailySync} onChange={setDailySync} />
          </div>
          <div style={{ marginTop: 14, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16 }}>
            <div style={{ fontSize: 13.5, fontWeight: 500 }}>Tijdzone</div>
            <select disabled style={ST.select}>
              <option>Europe/Amsterdam (CEST)</option>
            </select>
          </div>
        </div>

        {/* Merk & weergave */}
        <div style={{ ...CARD, padding: '20px 22px' }}>
          <h2 style={CARD_TITLE}>Merk &amp; weergave</h2>
          <div style={{ marginTop: 16, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16, paddingBottom: 16, borderBottom: '1px solid var(--hairline)' }}>
            <div>
              <div style={{ fontSize: 13.5, fontWeight: 500 }}>Accentkleur</div>
              <div style={{ fontSize: 12.5, color: 'var(--muted)', marginTop: 2 }}>Gebruikt in de hele werkruimte</div>
            </div>
            <div style={{ display: 'flex', gap: 8 }}>
              {accents.map((c) => (
                <button key={c} onClick={() => setTweak('accent', c)} title={c} style={{
                  width: 26, height: 26, borderRadius: 8, cursor: 'pointer', background: c,
                  border: t.accent === c ? '2px solid var(--ink)' : '1px solid rgba(0,0,0,.08)',
                  outline: t.accent === c ? '2px solid #fff' : 'none', outlineOffset: -3,
                  boxShadow: t.accent === c ? '0 0 0 1px ' + c : 'none',
                }} />
              ))}
            </div>
          </div>
          <div style={{ marginTop: 16, display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 16 }}>
            <div style={{ fontSize: 13.5, fontWeight: 500 }}>Lettertype</div>
            <select value={t.font} onChange={(e) => setTweak('font', e.target.value)} style={ST.select}>
              <option value="Geist">Geist</option>
              <option value="Inter">Inter</option>
              <option value="system-ui">system-ui</option>
            </select>
          </div>
        </div>

        {/* Gebruikers */}
        <div style={{ ...CARD, padding: '20px 22px' }}>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <h2 style={CARD_TITLE}>Gebruikers</h2>
            <button disabled style={{ ...ST.btnSec, opacity: 0.45, cursor: 'not-allowed' }}>Gebruiker uitnodigen</button>
          </div>
          <div style={{ marginTop: 14, display: 'flex', alignItems: 'center', gap: 11 }}>
            <div style={SB.avatar}>IP</div>
            <div style={{ flex: 1 }}>
              <div style={{ fontSize: 13.5, fontWeight: 500 }}>Ivo Peeters</div>
              <div style={{ fontSize: 12, color: 'var(--muted)' }}>ivo@techweise.nl</div>
            </div>
            <span style={ST.rolePill}>Owner</span>
          </div>
        </div>

      </div>
    </React.Fragment>
  );
}
const ST = {
  rowLabel: { fontSize: 12, color: 'var(--muted)', marginBottom: 3 },
  btnSec: { height: 36, padding: '0 14px', fontSize: 13, fontWeight: 500, color: 'var(--ink)', background: 'var(--surface)', border: '1px solid var(--hairline-strong)', borderRadius: 9, cursor: 'pointer', whiteSpace: 'nowrap' },
  select: { height: 36, padding: '0 30px 0 12px', fontSize: 13, fontFamily: 'inherit', color: 'var(--ink)', background: 'var(--surface)', border: '1px solid var(--hairline-strong)', borderRadius: 9, cursor: 'pointer', appearance: 'none', WebkitAppearance: 'none', backgroundImage: 'url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\' width=\'12\' height=\'12\' viewBox=\'0 0 24 24\' fill=\'none\' stroke=\'%238A8A8A\' stroke-width=\'2\' stroke-linecap=\'round\' stroke-linejoin=\'round\'><path d=\'m6 9 6 6 6-6\'/></svg>")', backgroundRepeat: 'no-repeat', backgroundPosition: 'right 10px center' },
  rolePill: { fontSize: 11, fontWeight: 500, color: 'var(--ink-2)', background: '#F4F4F3', border: '1px solid var(--hairline)', borderRadius: 99, padding: '3px 10px' },
};

/* ----------------------------------------------------------------- app */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#0EA5A4",
  "font": "Geist"
}/*EDITMODE-END*/;

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [view, setView] = useState('partner');
  useEffect(() => {
    const ink = mixDarken(t.accent);
    document.documentElement.style.setProperty('--accent', t.accent);
    document.documentElement.style.setProperty('--accent-ink', ink);
    document.documentElement.style.setProperty('--app-font', `'${t.font}', -apple-system, BlinkMacSystemFont, system-ui, sans-serif`);
  }, [t.accent, t.font]);

  return (
    <div style={{ paddingLeft: 240 }}>
      <Sidebar view={view} setView={setView} />
      <main>
        {view === 'partner' && <PartnerBoard />}
        {view === 'creative' && <CreativeBoard />}
        {view === 'settings' && <SettingsView t={t} setTweak={setTweak} />}
      </main>

      <TweaksPanel>
        <TweakSection label="Merk" />
        <TweakColor label="Accentkleur" value={t.accent}
          options={['#0EA5A4', '#2A6FDB', '#7A5AE0', '#E0556B', '#1F8A5B', '#E0822A']}
          onChange={(v) => setTweak('accent', v)} />
        <TweakSection label="Typografie" />
        <TweakSelect label="Lettertype" value={t.font}
          options={['Geist', 'Inter', 'system-ui']}
          onChange={(v) => setTweak('font', v)} />
      </TweaksPanel>
    </div>
  );
}

function mixDarken(hex) {
  // produce a slightly darker variant for "ink" accent
  const m = hex.replace('#', '');
  const n = parseInt(m.length === 3 ? m.split('').map((c) => c + c).join('') : m, 16);
  let r = (n >> 16) & 255, g = (n >> 8) & 255, b = n & 255;
  r = Math.round(r * 0.82); g = Math.round(g * 0.82); b = Math.round(b * 0.82);
  return '#' + [r, g, b].map((x) => x.toString(16).padStart(2, '0')).join('');
}

/* hover styles injected once */
(function injectStyles() {
  const css = `
    .data-row:hover { background: var(--row-hover); }
    .data-row:hover .editable-cell { border-bottom-color: var(--hairline-strong); }
    .data-row:hover .edit-pencil { opacity: 0.55; }
    .editable-cell:hover { border-bottom-color: var(--violet) !important; }
    .editable-cell:hover .edit-pencil { opacity: 1 !important; }
    .vid-pill:hover { background: color-mix(in srgb, var(--accent) 16%, white) !important; }
    button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
  `;
  const s = document.createElement('style');
  s.textContent = css;
  document.head.appendChild(s);
})();
