// Story-Mode: 6 Story-Fragen statt 13 Sections.
// Mappt Story-Antworten zurück auf das bestehende Schema (state.data, state.users etc.),
// damit der Skill-Export 1:1 weiterläuft.

const StoryMode = (function() {
 const { useState, useMemo, useEffect } = React;

  // ============================================================
  // 1) Story-Schema: 6 Fragen
  // ============================================================
 const STORY_QUESTIONS = [
 {
 id: "intro",
 topic: "Vorab",
 title: "Wir möchten Ihre Telefonie genau richtig einrichten.",
 sub: "Sie müssen nichts wissen, was Sie nicht aus Ihrem Alltag kennen. Alles Technische leiten wir aus Ihren Antworten ab. Bevor's losgeht: zwei kurze Angaben zu Ihnen.",
 kind: "intro"
 },
 {
 id: "team",
 topic: "Team",
 title: "Wer soll telefonieren können?",
 sub: "Tragen Sie alle Personen ein, die mit der neuen Anlage telefonieren werden, wie ein Team-Verzeichnis. Durchwahlen und Apps regeln wir später.",
 kind: "team-list"
 },
 {
 id: "incoming",
 topic: "Anrufer an der Hauptnummer",
 title: "Stellen Sie sich vor: jemand ruft Ihre Hauptnummer an. Was soll als erstes passieren?",
 sub: "Wählen Sie die Variante, die Ihrem Alltag am nächsten kommt. Das Technische bauen wir dahinter zusammen.",
 kind: "choice",
 options: [
 {
 id: "reception",
 icon: "phone",
 tag: "üblich",
 head: "Eine Person nimmt ab, unser „Empfang“",
 detail: "Es klingelt direkt bei einer Person oder einem kleinen Team, das alle Anrufe annimmt und durchstellt, wie der Tresen vorne.",
 followUp: { kind: "person-pick", q: "Wer sitzt typischerweise auf dem Empfang?" }
 },
 {
 id: "ivr",
 icon: "grid-3x3",
 head: "Der Anrufer wählt selbst aus, wohin er möchte",
 detail: "Eine Stimme begrüßt: „Drücken Sie 1 für Vertrieb, 2 für Service …“ und verbindet automatisch.",
 followUp: { kind: "ivr-options", q: "Welche Tasten-Optionen wären typisch? (später anpassbar)" }
 },
 {
 id: "team",
 icon: "users",
 head: "Es klingelt bei mehreren gleichzeitig",
 detail: "Anrufe gehen an ein ganzes Team auf einmal, wer Zeit hat, nimmt ab. Üblich in Agenturen, Beratung, kleineren Büros ohne festen Empfang.",
 followUp: { kind: "team-pick", q: "Wer gehört zu diesem Team?" }
 },
 {
 id: "directdial",
 icon: "corner-down-right",
 head: "Hauptnummer ist nur Sammelpunkt, die meisten kennen ihre Durchwahl",
 detail: "Externe wählen direkt die Person. An die Hauptnummer kommen nur Erstkontakte; die laufen z.B. ans Sekretariat.",
 followUp: { kind: "person-pick", q: "Wer kümmert sich um die Hauptnummer / Erstkontakte?" }
 }
 ]
 },
 {
 id: "hours",
 topic: "Erreichbarkeit",
 title: "Wann wird bei Ihnen telefoniert?",
 sub: "Innerhalb dieser Zeiten landen Anrufe wie eben gewählt. Außerhalb regeln wir's gleich in der nächsten Frage.",
 kind: "hours"
 },
 {
 id: "afterhours",
 topic: "Außerhalb der Sprechzeiten",
 title: "Was passiert, wenn niemand abnimmt, oder es nach Feierabend ist?",
 sub: "Sie können das später anders einstellen für Mittagspause, Urlaub usw., fürs Erste reicht eine Standardeinstellung.",
 kind: "choice",
 options: [
 {
 id: "voicemail",
 icon: "voicemail",
 tag: "üblich",
 head: "Anrufbeantworter, Nachricht kommt per E-Mail",
 detail: "Anrufer können eine Nachricht hinterlassen. Die Aufnahme bekommen Sie sofort als E-Mail-Anhang.",
 followUp: { kind: "vm-mail", q: "An welche E-Mail-Adresse sollen die Nachrichten gehen?" }
 },
 {
 id: "announce",
 icon: "megaphone",
 head: "Nur eine kurze Ansage, keine Aufnahme",
 detail: "„Sie erreichen uns Mo bis Fr von 8 bis 17 Uhr …“, danach legt das System auf. Kein Anrufbeantworter.",
 followUp: null
 },
 {
 id: "forward",
 icon: "phone-forwarded",
 head: "An eine andere Nummer weiterleiten",
 detail: "Z.B. an einen Notdienst, ein Mobiltelefon oder einen Bereitschaftsdienst.",
 followUp: { kind: "external-number", q: "An welche Nummer soll weitergeleitet werden?" }
 },
 {
 id: "ringlonger",
 icon: "hourglass",
 head: "Einfach länger klingeln lassen",
 detail: "Wenn niemand drangeht, klingelt es so lange weiter, bis der Anrufer auflegt. Wir empfehlen das nicht, aber manche Branchen wollen das so.",
 followUp: null
 }
 ]
 },
 {
 id: "outgoing",
 topic: "Wenn Sie raustelefonieren",
 title: "Welche Nummer sieht der Angerufene, wenn Sie raustelefonieren?",
 sub: "Das ist die Nummer, die im Display des Angerufenen erscheint. Sie können das pro Person oder Abteilung später feiner einstellen.",
 kind: "choice",
 options: [
 {
 id: "main",
 icon: "building-2",
 tag: "üblich",
 head: "Immer die Hauptnummer der Firma",
 detail: "Egal wer telefoniert, beim Angerufenen erscheint die zentrale Firmen-Nummer. So rufen Rückrufe wieder im Empfang an.",
 followUp: null
 },
 {
 id: "department",
 icon: "network",
 head: "Abteilungs-Nummer (z.B. Vertrieb, Service)",
 detail: "Verschiedene Abteilungen treten mit unterschiedlichen Rufnummern auf. Geeignet, wenn Sie z.B. eine Service-Hotline haben.",
 followUp: null
 },
 {
 id: "individual",
 icon: "user",
 head: "Jede Person mit ihrer eigenen Durchwahl",
 detail: "Jeder Mitarbeitende telefoniert mit der individuellen Direktwahl. Rückrufe gehen direkt zur richtigen Person.",
 followUp: null
 },
 {
 id: "anonymous",
 icon: "eye-off",
 head: "Nummer unterdrückt anzeigen",
 detail: "Der Angerufene sieht „unbekannt“ oder „anonym“. Manche schalten dann gar nicht erst ans Telefon, wir empfehlen das nur in Sonderfällen.",
 followUp: null
 }
 ]
 },
 {
 id: "devices",
 topic: "Telefone und Apps",
 title: "Womit sollen Ihre Mitarbeitenden telefonieren?",
 sub: "Wir richten alles für die nächsten 5 Jahre zukunftssicher ein, Tischtelefone, Smartphone-App, Headset am Computer. Sie können das später pro Person ändern.",
 kind: "choice",
 options: [
 {
 id: "app-only",
 icon: "smartphone",
 tag: "modern",
 head: "Nur die 3CX-App auf Smartphone und Computer",
 detail: "Keine Tischtelefone. Anrufe laufen über die App, am PC mit Headset, unterwegs aufs Handy. Spart Hardware-Kosten und ist überall verfügbar.",
 followUp: null
 },
 {
 id: "mixed",
 icon: "monitor-smartphone",
 tag: "üblich",
 head: "Tischtelefone für manche, App für alle",
 detail: "Wer viel telefoniert (z.B. Empfang, Service) bekommt ein richtiges Tischtelefon. Alle anderen nutzen nur die App.",
 followUp: { kind: "device-mix", q: "Wer bekommt ein Tischtelefon?" }
 },
 {
 id: "phones-all",
 icon: "phone",
 head: "Tischtelefone für alle",
 detail: "Klassisch, jeder Arbeitsplatz mit Festtelefon. Die App gibt's zusätzlich fürs Handy unterwegs.",
 followUp: null
 },
 {
 id: "decide",
 icon: "circle-help",
 head: "Entscheidet ihr, wir kennen den Markt nicht",
 detail: "Wir empfehlen je nach Team-Struktur die passende Mischung und besprechen das beim Vor-Ort-Termin.",
 followUp: null
 }
 ]
 }
 ];

  // ============================================================
  // 2) Mapping: Story → Schema
  // ============================================================
 function mapStoryToSchema(story, baseState) {
 const next = JSON.parse(JSON.stringify(baseState));
 next.data = next.data || {};
 next.users = next.users || [];
 next.hours = next.hours || {};
 next.unsure = next.unsure || {};
    // Optionstexte exakt wie in schema.js (SUPPORTED_PHONES)
 const APP_ONLY = "Nein, nur App / kein Tischtelefon";
 const DESK_PHONE = "Tischtelefon, Modell empfiehlt X-sec";
    // Stand der letzten Übernahme (takeStory in app.jsx): seitdem unveränderte Antworten nicht erneut anwenden,
    // damit spätere Änderungen im Profi-Bogen erhalten bleiben
 const prev = story.taken || {};
 const changed = (k) => JSON.stringify(story[k] || null) !== JSON.stringify(prev[k] || null);

    // Skipped Story-Fragen → unsure-Marker (X-sec entscheidet)
 if (story.skipped && changed("skipped")) {
 const skipToFields = {
 incoming: ["erst_annahme", "ivr_aktiv"],
 afterhours: ["verhalten_ausser", "vm_wer", "vm_email"],
 outgoing: ["clip_standard"],
 devices: ["phone_provisioning"],
 hours: ["geschaeftszeiten"]
 };
 Object.keys(story.skipped).forEach(qid => {
 (skipToFields[qid] || []).forEach(f => { next.unsure[f] = true; });
 });
 }

    // Frage 0: Intro mit Firma / Ansprechpartner / Kontakt
 if (story.intro) {
 ["firma", "ansprechpartner", "kontakt_email"].forEach(k => {
 if (story.intro[k] && story.intro[k] !== (prev.intro || {})[k]) next.data[k] = story.intro[k];
 });
 }

    // Frage 1: Team, mit vorhandenen Nutzern zusammenführen (gleicher Name = gleiche Person), nichts ersetzen
 if (story.team && Array.isArray(story.team)) {
 const named = story.team.filter(u => u.name && u.name.trim()).filter(u => {
 const before = (prev.team || []).find(x => x.name === u.name);
 return !before || (before.email || "") !== (u.email || "") || (before.durchwahl || "") !== (u.durchwahl || "");
 });
 if (named.length) {
 const users = next.users.filter(u => (u.name || "").trim() || (u.email || "").trim());
 named.forEach(u => {
 const known = users.find(x => (x.name || "").trim() === u.name.trim());
 if (known) {
 if (u.email) known.email = u.email;
 if (u.durchwahl) known.durchwahl = u.durchwahl;
 return;
 }
 users.push({
 name: u.name,
 email: u.email || "",
 durchwahl: u.durchwahl || "",
 phone: u.device === "phone" ? DESK_PHONE : (u.device === "app" ? APP_ONLY : ""),
 apps: u.apps || "Beide",
 abteilungen: u.abteilungen || [],
 sonderrufe: ""
 });
 });
 next.users = users;
 }
 }

    // Frage 2: Eingehend
 if (story.incoming && changed("incoming")) {
 const c = story.incoming.choice;
 const person = story.incoming.followUp?.person;
 if (c === "reception") {
 next.data.erst_annahme = person ? "user:" + person : "free:Empfang (Person wird noch festgelegt)";
 next.data.ivr_aktiv = "Nein";
 } else if (c === "ivr") {
 next.data.erst_annahme = "ivr:main";
 next.data.ivr_aktiv = "Ja";
 next.data.ivr_begruessung = "Willkommen bei " + (next.data.firma || "uns") + ". Drücken Sie …";
 if (Array.isArray(story.incoming.followUp?.options)) {
 next.ivr = story.incoming.followUp.options.map((opt, i) => ({
 key: String(i + 1),
 label: opt,
 target: ""
 }));
 }
 } else if (c === "team") {
 const members = story.incoming.followUp?.members || [];
 next.data.erst_annahme = "free:Team, alle klingeln gleichzeitig" + (members.length ? ": " + members.join(", ") : "");
 next.data.ws_strategie = "Alle gleichzeitig";
 } else if (c === "directdial") {
 next.data.erst_annahme = person ? "user:" + person : "free:Sekretariat";
 }
 }

    // Frage 3: Geschäftszeiten: nur in der Story geänderte Tage übernehmen, vorhandene Zeiten bleiben sonst erhalten
 if (story.hours) {
 const ref = prev.hours || defaultHours();
 Object.keys(story.hours).forEach(k => {
 if (!sameDay(story.hours[k], ref[k])) next.hours[k] = story.hours[k];
 });
 }

    // Frage 4: Außerhalb / niemand abnimmt
 if (story.afterhours && changed("afterhours")) {
 const c = story.afterhours.choice;
 if (c === "voicemail") {
 next.data.verhalten_ausser = "Ansage + Voicemail";
 next.data.vm_wer = "Alle Nutzer";
 next.data.vm_email = "Ja, an persönliche E-Mail";
 const mail = story.afterhours.followUp?.email;
      // Kein eigenes Schema-Feld für die Adresse: sie landet in der Sammel-Voicemail (Klartext und Payload)
 if (mail && !(next.data.vm_sammel || "").includes(mail)) {
 const entry = "Hauptnummer: Voicemails per E-Mail an " + mail;
 next.data.vm_sammel = next.data.vm_sammel ? next.data.vm_sammel + "\n" + entry : entry;
 }
 } else if (c === "announce") {
 next.data.verhalten_ausser = "Ansage + Auflegen";
 } else if (c === "forward") {
 next.data.verhalten_ausser = "Notfallweiterleitung an Mobilnummer";
 if (story.afterhours.followUp?.number) {
 next.data.verhalten_ausser_nummer = story.afterhours.followUp.number;
 }
 } else if (c === "ringlonger") {
      // verhalten_ausser hat dafür keine Option: als Ziel "Wenn niemand rangeht" erfassen
 next.data.nicht_erreicht_ziel = "free:Weiterklingeln lassen, bis der Anrufer auflegt";
 }
 }

    // Frage 5: Ausgehende CLIP (clip_anzeigen betrifft eingehende Anrufe und wird hier nicht gesetzt)
 if (story.outgoing && changed("outgoing")) {
 const c = story.outgoing.choice;
 if (c === "main") next.data.clip_standard = "Hauptnummer der Firma";
 else if (c === "department") next.data.clip_standard = "Abhängig von Abteilung";
 else if (c === "individual") next.data.clip_standard = "Persönliche Durchwahl des Mitarbeitenden";
 else if (c === "anonymous") next.data.clir = "Ja, generell";
 }

    // Frage 6: Endgeräte
 if (story.devices && (changed("devices") || changed("team"))) {
 const c = story.devices.choice;
      // Pauschal in alle users propagieren, wo phone leer ist
 const phoneFor = (u) => u.phone || "";
 next.users = next.users.map(u => {
 if (u.phone) return u;
 if (c === "app-only") return { ...u, phone: APP_ONLY, apps: u.apps || "Beide" };
 if (c === "phones-all") return { ...u, phone: DESK_PHONE, apps: u.apps || "Beide" };
 if (c === "mixed") {
 const wantsPhone = (story.devices.followUp?.phoneUsers || []).includes(u.name);
 return { ...u, phone: wantsPhone ? DESK_PHONE : APP_ONLY, apps: u.apps || "Beide" };
 }
 return u;
 });
 }

    // Smart-Defaults für alles, was die Story nicht abdeckt
 if (window.EASY_MODE) {
 const r = window.EASY_MODE.applySmartDefaults(next);
 return r.state;
 }
 return next;
 }

 function sameDay(a, b) {
 return ["open", "from", "to", "pause", "pause_from", "pause_to"].every(f => ((a || {})[f] || "") === ((b || {})[f] || ""));
 }

  // Wurde in der Story tatsächlich etwas beantwortet? Eine unberührte Default-Story darf den Profi-Bogen nicht verändern.
 function isStoryAnswered(story, baseState) {
 if (!story) return false;
 const d = (baseState && baseState.data) || {};
 const intro = story.intro || {};
 const def = defaultHours();
 return ["incoming", "afterhours", "outgoing", "devices"].some(k => story[k] && story[k].choice)
 || Object.keys(story.skipped || {}).length > 0
 || (story.team || []).some(u => u.name && u.name.trim())
 || ["firma", "ansprechpartner", "kontakt_email"].some(k => intro[k] && intro[k] !== d[k])
 || Object.keys(story.hours || {}).some(k => !sameDay(story.hours[k], def[k]));
 }

  // ============================================================
  // 3) UI-Komponenten
  // ============================================================

 function ProgressBar({ done, total }) {
 const pct = (done / total) * 100;
 return (
 <div className="story-prog"><div className="story-prog-bar" style={{width: pct +"%"}} /></div>
 );
 }

 function StoryHeader({ idx, total, onJumpProfi, onSave, onHome }) {
    // Einzige Fortschrittsangabe: "Vorab" ohne Nummer, danach Frage 1 bis 6 mit dem Thema der Frage
 const step = idx >= total ? "Zusammenfassung"
 : idx === 0 ? STORY_QUESTIONS[0].topic
 : `Frage ${idx} von ${total - 1} · ${STORY_QUESTIONS[idx].topic}`;
 return (
 <header className="story-top">
 <div className="story-top-inner">
 <div className="story-top-l">
 <div className="story-top-title">3CX-Einrichtung</div>
 <div className="story-top-mode">Einfach-Modus</div>
 </div>
 <div className="story-top-c">
 <ProgressBar done={idx + 1} total={total + 1} />
 <div className="story-top-step">{step}</div>
 </div>
 <div className="story-top-r">
 {onHome && <button className="story-top-link" onClick={onHome}><XsecIcon name="arrow-left" /> Startseite</button>}
 <button className="story-top-link" onClick={onSave} title="Sie können jederzeit pausieren, alles bleibt im Browser gespeichert."><XsecIcon name="pause" /> Pause</button>
 <button className="story-top-link is-pro" onClick={onJumpProfi} title="Für technisch versierte Kunden: alle Detail-Abschnitte des klassischen Bogens."><XsecIcon name="settings" /> Profi-Modus <XsecIcon name="arrow-right" /></button>
 </div>
 </div>
 </header>
 );
 }

 function ChoiceCard({ opt, selected, onSelect, followUpUI }) {
 return (
 <>
 <button
 className={`story-opt ${selected ? "is-sel" : ""}`}
 onClick={() => onSelect(opt.id)}
 type="button"
 >
 <div className="story-opt-head">
 <span className="story-opt-icon" aria-hidden="true"><XsecIcon name={opt.icon} /></span>
 <span className="story-opt-title">{opt.head}</span>
 {opt.tag && <span className="story-opt-tag">{opt.tag}</span>}
 </div>
 <div className="story-opt-detail">{opt.detail}</div>
 </button>
 {selected && opt.followUp && (
 <div className="story-followup">
 <div className="story-followup-q">{opt.followUp.q}</div>
 {followUpUI}
 </div>
 )}
 </>
 );
 }

  // Conditional Follow-up renderers
 function FollowUp({ kind, value, onChange, users }) {
 if (kind === "person-pick") {
 const v = value || {};
 const personOptions = users.filter(u => u.name).map(u => u.name);
 return (
 <div>
 {personOptions.length > 0 ? (
 <select className="story-input" value={v.person || ""} onChange={e => onChange({ ...v, person: e.target.value })}>
 <option value="">Bitte auswählen</option>
 {personOptions.map(n => <option key={n} value={n}>{n}</option>)}
 </select>
 ) : (
 <input className="story-input" placeholder="Name eingeben (z.B. Anna Berger)" value={v.person || ""} onChange={e => onChange({ ...v, person: e.target.value })} />
 )}
 <div className="story-mini-hint">Tipp: Sie können in Frage 1 jederzeit weitere Personen ergänzen.</div>
 </div>
 );
 }
 if (kind === "ivr-options") {
 const v = value || { options: ["Termine", "Rezepte", "Sonstiges"] };
 const opts = v.options || [];
 const update = (i, val) => onChange({ ...v, options: opts.map((o, j) => j === i ? val : o) });
 const add = () => onChange({ ...v, options: [...opts, ""] });
 const remove = (i) => onChange({ ...v, options: opts.filter((_, j) => j !== i) });
 return (
 <div className="story-ivr-list">
 {opts.map((o, i) => (
 <div key={i} className="story-ivr-row">
 <span className="story-ivr-key">{i + 1}</span>
 <input className="story-input" value={o} onChange={e => update(i, e.target.value)} placeholder="z.B. Termine" />
 <button className="story-ivr-rm" onClick={() => remove(i)} aria-label="Entfernen"><XsecIcon name="x" /></button>
 </div>
 ))}
 <button className="story-ivr-add" onClick={add}>+ Option hinzufügen</button>
 </div>
 );
 }
 if (kind === "team-pick") {
 const v = value || { members: [] };
 const personOptions = users.filter(u => u.name).map(u => u.name);
 const toggle = (n) => {
 const has = (v.members || []).includes(n);
 onChange({ ...v, members: has ? v.members.filter(m => m !== n) : [...(v.members || []), n] });
 };
 if (personOptions.length === 0) {
 return (
 <div>
 <input className="story-input" placeholder="Namen kommagetrennt (z.B. Anna, Tom, Sarah)"
 value={(v.freetext || "")}
 onChange={e => onChange({ ...v, freetext: e.target.value, members: e.target.value.split(", ").map(x => x.trim()).filter(Boolean) })} />
 <div className="story-mini-hint">Sie können das Team auch in Frage 1 strukturiert eintragen, dann sind die Namen direkt anklickbar.</div>
 </div>
 );
 }
 return (
 <div className="story-chip-grid">
 {personOptions.map(n => (
 <button key={n} className={`story-chip ${(v.members || []).includes(n) ? "is-sel" : ""}`} onClick={() => toggle(n)}>{n}</button>
 ))}
 </div>
 );
 }
 if (kind === "vm-mail") {
 const v = value || {};
 return (
 <input className="story-input" type="email" placeholder="z.B. empfang@firma.de" value={v.email || ""} onChange={e => onChange({ ...v, email: e.target.value })} />
 );
 }
 if (kind === "external-number") {
 const v = value || {};
 return (
 <input className="story-input" placeholder="z.B. +49 211 1234567" value={v.number || ""} onChange={e => onChange({ ...v, number: e.target.value })} />
 );
 }
 if (kind === "device-mix") {
 const v = value || { phoneUsers: [] };
 const personOptions = users.filter(u => u.name).map(u => u.name);
 const toggle = (n) => {
 const has = (v.phoneUsers || []).includes(n);
 onChange({ ...v, phoneUsers: has ? v.phoneUsers.filter(m => m !== n) : [...(v.phoneUsers || []), n] });
 };
 if (personOptions.length === 0) {
 return (
 <div>
 <input className="story-input" placeholder="Wer bekommt ein Tischtelefon? (Namen kommagetrennt)"
 value={(v.freetext || "")}
 onChange={e => onChange({ ...v, freetext: e.target.value, phoneUsers: e.target.value.split(", ").map(x => x.trim()).filter(Boolean) })} />
 <div className="story-mini-hint">Tipp: tragen Sie das Team in Frage 1 strukturiert ein, dann sind die Namen direkt anklickbar.</div>
 </div>
 );
 }
 return (
 <div className="story-chip-grid">
 {personOptions.map(n => (
 <button key={n} className={`story-chip ${(v.phoneUsers || []).includes(n) ? "is-sel" : ""}`} onClick={() => toggle(n)}>{n}</button>
 ))}
 </div>
 );
 }
 return null;
 }

  // Frage 0: Intro mit Firma / Ansprechpartner / Kontakt
 function IntroQuestion({ value, onChange }) {
 const v = value || {};
 const set = (k, val) => onChange({ ...v, [k]: val });
 return (
 <div className="story-intro-fields">
 <div className="story-field">
 <label className="story-field-label">Wie heißt Ihr Unternehmen? <span className="story-req">*</span></label>
 <input className="story-input" placeholder="z.B. Praxis Dr. Mustermann" value={v.firma || ""} onChange={e => set("firma", e.target.value)} autoFocus />
 </div>
 <div className="story-field">
 <label className="story-field-label">Wer füllt das aus? <span className="story-req">*</span></label>
 <input className="story-input" placeholder="z.B. Anna Berger, Praxismanagerin" value={v.ansprechpartner || ""} onChange={e => set("ansprechpartner", e.target.value)} />
 <div className="story-mini-hint">Damit wir wissen, wen wir bei Rückfragen ansprechen dürfen.</div>
 </div>
 <div className="story-field">
 <label className="story-field-label">Ihre E-Mail oder Telefon</label>
 <input className="story-input" placeholder="anna@firma.de oder 0211 123456" value={v.kontakt_email || ""} onChange={e => set("kontakt_email", e.target.value)} />
 <div className="story-mini-hint">Optional, hier melden wir uns mit dem Ergebnis.</div>
 </div>
 <div className="story-intro-perks">
 <div className="story-intro-perk"><span className="story-intro-perk-icon" aria-hidden="true"><XsecIcon name="check" /></span> Speichert automatisch im Browser</div>
 <div className="story-intro-perk"><span className="story-intro-perk-icon" aria-hidden="true"><XsecIcon name="check" /></span> Sie können jederzeit pausieren und später weitermachen</div>
 <div className="story-intro-perk"><span className="story-intro-perk-icon" aria-hidden="true"><XsecIcon name="check" /></span> Bei Unsicherheit: „Weiß nicht, entscheidet ihr“</div>
 </div>
 </div>
 );
 }

  // Frage 1: Team-Liste (eigenes UI)
 function TeamQuestion({ value, onChange }) {
 const team = value || [];
 const update = (i, key, val) => onChange(team.map((u, j) => j === i ? { ...u, [key] : val } : u));
 const add = () => onChange([...team, { name: "", email:"", durchwahl:"" }]);
 const remove = (i) => onChange(team.filter((_, j) => j !== i));

    // Mindestens 1 Reihe
 useEffect(() => {
 if (team.length === 0) onChange([{ name: "", email:"", durchwahl:"" }]);
 }, []);

 return (
 <div className="story-team">
 <div className="story-team-head">
 <span>Name</span>
 <span>E-Mail (optional)</span>
 <span>Durchwahl (optional)</span>
 <span></span>
 </div>
 {team.map((u, i) => (
 <div key={i} className="story-team-row">
 <input className="story-input" placeholder="z.B. Anna Berger" value={u.name || ""} onChange={e => update(i, "name", e.target.value)} />
 <input className="story-input" placeholder="anna@firma.de" value={u.email || ""} onChange={e => update(i, "email", e.target.value)} />
 <input className="story-input" placeholder="z.B. 100" value={u.durchwahl || ""} onChange={e => update(i, "durchwahl", e.target.value)} />
 <button className="story-team-rm" onClick={() => remove(i)} aria-label="Person entfernen" disabled={team.length <= 1}><XsecIcon name="x" /></button>
 </div>
 ))}
 <button className="story-team-add" onClick={add}>+ Person hinzufügen</button>
 <div className="story-mini-hint">Sie müssen weder E-Mail noch Durchwahl angeben, wir vergeben sinnvolle Werte (Durchwahlen ab 100, Welcome-Mail über die hinterlegte Adresse).</div>
 </div>
 );
 }

  // Frage 3: Geschäftszeiten, wir verwenden die bestehende WeekHours-Komponente
 function HoursQuestion({ value, onChange }) {
 return <WeekHours hours={value || defaultHours()} onChange={onChange} />;
 }

  // ============================================================
  // 4) Zusammenfassung vor dem Senden
  // ============================================================
 const summaryLine = (story, users) => {
 const lines = [];
 if (story.incoming?.choice === "reception") {
 const p = story.incoming.followUp?.person;
 lines.push(["Ankommende Anrufe", p ? `Empfang (${p})` : "Empfang, Person wird noch festgelegt"]);
 } else if (story.incoming?.choice === "ivr") {
 const opts = story.incoming.followUp?.options || [];
 lines.push(["Ankommende Anrufe", opts.length ? `Sprachmenü mit ${opts.length} Optionen` : "Sprachmenü (Optionen folgen)"]);
 } else if (story.incoming?.choice === "team") {
 const m = story.incoming.followUp?.members || [];
 lines.push(["Ankommende Anrufe", m.length ? `Team gleichzeitig (${m.length} Personen)` : "Team gleichzeitig"]);
 } else if (story.incoming?.choice === "directdial") {
 lines.push(["Ankommende Anrufe", `Direkt-Durchwahl, Hauptnummer: ${story.incoming.followUp?.person || "Sekretariat"}`]);
 }

 const hrs = story.hours || {};
 const openDays = WEEKDAYS.filter(({k}) => hrs[k]?.open).map(({l}) => l);
 if (openDays.length > 0) {
 const first = WEEKDAYS.find(({k}) => hrs[k]?.open);
 const f = hrs[first.k];
 lines.push(["Erreichbar", `${openDays.join(", ")} · ca. ${f.from} bis ${f.to}`]);
 }

 if (story.afterhours?.choice === "voicemail") {
 const m = story.afterhours.followUp?.email;
 lines.push(["Pause / Feierabend", `Anrufbeantworter${m ? " → " + m : ""}`]);
 } else if (story.afterhours?.choice === "announce") lines.push(["Pause / Feierabend", "Nur Ansage, dann auflegen"]);
 else if (story.afterhours?.choice === "forward") lines.push(["Pause / Feierabend", `Weiterleitung an ${story.afterhours.followUp?.number || ""}`]);
 else if (story.afterhours?.choice === "ringlonger") lines.push(["Pause / Feierabend", "Klingelt einfach weiter"]);

 const out = story.outgoing?.choice;
 if (out === "main") lines.push(["Ausgehende Anzeige", "Hauptnummer der Firma"]);
 else if (out === "department") lines.push(["Ausgehende Anzeige", "Abteilungs-Nummer"]);
 else if (out === "individual") lines.push(["Ausgehende Anzeige", "Persönliche Durchwahl"]);
 else if (out === "anonymous") lines.push(["Ausgehende Anzeige", "Anonym"]);

 const dev = story.devices?.choice;
 if (dev === "app-only") lines.push(["Telefone", "Nur 3CX-App auf Smartphone + PC"]);
 else if (dev === "mixed") {
 const ph = (story.devices.followUp?.phoneUsers || []).length;
 lines.push(["Telefone", `${ph} mit Tischtelefon · App für alle anderen`]);
 } else if (dev === "phones-all") lines.push(["Telefone", "Tischtelefone für alle, plus App"]);
 else if (dev === "decide") lines.push(["Telefone", "Wir empfehlen beim Vor-Ort-Termin"]);

 const team = users.filter(u => u.name).length;
 if (team > 0) lines.push(["Mitarbeitende", `${team} Personen`]);

 return lines;
 };

 function SummaryScreen({ story, users, onBack, onSubmit, onPdf, onCall, derivedCount }) {
 const lines = summaryLine(story, users);
 const firma = story.intro?.firma || "";
 const skipped = Object.keys(story.skipped || {});
 return (
 <div className="story-summary">
 <div className="story-summary-card">
 <h2>Geschafft{firma ? ", "+ firma : ""}. Wir haben alles, was wir brauchen.</h2>
 <p>Aus Ihren Antworten haben wir <strong>{derivedCount} technische Einstellungen</strong> abgeleitet, Rufnummernführung, Anrufbeantworter, Wartemusik, App-Konfiguration, Notrufadresse. Sie müssen davon nichts wissen.</p>
 {skipped.length > 0 && (
 <div className="story-summary-skipped">
 <span aria-hidden="true"><XsecIcon name="circle-help" /></span> Bei {skipped.length === 1 ? "einem Punkt" : skipped.length +" Punkten"} entscheiden wir für Sie nach unseren Standardempfehlungen.
 </div>
 )}
 </div>

 <h3 className="story-summary-head">Das hat X-sec aus Ihren Antworten gemacht</h3>
 <div className="story-summary-grid">
 {lines.map(([k, v], i) => (
 <div key={i} className="story-summary-cell">
 <div className="story-summary-label">{k}</div>
 <div className="story-summary-value">{v}</div>
 </div>
 ))}
 </div>

 <h3 className="story-summary-head" style={{marginTop: 8}}>Wie geht's weiter?</h3>
 <div className="story-send-options">
 <div className="story-send-option">
 <div className="story-send-icon" aria-hidden="true"><XsecIcon name="mail" size={18} /></div>
 <div className="story-send-text">
 <div className="story-send-title">An X-sec schicken</div>
 <div className="story-send-detail">Wir richten Ihre Anlage in 1 bis 2 Werktagen ein und melden uns per E-Mail.</div>
 </div>
 <button className="story-btn story-btn-prim" onClick={onSubmit}>Senden <XsecIcon name="arrow-right" /></button>
 </div>
 <div className="story-send-option">
 <div className="story-send-icon" aria-hidden="true"><XsecIcon name="file-down" size={18} /></div>
 <div className="story-send-text">
 <div className="story-send-title">PDF herunterladen</div>
 <div className="story-send-detail">Ausdruck für die Akte oder die Geschäftsleitung.</div>
 </div>
 <button className="story-btn" onClick={onPdf}>PDF</button>
 </div>
 <div className="story-send-option">
 <div className="story-send-icon" aria-hidden="true"><XsecIcon name="phone" size={18} /></div>
 <div className="story-send-text">
 <div className="story-send-title">Mit jemandem sprechen</div>
 <div className="story-send-detail">Unsicher bei einer Antwort? Wir gehen den Bogen mit Ihnen durch.</div>
 </div>
 <a className="story-btn" href="tel:+492104493770" onClick={onCall}>Anrufen</a>
 </div>
 </div>

 <div className="story-summary-foot">
 <button className="story-btn-ghost" onClick={onBack}><XsecIcon name="arrow-left" /> Nochmal durchgehen</button>
 <span className="story-summary-foot-note">Alles bleibt gespeichert, Sie können später zurückkommen.</span>
 </div>
 </div>
 );
 }

  // ============================================================
  // 5) Haupt-Komponente
  // ============================================================
 function StoryApp({ initialStory, baseState, onSubmitStory, onJumpProfi, onPdfPrint, onSaveDraft, persistStory, onHome }) {
 const [idx, setIdx] = useState(0);
 const [story, setStory] = useState(initialStory || {
 intro: {
 firma: baseState?.data?.firma || "",
 ansprechpartner: baseState?.data?.ansprechpartner || "",
 kontakt_email: baseState?.data?.kontakt_email || ""
 },
 team: [{ name: "", email:"", durchwahl:"" }],
 incoming: null,
 hours: defaultHours(),
 afterhours: null,
 outgoing: null,
 devices: null
 });
 const [showSummary, setShowSummary] = useState(false);

    // Persist whenever story changes
 useEffect(() => {
 persistStory && persistStory(story);
 }, [story]);

 const total = STORY_QUESTIONS.length;
 const q = STORY_QUESTIONS[idx];
 const users = (story.team || []).filter(u => u.name);

    // Reset to step 0 if intro is missing on resume, ensures intro always asked at least once
 useEffect(() => {
 if (!initialStory && !story.intro) setIdx(0);
 }, []);

    // dirty: seit der letzten Übernahme in den Profi-Bogen geändert (siehe takeStory in app.jsx)
 const setChoice = (qid, choice) => {
 setStory(s => {
 const next = { ...s, dirty: true };
 next[qid] = { ...(s[qid] || {}), choice, followUp: (s[qid]?.choice === choice) ? s[qid]?.followUp : null };
 if (next.skipped && next.skipped[qid]) {
 next.skipped = { ...next.skipped };
 delete next.skipped[qid];
 }
 return next;
 });
 };
 const setFollowUp = (qid, fu) => {
 setStory(s => ({ ...s, dirty: true, [qid]: { ...(s[qid] || {}), followUp: fu } }));
 };
 const setIntro = (intro) => setStory(s => ({ ...s, dirty: true, intro }));
 const setTeam = (team) => setStory(s => ({ ...s, dirty: true, team }));
 const setHours = (hours) => setStory(s => ({ ...s, dirty: true, hours }));

 const canNext = () => {
 if (q.id === "intro") {
 const v = story.intro || {};
 return !!(v.firma && v.firma.trim() && v.ansprechpartner && v.ansprechpartner.trim());
 }
 if (q.id === "team") return (story.team || []).some(u => u.name && u.name.trim());
 if (q.id === "hours") return Object.values(story.hours || {}).some(d => d.open);
 if (q.kind === "choice") return !!story[q.id]?.choice;
 return true;
 };

 const skipCurrent = () => {
 setStory(s => ({
 ...s,
 dirty: true,
 skipped: { ...(s.skipped || {}), [q.id]: true }
 }));
 if (idx < total - 1) setIdx(idx + 1);
 else setShowSummary(true);
 };

 const next = () => {
 if (idx < total - 1) setIdx(idx + 1);
 else setShowSummary(true);
 };
 const prev = () => {
 if (showSummary) { setShowSummary(false); return; }
 if (idx > 0) setIdx(idx - 1);
 };

 const derivedCount = useMemo(() => {
 const mapped = mapStoryToSchema(story, baseState);
 return Object.keys(mapped.data || {}).length;
 }, [story, baseState]);

 if (showSummary) {
 return (
 <div className="story-shell">
 <StoryHeader idx={total} total={total} onJumpProfi={onJumpProfi} onSave={onSaveDraft} onHome={onHome} />
 <main className="story-main">
 <SummaryScreen
 story={story}
 users={story.team || []}
 onBack={() => setShowSummary(false)}
 onSubmit={() => onSubmitStory(mapStoryToSchema(story, baseState), story)}
 onPdf={() => onPdfPrint(mapStoryToSchema(story, baseState), story)}
 onCall={() => {}}
 derivedCount={derivedCount}
 />
 </main>
 </div>
 );
 }

 const a = story[q.id];
 const sel = a?.choice;
 const opt = q.options?.find(o => o.id === sel);

 return (
 <div className="story-shell">
 <StoryHeader idx={idx} total={total} onJumpProfi={onJumpProfi} onSave={onSaveDraft} onHome={onHome} />
 <main className="story-main">
 <h1 className="story-q">{q.title}</h1>
 <p className="story-sub">{q.sub}</p>

 {q.kind === "intro" && (
 <IntroQuestion value={story.intro} onChange={setIntro} />
 )}

 {q.kind === "team-list" && (
 <TeamQuestion value={story.team} onChange={setTeam} />
 )}

 {q.kind === "hours" && (
 <HoursQuestion value={story.hours} onChange={setHours} />
 )}

 {q.kind === "choice" && (
 <div className="story-opts">
 {q.options.map(o => (
 <ChoiceCard
 key={o.id}
 opt={o}
 selected={sel === o.id}
 onSelect={(id) => setChoice(q.id, id)}
 followUpUI={
 o.followUp ? (
 <FollowUp
 kind={o.followUp.kind}
 value={a?.followUp}
 onChange={(fu) => setFollowUp(q.id, fu)}
 users={users}
 />
 ) : null
 }
 />
 ))}
 </div>
 )}

 <div className="story-acts">
 <button className="story-btn-ghost" onClick={prev} disabled={idx === 0}><XsecIcon name="arrow-left" /> Zurück</button>
 <div className="story-acts-r">
 {q.id !== "intro"&& q.id !== "team" && (
 <button className="story-btn-ghost" onClick={skipCurrent} title="Sie können diese Frage überspringen, wir entscheiden für Sie."><XsecIcon name="circle-help" /> Weiß nicht, entscheidet ihr</button>
 )}
 <button className="story-btn story-btn-prim" onClick={next} disabled={!canNext()}>
 {idx < total - 1 ? "Weiter" : "Zusammenfassung"} <XsecIcon name="arrow-right" />
 </button>
 </div>
 </div>
 </main>
 </div>
 );
 }

 return { StoryApp, mapStoryToSchema, isStoryAnswered, STORY_QUESTIONS };
})();

window.StoryMode = StoryMode;
