/* global React */
const { useState, useEffect, useRef } = React;

// ---- Reveal on scroll hook ----
const useReveal = () => {
  useEffect(() => {
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => { if (e.isIntersecting) e.target.classList.add('in'); });
    }, { threshold: 0.12 });
    document.querySelectorAll('.reveal').forEach(el => io.observe(el));
    return () => io.disconnect();
  }, []);
};

// ---- Animated counter ----
const Counter = ({ to, duration = 1800, prefix = '', suffix = '', decimals = 0 }) => {
  const [val, setVal] = useState(0);
  const ref = useRef(null);
  const started = useRef(false);
  useEffect(() => {
    const io = new IntersectionObserver((entries) => {
      entries.forEach(e => {
        if (e.isIntersecting && !started.current) {
          started.current = true;
          const start = performance.now();
          const tick = (t) => {
            const p = Math.min((t - start) / duration, 1);
            const eased = 1 - Math.pow(1 - p, 3);
            setVal(to * eased);
            if (p < 1) requestAnimationFrame(tick);
          };
          requestAnimationFrame(tick);
        }
      });
    }, { threshold: 0.4 });
    if (ref.current) io.observe(ref.current);
    return () => io.disconnect();
  }, [to, duration]);
  const display = val.toLocaleString('de-CH', { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
  return <span ref={ref}>{prefix}{display}{suffix}</span>;
};

// ---- Icons ----
const Icon = ({ name, size = 20 }) => {
  const p = {
    arrow: <path d="M5 12h14M13 6l6 6-6 6"/>,
    plus: <><path d="M12 5v14"/><path d="M5 12h14"/></>,
    play: <path d="M6 4v16l14-8-14-8z" fill="currentColor" stroke="none"/>,
    target: <><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></>,
    wave: <><path d="M17 21v-2a4 4 0 0 0-4-4H7a4 4 0 0 0-4 4v2"/><circle cx="10" cy="7" r="4"/><path d="M21 15v6M18 18h6"/></>,
    chart: <><path d="M3 3v18h18"/><path d="M7 14l4-4 4 4 5-5"/></>,
    check: <path d="M5 12l5 5L20 7"/>,
    close: <><path d="M18 6L6 18"/><path d="M6 6l12 12"/></>,
  };
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
      {p[name] || p.arrow}
    </svg>
  );
};

// ---- Cursor ----
const Cursor = () => {
  const ref = useRef(null);
  useEffect(() => {
    const move = (e) => {
      if (!ref.current) return;
      ref.current.style.left = e.clientX + 'px';
      ref.current.style.top = e.clientY + 'px';
    };
    const over = (e) => {
      if (e.target.closest('a,button,.industry,.case-card,.testi-video,.faq-q')) {
        ref.current?.classList.add('hover');
      } else {
        ref.current?.classList.remove('hover');
      }
    };
    window.addEventListener('mousemove', move);
    window.addEventListener('mouseover', over);
    return () => { window.removeEventListener('mousemove', move); window.removeEventListener('mouseover', over); };
  }, []);
  return <div ref={ref} className="cursor"/>;
};

// ---- NAV ----
const NavBar = ({ onCTA, onBook }) => {
  const [scrolled, setScrolled] = useState(false);
  const [mob, setMob] = useState(false);
  useEffect(() => {
    const h = () => setScrolled(window.scrollY > 40);
    window.addEventListener('scroll', h);
    return () => window.removeEventListener('scroll', h);
  }, []);
  return (
    <>
      <nav className={`nav ${scrolled ? 'scrolled' : ''}`}>
        <div className="container nav-inner">
          <a href="#" className="nav-logo">
            <img src="assets/logo-mark-transparent.png" alt="Explicit Marketing"/>
          </a>
          <div className="nav-links">
            <a href="#methode" className="nav-link">So arbeiten wir</a>
            <a href="#resultate" className="nav-link">Resultate</a>
            <div className="nav-dropdown">
              <a href="#branchen" className="nav-link">Für Ihre Branche ↓</a>
              <div className="nav-dropdown-menu">
                <a href="#handwerk">Handwerk &amp; Bau <span className="mini">Ø CHF 14.40</span></a>
                <a href="#pflege">Pflege &amp; Gesundheit <span className="mini">Ø CHF 43.41</span></a>
                <a href="#gastro">Gastronomie <span className="mini">Ø CHF 22.00</span></a>
                <a href="#logistik">Logistik &amp; Transport <span className="mini">Ø CHF 3.62</span></a>
                <a href="#kader">Kader &amp; Spezialisten <span className="mini">Ø CHF 95.00</span></a>
              </div>
            </div>
            <a href="#insights" className="nav-link">Insights</a>
            <a href="#ueber-uns" className="nav-link">Über uns</a>
            <div className="nav-ctas">
              <button className="btn btn-ghost nav-cta-ghost" onClick={onBook}>Gespräch</button>
              <button className="btn btn-primary" onClick={onCTA}>Gratis Audit →</button>
            </div>
          </div>
          <button className={`nav-burger ${mob ? 'open' : ''}`} onClick={() => setMob(!mob)} aria-label="Menu">
            <span/>
          </button>
        </div>
      </nav>
      <div className={`mobile-menu ${mob ? 'open' : ''}`}>
        <a href="#methode" onClick={() => setMob(false)}>So arbeiten wir</a>
        <a href="#resultate" onClick={() => setMob(false)}>Resultate</a>
        <a href="#insights" onClick={() => setMob(false)}>Insights</a>
        <a href="#ueber-uns" onClick={() => setMob(false)}>Über uns</a>
        <div className="mm-section">Für Ihre Branche</div>
        <div className="mm-sub">
          <a href="#handwerk" onClick={() => setMob(false)}>Handwerk &amp; Bau</a>
          <a href="#pflege" onClick={() => setMob(false)}>Pflege &amp; Gesundheit</a>
          <a href="#gastro" onClick={() => setMob(false)}>Gastronomie</a>
          <a href="#logistik" onClick={() => setMob(false)}>Logistik &amp; Transport</a>
          <a href="#kader" onClick={() => setMob(false)}>Kader &amp; Spezialisten</a>
        </div>
        <div style={{marginTop:32, display:'flex', flexDirection:'column', gap:12}}>
          <button className="btn btn-primary btn-lg" onClick={() => { setMob(false); onCTA(); }}>Gratis Audit starten →</button>
          <button className="btn btn-ghost btn-lg" onClick={() => { setMob(false); onBook(); }}>Gespräch buchen</button>
        </div>
      </div>
    </>
  );
};

// ---- HERO ----
const SPARKLINES = [
  '0,70 20,60 40,55 60,45 80,50 100,40 120,35 140,28 160,30 180,20 200,22 220,14 240,16 260,8 280,6 300,2',
  '0,72 30,68 60,62 90,58 120,54 150,48 180,42 210,36 240,30 270,22 300,14',
  '0,75 20,60 40,44 60,38 80,35 100,30 120,28 140,24 160,22 200,20 250,16 300,12',
  '0,70 40,65 80,58 120,50 150,46 180,42 210,35 240,28 270,20 300,16',
  '0,78 20,70 40,60 60,45 80,30 100,24 120,18 150,12 200,8 250,5 300,2',
  '0,74 50,66 100,56 150,46 180,38 220,28 260,18 300,10',
];

function buildHeroCards() {
  const raw = localStorage.getItem('em_data');
  const data = raw ? JSON.parse(raw) : window.EM_DATA;
  const eligible = data.results.filter(r => r.showInHero);
  if (!eligible.length) return [];
  return eligible.map((r, i) => {
    const client = data.clients.find(c => c.id === r.clientId);
    return {
      label: r.label,
      brand: client ? client.name : '—',
      apps:  r.apps,
      cpa:   r.cpa,
      pts:   SPARKLINES[i % SPARKLINES.length],
    };
  });
}

const AuroraBackground = ({ children, showRadialGradient = true, className = '' }) => (
  <div className={`aurora-bg ${className}`} aria-hidden={!children}>
    <div className={`aurora-layer${showRadialGradient ? ' aurora-masked' : ''}`} aria-hidden="true" />
    {children && <div className="motion-fade-up">{children}</div>}
  </div>
);

const Hero = ({ onCTA, onBook }) => {
  const [cards, setCards] = useState(() => buildHeroCards());
  const [cardIdx, setCardIdx] = useState(0);
  const [phase, setPhase] = useState('idle'); // 'idle' | 'exiting' | 'entering'
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    const raf = requestAnimationFrame(() => setMounted(true));
    return () => cancelAnimationFrame(raf);
  }, []);

  useEffect(() => {
    const refresh = () => {
      setCards(buildHeroCards());
      setCardIdx(0);
    };
    window.addEventListener('em_data_updated', refresh);
    return () => window.removeEventListener('em_data_updated', refresh);
  }, []);

  useEffect(() => {
    if (!cards.length) return;
    const interval = setInterval(() => {
      setPhase('exiting');
      setTimeout(() => {
        setCardIdx(i => (i + 1) % cards.length);
        setPhase('entering');
        setTimeout(() => setPhase('idle'), 420);
      }, 350);
    }, 4500);
    return () => clearInterval(interval);
  }, [cards]);

  const card = cards[cardIdx];
  return (
    <section className="hero">
      <AuroraBackground />
      <div className={`container hero-motion${mounted ? ' in' : ''}`}>
        <div className="hero-eyebrow">
          <span className="pulse"/> 100+ Projekte · 10'000+ Bewerbungen · CHF 50'000+ Budget
        </div>
        <h1 className="hero-title">
          <span className="line"><span>Planbar neue</span></span>
          <span className="line"><span>Mitarbeiter <em className="accent-grad">über Social Media</em>.</span></span>
          <span className="line"><span>Ohne Jobbörsen.</span></span>
        </h1>
        <p className="hero-sub">
          Wir holen Ihnen qualifizierte Bewerbungen direkt aus Instagram und Facebook. In 100+ Projekten haben wir über 10'000 Bewerbungen gebracht. Kosten pro Bewerbung im Schnitt: CHF 10.
        </p>
        <div className="hero-ctas">
          <button className="btn btn-primary btn-xl" onClick={onCTA}>
            Gratis Recruiting-Audit <Icon name="arrow" size={18}/>
          </button>
          <button className="btn btn-outline btn-xl" onClick={onBook}>
            Gespräch buchen
          </button>
        </div>
        <div className="hero-meta">
          <div className="hero-meta-item">
            <div className="v"><Counter to={10000} />+</div>
            <div className="l">Qualifizierte Bewerbungen</div>
          </div>
          <div className="hero-meta-item">
            <div className="v">CHF <Counter to={10} /></div>
            <div className="l">Ø Kosten pro Bewerbung</div>
          </div>
          <div className="hero-meta-item">
            <div className="v"><Counter to={3} /> Tage</div>
            <div className="l">bis zur ersten Bewerbung</div>
          </div>
          <div className="hero-meta-item">
            <div className="v"><Counter to={5} /> Mio+</div>
            <div className="l">Ad-Impressionen</div>
          </div>
        </div>
      </div>

      {card && (
        <div className="hero-card">
          <div className={`hero-card-inner${phase === 'exiting' ? ' exiting' : phase === 'entering' ? ' entering' : ''}`}>
            <div className="hero-card-label">{card.label}</div>
            <div className="hero-card-big">{card.apps} <span className="em-small">Bew.</span></div>
            <svg viewBox="0 0 300 80" preserveAspectRatio="none" style={{width:'100%', height:80}}>
              <defs>
                <linearGradient id="hcg" x1="0" y1="0" x2="0" y2="1">
                  <stop offset="0%" stopColor="#00C896" stopOpacity="0.6"/>
                  <stop offset="100%" stopColor="#00C896" stopOpacity="0"/>
                </linearGradient>
              </defs>
              <polygon points={card.pts + ' 300,80 0,80'} fill="url(#hcg)"/>
              <polyline points={card.pts} stroke="#00C896" strokeWidth="2" fill="none"/>
            </svg>
            <div className="hero-card-foot">
              <span>{card.brand}</span>
              <strong>CHF {Number(card.cpa).toFixed(card.cpa < 10 ? 2 : 0)} CPA</strong>
            </div>
          </div>
        </div>
      )}

      {/* Trust marquee */}
      {(() => {
        const raw = localStorage.getItem('em_data');
        const data = raw ? JSON.parse(raw) : window.EM_DATA;
        const names = data.clients.map(c => c.name);
        return (
          <div className="trust-bar" style={{position:'relative', zIndex:2}}>
            <div className="trust-track">
              {[...Array(2)].map((_, i) => (
                <React.Fragment key={i}>
                  {names.map((name, j) => (
                    <span key={j} className="trust-item">{name}<span className="dot"/></span>
                  ))}
                </React.Fragment>
              ))}
            </div>
          </div>
        );
      })()}
    </section>
  );
};

