// ============================================
// CUSTOM page — door admin aangemaakt via controlepaneel
// Ondersteunt blokken: heading, text, image, button, divider, html
// ============================================

// ---- Security helpers ----
// Sanitize HTML uit een html-blok: verwijdert <script>, on*-event handlers, javascript:-URLs en gevaarlijke tags
function sanitizeBlockHTML(html) {
  if (!html || typeof html !== 'string') return '';
  // Verwijder volledige <script>, <style>, <iframe>, <object>, <embed>, <link>, <meta>, <form> blokken (en hun inhoud)
  let cleaned = html.replace(/<(script|style|iframe|object|embed|link|meta|form|base)\b[\s\S]*?(<\/\1>|$)/gi, '');
  // Verwijder zelf-sluitende vormen van diezelfde gevaarlijke tags
  cleaned = cleaned.replace(/<(script|iframe|object|embed|link|meta|base)\b[^>]*\/?>/gi, '');
  // Verwijder alle on*-event-attributes (onclick, onerror, onload, ...)
  cleaned = cleaned.replace(/\son[a-z]+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/gi, '');
  // Verwijder javascript:/data:/vbscript:-URLs uit href/src/action
  cleaned = cleaned.replace(/\s(href|src|action|formaction|xlink:href)\s*=\s*(?:"\s*(?:javascript|data|vbscript)\s*:[^"]*"|'\s*(?:javascript|data|vbscript)\s*:[^']*'|(?:javascript|data|vbscript)\s*:[^\s>]*)/gi, ' $1="#"');
  return cleaned;
}

// Veilige href-validatie voor button-blokken: weiger javascript:, data:, vbscript:, file:
function sanitizeButtonHref(href) {
  if (!href || typeof href !== 'string') return '#';
  const trimmed = href.trim();
  // Whitelist: relatief pad, hash-link, https?, mailto, tel
  if (/^(\/|#|https?:\/\/|mailto:|tel:)/i.test(trimmed)) return trimmed;
  // Alles anders (javascript:, data:, vbscript:, file:, etc.) → block
  return '#';
}

function CustomPage({ page, navigate }) {
  const { Placeholder, Reveal, SectionHeader, Icon } = window.LM_UI;
  if (!page) return null;

  // Countdown: pagina nog niet gepubliceerd → toon timer i.p.v. inhoud
  const publishAt = page.publishAt ? new Date(page.publishAt) : null;
  if (publishAt && !isNaN(publishAt.getTime()) && publishAt.getTime() > Date.now()) {
    return <CountdownView page={page} publishAt={publishAt} navigate={navigate} />;
  }

  return (
    <div>
      {/* Intro */}
      {(page.title || page.eyebrow || page.subtitle) && (
        <section className="section" style={{ paddingBottom: 32 }}>
          <div className="container">
            <SectionHeader
              eyebrow={page.eyebrow || ''}
              title={page.title || ''}
              subtitle={page.subtitle || ''}
              align={page.align || 'left'}
            />
          </div>
        </section>
      )}

      {/* Blokken */}
      <section className="section">
        <div className="container" style={{ maxWidth: 880 }}>
          {(page.blocks || []).map((b, i) => {
            const key = b.id || i;
            switch (b.type) {
              case 'heading':
                return (
                  <Reveal key={key}>
                    <h2 className="display" style={{ fontSize: 'clamp(28px, 4vw, 48px)', margin: '32px 0 16px', textTransform: 'none', letterSpacing: '-0.01em' }}>
                      {b.text}
                    </h2>
                  </Reveal>
                );
              case 'text':
                return (
                  <Reveal key={key}>
                    <p style={{ fontSize: 17, color: 'var(--ink-700)', lineHeight: 1.7, margin: '0 0 20px', whiteSpace: 'pre-wrap' }}>
                      {b.text}
                    </p>
                  </Reveal>
                );
              case 'image':
                return (
                  <Reveal key={key}>
                    <div style={{ margin: '24px 0' }}>
                      <Placeholder
                        label={b.caption || 'afbeelding'}
                        src={b.url || ''}
                        ratio={b.ratio || '16/9'}
                        style={{ borderRadius: 16 }}
                      />
                      {b.caption && (
                        <p className="mono" style={{ marginTop: 10, fontSize: 12, color: 'var(--ink-500)', letterSpacing: '0.06em', textAlign: 'center' }}>
                          {b.caption}
                        </p>
                      )}
                    </div>
                  </Reveal>
                );
              case 'button': {
                const safeHref = sanitizeButtonHref(b.href);
                return (
                  <Reveal key={key}>
                    <div style={{ margin: '24px 0' }}>
                      <a className="btn btn-primary" href={safeHref}
                        onClick={(e) => {
                          // Interne hash-links → navigate
                          if (safeHref.startsWith('#/')) {
                            e.preventDefault();
                            navigate(safeHref.replace('#/', ''));
                          }
                        }}
                        target={b.external ? '_blank' : undefined}
                        rel={b.external ? 'noopener noreferrer' : undefined}>
                        {b.text || 'Klik hier'} <Icon.ArrowRight />
                      </a>
                    </div>
                  </Reveal>
                );
              }
              case 'divider':
                return <hr key={key} style={{ margin: '40px 0', border: 'none', borderTop: '1px solid var(--border)' }} />;
              case 'html':
                return (
                  <div key={key} style={{ margin: '20px 0' }} dangerouslySetInnerHTML={{ __html: sanitizeBlockHTML(b.html) }} />
                );
              case 'file':
                return <FileBlock key={key} block={b} />;
              case 'form':
                return <FormBlock key={key} block={b} />;
              default:
                return null;
            }
          })}
        </div>
      </section>
    </div>
  );
}

// ============================================
// CountdownView — toont een aftellings-scherm tot publishAt
// Geadapteerd uit shadcn-design naar vanilla JSX + inline styles
// ============================================
function CountdownView({ page, publishAt, navigate }) {
  const { Reveal, Icon } = window.LM_UI;

  const calc = () => {
    const diff = publishAt.getTime() - Date.now();
    if (diff <= 0) return { d: 0, h: 0, m: 0, s: 0, done: true };
    return {
      d: Math.floor(diff / 86400000),
      h: Math.floor((diff % 86400000) / 3600000),
      m: Math.floor((diff % 3600000) / 60000),
      s: Math.floor((diff % 60000) / 1000),
      done: false,
    };
  };

  const [t, setT] = React.useState(calc);

  React.useEffect(() => {
    const id = setInterval(() => {
      const next = calc();
      setT(next);
      if (next.done) {
        clearInterval(id);
        // Pagina herladen zodat de inhoud verschijnt
        setTimeout(() => window.location.reload(), 800);
      }
    }, 1000);
    return () => clearInterval(id);
  }, [publishAt.getTime()]);

  const dateStr = publishAt.toLocaleDateString('nl-BE', {
    weekday: 'long', day: 'numeric', month: 'long', year: 'numeric',
  });
  const timeStr = publishAt.toLocaleTimeString('nl-BE', { hour: '2-digit', minute: '2-digit' });

  return (
    <section style={{
      position: 'relative',
      minHeight: 'calc(100vh - 200px)',
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      padding: '60px 20px',
      overflow: 'hidden',
      background: 'linear-gradient(135deg, #08080B 0%, #16161C 100%)',
      color: 'white',
    }}>
      {/* Achtergrond-glow */}
      <div style={{
        position: 'absolute', inset: 0, pointerEvents: 'none',
        background: 'radial-gradient(ellipse 800px 600px at 30% 20%, rgba(63,168,158,.18), transparent 60%), radial-gradient(ellipse 600px 600px at 80% 80%, rgba(45,111,165,.18), transparent 60%)',
      }} />

      <Reveal>
        <div style={{
          position: 'relative',
          maxWidth: 760,
          margin: '0 auto',
          padding: 'clamp(28px, 5vw, 56px)',
          borderRadius: 28,
          background: 'rgba(255,255,255,.05)',
          backdropFilter: 'blur(20px)',
          border: '1px solid rgba(255,255,255,.1)',
          boxShadow: '0 40px 80px rgba(14,26,38,.5)',
          textAlign: 'center',
          overflow: 'hidden',
        }}>
          <div style={{
            position: 'absolute', inset: 0,
            background: 'linear-gradient(180deg, rgba(255,255,255,.06) 0%, transparent 30%)',
            pointerEvents: 'none',
          }} />

          {/* Badge */}
          <div style={{
            display: 'inline-flex',
            alignItems: 'center',
            gap: 8,
            padding: '6px 14px',
            borderRadius: 999,
            background: 'rgba(63,168,158,.18)',
            border: '1px solid rgba(63,168,158,.3)',
            fontSize: 11,
            fontWeight: 600,
            letterSpacing: '0.12em',
            textTransform: 'uppercase',
            color: 'var(--teal-300, #7dd3c0)',
            marginBottom: 20,
          }}>
            ✦ Binnenkort beschikbaar
          </div>

          {/* Titel + intro uit de pagina */}
          <h1 className="display" style={{
            fontSize: 'clamp(32px, 5vw, 56px)',
            margin: '0 0 14px',
            color: 'white',
            textTransform: 'none',
            letterSpacing: '-0.015em',
            lineHeight: 1.1,
          }}>
            {page.title || 'Coming soon'}
          </h1>

          {page.subtitle && (
            <p style={{
              fontSize: 17,
              color: 'rgba(255,255,255,.7)',
              maxWidth: 480,
              margin: '0 auto 40px',
              lineHeight: 1.55,
            }}>
              {page.subtitle}
            </p>
          )}

          {/* Counter — altijd op één rij */}
          <div style={{
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            gap: 'clamp(2px, 1vw, 10px)',
            marginBottom: 32,
            flexWrap: 'nowrap',
            width: '100%',
            maxWidth: '100%',
          }}>
            <TimeUnit value={t.d} label="Dagen" />
            <CountdownSep />
            <TimeUnit value={t.h} label="Uren" />
            <CountdownSep />
            <TimeUnit value={t.m} label="Minuten" />
            <CountdownSep />
            <TimeUnit value={t.s} label="Seconden" />
          </div>

          {/* Datum */}
          <p className="mono" style={{
            fontSize: 12,
            color: 'rgba(255,255,255,.5)',
            letterSpacing: '0.1em',
            textTransform: 'uppercase',
            margin: '0 0 28px',
          }}>
            Live op {dateStr} om {timeStr}
          </p>

          {/* CTA */}
          <div style={{ display: 'flex', gap: 10, justifyContent: 'center', flexWrap: 'wrap' }}>
            <button className="btn btn-primary" onClick={() => navigate('home')}>
              Terug naar home <Icon.ArrowRight />
            </button>
            <button className="btn" style={{
              background: 'rgba(255,255,255,.08)',
              color: 'white',
              border: '1.5px solid rgba(255,255,255,.2)',
              backdropFilter: 'blur(8px)',
            }} onClick={() => navigate('contact')}>
              Contacteer ons
            </button>
          </div>
        </div>
      </Reveal>

      <style>{`
        @keyframes lmTickIn   { 0% { opacity: 0; transform: scale(0.85); } 60% { opacity: 1; transform: scale(1.05); } 100% { transform: scale(1); } }
        @keyframes lmSepBlink { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
      `}</style>
    </section>
  );
}

function TimeUnit({ value, label }) {
  const text = String(value).padStart(2, '0');
  return (
    <div style={{
      display: 'flex',
      flexDirection: 'column',
      alignItems: 'center',
      gap: 8,
      flex: '1 1 0',
      minWidth: 0,
    }}>
      <div style={{
        width: '100%',
        aspectRatio: '1.05 / 1',
        maxHeight: 120,
        padding: 'clamp(6px, 1.5vw, 14px)',
        background: 'rgba(255,255,255,.08)',
        backdropFilter: 'blur(8px)',
        border: '1px solid rgba(255,255,255,.14)',
        borderRadius: 14,
        boxShadow: 'inset 0 1px 0 rgba(255,255,255,.1), 0 6px 20px rgba(0,0,0,.25)',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        lineHeight: 1,
      }}>
        <span
          key={text}
          style={{
            fontFamily: 'JetBrains Mono, monospace',
            fontSize: 'clamp(22px, 6.5vw, 56px)',
            fontWeight: 600,
            letterSpacing: '-0.02em',
            color: 'white',
            textShadow: '0 2px 12px rgba(0,0,0,.35)',
            display: 'inline-block',
            animation: 'lmTickIn .35s ease',
          }}
        >
          {text}
        </span>
      </div>
      <span className="mono" style={{
        fontSize: 'clamp(9px, 1.4vw, 11px)',
        fontWeight: 600,
        letterSpacing: '0.16em',
        textTransform: 'uppercase',
        color: 'rgba(255,255,255,.7)',
        whiteSpace: 'nowrap',
      }}>{label}</span>
    </div>
  );
}

function CountdownSep() {
  return (
    <span style={{
      fontFamily: 'JetBrains Mono, monospace',
      fontSize: 'clamp(16px, 4vw, 32px)',
      color: 'rgba(255,255,255,.4)',
      fontWeight: 300,
      paddingBottom: 22,
      flex: '0 0 auto',
      animation: 'lmSepBlink 1.5s ease-in-out infinite',
    }}>:</span>
  );
}

// ============================================
// FormBlock — rendert een dynamisch formulier op basis van block.fields
// Submit naar /api/form-submit met block.formId
// ============================================
// ============================================
// FileBlock — toont een klikbare kaart die het bestand in een nieuw tabblad opent
// ============================================
function FileBlock({ block }) {
  const { Reveal, Icon } = window.LM_UI;
  if (!block.url) return null;
  const url = block.url.replace(/^(?!\/|https?:\/\/|\/\/|data:)/, '/');

  // Detecteer bestandstype voor icoon + label
  const ext = (block.url.split('.').pop() || '').toLowerCase();
  const isImage = /(jpe?g|png|gif|webp|svg)/.test(ext);
  const isVideo = /(mp4|webm|mov|m4v)/.test(ext);
  const isPdf   = ext === 'pdf';
  const isDoc   = /(docx?)/.test(ext);
  const isXls   = /(xlsx?|csv)/.test(ext);
  const isPpt   = /(pptx?)/.test(ext);
  const isZip   = ext === 'zip';

  let icon = '📄', typeLabel = ext.toUpperCase() || 'BESTAND', accent = 'var(--ink-500)';
  if (isPdf)   { icon = '📕'; typeLabel = 'PDF';        accent = '#b91c1c'; }
  else if (isDoc)   { icon = '📘'; typeLabel = 'Word';       accent = '#2563eb'; }
  else if (isXls)   { icon = '📗'; typeLabel = 'Excel';      accent = '#15803d'; }
  else if (isPpt)   { icon = '📙'; typeLabel = 'PowerPoint'; accent = '#c2410c'; }
  else if (isZip)   { icon = '🗜';  typeLabel = 'ZIP';        accent = 'var(--ink-700)'; }
  else if (isImage) { icon = '🖼';  typeLabel = ext.toUpperCase(); accent = 'var(--teal-500)'; }
  else if (isVideo) { icon = '🎬'; typeLabel = ext.toUpperCase(); accent = 'var(--blue-500)'; }

  const fileName = (block.url.split('/').pop() || 'bestand');
  const displayLabel = block.text || fileName;

  return (
    <Reveal>
      <a
        href={url}
        target="_blank"
        rel="noreferrer"
        className="card"
        style={{
          display: 'flex',
          alignItems: 'center',
          gap: 16,
          padding: 18,
          margin: '14px 0',
          textDecoration: 'none',
          color: 'inherit',
          transition: 'transform .15s, box-shadow .15s, border-color .15s',
          position: 'relative',
          overflow: 'hidden',
        }}
        onMouseEnter={(e) => { e.currentTarget.style.transform = 'translateY(-2px)'; e.currentTarget.style.boxShadow = 'var(--shadow-md)'; e.currentTarget.style.borderColor = accent; }}
        onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateY(0)';   e.currentTarget.style.boxShadow = 'var(--shadow-sm)'; e.currentTarget.style.borderColor = ''; }}
      >
        {/* Accent-streep links */}
        <span style={{
          position: 'absolute', top: 0, left: 0, bottom: 0, width: 3, background: accent,
        }} />

        <div style={{
          width: 56, height: 56,
          borderRadius: 12,
          background: 'var(--ink-50)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          fontSize: 30,
          flexShrink: 0,
        }}>
          {icon}
        </div>

        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap', marginBottom: 4 }}>
            <span style={{
              fontSize: 10,
              fontFamily: 'var(--font-mono)',
              fontWeight: 600,
              letterSpacing: '0.14em',
              textTransform: 'uppercase',
              color: accent,
              background: 'var(--ink-50)',
              padding: '2px 8px',
              borderRadius: 4,
            }}>
              {typeLabel}
            </span>
          </div>
          <div className="display" style={{ fontSize: 17, textTransform: 'none', letterSpacing: '-0.005em', lineHeight: 1.3, marginBottom: 2 }}>
            {displayLabel}
          </div>
          {block.caption && (
            <div style={{ fontSize: 13, color: 'var(--ink-500)', lineHeight: 1.45 }}>
              {block.caption}
            </div>
          )}
        </div>

        <div style={{
          display: 'flex',
          alignItems: 'center',
          gap: 6,
          fontSize: 13,
          color: accent,
          fontWeight: 700,
          flexShrink: 0,
        }}>
          ↗ Openen
        </div>
      </a>
    </Reveal>
  );
}

function FormBlock({ block }) {
  const { Reveal, Icon } = window.LM_UI;
  const fields = block.fields || [];

  // Initiele state voor elk veld
  const initState = React.useMemo(() => {
    const o = {};
    fields.forEach(f => {
      if (['heading', 'divider', 'info'].includes(f.type)) return;
      if (f.type === 'checkboxes') o[f.name] = [];
      else if (f.type === 'checkbox') o[f.name] = false;
      else o[f.name] = f.defaultValue || '';
    });
    return o;
  }, [block.formId]);

  const [values, setValues] = React.useState(initState);
  const [sending, setSending] = React.useState(false);
  const [sent, setSent] = React.useState(false);
  const [error, setError] = React.useState('');

  const set = (name, value) => setValues(v => ({ ...v, [name]: value }));
  const toggleCheck = (name, opt) => setValues(v => {
    const arr = Array.isArray(v[name]) ? v[name] : [];
    return { ...v, [name]: arr.includes(opt) ? arr.filter(x => x !== opt) : [...arr, opt] };
  });

  const validate = () => {
    for (const f of fields) {
      if (!f.required) continue;
      if (['heading', 'divider', 'info'].includes(f.type)) continue;
      const v = values[f.name];
      const empty = v === undefined || v === null || v === '' || (Array.isArray(v) && v.length === 0) || v === false;
      if (empty) return `${f.label || f.name} is verplicht`;
      if (f.type === 'email' && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(String(v))) {
        return `${f.label} is geen geldig e-mailadres`;
      }
    }
    return '';
  };

  const submit = async (e) => {
    e.preventDefault();
    const err = validate();
    if (err) { setError(err); return; }
    setError('');
    setSending(true);
    try {
      const res = await fetch('/api/form-submit', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ formId: block.formId, data: values }),
      });
      const body = await res.json().catch(() => ({}));
      if (!res.ok) throw new Error(body.message || 'Versturen mislukt');
      setSent(true);
    } catch (ex) {
      setError(ex.message || 'Er ging iets mis. Probeer het later opnieuw.');
    } finally {
      setSending(false);
    }
  };

  if (sent) {
    return (
      <>
        <Reveal>
          <div className="card" style={{ padding: '48px 40px', textAlign: 'center', margin: '24px 0' }}>
            <div style={{
              width: 64, height: 64, borderRadius: '50%',
              background: 'var(--gradient)', color: 'white',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
              margin: '0 auto 20px',
            }}>
              <Icon.Check size={28} />
            </div>
            <h3 className="display" style={{ fontSize: 26, margin: '0 0 12px', textTransform: 'none', letterSpacing: '-0.01em' }}>
              Verzonden!
            </h3>
            <p style={{ color: 'var(--ink-500)', margin: 0 }}>
              {block.successMessage || 'Bedankt! We nemen snel contact op.'}
            </p>
          </div>
        </Reveal>
        {block.deliveryPublic && <FormPublicWall block={block} key={Date.now()} />}
      </>
    );
  }

  return (
    <>
    <Reveal>
      <form onSubmit={submit} className="card" style={{ padding: 36, margin: '24px 0' }}>
        {block.title && (
          <h3 className="display" style={{ fontSize: 24, margin: '0 0 8px', textTransform: 'none', letterSpacing: '-0.01em' }}>
            {block.title}
          </h3>
        )}
        {block.description && (
          <p style={{ color: 'var(--ink-500)', margin: '0 0 24px' }}>{block.description}</p>
        )}

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }} className="lm-form-grid">
          {fields.map((f, i) => <FormField key={f.id || i} field={f} value={values[f.name]} onSet={set} onToggleCheck={toggleCheck} />)}
        </div>

        {error && (
          <div style={{ marginTop: 16, background: '#fde8e8', color: '#9b1c1c', padding: 12, borderRadius: 8, fontSize: 14 }}>
            {error}
          </div>
        )}

        <button type="submit" className="btn btn-primary" disabled={sending} style={{ marginTop: 24 }}>
          {sending ? 'Versturen…' : (block.submitLabel || 'Verstuur')} <Icon.ArrowRight />
        </button>

        <style>{`
          @media (max-width: 720px) {
            .lm-form-grid { grid-template-columns: 1fr !important; }
          }
        `}</style>
      </form>
    </Reveal>
    {block.deliveryPublic && <FormPublicWall block={block} />}
    </>
  );
}

