// Extras: CountUp, ScrollSpy, BauakteMockup, ChatDemo, RoiCalc, LogoStrip, Testimonials, FAQ, Cursor
const { useState, useEffect, useRef, useMemo } = React;

// ===== utility hooks =====
function useInView(ref, opts = { rootMargin: '-10% 0px -10% 0px', threshold: 0 }) {
  const [seen, setSeen] = useState(false);
  useEffect(() => {
    if (!ref.current || seen) return;
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => { if (e.isIntersecting) { setSeen(true); io.disconnect(); } });
    }, opts);
    io.observe(ref.current);
    return () => io.disconnect();
  }, [ref, seen]);
  return seen;
}

function CountUp({ to, dur = 1400, prefix = '', suffix = '', decimals = 0 }) {
  const ref = useRef(null);
  const seen = useInView(ref);
  const [v, setV] = useState(0);
  const cur = useRef(0);
  useEffect(() => {
    if (!seen) return;
    const start = performance.now();
    // continue from the currently shown value so live updates don't restart at 0
    const from = cur.current;
    let raf;
    const tick = (t) => {
      const p = Math.min(1, (t - start) / dur);
      const eased = 1 - Math.pow(1 - p, 3);
      cur.current = from + (to - from) * eased;
      setV(cur.current);
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [seen, to, dur]);
  const fmt = v.toLocaleString('de-DE', { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
  return <span ref={ref}>{prefix}{fmt}{suffix}</span>;
}

// ===== Section Indicator (left rail TOC) =====
function SectionIndicator({ sections }) {
  const [active, setActive] = useState(sections[0]?.id);
  useEffect(() => {
    const io = new IntersectionObserver((entries) => {
      entries.forEach((e) => {
        if (e.isIntersecting) {
          setActive(e.target.id);
          // toggle dark-section class on body so indicator inverts
          const isDark = e.target.dataset.dark === '1';
          document.body.classList.toggle('ai-section-active', isDark);
        }
      });
    }, { rootMargin: '-40% 0px -55% 0px', threshold: 0 });
    sections.forEach((s) => {
      const el = document.getElementById(s.id);
      if (el) io.observe(el);
    });
    return () => io.disconnect();
  }, []);
  return (
    <div className="sec-indicator">
      {sections.map((s) => (
        <a key={s.id} href={'#' + s.id} data-active={active === s.id ? '1' : '0'}>
          <span className="tick"></span>
          <span className="lbl">{s.n} · {s.label}</span>
        </a>
      ))}
    </div>
  );
}

// ===== Bauakte Mockup =====
function BauakteMockup() {
  const [active, setActive] = useState(2);
  const items = ['Übersicht', 'Aufmaß', 'Fotodoku', 'Stunden', 'Material', 'Nachträge'];
  const tasks = [
    { name: 'Estrich EG verlegen', meta: 'KW 21 · 3 MA', status: 'ok', tag: 'erledigt' },
    { name: 'Trockenbau OG · Wand W12', meta: 'KW 22 · Müller', status: 'live', tag: 'live' },
    { name: 'Fliesen Bad 2.OG', meta: 'KW 23 · 2 MA', status: 'warn', tag: 'verzögert' },
    { name: 'Elektro Rohbau · Sektor B', meta: 'KW 23 · BV-Strom', status: 'ok', tag: 'geplant' }
  ];
  return (
    <div className="bauakte" id="bauakte-mockup">
      <div className="bk-top">
        <div className="dots"><i></i><i></i><i></i></div>
        <div>BV 042 / WOHNHAUS MÜLLER · OS</div>
        <div>● LIVE · {new Date().toLocaleDateString('de-DE', { day:'2-digit', month:'2-digit' })}</div>
      </div>
      <div className="bk-body">
        <div className="bk-side">
          {items.map((it, i) => (
            <div className={'it' + (i === active ? ' on' : '')} key={i} onClick={() => setActive(i)} style={{cursor:'pointer'}}>
              <span className="n">0{i+1}</span>{it}
            </div>
          ))}
        </div>
        <div className="bk-main">
          {tasks.map((t, i) => (
            <div className={'bk-row' + (t.status === 'live' ? ' live' : '')} key={i}>
              <div className="thumb"></div>
              <div>
                <div className="name">{t.name}</div>
                <div className="meta">{t.meta}</div>
              </div>
              <div className={'pill-s ' + t.status}>{t.tag}</div>
            </div>
          ))}
        </div>
      </div>
      <div className="bk-bottom">
        <div>BAUAKTE v2 / KI-PFLEGE: aktiv</div>
        <div>letzte sync · vor 2 min</div>
      </div>
    </div>
  );
}

// ===== Chat Demo =====
const CHAT_RESPONSES = {
  'Wie viele Stunden auf BV Müller diesen Monat?': {
    text: '264 Stunden im Mai 2026. Davon entfallen 142 h auf den Trockenbau (Team Klaus), 88 h auf Elektro und 34 h auf Aufräumarbeiten. Trend: +12 h gegenüber April – aktuell 4 h über Plan.',
    src: 'STUNDEN/2026-05.xlsx · 18 Einträge'
  },
  'Welches Material fehlt für Dachstuhl OG?': {
    text: 'Im Lager fehlen 24 Sparren KVH 8×16, 6 m und 2 Pakete Unterspannbahn. Vorschlag: Bestellung bei Holz Schmitt – Lieferung Mi., 20.05. (vor Montagestart Do.).',
    src: 'MATERIAL_LAGER.json · LV §3.4.1'
  },
  'Wer war gestern auf welcher Baustelle?': {
    text: 'BV Müller: Klaus, Tarek, Jens (07:00–16:30). BV Schultheiss: Marco, Andi (07:30–15:00). BV Stadtwerke: Sascha (Halbtag, Abnahme 13:00). Alle Stundenzettel digital eingereicht.',
    src: 'STUNDENZETTEL · 17.05.2026'
  },
  'Gibt es Nachtragspotenzial im LV?': {
    text: 'Ja – 3 mögliche Nachträge identifiziert: (a) Mehrleistung Estrich §2.4 ca. 1.840 €, (b) zusätzliche Wandstärke W12 §3.1.7 ca. 920 €, (c) geänderter Bodenaufbau Bad ca. 1.250 €. Detailprüfung empfohlen.',
    src: 'LV-ANALYSE · KI-Modul · 92 % Confidence'
  }
};

function ChatDemo() {
  const [msgs, setMsgs] = useState([
    { kind: 'ai', text: 'Hi. Ich bin in deine Baustelle eingeloggt. Frag mich irgendwas – Stunden, Material, Termine, LV.', typed: true }
  ]);
  const [typingTxt, setTypingTxt] = useState(null);
  const [input, setInput] = useState('');
  const streamRef = useRef(null);
  useEffect(() => {
    if (streamRef.current) streamRef.current.scrollTop = streamRef.current.scrollHeight;
  }, [msgs, typingTxt]);

  function send(q) {
    if (!q.trim()) return;
    setMsgs((m) => [...m, { kind: 'user', text: q, typed: true }]);
    setInput('');
    // simulate KI typing
    const resp = CHAT_RESPONSES[q] || {
      text: 'Hmm, dafür hätte ich Zugriff auf eure echte Bauakte gebraucht — im Demo-Modus antworte ich nur auf die Beispiele unten. Mach gern einen Termin, dann zeige ich dir das mit deinen Daten.',
      src: 'DEMO MODE'
    };
    setTimeout(() => {
      // type-out effect
      let i = 0;
      const tick = () => {
        i += Math.max(2, Math.round(resp.text.length / 80));
        if (i >= resp.text.length) {
          setTypingTxt(null);
          setMsgs((m) => [...m, { kind: 'ai', text: resp.text, src: resp.src, typed: true }]);
        } else {
          setTypingTxt({ text: resp.text.slice(0, i), src: resp.src });
          setTimeout(tick, 24);
        }
      };
      setTimeout(tick, 380);
    }, 240);
  }

  const suggestions = Object.keys(CHAT_RESPONSES);

  return (
    <div className="chat">
      <div className="chat-window">
        <div className="chat-head">
          <span>BV-042 · CHAT</span>
          <span className="live">LIVE DEMO</span>
        </div>
        <div className="chat-stream" ref={streamRef}>
          {msgs.map((m, i) => (
            <div className={'bubble ' + m.kind} key={i}>
              {m.text}
              {m.src && <span className="src">// {m.src}</span>}
            </div>
          ))}
          {typingTxt && (
            <div className="bubble ai">
              {typingTxt.text}<span className="caret"></span>
              <span className="src">// {typingTxt.src}</span>
            </div>
          )}
        </div>
      </div>
      <div className="chat-suggest">
        {suggestions.map((s) => (
          <button key={s} onClick={() => send(s)}>{s}</button>
        ))}
      </div>
      <form className="chat-input" onSubmit={(e) => { e.preventDefault(); send(input); }}>
        <input
          placeholder="Frag deine Baustelle …"
          value={input}
          onChange={(e) => setInput(e.target.value)}
        />
        <button type="submit">Senden ↗</button>
      </form>
    </div>
  );
}

function DemoSection() {
  return (
    <section className="demo" id="demo">
      <div className="demo-grid">
        <div className="demo-copy">
          <h2 className="sec-title">Chatte mit deiner <span style={{display:'inline-block', lineHeight:'1.3'}}><span className="hi">Baustelle</span></span>.</h2>
          <p className="sec-sub">Jede Information aus Ihrer Bauakte — per natürlicher Sprache.</p>
          <ul className="demo-points">
            <li><b>Schnelle Antworten</b> — auch bei komplexen Fragen.</li>
            <li><b>Kein Suchen, kein Klicken.</b> Einfach in natürlicher Sprache fragen.</li>
            <li><b>Quellen­nachweis bei jeder Antwort.</b> Nachvollziehbar, nicht geraten.</li>
            <li><b>Immer dabei.</b> Auf der Baustelle, im Büro, im Auto — funktioniert überall.</li>
          </ul>
          <p className="demo-hint">→ Klicken Sie rechts auf eine Beispiel­frage.</p>
        </div>
        <div className="demo-right">
          <ChatDemo />
        </div>
      </div>
    </section>
  );
}

// ===== ROI-Rechner: Abo vs. eigene Software =====
// Modell (bewusst simpel):
//   Abo:        Mitarbeiter × 40 €/Monat — läuft weiter, kumuliert sich
//   Eigene SW:  10.000 € einmalig + 100 €/Monat Hosting & Pflege
const COST_FIXED = 10000;
const COST_CARE = 100;
const COST_SEAT = 40;
const COST_YEARS_MIN = 4;                     // Standard-Horizont der Kurve
const COST_YEARS_MAX = 10;                    // so weit wird gedehnt, damit der Break-even reinpasst
const COST_DEFAULTS = { users: 15, month: 24 };

const eur = (n) => Math.round(n).toLocaleString('de-DE') + ' €';

// Geometrie des Diagramms (SVG-Koordinaten, viewBox 0 0 1000 380)
const CH = { w: 1000, y0: 340, y1: 20 };

function costModel({ users, month: rawMonth }) {
  const abo = (m) => users * COST_SEAT * m;
  const own = (m) => COST_FIXED + COST_CARE * m;

  const perMonth = users * COST_SEAT - COST_CARE;   // Ersparnis pro Monat nach Break-even
  const beExact = perMonth > 0 ? COST_FIXED / perMonth : null;

  // Zeitachse: normal vier Jahre. Liegt der Break-even dahinter, wird sie gedehnt,
  // bis er mit etwas Luft hineinpasst — sonst behauptet die Überschrift einen
  // Zeitpunkt, den das Diagramm nicht zeigt. Ab fünf Jahren in Zweierschritten
  // beschriftet, damit die Achse nicht zuläuft.
  let years = COST_YEARS_MIN;
  if (beExact !== null && beExact > COST_YEARS_MIN * 12 && beExact <= COST_YEARS_MAX * 12) {
    years = Math.ceil((beExact * 1.15) / 12);
    if (years > 5) years = Math.ceil(years / 2) * 2;
    years = Math.min(COST_YEARS_MAX, years);
  }
  const N = years * 12;
  const month = Math.min(rawMonth, N);              // Achse kann schrumpfen, Scrubber nicht rausfallen
  const maxY = Math.max(abo(N), own(N)) * 1.05;
  const X = (m) => (m / N) * CH.w;
  const Y = (v) => CH.y0 - (v / maxY) * (CH.y0 - CH.y1);
  const pts = (f) => Array.from({ length: N + 1 }, (_, m) => `${X(m).toFixed(1)},${Y(f(m)).toFixed(1)}`);

  const be = beExact !== null ? Math.ceil(beExact) : null;
  const beIn = beExact !== null && beExact <= N;    // Break-even liegt im gezeigten Zeitraum

  // Fläche zwischen den Kurven ab dem Break-even = die Ersparnis
  let savePath = '';
  if (beIn) {
    const s = Math.floor(beExact);
    const a = [`${X(beExact).toFixed(1)},${Y(abo(beExact)).toFixed(1)}`, ...pts(abo).slice(s + 1)];
    const o = pts(own).slice(s + 1).reverse();
    savePath = 'M' + a.join(' L') + ' L' + o.join(' L') + ' Z';
  }

  const beX = beIn ? X(beExact) : -100;
  const beY = beIn ? Y(abo(beExact)) : -100;
  const sAbo = abo(month);
  const sOwn = own(month);
  const diff = sAbo - sOwn;

  const tickStep = years > 5 ? 2 : 1;
  const ticks = [{ x: 0, label: 'HEUTE' }];
  for (let y = tickStep; y <= years; y += tickStep) {
    ticks.push({ x: X(y * 12), label: 'JAHR ' + y });
  }

  return {
    perMonth, be, beIn, worth: be !== null && be <= 120,
    N, month, ticks,
    aboPath: 'M' + pts(abo).join(' L'),
    ownPath: 'M' + pts(own).join(' L'),
    savePath, beX, beY,
    beLabelX: beX + (beX > 700 ? -14 : 14),
    beLabelY: Math.min(CH.y0 - 8, beY + 48),   // klar unter der Kurve, nicht darauf
    beAnchor: beX > 700 ? 'end' : 'start',
    scrubX: X(month),
    scrubPct: (month / N) * 100 + '%',
    scrubAboY: Y(sAbo),
    scrubOwnY: Y(sOwn),
    scrubAbo: eur(sAbo),
    scrubOwn: eur(sOwn),
    scrubHosting: eur(COST_CARE * month),
    scrubDiff: eur(Math.abs(diff)),
    diffLabel: diff >= 0 ? 'Ihre Ersparnis bis dahin' : 'Noch bis zum Break-even'
  };
}

function RoiCalc({ value, onChange }) {
  const [inner, setInner] = useState(COST_DEFAULTS);
  const v = value || inner;
  const set = onChange || setInner;
  const m = costModel(v);

  return (
    <div className="roi">
      <div className="roi-head">
        <label className="roi-ctrl">
          <span className="roi-q">Mitarbeiter mit Zugang</span>
          <span className="roi-val">{v.users}</span>
          <input
            type="range" min="2" max="60" step="1" value={v.users}
            aria-label="Anzahl Mitarbeiter mit Zugang"
            onChange={(e) => set({ ...v, users: +e.target.value })}
          />
        </label>
        <div className="roi-legend mono">
          <span><i className="sw std"></i>Abo, kumuliert</span>
          <span><i className="sw own"></i>Eigene Software inkl. Hosting &amp; Pflege</span>
        </div>
      </div>

      <div className="roi-chart">
        <svg viewBox="0 0 1000 380" role="img"
             aria-label={`Kostenverlauf über ${m.N / 12} Jahre bei ${v.users} Mitarbeitern. Im Monat ${m.month} kostet das Abo ${m.scrubAbo}, die eigene Software ${m.scrubOwn}.`}>
          <line className="roi-axis" x1="0" y1="340" x2="1000" y2="340" />
          <line className="roi-grid" x1="0" y1="20" x2="1000" y2="20" />
          <line className="roi-grid" x1="0" y1="180" x2="1000" y2="180" />
          <path className="roi-area" d={m.savePath} />
          <path className="roi-line own" d={m.ownPath} />
          <path className="roi-line std" d={m.aboPath} />
          {m.beIn && (
            <g>
              <line className="roi-be-line" x1={m.beX} y1="20" x2={m.beX} y2="340" />
              <circle className="roi-be-pulse" cx={m.beX} cy={m.beY} r="18" />
              <circle className="roi-be-dot" cx={m.beX} cy={m.beY} r="9" />
              <text className="roi-be-label mono" x={m.beLabelX} y={m.beLabelY} textAnchor={m.beAnchor}>
                AB HIER GEHÖRT SIE IHNEN
              </text>
            </g>
          )}
          <line className="roi-scrub-line" x1={m.scrubX} y1="0" x2={m.scrubX} y2="340" />
          <circle className="roi-dot std" cx={m.scrubX} cy={m.scrubAboY} r="7" />
          <circle className="roi-dot own" cx={m.scrubX} cy={m.scrubOwnY} r="7" />
          {m.ticks.map((t, i) => (
            <text className="roi-tick mono" key={t.label} x={t.x} y="368"
                  textAnchor={i === m.ticks.length - 1 ? 'end' : 'start'}>{t.label}</text>
          ))}
        </svg>
        <input
          className="roi-scrub"
          type="range" min="1" max={m.N} step="1" value={m.month}
          aria-label="Monat"
          onChange={(e) => set({ ...v, month: +e.target.value })}
        />
        <div className="roi-scrub-tag mono" style={{ left: m.scrubPct }}>MONAT {m.month}</div>
      </div>

      <div className="roi-stats">
        <div className="roi-stat">
          <span className="k mono">Abo bis Monat {m.month}</span>
          <span className="n">{m.scrubAbo}</span>
        </div>
        <div className="roi-stat">
          <span className="k mono">Eigene Software bis Monat {m.month}</span>
          <span className="n own">{m.scrubOwn}</span>
          <span className="sub mono">{eur(COST_FIXED)} einmalig + {m.scrubHosting} Hosting &amp; Pflege</span>
        </div>
        <div className="roi-stat">
          <span className="k mono">{m.diffLabel}</span>
          <span className="n">{m.scrubDiff}</span>
        </div>
      </div>
    </div>
  );
}

// ===== Vergleich: individuelle Software bei der Agentur vs. bei uns =====
function AgencyCompare() {
  return (
    <div className="agency">
      <div className="agency-rows">
        <span className="agency-lbl">
          Individuelle Software<br /><span className="mute">bei klassischer Agentur</span>
        </span>
        <div className="agency-bar old">
          <span className="amt">30.000 €</span>
          <span className="dur mono">3 MONATE</span>
        </div>

        <span className="agency-lbl">
          Individuelle Software<br /><span className="hi-txt">bei bau-digital.ai</span>
        </span>
        <div className="agency-new">
          <div className="agency-bar new">
            <span className="amt">{eur(COST_FIXED)}</span>
            <span className="dur mono">4 WOCHEN</span>
          </div>
          <div className="agency-lead mono">→ LÄUFT SCHON · 9 WOCHEN VORSPRUNG</div>
        </div>
      </div>

      <div className="agency-scale">
        <span></span>
        <div className="agency-ticks mono">
          <span style={{ gridColumn: 1 }}>HEUTE</span>
          <span style={{ gridColumn: 5 }}>WOCHE 4</span>
          <span style={{ gridColumn: 9 }}>WOCHE 8</span>
          <span style={{ gridColumn: 13 }}>WOCHE 13</span>
        </div>
      </div>
    </div>
  );
}

// ===== Proof: Logos + Testimonials =====
function ProofSection() {
  const logos = [
    { nm: 'Klaus Bau', sub: 'Trockenbau · 18 MA' },
    { nm: <>Schultheiss<em>+</em></>, sub: 'GU · Osnabrück' },
    { nm: 'Holz & Form', sub: 'Zimmerei · 24 MA' },
    { nm: 'Müller Elektro', sub: 'Elektrotechnik · 9 MA' },
    { nm: <>Brand<em>werk</em></>, sub: 'Sanitär · Heizung' },
    { nm: 'PE-Bau', sub: 'Hochbau · 42 MA' }
  ];
  const t = [
    {
      metric: <>−14<span className="u">h / wo</span></>,
      quote: 'Aufmaß und Stundenzettel laufen jetzt komplett digital. Zwei Tage Büroarbeit fallen einfach weg. Das war in vier Wochen aufgesetzt – nicht in vier Monaten.',
      who: 'Klaus Müller', role: 'GF · Klaus Bau GmbH', av: 'KM'
    },
    {
      metric: <><CountUp to={3.2} decimals={1} />×</>,
      quote: 'Die KI findet Nachtragspotenzial im LV, das wir früher übersehen haben. Allein im ersten Quartal hat sich die Software schon dreifach amortisiert.',
      who: 'Sandra Petersen', role: 'Projektleitung · Schultheiss+', av: 'SP'
    },
    {
      metric: <>0<span className="u">€ Lizenz</span></>,
      quote: 'Wir hatten vorher drei Tools im Abo – über 1.800 € pro Monat. Heute eine eigene Lösung, die exakt für unsere Abläufe gebaut ist. Und sie gehört uns.',
      who: 'Tobias Brand', role: 'Inhaber · Brandwerk', av: 'TB'
    }
  ];
  return (
    <section className="proof" id="proof">
      <SectionHead
        title={<>Was unsere Kunden <span className="hi">danach</span> sagen.</>}
      />
      <div className="testimonials">
        {t.map((x, i) => (
          <div className="testi" key={i}>
            <div className="metric">{x.metric}</div>
            <div className="quote">{x.quote}</div>
            <div className="author">
              <div className="av">{x.av}</div>
              <div className="who">{x.who}<span className="r">{x.role}</span></div>
            </div>
          </div>
        ))}
      </div>
      <div className="logo-strip">
        {logos.map((l, i) => (
          <div className="logo" key={i}>
            <div className="nm">{l.nm}</div>
            <div className="sub">{l.sub}</div>
          </div>
        ))}
      </div>
    </section>
  );
}

// ===== FAQ =====
const FAQ_ITEMS = [
  { q: 'Was passiert, wenn die KI Fehler macht?', a: 'Jede generierte Funktion wird automatisiert getestet — und vor Auslieferung von uns geprüft. Bei Fehlern im Live-Betrieb kümmern wir uns zeitnah um einen Fix; das ist Teil der Pflege-Pauschale. KI ersetzt Entwickler nicht, sie beschleunigt sie.' },
  { q: 'Wem gehört am Ende die Anwendung?', a: 'Ihnen. Komplett. Sie erhalten den Quellcode, die Dokumentation und alles, was zum Betrieb dazugehört. Sie können das System bei jedem anderen Dienstleister weiterführen lassen oder selbst betreiben. Sie sind nicht an uns gebunden.' },

  { q: 'Wie sicher sind unsere Bau-Daten?', a: 'Ihre Daten liegen auf Servern in Deutschland und damit unter deutschem Datenschutzrecht (DSGVO). Sie sind verschlüsselt gespeichert und verschlüsselt übertragen — technisch auf dem Niveau, das Sie vom Online-Banking kennen. Auf Wunsch läuft alles komplett auf Servern in Ihrem eigenen Betrieb.' },
  { q: 'Wir haben schon Software A, B und C — kann eure mit denen reden?', a: 'In der Regel ja. Übliche Verdächtige (DATEV, Pro-Bau-S, Capmo, BauProfessor, Excel-Listen) binden wir per Schnittstelle oder direktem Datei-Import an. Manchmal ersetzen wir auch — je nachdem, was günstiger ist.' },
  { q: 'Wie bringen wir diese Software an unsere Mitarbeiter?', a: 'Das ist oft die entscheidende Frage — und eine, die wir von Anfang an mitdenken. Wir entwickeln gemeinsam mit Ihnen ein passendes Einführungskonzept: von der ersten Schulung bis zur täglichen Nutzung. Wo es sinnvoll ist, holen wir Fachleute dazu, die Erfahrung darin haben, Teams in Handwerk und Bau an neue Abläufe heranzuführen — nicht mit Folien, sondern praxisnah auf der Baustelle. Kurz: Sie bauen die Software nicht allein ein. Wir begleiten Sie.' },
  { q: 'Was, wenn wir mittendrin Anforderungen ändern?', a: 'Erwartet. Genau deshalb arbeiten wir in kleinen Schritten. Sie sehen alle 1–2 Wochen einen lauffähigen Stand, geben Feedback, wir passen an. Änderungen kosten kein Vermögen, weil wir nicht von null neu programmieren — die KI passt bestehende Bausteine an.' }
];

function FAQSection() {
  return (
    <section className="faq" id="faq">
      <SectionHead
        title={<>Was Hand­werker uns <span style={{display:'inline-block', lineHeight:'1.3'}}><span className="hi">wirklich</span></span> fragen.</>}
      />
      <div className="faq-list">
        {FAQ_ITEMS.map((it, i) => (
          <details className="faq-item" key={i}>
            <summary>
              <span className="qn mono">{String(i+1).padStart(2,'0')}</span>
              <span className="q">{it.q}</span>
              <span className="plus">+</span>
            </summary>
            <div className="answer">{it.a}</div>
          </details>
        ))}
      </div>
    </section>
  );
}

// ===== Calendly Embed =====
function CalendlyEmbed() {
  const ref = useRef(null);
  useEffect(() => {
    const url = 'https://calendly.com/webadmin-bau-digital/30min?hide_gdpr_banner=1&background_color=faf7ee&text_color=1a1714&primary_color=ff5b14';
    const init = () => {
      if (window.Calendly && ref.current) {
        // ensure we don't double-init
        if (!ref.current.dataset.cinit) {
          ref.current.dataset.cinit = '1';
          window.Calendly.initInlineWidget({ url, parentElement: ref.current });
        }
      }
    };
    if (!document.getElementById('calendly-script')) {
      const s = document.createElement('script');
      s.id = 'calendly-script';
      s.src = 'https://assets.calendly.com/assets/external/widget.js';
      s.async = true;
      s.onload = init;
      document.head.appendChild(s);
    } else {
      init();
    }
    // also load Calendly's CSS once
    if (!document.getElementById('calendly-css')) {
      const l = document.createElement('link');
      l.id = 'calendly-css';
      l.rel = 'stylesheet';
      l.href = 'https://assets.calendly.com/assets/external/widget.css';
      document.head.appendChild(l);
    }
    // Auto-resize the widget to its content height — Calendly's iframe posts
    // its current page height, so there is no inner scrollbar and no empty
    // space below, in every step of the booking flow.
    const onMessage = (e) => {
      if (!e.data || typeof e.data !== 'object') return;
      if (typeof e.origin === 'string' && e.origin.indexOf('calendly.com') === -1) return;
      if (e.data.event === 'calendly.page_height' && e.data.payload && e.data.payload.height) {
        const h = parseInt(e.data.payload.height, 10);
        // ignore transient tiny / 0 values that would collapse the widget
        if (!isNaN(h) && h >= 400 && ref.current) {
          ref.current.style.height = h + 'px';
          const iframe = ref.current.querySelector('iframe');
          if (iframe) iframe.style.height = h + 'px';
        }
      }
    };
    window.addEventListener('message', onMessage);
    return () => window.removeEventListener('message', onMessage);
  }, []);
  return (
    <div className="calendly-wrap">
      <div
        ref={ref}
        style={{minWidth:'320px', minHeight:'700px', height:'700px', background:'var(--paper)', borderRadius:18}}
      ></div>
    </div>
  );
}

// ===== Custom Crosshair Cursor =====
function CrosshairCursor() {
  const ref = useRef(null);
  const labelRef = useRef(null);
  useEffect(() => {
    let raf, tx = 0, ty = 0, cx = 0, cy = 0;
    const move = (e) => {
      tx = e.clientX; ty = e.clientY;
      // detect hover target
      const el = e.target.closest('a, button, [role=button], .problem, .ai-card, .faq-item summary, .bk-side .it, .chat-suggest button');
      if (ref.current) {
        if (el) {
          ref.current.classList.add('lg');
          const lbl = el.tagName === 'A' || el.tagName === 'BUTTON' || el.closest('.chat-suggest') ? 'TAP' : 'EXPLORE';
          if (labelRef.current) labelRef.current.textContent = lbl;
        } else {
          ref.current.classList.remove('lg');
        }
      }
    };
    const tick = () => {
      cx += (tx - cx) * 0.28;
      cy += (ty - cy) * 0.28;
      if (ref.current) ref.current.style.transform = `translate(${cx}px, ${cy}px) translate(-50%,-50%)`;
      raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    window.addEventListener('pointermove', move);
    return () => { cancelAnimationFrame(raf); window.removeEventListener('pointermove', move); };
  }, []);
  return (
    <div className="cursor" ref={ref}>
      <span ref={labelRef}></span>
    </div>
  );
}

// Export to window
Object.assign(window, {
  CountUp, SectionIndicator, BauakteMockup, ChatDemo, DemoSection, RoiCalc,
  costModel, COST_DEFAULTS, COST_FIXED, COST_CARE, COST_SEAT,
  ProofSection, FAQSection, CrosshairCursor, CalendlyEmbed
});