// ---- Industries bento ----
const Industries = ({ onCTA, onPlaybook }) => {
  const items = [
    { num: '01', title: 'Handwerk & Bau',       desc: 'Elektriker, Schreiner, Maler. Ads, die im Feierabend ziehen.',        stat: 14.40, decimals: 2, pre: 'CHF ', unit: 'Ø CPA', id: 'handwerk', cls: 'ind-1' },
    { num: '02', title: 'Pflege & Gesundheit',   desc: 'HF, FH, FaGe, MPA. Auch im leergefegten Markt.',              stat: 43.41, decimals: 2, pre: 'CHF ', unit: 'Ø CPA', id: 'pflege',   cls: 'ind-2' },
    { num: '03', title: 'Gastronomie',            desc: 'Service, Küche, Housekeeping. Vom Frühstück bis zum Dinner.', stat: 22,    decimals: 2, pre: 'CHF ', unit: 'Ø CPA', id: 'gastro',   cls: 'ind-3' },
    { num: '04', title: 'Logistik & Transport',  desc: 'Chauffeure, Lager, Kurier. Hier fallen unsere tiefsten Kosten pro Bewerbung.',  stat: 3.62,  decimals: 2, pre: 'CHF ', unit: 'Ø CPA', id: 'logistik', cls: 'ind-4' },
    { num: '05', title: 'Kader & Spezialisten',  desc: 'Ärzte, Bauführer, GL, Ingenieure. Ohne Honorar vom Headhunter.', stat: 95.00, decimals: 2, pre: 'CHF ', unit: 'Ø CPA', id: 'kader',    cls: 'ind-5' },
  ];
  return (
    <section className="section" id="branchen">
      <div className="container">
        <div className="section-head reveal">
          <span className="section-eyebrow">Für welche Branche?</span>
          <h2 className="section-title">5 Branchen.<br/>5 fertige <em>Playbooks</em>.</h2>
          <p className="section-sub">Für jede dieser Branchen haben wir getestete Kampagnen-Vorlagen. Jede Zahl auf dieser Seite kommt aus echten Projekten.</p>
        </div>
        <div className="industries">
          {items.map(it => (
            <a key={it.id} href={'#' + it.id} className={`industry ${it.cls} reveal`}
               onClick={(e) => { if (onPlaybook) { e.preventDefault(); onPlaybook(it.id); } }}>
              <div>
                <div className="ind-num">{it.num}</div>
                <h3>{it.title}</h3>
                <p>{it.desc}</p>
              </div>
              <div className="ind-stat">
                <div className="big"><Counter to={it.stat} decimals={it.decimals || 0} prefix={it.pre || ''} /></div>
                <div className="unit">{it.unit}</div>
              </div>
              <div className="ind-arrow"><Icon name="arrow" size={18}/></div>
              <div className="ind-deco">
                <div className="ind-deco-ring" style={{width:200, height:200, right:-60, bottom:-60}}/>
                <div className="ind-deco-ring" style={{width:320, height:320, right:-140, bottom:-140}}/>
              </div>
            </a>
          ))}
        </div>
      </div>
    </section>
  );
};

// ---- Statement ----
const Statement = () => (
  <section className="statement">
    <div className="container">
      <h2 className="statement-text reveal">
        <span className="faded">Stellenanzeigen schalten.</span><br/>
        <span className="faded">Warten. Hoffen.</span><br/>
        Das war <span className="grad">gestern</span>.
      </h2>
    </div>
  </section>
);

// ---- KPI dark section ----
const KPI = () => (
  <section className="section" style={{padding:'40px 0'}}>
    <div className="kpi-section">
      <div className="container">
        <div className="kpi-head reveal">
          <span className="section-eyebrow kpi-eyebrow">Das leisten unsere Kampagnen</span>
          <h2>Zahlen, die sich nachrechnen lassen.</h2>
          <p>Jede Kennzahl kommt aus über 100 dokumentierten Projekten. Keine Hochrechnung, keine Branchen-Durchschnitte.</p>
        </div>
        <div className="kpi-grid reveal">
          <div className="kpi">
            <div className="k-big"><Counter to={10000}/>+</div>
            <div className="k-label">Generierte Bewerbungen über alle Projekte</div>
          </div>
          <div className="kpi">
            <div className="k-big">CHF <Counter to={10}/></div>
            <div className="k-label">Ø Kosten pro Bewerbung (volumengewichtet)</div>
          </div>
          <div className="kpi">
            <div className="k-big"><Counter to={3}/><span style={{fontSize:'0.5em', color:'#B5B5B5'}}> Tage</span></div>
            <div className="k-label">bis zur ersten Bewerbung im Schnellfall</div>
          </div>
          <div className="kpi">
            <div className="k-big"><Counter to={5}/><span style={{fontSize:'0.5em', color:'#B5B5B5'}}> Mio+</span></div>
            <div className="k-label">generierte Ad-Impressionen</div>
          </div>
        </div>
      </div>
    </div>
  </section>
);

// ---- Problem / Solution split ----
const Split = () => (
  <section className="section">
    <div className="container">
      <div className="section-head reveal">
        <span className="section-eyebrow">Warum klassisches Recruiting killt</span>
        <h2 className="section-title">Was Sie kennen.<br/>Was wir <em>ändern</em>.</h2>
      </div>
      <div className="split reveal">
        <div className="split-col split-col-pain">
          <span className="split-label">⚠ Das kennen Sie</span>
          <div className="split-items">
            <div className="split-item">
              <div className="mark">✕</div>
              <div className="txt"><strong>Stellenanzeigen laufen ins Leere.</strong> Jobs.ch und Jobscout24 kosten 500 bis 2'000 CHF pro Monat. Resultat: 1 oder 2 Bewerbungen, die nicht passen.</div>
            </div>
            <div className="split-item">
              <div className="mark">✕</div>
              <div className="txt"><strong>Bewerber tauchen zum Gespräch nicht auf.</strong> Sie schreiben zurück, vereinbaren Termine. Dann sehen Sie die Leute nie wieder.</div>
            </div>
            <div className="split-item">
              <div className="mark">✕</div>
              <div className="txt"><strong>Sie erreichen nur die 20% aktiv Suchenden.</strong> Die besten Leute sind bereits angestellt und schauen gar nicht erst auf Jobportale.</div>
            </div>
          </div>
        </div>
        <div className="split-col split-col-fix">
          <span className="split-label">✓ So lösen wir das</span>
          <div className="split-items">
            <div className="split-item">
              <div className="mark">✓</div>
              <div className="txt"><strong>Ø CHF 10 pro qualifizierter Bewerbung.</strong> Planbar und messbar. Sie sehen jeden Franken und jede Bewerbung live in Ihrem Zugang.</div>
            </div>
            <div className="split-item">
              <div className="mark">✓</div>
              <div className="txt"><strong>Vorqualifizierung per Chatbot.</strong> Sie sprechen nur mit Kandidaten, die Ihre Grundkriterien erfüllen und echtes Interesse zeigen.</div>
            </div>
            <div className="split-item">
              <div className="mark">✓</div>
              <div className="txt"><strong>Wir erreichen die 80% passiver Kandidaten.</strong> Ads auf Instagram und Facebook. In Ihrer Region, in Ihrer Sprache, mit Ihren Bildern.</div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </section>
);

// ---- Method ----
const Method = ({ onCTA }) => {
  const steps = [
    {
      n: '01',
      t: 'Briefing',
      m: 'Woche 1 · Formular',
      d: 'Sie füllen ein kurzes Formular aus: Wer soll die Stelle besetzen, was bringt jemand mit, wie ist das Team. Klingt simpel. Ist aber der Grund, warum unsere Ads nicht klingen wie jedes andere Inserat.',
      you: 'Ihr Aufwand: ca. 20 Min.',
    },
    {
      n: '02',
      t: 'Onboarding Call',
      m: 'Woche 1 · 30 Min.',
      d: 'Wir gehen das Briefing gemeinsam durch, stellen noch ein paar Fragen und klären alles Organisatorische. Danach wissen wir genug, um loszulegen.',
      you: 'Ihr Aufwand: 30 Min. Call',
    },
    {
      n: '03',
      t: 'Creatives und Freigabe',
      m: 'Woche 1 bis 2 · Produktion',
      d: 'Wir schreiben die Texte und bauen die Ads. Alles kommt zur Freigabe zu Ihnen. Was nicht passt, wird angepasst, bevor irgendetwas online geht.',
      you: 'Ihr Aufwand: Freigabe geben',
    },
    {
      n: '04',
      t: 'Livegang und Bewerbungen',
      m: 'Ab Woche 2 · laufend',
      d: 'Die Kampagne läuft. Sie sehen die Bewerbungen direkt in Ihrem Zugang. Wir schauen laufend drauf und optimieren, auch wenn Sie uns sagen, dass Kandidaten nicht passen.',
      you: 'Sie: Bewerbungen prüfen und Feedback geben',
    },
    {
      n: '05',
      t: 'Reporting',
      m: 'Kampagnenende',
      d: 'Sie bekommen einen Abschlussbericht mit allen Zahlen. Wer sich die Resultate lieber gemeinsam ansehen möchte, kann einen kurzen Call dazubuchen.',
      you: 'Auf Wunsch: Abschlusscall',
    },
  ];
  return (
    <section className="section" id="methode">
      <div className="container">
        <div className="section-head reveal">
          <span className="section-eyebrow">So arbeiten wir</span>
          <h2 className="section-title">Von Briefing zur ersten <em>Bewerbung</em> in 2 Wochen.</h2>
          <p className="section-sub">Ihr Gesamtaufwand zu Beginn: ein Formular und ein Call. Danach laufen Kampagne, Optimierung und Reporting bei uns. Sie konzentrieren sich auf die Bewerbungen.</p>
        </div>
        <div className="method-steps">
          {steps.map((s,i) => (
            <div key={i} className="method-step reveal" style={{transitionDelay: i * 80 + 'ms'}}>
              <div className="m-num">{s.n}</div>
              <div>
                <h4>{s.t}</h4>
                <p>{s.d}</p>
                <div className="m-meta">{s.m} &nbsp;·&nbsp; <em>{s.you}</em></div>
              </div>
            </div>
          ))}
        </div>
        <div className="reveal" style={{textAlign:'center', marginTop:48}}>
          <button className="btn btn-primary btn-xl" onClick={onCTA}>
            Genau das will ich für meine Firma <Icon name="arrow" size={18}/>
          </button>
        </div>
      </div>
    </section>
  );
};