// ============================================
// FormPublicWall — toont goedgekeurde inzendingen onder het formulier
// ============================================
function FormPublicWall({ block }) {
  const { Reveal } = window.LM_UI;
  const [items, setItems] = React.useState(null); // null = laden, [] = leeg

  React.useEffect(() => {
    let cancelled = false;
    fetch('/api/form-submissions/' + encodeURIComponent(block.formId), { cache: 'no-store' })
      .then(r => r.ok ? r.json() : { items: [] })
      .then(d => { if (!cancelled) setItems(d.items || []); })
      .catch(() => { if (!cancelled) setItems([]); });
    return () => { cancelled = true; };
  }, [block.formId]);

  if (!items) return null;
  if (items.length === 0) return null; // toon niets als er nog niets goedgekeurd is

  // Bepaal labels voor velden uit het formulier-blok zelf
  const labelFor = (name) => {
    const f = (block.fields || []).find(x => x.name === name);
    return f?.label || name;
  };

  // Heuristiek: het langste tekstveld is het hoofdbericht, andere worden de subline
  const longestKey = (data) => {
    let bestKey = null, bestLen = -1;
    Object.entries(data || {}).forEach(([k, v]) => {
      const s = Array.isArray(v) ? v.join(', ') : String(v ?? '');
      if (s.length > bestLen) { bestLen = s.length; bestKey = k; }
    });
    return bestKey;
  };

  return (
    <Reveal>
      <div style={{ marginTop: 48 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 16 }}>
          <span className="stripe-accent"></span>
          <span className="eyebrow">{block.publicHeading || 'Reacties'} · {items.length}</span>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))', gap: 16 }}>
          {items.map(item => {
            const mainKey = longestKey(item.data);
            const mainValue = item.data && mainKey ? item.data[mainKey] : '';
            const otherEntries = Object.entries(item.data || {}).filter(([k]) => k !== mainKey);
            return (
              <article key={item.id} className="card" style={{ padding: 22, display: 'flex', flexDirection: 'column' }}>
                {mainValue && (
                  <p style={{
                    fontSize: 15,
                    lineHeight: 1.6,
                    margin: '0 0 14px',
                    whiteSpace: 'pre-wrap',
                    color: 'var(--ink-700)',
                    flex: 1,
                  }}>
                    {Array.isArray(mainValue) ? mainValue.join(', ') : String(mainValue)}
                  </p>
                )}
                {otherEntries.length > 0 && (
                  <div style={{ paddingTop: 12, borderTop: '1px solid var(--border)', marginBottom: 6 }}>
                    {otherEntries.map(([k, v]) => (
                      <div key={k} style={{ display: 'flex', gap: 8, fontSize: 12, color: 'var(--ink-700)', marginBottom: 2 }}>
                        <span className="mono" style={{ color: 'var(--ink-500)', minWidth: 80, textTransform: 'uppercase', letterSpacing: '0.05em', fontSize: 10 }}>{labelFor(k)}</span>
                        <span style={{ wordBreak: 'break-word' }}>{Array.isArray(v) ? v.join(', ') : String(v)}</span>
                      </div>
                    ))}
                  </div>
                )}
                <div className="mono" style={{ fontSize: 10, color: 'var(--ink-400)', letterSpacing: '0.1em', textTransform: 'uppercase', marginTop: 'auto', paddingTop: 8 }}>
                  {new Date(item.createdAt).toLocaleDateString('nl-BE', { day: '2-digit', month: 'long', year: 'numeric' })}
                </div>
              </article>
            );
          })}
        </div>
      </div>
    </Reveal>
  );
}