// ---- Cases ----
function buildCases() {
  const raw = localStorage.getItem('em_data');
  const data = raw ? JSON.parse(raw) : window.EM_DATA;
  return data.results.map(r => {
    const client = data.clients.find(c => c.id === r.clientId);
    return {
      id:     r.id,
      brand:  client ? client.name : '—',
      branch: client ? client.branch : '',
      role:   r.role,
      apps:   r.apps,
      cpa:    r.cpa,
      days:   r.days,
      q:      r.quote,
      qPerson: r.quotePerson,
      filter: client ? client.branch : '',
    };
  });
}

const Cases = () => {
  const [filter, setFilter] = useState('Alle');
  const [all, setAll] = useState(() => buildCases());
  const [revealed, setRevealed] = useState(false);
  const [expanded, setExpanded] = useState({});
  const [overflows, setOverflows] = useState({});
  const sectionRef = useRef(null);
  const quoteRefs = useRef(new Map());

  useEffect(() => {
    const el = sectionRef.current;
    if (!el) return;
    const io = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) { setRevealed(true); io.disconnect(); }
    }, { threshold: 0.1 });
    io.observe(el);
    return () => io.disconnect();
  }, []);

  useEffect(() => {
    const refresh = () => setAll(buildCases());
    window.addEventListener('em_data_updated', refresh);
    return () => window.removeEventListener('em_data_updated', refresh);
  }, []);

  const branches = ['Alle', ...Array.from(new Set(all.map(c => c.branch).filter(Boolean)))];
  const shown = filter === 'Alle' ? all : all.filter(c => c.filter === filter);

  useEffect(() => {
    const next = {};
    quoteRefs.current.forEach((el, id) => {
      if (el) next[id] = el.scrollHeight > el.clientHeight + 1;
    });
    setOverflows(prev => {
      const keys = new Set([...Object.keys(prev), ...Object.keys(next)]);
      for (const k of keys) if (prev[k] !== next[k]) return next;
      return prev;
    });
  }, [shown, revealed, all]);
  return (
    <section ref={sectionRef} className="section" id="resultate">
      <div className="container">
        <div className={`cases-head reveal${revealed ? ' in' : ''}`}>
          <div style={{maxWidth:720}}>
            <span className="section-eyebrow">Resultate</span>
            <h2 className="section-title">Was wir bewegt haben. <em>Belegbar</em>.</h2>
          </div>
          <div className="case-filter">
            {branches.map(f => (
              <button key={f} className={filter === f ? 'active' : ''} onClick={() => setFilter(f)}>{f}</button>
            ))}
          </div>
        </div>
        <div className="cases-grid">
          {shown.map((c,i) => (
            <div key={c.id || c.brand} className={`case-card reveal${revealed ? ' in' : ''}`} style={{transitionDelay: revealed && filter === 'Alle' ? i * 60 + 'ms' : '0ms'}}>
              <div className="c-grad-bar"/>
              <div className="c-head">
                <div className="c-logo">{c.brand}</div>
                <div className="c-tag">{c.branch}</div>
              </div>
              <p className="c-role">{c.role}</p>
              <div className="c-stats">
                <div className="c-stat"><div className="v">{c.apps}</div><div className="l">Bew.</div></div>
                <div className="c-stat"><div className="v">{c.cpa.toFixed(c.cpa < 10 ? 2 : 0)}</div><div className="l">CHF CPA</div></div>
                <div className="c-stat"><div className="v">{c.days}</div><div className="l">Tage</div></div>
              </div>
              {c.q && (
                <div className="c-quote-block">
                  <p
                    ref={el => {
                      if (el) quoteRefs.current.set(c.id, el);
                      else quoteRefs.current.delete(c.id);
                    }}
                    className={`c-quote${expanded[c.id] ? ' expanded' : ''}`}
                  >{c.q}</p>
                  {overflows[c.id] && (
                    <button
                      type="button"
                      className="c-quote-toggle"
                      onClick={() => setExpanded(s => ({ ...s, [c.id]: !s[c.id] }))}
                    >{expanded[c.id] ? 'Weniger' : 'Mehr lesen'}</button>
                  )}
                  {c.qPerson && <div className="c-quote-person">{c.qPerson}</div>}
                </div>
              )}
            </div>
          ))}
        </div>
      </div>
    </section>
  );
};

// ---- Why / Differentiation ----
const Why = () => {
  const items = [
    { n: '01', i: 'target', t: 'Spezialisiert', d: 'Wir machen nur Social Recruiting. Kein SEO nebenbei, keine Website-Bastelei. Deshalb sind unsere Kampagnen rund 3× effizienter.' },
    { n: '02', i: 'wave', t: 'Direkter Draht', d: 'Sie sprechen mit den Leuten, die auch Ihre Kampagnen bauen. Ohne Account-Manager dazwischen, ohne Meeting-Kette.' },
    { n: '03', i: 'chart', t: 'Nachweisbar', d: 'Jede Kampagne hat ein eigenes Dashboard. Jeden Franken, jede Bewerbung, jede Conversion sehen Sie live. Ohne Blackbox.' },
  ];
  return (
    <section className="section" id="ueber-uns">
      <div className="container">
        <div className="section-head reveal">
          <span className="section-eyebrow">Warum Explicit</span>
          <h2 className="section-title">Warum wir. Und nicht eine von <em>200 anderen</em>.</h2>
        </div>
        <div className="why-grid">
          {items.map((it,i) => (
            <div key={it.n} className="why-card reveal" style={{transitionDelay: i * 80 + 'ms'}}>
              <div className="why-icon"><Icon name={it.i} size={28}/></div>
              <div className="why-num">{it.n}</div>
              <h3>{it.t}</h3>
              <p>{it.d}</p>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
};

// ---- ROI Calculator ----
const ROI = ({ onCTA }) => {
  const [stellen, setStellen] = useState(3);
  const [gehalt, setGehalt] = useState(6500);
  const [monate, setMonate] = useState(4);
  const [infoOpen, setInfoOpen] = useState(false);
  const monat = stellen * (gehalt * 2.5) * monate / 12;
  const jahr = monat * 12;
  const fmt = (n) => Math.round(n).toLocaleString('de-CH');
  return (
    <section className="section">
      <div className="container">
        <div className="section-head reveal">
          <span className="section-eyebrow">ROI-Rechner</span>
          <h2 className="section-title">Was kostet Sie eine offene Stelle <em>pro Monat</em>?</h2>
          <p className="section-sub">Bewegen Sie die Schieber. Die Zahl wird Sie überraschen.</p>
        </div>
        <div className="roi-shell reveal">
          <div className="roi-grid">
            <div className="roi-controls">
              <div className="roi-control">
                <div className="r-top"><span className="r-label">Offene Stellen</span><span className="r-val">{stellen}</span></div>
                <input type="range" min="1" max="20" value={stellen} onChange={e => setStellen(+e.target.value)}/>
              </div>
              <div className="roi-control">
                <div className="r-top"><span className="r-label">Ø Gehalt brutto / Monat</span><span className="r-val">CHF {fmt(gehalt)}</span></div>
                <input type="range" min="4000" max="12000" step="100" value={gehalt} onChange={e => setGehalt(+e.target.value)}/>
              </div>
              <div className="roi-control">
                <div className="r-top"><span className="r-label">Wie lange unbesetzt?</span><span className="r-val">{monate} Monate</span></div>
                <input type="range" min="1" max="12" value={monate} onChange={e => setMonate(+e.target.value)}/>
              </div>
              <p style={{fontSize:12, color:'#7D7D7D', margin:0, lineHeight:1.5}}>
                Konservative Schätzung mit Faktor 2.5. Beinhaltet Produktivitätsausfall, Überstunden der Kollegen und entgangene Aufträge.
              </p>
              <button
                type="button"
                className={`roi-info-toggle${infoOpen ? ' open' : ''}`}
                aria-expanded={infoOpen}
                onClick={() => setInfoOpen(v => !v)}
              >
                <span>Woher kommt der Faktor 2.5?</span>
                <span className="roi-info-ico">{infoOpen ? '×' : '+'}</span>
              </button>
              <div className="roi-info-panel" style={{maxHeight: infoOpen ? 420 : 0}}>
                <div className="roi-info-inner">
                  <p>Der Wert kommt aus Studien, die den Gesamtschaden einer unbesetzten Stelle untersucht haben. Er deckt drei Dinge ab:</p>
                  <ul>
                    <li><strong>Arbeit, die liegen bleibt.</strong> Aufträge werden langsamer oder gar nicht erledigt.</li>
                    <li><strong>Überstunden im Team.</strong> Kollegen kompensieren — mehr Lohnkosten, mehr Belastung.</li>
                    <li><strong>Umsatz, der wegfällt.</strong> Ein fehlender Chauffeur fährt nicht. Ein fehlender Handwerker baut nicht. Ein fehlender Pfleger betreut nicht.</li>
                  </ul>
                  <p className="roi-info-note">Die Studien nennen eine Range von 1.5× bis 2.5× Jahresgehalt. Wir rechnen mit 2.5× — weil in Ihren Branchen mit einer fehlenden Fachkraft direkter Umsatz ausfällt, nicht nur Produktivität.</p>
                </div>
              </div>
            </div>
            <div className="roi-output">
              <div>
                <div className="o-label">Aktueller Monatsschaden</div>
                <div className="o-big">CHF {fmt(monat)}</div>
                <div className="o-annual">Jahresschaden (Hochrechnung): <strong>CHF {fmt(jahr)}</strong></div>
              </div>
              <div className="o-cta">
                <button className="btn btn-gradient btn-xl" style={{width:'100%', justifyContent:'center'}} onClick={onCTA}>
                  Schaden stoppen. Audit starten. <Icon name="arrow" size={18}/>
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </section>
  );
};

// ---- FAQ ----
const FAQ = () => {
  const [open, setOpen] = useState(-1);
  const [revealed, setRevealed] = useState(false);
  const sectionRef = useRef(null);

  useEffect(() => {
    const el = sectionRef.current;
    if (!el) return;
    const io = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) { setRevealed(true); io.disconnect(); }
    }, { threshold: 0.1 });
    io.observe(el);
    return () => io.disconnect();
  }, []);

  const items = [
    { q: 'Wir haben Social Recruiting schon mal versucht. Hat nicht funktioniert.', a: 'Das hören wir oft. Häufige Gründe: generische Anzeigen ohne Branchenkenntnis, falsches Targeting oder die falsche Zielgruppe. Für jede unserer Branchen bringen wir fertige Playbooks mit. Bildsprache, Texte und Zielgruppen, die nachweislich funktionieren. Ein 15-minütiges Audit zeigt Ihnen konkret, woran es zuvor gescheitert ist.' },
    { q: 'Wie lange dauert es bis zur ersten Bewerbung?', a: 'Ab Start der Zusammenarbeit dauert es im Schnitt 3 bis 10 Tage bis zur ersten Bewerbung. Nach dem Livegang der Kampagne selbst kommen die ersten Bewerbungen meist innerhalb von 1 bis 2 Tagen.' },
    { q: 'Was passiert, wenn keine Bewerbungen kommen?', a: 'Wir holen das Bestmögliche raus. Liefert eine Kampagne nicht die gewünschten Resultate, optimieren wir laufend. Falls wir merken, dass die Zielgruppe grundlegend falsch angesprochen wird, setzen wir die Kampagne auch komplett neu auf. Mitten in der Laufzeit, wenn nötig.' },
    { q: 'Wie viel Budget muss ich einplanen?', a: 'Ad-Budget ab CHF 500 pro Monat. Unser Honorar besprechen wir im Audit, abhängig von Ihren offenen Stellen.' },
    { q: 'Muss ich mich um Technik, Pixel, Ads kümmern?', a: 'Nein. Creatives, Setup, Tracking und Pixel laufen alles bei uns. Am Ende der Kampagne bekommen Sie ein detailliertes Reporting mit allen Kennzahlen. Auf Wunsch besprechen wir es gemeinsam.' },
    { q: 'Wer erstellt die Anzeigen?', a: 'Wir. Hauptsächlich arbeiten wir mit statischen Ad-Designs, teilweise auch mit Video. Von Ihnen brauchen wir Bildmaterial aus dem Betrieb und ein kurzes Briefing-Formular.' },
    { q: 'Was passiert, wenn wir genug Bewerbungen haben?', a: 'Die Kampagne läuft für die vereinbarte Dauer. Merken Sie zwischendurch, dass Sie bereits genug Kandidaten im Prozess haben, sagen Sie uns Bescheid. Wir berücksichtigen das bei der weiteren Optimierung.' },
    { q: 'Funktioniert das für jede Unternehmensgrösse?', a: 'Ja. Wir arbeiten mit KMU jeder Grösse. Von kleinen Handwerksbetrieben bis zu Organisationen mit mehreren offenen Stellen.' },
    { q: 'Seid ihr in meiner Region?', a: 'Wir arbeiten deutschschweizweit. Kunden in Zürich, Aargau, Bern, Luzern, Ostschweiz und beide Basel. Keine Westschweiz, kein Tessin.' },
  ];
  return (
    <section ref={sectionRef} className="section">
      <div className="container">
        <div className={`section-head center reveal${revealed ? ' in' : ''}`}>
          <span className="section-eyebrow">Fragen &amp; Antworten</span>
          <h2 className="section-title">Was Kunden <em>häufig fragen</em>.</h2>
        </div>
        <div className="faq">
          {items.map((f,i) => (
            <div key={i} className={`faq-item ${open === i ? 'open' : ''} reveal${revealed ? ' in' : ''}`}>
              <button className="faq-q" onClick={() => setOpen(open === i ? -1 : i)}>
                {f.q}
                <span className="faq-ico">{open === i ? '×' : '+'}</span>
              </button>
              <div className="faq-a" style={{maxHeight: open === i ? 400 : 0}}>
                <div className="faq-a-inner">{f.a}</div>
              </div>
            </div>
          ))}
        </div>
      </div>
    </section>
  );
};

// ---- Final CTA ----
// ---- Magnetic Button ----
const MagneticButton = ({ children, className, style, onClick, strength = 0.25 }) => {
  const ref = useRef(null);
  const onMove = (e) => {
    const el = ref.current;
    if (!el) return;
    const r = el.getBoundingClientRect();
    const x = (e.clientX - r.left - r.width / 2) * strength;
    const y = (e.clientY - r.top - r.height / 2) * strength;
    el.style.transform = `translate(${x}px, ${y}px)`;
  };
  const onLeave = () => { if (ref.current) ref.current.style.transform = ''; };
  return (
    <button ref={ref} className={className} style={style} onClick={onClick}
            onMouseMove={onMove} onMouseLeave={onLeave}>
      {children}
    </button>
  );
};

// ---- Cinematic Footer (Closer + Footer in one) ----
const MARQUEE_ITEMS = [
  'SOCIAL RECRUITING', 'CONTENT CREATION', 'MEHR BEWERBUNGEN',
  'DEUTSCHSCHWEIZ', 'KMU 30–250 MA', 'HANDWERK · PFLEGE · INDUSTRIE · TRANSPORT',
  'PLANBAR · MESSBAR · EHRLICH',
];

const CinematicFooter = ({ onCTA, onBook, onImpressum, onDatenschutz, onAGB }) => {
  const ref = useRef(null);
  const bigTextRef = useRef(null);

  useEffect(() => {
    let raf = 0;
    const update = () => {
      raf = 0;
      const el = ref.current, big = bigTextRef.current;
      if (!el || !big) return;
      const r = el.getBoundingClientRect();
      const vh = window.innerHeight || 1;
      const progress = Math.max(0, Math.min(1, 1 - r.top / vh));
      big.style.transform = `translateX(calc(-50% + ${(progress - 0.5) * 240}px))`;
    };
    const onScroll = () => { if (!raf) raf = requestAnimationFrame(update); };
    window.addEventListener('scroll', onScroll, { passive: true });
    update();
    return () => { window.removeEventListener('scroll', onScroll); if (raf) cancelAnimationFrame(raf); };
  }, []);

  const marquee = (
    <div className="cine-marquee-track" aria-hidden="true">
      {[0, 1].map(k => (
        <div className="cine-marquee-group" key={k}>
          {MARQUEE_ITEMS.map((t, i) => (
            <span key={i} className="cine-marquee-item">{t}<span className="cine-marquee-dot">●</span></span>
          ))}
        </div>
      ))}
    </div>
  );

  return (
    <footer ref={ref} className="cine-footer">
      <div className="cine-marquee">{marquee}</div>
      <div className="cine-aurora" aria-hidden="true"/>
      <div ref={bigTextRef} className="cine-bigtext" aria-hidden="true">EXPLICIT</div>

      <div className="container cine-inner">
        <div className="cine-closer">
          <span className="cine-eyebrow reveal">Letzter Schritt</span>
          <h2 className="cine-headline reveal">Bereit für <em>planbare</em><br/>Bewerbungen?</h2>
          <p className="cine-sub reveal">In 15 Minuten wissen Sie, ob Social Recruiting für Ihren Betrieb funktioniert. Ohne Kreditkarte, ohne Verkaufsdruck.</p>
          <div className="cine-cta-row reveal">
            <MagneticButton className="btn btn-gradient btn-xl cine-btn" onClick={onCTA}>
              Gratis Recruiting-Audit <Icon name="arrow" size={18}/>
            </MagneticButton>
            <MagneticButton className="btn btn-outline btn-xl cine-btn cine-btn-ghost" onClick={onBook}>
              Lieber direkt sprechen
            </MagneticButton>
          </div>
        </div>

        <div className="cine-grid">
          <div className="cine-brand">
            <img src="assets/logo-wordmark-transparent-light.png" alt="Explicit Marketing"/>
            <p>Social Recruiting für Schweizer KMU. Schnell aufgesetzt, klar im Reporting.</p>
            <p className="cine-addr">
              Explicit Marketing GmbH<br/>
              Gheidmattweg 15, 4600 Olten<br/>
              +41 76 596 53 55 · info@explicit-marketing.com
            </p>
          </div>
          <div>
            <h5>Navigation</h5>
            <ul>
              <li><a href="#methode">So arbeiten wir</a></li>
              <li><a href="#resultate">Resultate</a></li>
              <li><a href="#insights">Insights</a></li>
              <li><a href="#ueber-uns">Über uns</a></li>
            </ul>
          </div>
          <div>
            <h5>Branchen</h5>
            <ul>
              <li><a href="#handwerk">Handwerk &amp; Bau</a></li>
              <li><a href="#pflege">Pflege &amp; Gesundheit</a></li>
              <li><a href="#gastro">Gastronomie</a></li>
              <li><a href="#logistik">Logistik &amp; Transport</a></li>
              <li><a href="#kader">Kader &amp; Spezialisten</a></li>
            </ul>
          </div>
          <div>
            <h5>Social</h5>
            <ul>
              <li><a href="https://www.instagram.com/explicit_marketing/" target="_blank" rel="noopener noreferrer">Instagram</a></li>
              <li><a href="https://www.facebook.com/explicit.marketing.net" target="_blank" rel="noopener noreferrer">Facebook</a></li>
              <li><a href="https://www.linkedin.com/company/explicit-marketing/" target="_blank" rel="noopener noreferrer">LinkedIn</a></li>
              <li><a href="https://wa.me/message/WN5TK26DVBN4C1" target="_blank" rel="noopener noreferrer">WhatsApp</a></li>
            </ul>
          </div>
        </div>

        <div className="cine-bottom">
          <div>© 2026 Explicit Marketing GmbH</div>
          <div className="cine-bottom-links">
            <a href="#" onClick={(e) => { e.preventDefault(); onAGB && onAGB(); }}>AGB</a>
            <a href="#" onClick={(e) => { e.preventDefault(); onDatenschutz && onDatenschutz(); }}>Datenschutz</a>
            <a href="#" onClick={(e) => { e.preventDefault(); onImpressum && onImpressum(); }}>Impressum</a>
            <MagneticButton className="cine-totop" strength={0.4}
              onClick={() => window.scrollTo({ top: 0, behavior: 'smooth' })}>
              <span aria-hidden="true">↑</span>
              <span className="sr-only">Nach oben</span>
            </MagneticButton>
          </div>
        </div>
      </div>
    </footer>
  );
};

// ---- Playbooks data ----
const PLAYBOOKS = {
  handwerk: {
    title: 'Handwerk & Bau',
    brancheLabel: 'Handwerk & Bau',
    eyebrow: 'Playbook 01',
    oneLiner: 'Was wir über Handwerk und Bau wissen. Und was hier nachweislich funktioniert.',
    cpa: { value: 14.40, label: 'Ø CPA pro Bewerbung' },
    profile: {
      roles: 'Elektriker EFZ, Schreiner EFZ, Sanitärinstallateur, Maler EFZ, Maurer EFZ, Dachdecker, Monteure',
      age: '20 bis 55 Jahre',
      gender: 'überwiegend männlich (~90%)',
      online: 'Kaum auf Jobs.ch unterwegs. Aktiv auf Instagram und Facebook, meist zwischen 17 und 22 Uhr. Auf dem Sofa oder im Auto vor der Baustelle.',
    },
    wants: [
      'Pünktlicher Feierabend ohne Dauereinsatz',
      'Fairer Lohn plus 13. Monatslohn',
      'Moderner Fuhrpark und gutes Werkzeug',
      'Respektvoller Umgang vom Chef',
      'Team-Kultur mit gemeinsamem Z\'mittag und Freitag-Bier',
      'Planbare Wochenenden',
    ],
    pains: [
      'Ständige Überstunden ohne klaren Ausgleich',
      'Kaputtes Material, alte Fahrzeuge',
      'Akkord-Druck ohne Zeit für saubere Arbeit',
      'Chef der nur kritisiert, nie lobt',
    ],
    whyFail: 'Handwerker lesen keine Stelleninserate mehr. Sie scrollen abends durch Instagram und Facebook. Klassische HR-Anzeigen mit 15 Anforderungen und "dynamischem Umfeld" erreichen sie nicht. Sie brauchen Bilder vom echten Team und Sätze, die klingen wie vom Kollegen. Nicht wie vom Personalchef.',
    voice: {
      tone: 'Du-Form. Direkt, kurz. Wie ein Kollege, nicht wie ein HR-Mensch.',
      visuals: 'Echte Werkstatt, Baustelle, Firmenbus. Mitarbeiter-Shots mit Gesicht. Niemals Stockfotos.',
      noGo: ['"Dynamisches Umfeld"', '"Teamplayer gesucht"', 'Lebenslauf-Pflicht direkt im Inserat', 'Bullet-Listen mit 15 Muss-Kriterien'],
    },
    benefits: [
      '13. Monatslohn garantiert',
      'Firmenbus zum Mitnehmen',
      'Moderne Maschinen und Werkzeug',
      'Kein Akkord, klare Arbeitszeiten',
      'Weiterbildung zu 100% bezahlt',
      '5 Wochen Ferien, ab 40 Jahren 6 Wochen',
      'Team-Events und gemeinsames Z\'mittag',
    ],
    numbers: {
      cpa: 'Ø CHF 14.40 pro Bewerbung',
      timeline: 'Erste Bewerbungen 1 bis 2 Tage nach Livegang. Gesamte Kampagne 3 bis 10 Tage ab Start.',
      budget: 'CHF 500 bis 1\'200 Mediabudget pro Stelle und Monat',
    },
  },
  pflege: {
    title: 'Pflege & Gesundheit',
    brancheLabel: 'Pflege & Gesundheit',
    eyebrow: 'Playbook 02',
    oneLiner: 'Was wir über Pflege und Gesundheit wissen. Und warum hier Ehrlichkeit mehr zählt als Hochglanz.',
    cpa: { value: 43.41, label: 'Ø CPA pro Bewerbung' },
    profile: {
      roles: 'FaGe, Dipl. Pflegefachperson HF/FH, AGS, MPA, Pflegehelfer SRK',
      age: '22 bis 55 Jahre',
      gender: 'überwiegend weiblich (~85%)',
      online: 'Aktiv auf Instagram und Facebook, oft in Pausen oder spät abends nach dem Spätdienst. Sehr kritisch gegenüber Werbung. Reagieren nur auf authentische Team-Inhalte.',
    },
    wants: [
      'Dienstplan 2 Monate im Voraus, damit Familie planbar ist',
      'Geregelte Pausen, echte Entlastung',
      'Genug Zeit für Patienten, nicht im Akkord',
      'Wertschätzung und Rückhalt von der Leitung',
      'Weiterbildung mit bezahlter Freistellung',
      'Familienfreundliche Dienstzeiten',
      'Team das zusammenhält',
    ],
    pains: [
      'Kurzfristig eingeteilte Sprungdienste',
      'Burnout-Risiko durch ständige Unterbesetzung',
      'Kritik statt Wertschätzung vom Vorgesetzten',
      'Tiefer Lohn bei hoher Verantwortung',
    ],
    whyFail: 'Pflegefachpersonen werden von jedem Spital umworben. Generische Inserate mit "spannendes Umfeld" und "motiviertes Team" gehen komplett unter. Wechselwillige outen sich nicht öffentlich. Sie brauchen diskrete Sichtbarkeit und ehrliche Einblicke in Team und Führungskultur, bevor sie sich bewerben.',
    voice: {
      tone: 'Du-Form. Respektvoll, einfühlsam, ruhig. Keine Superlative.',
      visuals: 'Authentische Teamszenen. Kurze Mitarbeiter-Statements. Keine gestellten Lach-Shots, keine Stock-Schwestern.',
      noGo: ['"Herausforderndes Umfeld"', '"Stressresistenz vorausgesetzt"', 'Fokus nur auf Anforderungen', 'Lachende Pflegende in Stock-Optik'],
    },
    benefits: [
      'Dienstplan 8 Wochen im Voraus',
      'Mindestens 11h zwischen Diensten',
      'Weiterbildung mit bezahlter Freistellung',
      'Geregelte Pausen, garantiert',
      '13. Monatslohn und Treueprämien',
      'Parkplatz oder ÖV-Abo bezahlt',
      'Psychologische Supervision im Team',
    ],
    numbers: {
      cpa: 'Ø CHF 43.41 pro Bewerbung',
      timeline: 'Erste Bewerbungen 2 bis 4 Tage nach Livegang. Entscheidungsphase der Kandidaten oft 2 bis 4 Wochen.',
      budget: 'CHF 800 bis 2\'000 Mediabudget pro Stelle und Monat',
    },
  },
  gastro: {
    title: 'Gastronomie',
    brancheLabel: 'Gastronomie',
    eyebrow: 'Playbook 03',
    oneLiner: 'Was wir über Gastro wissen. Und warum hier Tempo und Ehrlichkeit alles sind.',
    cpa: { value: 22.00, label: 'Ø CPA pro Bewerbung' },
    profile: {
      roles: 'Service-Mitarbeiter, Koch/Köchin EFZ, Commis de cuisine, Chef de Rang, Housekeeping, Restaurantleitung',
      age: '18 bis 40 Jahre',
      gender: 'gemischt, leichter Überschuss weiblich im Service',
      online: 'Sehr aktiv auf Instagram, TikTok und Facebook. Kurze Entscheidungsphasen. Sie bewerben sich oft noch am selben Abend, wenn die Ad gut trifft.',
    },
    wants: [
      '5-Tage-Woche garantiert',
      'Kein Split-Shift, Dienst in einem Stück',
      'Planbarer Feierabend, spätestens um 23 Uhr',
      'Personalverpflegung auf gutem Niveau',
      'Fairer Grundlohn plus Trinkgeld',
      'Team das Spass macht',
    ],
    pains: [
      'Ewige Arbeitstage mit Split-Shifts',
      'Chef-Ton in der Küche',
      'Zu wenig Personal, zu viel Tempo',
      'Unregelmässige freie Tage ohne Planung',
    ],
    whyFail: 'Gastro-Fachkräfte wechseln schnell. Und sind genauso schnell wieder weg, wenn Versprechen nicht gehalten werden. Klassische Inserate locken niemanden mehr. Sie brauchen kurze Video-Einblicke ins echte Team, konkrete Benefits und einen schnellen Bewerbungsprozess.',
    voice: {
      tone: 'Du-Form. Locker, energiegeladen, schnell. Emojis okay.',
      visuals: 'Action in Küche und Service. Schnelle Schnitte. Echtes Team in Aktion. Reels-Format funktioniert top.',
      noGo: ['"Belastbar"', '"Flexible Einsatzbereitschaft"', 'Nur Stellenbeschreibung ohne Benefits', 'Steife Studio-Fotos'],
    },
    benefits: [
      '5-Tage-Woche',
      'Kein Split-Shift',
      'Personalverpflegung inklusive',
      'Trinkgeld komplett ans Team',
      'Geregelte Überstunden-Kompensation',
      '13. Monatslohn ab 2. Jahr',
      'Mitarbeiter-Rabatt im Hotel oder Restaurant',
    ],
    numbers: {
      cpa: 'Ø CHF 22.00 pro Bewerbung',
      timeline: 'Erste Bewerbungen oft innert 24h nach Livegang. Typischer Kampagnen-Zeitraum 1 bis 3 Wochen.',
      budget: 'CHF 400 bis 1\'000 Mediabudget pro Stelle und Monat',
    },
  },
  logistik: {
    title: 'Logistik & Transport',
    brancheLabel: 'Logistik & Transport',
    eyebrow: 'Playbook 04',
    oneLiner: 'Was wir über Logistik und Transport wissen. Und warum hier unsere tiefsten Kosten pro Bewerbung fallen.',
    cpa: { value: 3.62, label: 'Ø CPA pro Bewerbung' },
    profile: {
      roles: 'Chauffeur Kat. CE, Chauffeur Kat. C, Kurierfahrer, Lageristen, Staplerfahrer, Dispo-Mitarbeiter',
      age: '20 bis 60 Jahre',
      gender: 'überwiegend männlich (~92%)',
      online: 'Stark auf Facebook und Instagram. Hohe emotionale Reaktion auf echte Fahrzeug- und Fahrer-Videos. Viele passive Kandidaten. Sie suchen nicht aktiv, lassen sich aber überzeugen.',
    },
    wants: [
      'Moderner, sauberer Fuhrpark',
      'Strukturierte Tagestouren',
      'Erfahrene Dispo, die keine Wunder erwartet',
      'Feierabend daheim, kein Wochenend-Schlafen im Truck',
      'Fairer Lohn, pünktlich gezahlt',
      'Respekt von der Dispo',
    ],
    pains: [
      'Chaos in der Dispo, ständige Last-Minute-Änderungen',
      'Alte, kaputte Fahrzeuge',
      'Lange unbezahlte Wartezeiten beim Kunden',
      'Keine klaren Feierabend-Zeiten',
    ],
    whyFail: 'Chauffeure lesen kaum Stelleninserate. Sie werden durch echte Fahrzeug-Videos, Einblicke in Touren und authentische Kollegen-Statements erreicht. Genau in ihren Pausen auf der Raststätte. Jobs.ch-Anzeigen ohne Bildsprache landen direkt im Papierkorb.',
    voice: {
      tone: 'Du-Form. Sehr direkt, kurz, kein Bullshit. Klartext.',
      visuals: 'Fahrzeuge im Detail zeigen. Fahrer am Lenkrad, Touren, Werkstatt, Tankstelle. Echte Leute, keine Schauspieler.',
      noGo: ['"Kundenorientiert"', '"Belastbarkeit"', 'Nur Text ohne Fahrzeug-Bilder', 'Generische Lkw-Stockfotos'],
    },
    benefits: [
      'Moderner Fuhrpark ab Euro 6',
      'Tagestouren, abends daheim',
      'Erfahrene Dispo mit Fahrer-Hintergrund',
      '13. Monatslohn',
      'Spesen fair und transparent',
      'Weiterbildungen (Kran, ADR) bezahlt',
      'Parkplatz am Standort',
    ],
    numbers: {
      cpa: 'Ø CHF 3.62 pro Bewerbung. Unser tiefster Schnitt über alle Branchen.',
      timeline: 'Erste Bewerbungen oft innert 24h. Vollbelegung einer Tour meist in 1 bis 2 Wochen.',
      budget: 'CHF 400 bis 900 Mediabudget pro Stelle und Monat. Volumengewichtet extrem effizient.',
    },
  },
  kader: {
    title: 'Kader & Spezialisten',
    brancheLabel: 'Kader & Spezialisten',
    eyebrow: 'Playbook 05',
    oneLiner: 'Was wir über Kader-Recruiting wissen. Premium-Positionen besetzen, ohne Honorar vom Headhunter.',
    cpa: { value: 95.00, label: 'Ø CPA pro Bewerbung' },
    profile: {
      roles: 'Ärzte (Allgemein, Spezialisten, Ober-/Chefarzt), Bauführer, Polier, GL-Mitglied, Ingenieure (Bau/Elektro/Maschinen), Architekten, Filialleitung, Pflegedienstleitung, Senior IT / Tech Lead, Treuhänder / Wirtschaftsprüfer',
      age: '30 bis 55 Jahre',
      gender: 'gemischt, je nach Rolle',
      online: 'Mix aus Instagram, LinkedIn und Facebook. Scrollt in der Mittagspause oder abends. Sehr kritisch gegenüber plakativer Werbung. Reagiert nur auf ruhige, substanzielle Inhalte.',
    },
    wants: [
      'Echte Verantwortung mit klarem Mandat',
      'Karriereperspektive ohne Politik-Spiele',
      'Top-Vergütung plus Beteiligung oder Bonus',
      'Work-Life-Balance auf Kader-Niveau',
      'Moderne Führungskultur ohne Hierarchie-Allüren',
      'Mitsprache bei Strategie und Investitionen',
      'Moderne Tools und Infrastruktur',
    ],
    pains: [
      'Mikromanagement von oben trotz Kader-Titel',
      'Intransparente Beförderungswege',
      'Ausgebrannte Kollegen, kaputte Kultur',
      'Veraltete IT und Prozesse, die Zeit fressen',
      'Endlose Sitzungen ohne Entscheidungen',
    ],
    whyFail: 'Kader bewerben sich nicht aktiv. Sie müssen überzeugt werden. Headhunter sind teuer (oft CHF 30\'000+ pro Besetzung) und langsam. LinkedIn-InMails werden ignoriert. Social Recruiting macht Ihre Firma sichtbar, ohne dass sich der Kandidat aktiv outen muss. Sie sehen Ihren Betrieb ruhig über Wochen in ihrem Feed und melden sich, wenn sie reif für den Wechsel sind.',
    voice: {
      tone: 'Sie-Form. Ruhig, professionell, auf Augenhöhe. Keine Superlative, keine Emojis, kein Verkaufston.',
      visuals: 'Hochwertige Aufnahmen. Authentische Statements von bestehenden Kadern. Office, OP, Baustelle in cinematischer Qualität. Keine Action-Schnitte, keine Stock-Materialien.',
      noGo: ['"Dynamisches Unternehmen"', '"Hands-on Mentalität"', 'Emojis im Ad-Text', 'Kurze Schnitte im Reel-Stil'],
    },
    benefits: [
      'Oberdurchschnittliche Vergütung plus Bonus',
      'Firmenwagen oder Mobilitätsbudget',
      'Beteiligung am Unternehmenserfolg',
      'Mandat mit echter Entscheidungsgewalt',
      'Moderne IT und Tools',
      'Weiterbildungsbudget ab CHF 10\'000 pro Jahr',
      'Flexible Arbeitszeit, Home-Office-Option',
    ],
    numbers: {
      cpa: 'Ø CHF 95.00 pro Bewerbung. Premium-Segment. Die Ersparnis pro Besetzung liegt meist über CHF 30\'000 gegenüber einem Headhunter.',
      timeline: 'Erste Bewerbungen 1 bis 2 Wochen nach Livegang. Entscheidungsphase oft 4 bis 8 Wochen. Ads laufen dementsprechend länger.',
      budget: 'CHF 1\'500 bis 3\'500 Mediabudget pro Stelle und Monat. Höhere Frequenz und längere Laufzeit nötig.',
    },
  },
};

// ---- Playbook Modal ----
const PlaybookModal = ({ slug, onClose, onCTA, onScrollMethod }) => {
  useEffect(() => {
    if (!slug) return;
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', onKey);
    document.body.style.overflow = 'hidden';
    return () => { document.removeEventListener('keydown', onKey); document.body.style.overflow = ''; };
  }, [slug, onClose]);
  if (!slug) return null;
  const p = PLAYBOOKS[slug];
  if (!p) return null;
  return (
    <div className="pb-backdrop" onClick={onClose}>
      <div className="pb-modal" onClick={e => e.stopPropagation()}>
        <button className="pb-close" onClick={onClose} aria-label="Schliessen"><Icon name="close" size={22}/></button>

        <div className="pb-hero">
          <span className="section-eyebrow">{p.eyebrow}</span>
          <h2>{p.title}</h2>
          <p className="pb-sub">{p.oneLiner}</p>
          <div className="pb-stat">
            <div className="pb-stat-big">CHF {p.cpa.value.toFixed(2)}</div>
            <div className="pb-stat-unit">{p.cpa.label}</div>
          </div>
        </div>

        <section className="pb-section">
          <h3>Kandidatenprofil</h3>
          <div className="pb-profile">
            <div><span className="pb-k">Typische Rollen</span><span className="pb-v">{p.profile.roles}</span></div>
            <div><span className="pb-k">Alter</span><span className="pb-v">{p.profile.age}</span></div>
            <div><span className="pb-k">Geschlecht (Tendenz)</span><span className="pb-v">{p.profile.gender}</span></div>
            <div><span className="pb-k">Online-Verhalten</span><span className="pb-v">{p.profile.online}</span></div>
          </div>
        </section>

        <div className="pb-grid-2">
          <section className="pb-section">
            <h3>Was sie wirklich wollen</h3>
            <ul className="pb-list pb-list-check">
              {p.wants.map((w, i) => <li key={i}>{w}</li>)}
            </ul>
          </section>
          <section className="pb-section">
            <h3>Was sie nervt</h3>
            <ul className="pb-list pb-list-cross">
              {p.pains.map((w, i) => <li key={i}>{w}</li>)}
            </ul>
          </section>
        </div>

        <section className="pb-section pb-section-accent">
          <h3>Warum klassisches Recruiting hier scheitert</h3>
          <p className="pb-why">{p.whyFail}</p>
        </section>

        <section className="pb-section">
          <h3>Sprache und Bildwelt</h3>
          <div className="pb-voice">
            <div><span className="pb-k">Tonalität</span><span className="pb-v">{p.voice.tone}</span></div>
            <div><span className="pb-k">Bildsprache</span><span className="pb-v">{p.voice.visuals}</span></div>
            <div>
              <span className="pb-k">Was nicht geht</span>
              <ul className="pb-list pb-list-cross pb-list-tight">
                {p.voice.noGo.map((g, i) => <li key={i}>{g}</li>)}
              </ul>
            </div>
          </div>
        </section>

        <section className="pb-section">
          <h3>Benefits, die in dieser Branche ziehen</h3>
          <ul className="pb-list pb-list-check pb-list-cols">
            {p.benefits.map((b, i) => <li key={i}>{b}</li>)}
          </ul>
        </section>

        <section className="pb-section">
          <h3>Realistische Kennzahlen</h3>
          <div className="pb-numbers">
            <div><span className="pb-k">Kosten pro Bewerbung</span><span className="pb-v">{p.numbers.cpa}</span></div>
            <div><span className="pb-k">Zeit bis zur ersten Bewerbung</span><span className="pb-v">{p.numbers.timeline}</span></div>
            <div><span className="pb-k">Empfohlenes Mediabudget</span><span className="pb-v">{p.numbers.budget}</span></div>
          </div>
        </section>

        <section className="pb-section pb-process">
          <div className="pb-process-inner">
            <h3>Der Ablauf ist bei jeder Branche gleich.</h3>
            <p>Briefing, Onboarding-Call, Creatives und Freigabe, Livegang, Reporting. Nur Inhalte, Hooks und Bildsprache passen wir an Ihre Branche an.</p>
            <button className="btn btn-ghost" onClick={onScrollMethod}>Zum Vorgehen <Icon name="arrow" size={16}/></button>
          </div>
        </section>

        <section className="pb-section pb-cta">
          <h3>Audit für {p.title}</h3>
          <p>15 Minuten, kostenlos. Sie bekommen eine konkrete Einschätzung für Ihre offenen Stellen. Ohne Verkaufsdruck.</p>
          <button className="btn btn-primary btn-xl" onClick={() => onCTA(p.brancheLabel)}>
            Gratis Audit starten <Icon name="arrow" size={18}/>
          </button>
        </section>
      </div>
    </div>
  );
};

// ---- Audit Modal ----
const WEBHOOK_URL = 'https://hook.eu2.make.com/me3wonbvcjdlcwi2nrig25totztkgkd8';

const AuditModal = ({ open, onClose, initialBranche = '' }) => {
  const [step, setStep] = useState(0);
  const [d, setD] = useState({ name:'', firma:'', branche:'', stellen:'', email:'', telefon:'', position:'' });
  useEffect(() => {
    if (open && initialBranche) setD(prev => ({ ...prev, branche: initialBranche }));
  }, [open, initialBranche]);
  if (!open) return null;
  const done = step === 1;
  const update = (k,v) => setD({...d, [k]:v});
  const valid = d.name && d.firma && d.branche && d.stellen && d.email && d.telefon;
  const handleClose = () => { setStep(0); setD({ name:'', firma:'', branche:'', stellen:'', email:'', telefon:'', position:'' }); onClose(); };
  const handleSubmit = async () => {
    await fetch(WEBHOOK_URL, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(d) });
    setStep(1);
  };
  return (
    <div style={{position:'fixed', inset:0, background:'rgba(10,10,10,0.6)', zIndex:200, display:'flex', alignItems:'center', justifyContent:'center', backdropFilter:'blur(8px)', padding:20}}
         onClick={handleClose}>
      <div onClick={e => e.stopPropagation()} style={{width:'min(560px, 100%)', background:'#fff', borderRadius:24, padding:36, boxShadow:'0 40px 80px rgba(0,0,0,0.35)', maxHeight:'90vh', overflow:'auto'}}>
        {!done ? (
          <>
            <div style={{display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom:8}}>
              <span className="section-eyebrow" style={{margin:0}}>Gratis Recruiting-Audit</span>
              <button onClick={handleClose} style={{background:'transparent', border:0, cursor:'pointer', color:'#7D7D7D'}}><Icon name="close" size={20}/></button>
            </div>
            <h3 style={{fontFamily:'var(--font-display)', fontWeight:800, fontSize:32, margin:'8px 0 6px', letterSpacing:'-0.025em', lineHeight:1.1}}>Kostenlos, unverbindlich, konkret.</h3>
            <p style={{color:'#7D7D7D', fontSize:14, margin:'0 0 24px', lineHeight:1.5}}>In 15 Minuten sehen Sie, wo Ihr Recruiting Geld verbrennt. Und mit welcher Kampagne Sie Ihre offene Stelle tatsächlich besetzen.</p>
            <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:12}}>
              <input className="em-input" placeholder="Vor- und Nachname *" value={d.name} onChange={e => update('name', e.target.value)}/>
              <input className="em-input" placeholder="Firmenname *" value={d.firma} onChange={e => update('firma', e.target.value)}/>
              <select className="em-input" value={d.branche} onChange={e => update('branche', e.target.value)}>
                <option value="">Branche *</option>
                <option>Handwerk &amp; Bau</option>
                <option>Pflege &amp; Gesundheit</option>
                <option>Gastronomie</option>
                <option>Logistik &amp; Transport</option>
                <option>Kader &amp; Spezialisten</option>
                <option>Andere</option>
              </select>
              <input className="em-input" placeholder="Offene Stellen *" type="number" value={d.stellen} onChange={e => update('stellen', e.target.value)}/>
              <input className="em-input" placeholder="Geschäfts-E-Mail *" type="email" value={d.email} onChange={e => update('email', e.target.value)}/>
              <input className="em-input" placeholder="Telefon *" type="tel" value={d.telefon} onChange={e => update('telefon', e.target.value)}/>
              <input className="em-input" placeholder="Wichtigste Position (optional)" style={{gridColumn:'1/-1'}} value={d.position} onChange={e => update('position', e.target.value)}/>
            </div>
            <button className="btn btn-primary btn-xl" style={{marginTop:20, width:'100%', justifyContent:'center', opacity: valid ? 1 : 0.45, cursor: valid ? 'pointer' : 'not-allowed'}} onClick={handleSubmit} disabled={!valid}>
              Audit anfordern (kostet 0.–) <Icon name="arrow" size={18}/>
            </button>
            <p style={{fontSize:12, color:'#7D7D7D', textAlign:'center', margin:'14px 0 0'}}>Antwort innert 24h. Kein Abo, keine Kreditkarte.</p>
          </>
        ) : (
          <div style={{textAlign:'center'}}>
            <div style={{width:72, height:72, borderRadius:999, background:'linear-gradient(135deg,#00C6FF,#1F6FEB)', color:'#fff', display:'inline-flex', alignItems:'center', justifyContent:'center', marginBottom:20, boxShadow:'0 10px 30px rgba(31,111,235,0.35)'}}>
              <Icon name="check" size={32}/>
            </div>
            <h3 style={{fontFamily:'var(--font-display)', fontWeight:800, fontSize:32, margin:'0 0 8px', letterSpacing:'-0.025em'}}>Anfrage gesendet.</h3>
            <p style={{color:'#4A4A4A', fontSize:16, margin:'0 0 24px', lineHeight:1.5}}>Wir melden uns innerhalb 24 Stunden bei <strong>{d.email || 'Ihnen'}</strong> mit einem Einladungslink zum Audit-Call.</p>
            <button className="btn btn-primary btn-lg" onClick={handleClose}>Schliessen</button>
          </div>
        )}
      </div>
    </div>
  );
};