function FormField({ field: f, value, onSet, onToggleCheck }) {
  const fullWidth = f.width !== 'half';
  const colStyle = { gridColumn: fullWidth ? '1 / -1' : 'auto' };

  // Layout-only velden
  if (f.type === 'heading') {
    return <h4 style={{ ...colStyle, margin: '12px 0 0', fontSize: 17, fontWeight: 700, color: 'var(--ink-900)' }}>{f.label}</h4>;
  }
  if (f.type === 'divider') {
    return <hr style={{ ...colStyle, border: 'none', borderTop: '1px solid var(--border)', margin: '8px 0' }} />;
  }
  if (f.type === 'info') {
    return <p style={{ ...colStyle, margin: 0, fontSize: 14, color: 'var(--ink-500)', background: 'var(--ink-50)', padding: 12, borderRadius: 8 }}>{f.label}</p>;
  }

  const label = (
    <label className="label">
      {f.label}{f.required ? <span style={{ color: 'var(--ink-900)', marginLeft: 4 }}>*</span> : null}
    </label>
  );
  const help = f.helpText ? (
    <small style={{ color: 'var(--ink-500)', display: 'block', marginTop: 4, fontSize: 12 }}>{f.helpText}</small>
  ) : null;

  switch (f.type) {
    case 'text':
    case 'email':
    case 'phone':
    case 'number':
    case 'date':
    case 'time':
    case 'url':
      return (
        <div style={colStyle}>
          {label}
          <input
            className="input"
            type={f.type === 'phone' ? 'tel' : f.type}
            required={!!f.required}
            value={value || ''}
            placeholder={f.placeholder || ''}
            min={f.min} max={f.max}
            onChange={e => onSet(f.name, e.target.value)}
          />
          {help}
        </div>
      );
    case 'textarea':
      return (
        <div style={colStyle}>
          {label}
          <textarea
            className="textarea"
            rows={f.rows || 5}
            required={!!f.required}
            value={value || ''}
            placeholder={f.placeholder || ''}
            onChange={e => onSet(f.name, e.target.value)}
          />
          {help}
        </div>
      );
    case 'select':
      return (
        <div style={colStyle}>
          {label}
          <select className="input" required={!!f.required} value={value || ''} onChange={e => onSet(f.name, e.target.value)}>
            <option value="">{f.placeholder || '— Kies een optie —'}</option>
            {(f.options || []).map((o, i) => <option key={i} value={o}>{o}</option>)}
          </select>
          {help}
        </div>
      );
    case 'radio':
      return (
        <div style={colStyle}>
          {label}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginTop: 6 }}>
            {(f.options || []).map((o, i) => (
              <label key={i} style={{ display: 'flex', gap: 10, alignItems: 'center', cursor: 'pointer', fontSize: 14 }}>
                <input type="radio" name={f.name} checked={value === o} onChange={() => onSet(f.name, o)} required={!!f.required} />
                <span>{o}</span>
              </label>
            ))}
          </div>
          {help}
        </div>
      );
    case 'checkboxes':
      return (
        <div style={colStyle}>
          {label}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 8, marginTop: 6 }}>
            {(f.options || []).map((o, i) => (
              <label key={i} style={{ display: 'flex', gap: 10, alignItems: 'center', cursor: 'pointer', fontSize: 14 }}>
                <input type="checkbox" checked={Array.isArray(value) && value.includes(o)} onChange={() => onToggleCheck(f.name, o)} />
                <span>{o}</span>
              </label>
            ))}
          </div>
          {help}
        </div>
      );
    case 'checkbox':
      return (
        <label style={{ ...colStyle, display: 'flex', gap: 10, alignItems: 'flex-start', cursor: 'pointer', fontSize: 14 }}>
          <input type="checkbox" checked={!!value} onChange={e => onSet(f.name, e.target.checked)} required={!!f.required} style={{ marginTop: 3 }} />
          <span>{f.label}{f.required ? <span style={{ color: 'var(--ink-900)', marginLeft: 4 }}>*</span> : null}</span>
        </label>
      );
    default:
      return null;
  }
}

window.LM_PAGES = window.LM_PAGES || {};
window.LM_PAGES.Custom = CustomPage;