// ---- Booking Modal (Calendly placeholder) ----
const BookingModal = ({ open, onClose }) => {
  if (!open) return null;
  return (
    <div style={{position:'fixed', inset:0, background:'rgba(10,10,10,0.6)', zIndex:200, display:'flex', alignItems:'center', justifyContent:'center', backdropFilter:'blur(8px)', padding:20}}
         onClick={onClose}>
      <div onClick={e => e.stopPropagation()} style={{width:'min(720px, 100%)', background:'#fff', borderRadius:24, padding:36, boxShadow:'0 40px 80px rgba(0,0,0,0.35)'}}>
        <div style={{display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom:8}}>
          <span className="section-eyebrow" style={{margin:0}}>Strategiegespräch</span>
          <button onClick={onClose} style={{background:'transparent', border:0, cursor:'pointer', color:'#7D7D7D'}}><Icon name="close" size={20}/></button>
        </div>
        <h3 style={{fontFamily:'var(--font-display)', fontWeight:800, fontSize:32, margin:'8px 0 6px', letterSpacing:'-0.025em', lineHeight:1.1}}>30 Minuten direkt mit Mattia.</h3>
        <p style={{color:'#7D7D7D', fontSize:14, margin:'0 0 20px', lineHeight:1.5}}>Kein Setter, kein Verkaufsdruck. Sie bekommen eine konkrete Einschätzung. Mit oder ohne Zusammenarbeit.</p>
        <div style={{display:'grid', gridTemplateColumns:'1fr 1fr', gap:12, marginBottom:20}}>
          {['Mo 28.04', 'Di 29.04', 'Mi 30.04', 'Do 01.05'].map(d => (
            <div key={d} style={{border:'1px solid #E6E8EC', borderRadius:12, padding:14}}>
              <div style={{fontWeight:700, fontSize:14, marginBottom:8}}>{d}</div>
              <div style={{display:'flex', gap:6, flexWrap:'wrap'}}>
                {['09:00','10:30','14:00','15:30'].map(t => (
                  <button key={t} style={{padding:'6px 10px', fontSize:12, fontWeight:600, border:'1px solid #E6E8EC', borderRadius:8, background:'#fff', cursor:'pointer'}}
                    onMouseOver={e => { e.currentTarget.style.background='#1A1A1A'; e.currentTarget.style.color='#fff'; }}
                    onMouseOut={e => { e.currentTarget.style.background='#fff'; e.currentTarget.style.color='inherit'; }}>
                    {t}
                  </button>
                ))}
              </div>
            </div>
          ))}
        </div>
        <p style={{fontSize:12, color:'#7D7D7D', margin:0, textAlign:'center'}}>Calendly-Integration: hier wird der iFrame eingebettet.</p>
      </div>
    </div>
  );
};

// ---- Legal Modals ----
const LegalModal = ({ open, onClose, eyebrow, title, children }) => {
  if (!open) return null;
  return (
    <div style={{position:'fixed', inset:0, background:'rgba(10,10,10,0.6)', zIndex:200, display:'flex', alignItems:'center', justifyContent:'center', backdropFilter:'blur(8px)', padding:20}}
         onClick={onClose}>
      <div onClick={e => e.stopPropagation()} style={{width:'min(760px, 100%)', maxHeight:'85vh', overflowY:'auto', background:'#fff', borderRadius:24, padding:36, boxShadow:'0 40px 80px rgba(0,0,0,0.35)'}}>
        <div style={{display:'flex', justifyContent:'space-between', alignItems:'flex-start', marginBottom:8, position:'sticky', top:-36, background:'#fff', paddingTop:36, marginTop:-36, paddingBottom:8, zIndex:1}}>
          <span className="section-eyebrow" style={{margin:0}}>{eyebrow}</span>
          <button onClick={onClose} style={{background:'transparent', border:0, cursor:'pointer', color:'#7D7D7D'}}><Icon name="close" size={20}/></button>
        </div>
        <h3 style={{fontFamily:'var(--font-display)', fontWeight:800, fontSize:28, margin:'4px 0 18px', letterSpacing:'-0.025em', lineHeight:1.15}}>{title}</h3>
        <div style={{fontSize:14, lineHeight:1.65, color:'#1A1A1A'}}>{children}</div>
      </div>
    </div>
  );
};

const ImpressumModal = ({ open, onClose }) => (
  <LegalModal open={open} onClose={onClose} eyebrow="Rechtliches" title="Impressum">
    <p style={{margin:'0 0 16px'}}><strong>Explicit Marketing GmbH</strong><br/>Gheidmattweg 15<br/>4600 Olten<br/>Schweiz</p>
    <p style={{margin:'0 0 16px'}}><strong>Geschäftsführung</strong><br/>Mattia Ribaudo</p>
    <p style={{margin:'0 0 16px'}}><strong>Kontakt</strong><br/>Telefon: +41 76 596 53 55<br/>E-Mail: info@explicit-marketing.com</p>
    <p style={{margin:'0 0 16px'}}><strong>Handelsregister</strong><br/>UID: CHE-158.887.396</p>
  </LegalModal>
);

const DatenschutzModal = ({ open, onClose }) => (
  <LegalModal open={open} onClose={onClose} eyebrow="Rechtliches" title="Datenschutzerklärung">
    <h4 style={{fontWeight:700, fontSize:15, margin:'0 0 6px'}}>1. Allgemeine Informationen</h4>
    <p style={{margin:'0 0 18px'}}>Die Explicit Marketing GmbH mit Sitz in Gheidmattweg 15, 4600 Olten, Schweiz betreibt diese Website. Das Unternehmen konzentriert sich auf performancebasiertes Online-Marketing und Social-Media-Kampagnen, insbesondere im Bereich Recruiting.</p>

    <h4 style={{fontWeight:700, fontSize:15, margin:'0 0 6px'}}>2. Erfassung und Verarbeitung personenbezogener Daten</h4>
    <ul style={{margin:'0 0 18px', paddingLeft:20}}>
      <li>Verarbeitung von aktiv übermittelten Daten durch externe Kontakt- oder Terminbuchungstools</li>
      <li>Erfasste Informationen: Name, E-Mail-Adresse, Telefonnummer und weitere Angaben</li>
      <li>Datenverarbeitung erfolgt gemäss den Bestimmungen des jeweiligen externen Anbieters</li>
      <li>Technische Zugriffsdaten (IP-Adresse, Browsertyp, Zugriffszeitpunkt) für Betrieb und Sicherheit</li>
    </ul>

    <h4 style={{fontWeight:700, fontSize:15, margin:'0 0 6px'}}>3. Zweck der Datenverarbeitung</h4>
    <ul style={{margin:'0 0 18px', paddingLeft:20}}>
      <li>Bearbeitung von Anfragen und Kontaktaufnahmen</li>
      <li>Organisation und Durchführung von Terminen</li>
      <li>Betrieb, Sicherheit und Optimierung der Website</li>
      <li>Kommunikation im geschäftlichen Kontext</li>
    </ul>
    <p style={{margin:'0 0 18px'}}>Eine weitergehende Nutzung zu Marketing- oder Trackingzwecken erfolgt derzeit nicht.</p>

    <h4 style={{fontWeight:700, fontSize:15, margin:'0 0 6px'}}>4. Einsatz von Analyse- und Tracking-Technologien</h4>
    <p style={{margin:'0 0 18px'}}>Aktuell setzen wir auf dieser Website keine Tracking- oder Analyse-Tools (wie z. B. Google Analytics oder Meta Pixel) ein. Bei zukünftigem Einsatz erfolgt eine Anpassung dieser Datenschutzerklärung sowie eine Cookie-Banner-Implementierung.</p>

    <h4 style={{fontWeight:700, fontSize:15, margin:'0 0 6px'}}>5. Weitergabe von Daten</h4>
    <p style={{margin:'0 0 8px'}}>Eine Weitergabe personenbezogener Daten an Dritte erfolgt grundsätzlich nicht, ausser:</p>
    <ul style={{margin:'0 0 18px', paddingLeft:20}}>
      <li>Nutzung externer Kontakt- oder Terminbuchungstools erforderlich</li>
      <li>Gesetzliche Verpflichtungen</li>
      <li>Ausdrückliche Einwilligung</li>
    </ul>

    <h4 style={{fontWeight:700, fontSize:15, margin:'0 0 6px'}}>6. Cookies</h4>
    <p style={{margin:'0 0 18px'}}>Unsere Website verwendet derzeit nur technisch notwendige Cookies, soweit diese für den Betrieb der Website erforderlich sind. Zukünftige Änderungen werden mitgeteilt.</p>

    <h4 style={{fontWeight:700, fontSize:15, margin:'0 0 6px'}}>7. Rechte der betroffenen Personen</h4>
    <ul style={{margin:'0 0 18px', paddingLeft:20}}>
      <li>Recht auf Auskunft</li>
      <li>Recht auf Berichtigung</li>
      <li>Recht auf Löschung</li>
      <li>Recht auf Einschränkung der Verarbeitung</li>
      <li>Recht auf Datenübertragbarkeit</li>
      <li>Recht auf Widerspruch</li>
    </ul>

    <h4 style={{fontWeight:700, fontSize:15, margin:'0 0 6px'}}>8. Kontakt</h4>
    <p style={{margin:'0 0 8px'}}><strong>Verantwortlich für die Datenverarbeitung:</strong></p>
    <p style={{margin:'0 0 18px'}}>Explicit Marketing GmbH<br/>Gheidmattweg 15<br/>4600 Olten<br/>Schweiz<br/>E-Mail: info@explicit-marketing.com</p>

    <p style={{margin:0, fontSize:12, color:'#7D7D7D'}}>Die Datenschutzerklärung kann angepasst werden; die aktuelle Version auf der Website gilt.</p>
  </LegalModal>
);

const AGBModal = ({ open, onClose }) => {
  const h = {fontWeight:700, fontSize:15, margin:'0 0 6px'};
  const p = {margin:'0 0 14px'};
  const sub = {margin:'0 0 8px', fontWeight:600};
  const ul = {margin:'0 0 14px', paddingLeft:20};
  return (
    <LegalModal open={open} onClose={onClose} eyebrow="Rechtliches" title="Allgemeine Geschäftsbedingungen">
      <p style={{...p, fontSize:13, color:'#7D7D7D'}}>Stand: April 2026 · Explicit Marketing GmbH, Gheidmattweg 15, 4600 Olten, Schweiz</p>

      <h4 style={h}>§1 Geltungsbereich</h4>
      <p style={p}>Diese Allgemeinen Geschäftsbedingungen (nachfolgend „AGB") gelten für alle Verträge zwischen der Explicit Marketing GmbH (nachfolgend „Auftragnehmer") und ihren Kunden (nachfolgend „Auftraggeber") über Social-Recruiting-Kampagnen, Content Creation und damit verbundene Dienstleistungen. Abweichende oder ergänzende Bedingungen des Auftraggebers gelten nur, wenn sie vom Auftragnehmer schriftlich anerkannt wurden.</p>

      <h4 style={h}>§2 Vertragsmodelle und Vertragsschluss</h4>
      <p style={p}>Der Auftragnehmer bietet seine Leistungen in zwei Modellen an:</p>
      <ul style={ul}>
        <li><strong>Abo-Modell:</strong> Wiederkehrende monatliche Leistungen mit einer Mindestlaufzeit von 3 Monaten, danach unbefristet mit monatlicher Kündigungsmöglichkeit gemäss §7.</li>
        <li><strong>Einmalkampagne:</strong> Einmaliger, projektbezogener Auftrag mit definiertem Start- und Endpunkt.</li>
      </ul>
      <p style={p}>Der Vertrag kommt durch eine vom Auftraggeber unterzeichnete oder per E-Mail bestätigte Auftragsbestätigung des Auftragnehmers zustande. Mündliche Nebenabreden bedürfen zu ihrer Gültigkeit der schriftlichen Bestätigung.</p>

      <h4 style={h}>§3 Leistungen</h4>
      <p style={p}>Der konkrete Leistungsumfang ergibt sich aus der jeweiligen Auftragsbestätigung bzw. dem Einzelvertrag. Der Auftragnehmer schuldet die fachgerechte Erbringung der vereinbarten Leistungen (Werkleistungspflicht), nicht jedoch einen bestimmten wirtschaftlichen Erfolg wie eine festgelegte Anzahl Bewerbungen oder Stellenbesetzungen, sofern dies nicht ausdrücklich schriftlich als Garantie zugesichert wurde.</p>

      <h4 style={h}>§4 Mitwirkungspflichten des Auftraggebers</h4>
      <p style={p}>Der Auftraggeber stellt dem Auftragnehmer alle für die Leistungserbringung erforderlichen Informationen und Materialien rechtzeitig und vollständig zur Verfügung, insbesondere:</p>
      <ul style={ul}>
        <li>Stellenbeschreibungen, Anforderungsprofile und Lohnangaben</li>
        <li>Logo, Bildmaterial, Markenrichtlinien und Texte</li>
        <li>Zugang zu relevanten Kanälen und Werbekonten</li>
        <li>Freigaben für Creatives und Anzeigen innert 5 Arbeitstagen</li>
      </ul>
      <p style={p}>Verzögerungen aufgrund unterlassener oder verspäteter Mitwirkung verlängern vereinbarte Fristen entsprechend und gehen nicht zulasten des Auftragnehmers.</p>

      <h4 style={h}>§5 Vergütung und Zahlungsbedingungen</h4>
      <p style={p}>Die Vergütung richtet sich nach der Auftragsbestätigung und versteht sich exklusive der gesetzlichen Mehrwertsteuer. Sämtliche Honorare sind im Voraus zu leisten und innerhalb von 30 Tagen ab Rechnungsstellung ohne Abzug zur Zahlung fällig. Bei Zahlungsverzug ist der Auftragnehmer berechtigt, Verzugszinsen in Höhe von 5% p.a. gemäss Art. 104 OR zu verrechnen sowie die Leistungserbringung bis zum Zahlungseingang einzustellen.</p>

      <h4 style={h}>§6 Mediabudget</h4>
      <p style={p}>Das Mediabudget für Werbeplattformen (insbesondere Meta/Facebook/Instagram) ist nicht im Honorar enthalten. Der Auftraggeber überweist das vereinbarte Mediabudget vorab an den Auftragnehmer, der dieses treuhänderisch verwaltet und für die vereinbarten Kampagnen einsetzt. Nicht verbrauchte Beträge werden auf den Folgemonat übertragen oder bei Vertragsende auf Wunsch des Auftraggebers zurückerstattet. Der Auftragnehmer haftet nicht für Massnahmen der Plattformbetreiber (vgl. §10).</p>

      <h4 style={h}>§7 Laufzeit und Kündigung</h4>
      <p style={sub}>(1) Abo-Modell:</p>
      <p style={p}>Die Mindestlaufzeit beträgt 3 Monate ab Vertragsbeginn. Danach verlängert sich der Vertrag auf unbestimmte Zeit und kann von beiden Seiten mit einer Frist von 30 Tagen jeweils zum Ende eines Kalendermonats schriftlich gekündigt werden.</p>
      <p style={sub}>(2) Einmalkampagne:</p>
      <p style={p}>Eine Kündigung nach Beginn der Setup-Arbeiten (Briefing-Call, Creative-Produktion oder Kampagnenaufbau) ist ausgeschlossen. Vor Setup-Start kann der Auftraggeber den Auftrag widerrufen; in diesem Fall wird das geleistete Honorar abzüglich einer Bearbeitungsgebühr von CHF 250 zurückerstattet.</p>
      <p style={sub}>(3) Ausserordentliche Kündigung:</p>
      <p style={p}>Das Recht zur ausserordentlichen Kündigung aus wichtigem Grund bleibt für beide Parteien unberührt.</p>

      <h4 style={h}>§8 Bewerber- und Personendaten</h4>
      <p style={p}>Der Auftragnehmer verarbeitet im Rahmen der Recruiting-Kampagnen personenbezogene Daten von Bewerbenden im Auftrag des Auftraggebers (Auftragsverarbeitung gemäss Art. 9 revDSG). Die Daten werden derzeit in einer für den Auftraggeber freigegebenen Google-Tabelle bzw. künftig in der hauseigenen Recruiting-Plattform des Auftragnehmers verwaltet und laufend aktualisiert. Die Aufbewahrung erfolgt maximal bis zur Besetzung der Stelle zuzüglich 30 Tagen, sofern keine längere gesetzliche Aufbewahrungspflicht besteht. Ein separater Auftragsverarbeitungsvertrag (AVV) wird auf Verlangen des Auftraggebers abgeschlossen und ist bei Bedarf integrierender Bestandteil dieses Vertrages.</p>

      <h4 style={h}>§9 Nutzungsrechte an erstellten Inhalten</h4>
      <p style={p}>Der Auftragnehmer räumt dem Auftraggeber an allen im Rahmen des Auftrags erstellten Inhalten (insbesondere Reels, Videos, Captions, Bilder, Ad-Creatives) ein nicht-exklusives, zeitlich und örtlich unbeschränktes Nutzungsrecht für eigene unternehmerische Zwecke ein. Das Urheberrecht und sämtliche darüber hinausgehenden Verwertungsrechte verbleiben beim Auftragnehmer. Der Auftragnehmer ist berechtigt, die erstellten Inhalte zu Referenz-, Marketing- und Case-Study-Zwecken zu verwenden, sofern dabei keine vertraulichen Informationen des Auftraggebers offengelegt werden.</p>

      <h4 style={h}>§10 Haftung</h4>
      <p style={sub}>(1)</p>
      <p style={p}>Der Auftragnehmer haftet unbeschränkt</p>
      <ul style={ul}>
        <li>bei Vorsatz oder grober Fahrlässigkeit,</li>
        <li>bei Verletzung von Leben, Körper oder Gesundheit,</li>
        <li>im Umfang einer vom Auftragnehmer ausdrücklich übernommenen Garantie.</li>
      </ul>
      <p style={sub}>(2)</p>
      <p style={p}>Bei leicht fahrlässiger Verletzung einer Pflicht, die wesentlich für die Erreichung des Vertragszwecks ist, ist die Haftung des Auftragnehmers der Höhe nach begrenzt auf den Schaden, der nach der Art des fraglichen Geschäfts vorhersehbar und typisch ist.</p>
      <p style={sub}>(3)</p>
      <p style={p}>Eine weitergehende Haftung des Auftragnehmers besteht nicht.</p>
      <p style={sub}>(4)</p>
      <p style={p}>Die vorstehende Haftungsbeschränkung gilt auch für die persönliche Haftung der Mitarbeitenden, Vertretenden und Organe des Auftragnehmers.</p>
      <p style={sub}>(5)</p>
      <p style={p}>Der Auftragnehmer haftet nicht für Massnahmen von Plattformbetreibern (z. B. Sperrung, Einschränkung oder Ablehnung von Werbeanzeigen oder Werbekonten), sofern diese nicht auf vorsätzlichem oder grob fahrlässigem Verhalten des Auftragnehmers beruhen. Ebenso haftet der Auftragnehmer nicht für Rechtsverletzungen, die auf vom Auftraggeber bereitgestellten Inhalten, Informationen oder Weisungen beruhen.</p>

      <h4 style={h}>§11 Geheimhaltung</h4>
      <p style={p}>Beide Parteien verpflichten sich, alle im Rahmen der Zusammenarbeit erlangten vertraulichen Informationen der jeweils anderen Partei strikt vertraulich zu behandeln und nicht an Dritte weiterzugeben. Diese Verpflichtung gilt auch nach Beendigung des Vertragsverhältnisses für eine Dauer von 3 Jahren fort. Ausgenommen sind Informationen, deren Offenlegung gesetzlich oder behördlich angeordnet ist.</p>

      <h4 style={h}>§12 Schlussbestimmungen</h4>
      <p style={p}>Es gilt ausschliesslich Schweizer Recht unter Ausschluss der Kollisionsnormen und des UN-Kaufrechts. Ausschliesslicher Gerichtsstand für alle Streitigkeiten aus oder im Zusammenhang mit diesem Vertrag ist Olten, Kanton Solothurn. Sollten einzelne Bestimmungen dieser AGB ganz oder teilweise unwirksam sein oder werden, bleibt die Wirksamkeit der übrigen Bestimmungen unberührt. An die Stelle der unwirksamen Bestimmung tritt eine Regelung, die dem wirtschaftlichen Zweck der unwirksamen Bestimmung am nächsten kommt. Änderungen und Ergänzungen dieser AGB bedürfen der Schriftform.</p>

      <p style={{margin:0, fontSize:12, color:'#7D7D7D'}}>Diese AGB können angepasst werden; die jeweils zum Zeitpunkt des Vertragsschlusses geltende Fassung ist verbindlich.</p>
    </LegalModal>
  );
};

Object.assign(window, { Cursor, NavBar, Hero, Industries, Statement, KPI, Split, Method, Cases, Why, ROI, FAQ, CinematicFooter, AuditModal, BookingModal, PlaybookModal, ImpressumModal, DatenschutzModal, AGBModal, useReveal, Icon });
