// MedLink · Visite-Tour-Modus (5-Phasen-Workflow nach deutscher Pflegeheim-Praxis)
// Öffnet per CustomEvent 'medlink:startVisite' — Detail: { visitId?, bewohnerIds? }.
// Echte Web Speech API (de-DE) in der Gesprächs-Phase.
// Real-Life-Orientierung: Briefing → Sichtung → Gespräch → Entscheidung → Protokoll.

(function () {
  const { useState, useEffect, useRef, useMemo, useCallback } = React;

  // ---------------- Speech Recognition helpers ----------------
  const getSR = () => window.SpeechRecognition || window.webkitSpeechRecognition;
  const speechSupported = typeof window !== "undefined" && !!getSR();

  // ---------------- Voice commands ----------------
  const COMMANDS = [
    { re: /(?:n(?:ä|ae)ch(?:ster?|es)\s*patient(?:in)?|weiter(?:\s*bitte)?|vor\s*weiter)/i, type: "next", label: "Nächste:r" },
    { re: /(?:zur(?:ü|ue)ck|vorherige[rn]?\s*patient)/i, type: "prev", label: "Zurück" },
    { re: /(?:(?:patient)?\s*(?:ü|ue)berspringen|skip)/i, type: "skip", label: "Übersprungen" },
    { re: /(?:visite\s*beenden|visite\s*ende|ende\s*der\s*visite|abschlie(?:ß|ss)en|fertig)/i, type: "end", label: "Visite beendet" },
    { re: /(?:freigeben|medikament\s*freigeben|verordnen|rezept\s*aus)/i, type: "approve", label: "Freigegeben" },
    { re: /blutdruck\s+(\d{2,3})\s*(?:zu|\/|\s)\s*(\d{2,3})/i, type: "vital", key: "bp", label: "Blutdruck" },
    { re: /puls(?:frequenz)?\s+(\d{2,3})/i, type: "vital", key: "pulse", label: "Puls" },
    { re: /temperatur\s+(\d{2}(?:[\.,]\d)?)/i, type: "vital", key: "temp", label: "Temperatur" },
    { re: /(?:sauerstoff[-\s]?)?s(?:ä|ae)ttigung\s+(\d{2,3})/i, type: "vital", key: "spo2", label: "SpO₂" },
    { re: /(?:diktat\s+)?(?:stopp|stop|ende\s+diktat)/i, type: "stopMic", label: "Diktat pausiert" },
    { re: /(?:objektiv|befund)/i, type: "soap", section: "O", label: "Objektiv" },
    { re: /(?:beurteilung|assessment|diagnose)/i, type: "soap", section: "A", label: "Beurteilung" },
    { re: /(?:plan|therapie|verordnung|n(?:ä|ae)chste\s+schritte)/i, type: "soap", section: "P", label: "Plan" },
  ];
  const parseCommand = (text) => {
    const trimmed = text.trim().toLowerCase();
    for (const cmd of COMMANDS) {
      const m = trimmed.match(cmd.re);
      if (m) return { ...cmd, match: m };
    }
    return null;
  };

  // ---------------- Helpers ----------------
  const fmtTime = (ms) => {
    const s = Math.max(0, Math.floor(ms / 1000));
    const m = Math.floor(s / 60);
    const r = s % 60;
    return `${String(m).padStart(2, "0")}:${String(r).padStart(2, "0")}`;
  };
  const firstInitial = (name) => (name || "?").split(",")[0].trim()[0] || "?";
  const lastName = (name) => (name || "").split(",")[0].trim();
  const bewById = (id) => (window.BEWOHNER || []).find((b) => b.id === id);
  const heimName = (id) => (window.HEIMS || []).find((h) => h.id === id)?.name || id;
  const lastOf = (v) => Array.isArray(v) ? v[v.length - 1] : v;

  const ensureVitals = (bid) => {
    const existing = (window.VITALS || {})[bid];
    if (existing) {
      const lastBP = lastOf(existing.bp);
      return {
        bp: Array.isArray(lastBP) ? `${lastBP[0]}/${lastBP[1]}` : (lastBP ? String(lastBP) : ""),
        pulse: lastOf(existing.puls) != null ? String(lastOf(existing.puls)) : "",
        temp: lastOf(existing.temp) != null ? String(lastOf(existing.temp)) : "",
        spo2: lastOf(existing.spo2) != null ? String(lastOf(existing.spo2)) : "",
      };
    }
    return { bp: "", pulse: "", temp: "", spo2: "" };
  };

  // Schätzt Visite-Dauer pro Bewohner (in Minuten) — realistisch: PG + offene Anfragen zählen.
  const estimateMinutes = (b) => {
    if (!b) return 8;
    let base = 7;
    base += (b.offen || 0) * 2;
    base += Math.max(0, (b.pflegegrad || 0) - 2) * 1.5;
    if ((b.allergien || []).length > 0) base += 1;
    if ((b.diagnosen || []).length > 2) base += 2;
    return Math.round(base);
  };

  // Prophylaxen-Flags anhand der Diagnosen + Pflegegrad.
  const prophylaxenFor = (b) => {
    if (!b) return [];
    const flags = [];
    const has = (sub) => (b.diagnosen || []).some((d) => d.toLowerCase().includes(sub));
    if ((b.pflegegrad || 0) >= 4) flags.push({ t: "sturz", l: "Sturzrisiko" });
    if (has("demenz") || has("parkinson")) flags.push({ t: "sturz", l: "Sturzrisiko" });
    if (has("copd") || has("schlaf")) flags.push({ t: "pneumo", l: "Pneumonie-Prophylaxe" });
    if ((b.pflegegrad || 0) >= 4) flags.push({ t: "dekubitus", l: "Dekubitus-Check" });
    if (has("diabetes")) flags.push({ t: "bz", l: "BZ-Kontrolle" });
    return flags.slice(0, 3); // max 3, sonst zu unübersichtlich
  };

  // Generiert SBAR-Briefing aus Daten — als wäre es von der Pflegekraft vorbereitet.
  const generateBriefing = (b) => {
    if (!b) return null;
    const pending = (window.ANFRAGEN || []).filter((a) => a.bewohner === b.id && a.status === "offen");
    const lastA = pending[0];
    const age = b.alter;
    const name = b.name.split(",")[0].trim();
    const diags = (b.diagnosen || []).slice(0, 2).join(", ");
    const pg = b.pflegegrad;
    const allergies = (b.allergien || []).length ? `Allergie: ${b.allergien.join(", ")}. ` : "";

    // Situation — was ist akut?
    const situations = [
      lastA?.notiz ? lastA.notiz : null,
      `${name} ist heute wach und zugewandt, Nahrungsaufnahme stabil.`,
      `${name} wirkt heute etwas ruhiger als gestern, kein Fieber.`,
    ].filter(Boolean);
    const situation = situations[0];

    // Background — Vorgeschichte
    const background = `${age} Jahre · ${diags}. Pflegegrad ${pg}. ${allergies}${pending.length > 0 ? `${pending.length} offene Arzt-Anfrage${pending.length > 1 ? "n" : ""}.` : "Stabiler Dauer-Verlauf."}`;

    // Assessment — Einschätzung
    const vitals = ensureVitals(b.id);
    const vitalStr = vitals.bp ? `RR ${vitals.bp}, Puls ${vitals.pulse || "—"}. ` : "";
    const mobility = pg >= 4 ? "Mobilität stark eingeschränkt" : (pg >= 3 ? "teilmobilisiert, mit Hilfestellung" : "eigenständig mobil");
    const assessment = `${vitalStr}${mobility}. Medikation regelmäßig eingenommen. ${lastA?.prio === "H" || lastA?.prio === "U" ? "Priorität erhöht." : ""}`;

    // Recommendation — was braucht der Arzt?
    const recommendation = lastA
      ? `Bitte prüfen: ${lastA.med}${lastA.dosis ? ` (${lastA.dosis})` : ""} — ${lastA.typ}. ${lastA.notiz ? "Kontext siehe oben." : ""}`
      : "Routine-Kontrolle. Kein akuter Handlungsbedarf von unserer Seite.";

    return {
      pflegekraft: "Maria Lehmann",
      schicht: "Frühdienst",
      zeit: new Date().toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" }),
      situation, background, assessment, recommendation,
    };
  };

  // ---------------- Specialty-specific configuration ----------------
  // Each Fachrichtung hat eigene Sichtung-Checkliste, Vital-/Assessment-Felder,
  // Medikations-Fokus, Protokoll-Pflichtpunkte. Hausarzt ist der Default.
  const SPECIALTY_CONFIG = {
    Hausarzt: {
      label: "Hausarzt",
      short: "H",
      tone: "teal",
      tagline: "Allgemeinmedizinische Regelvisite",
      focus: [
        "Dauermedikation (Polypharmazie-Check)",
        "RR- und BZ-Verlauf · Gewicht",
        "Wunden · Haut · Ödeme",
        "Impfstatus · Labor-Bedarf",
      ],
      sichtung: [
        { key: "haut", label: "Haut", hint: "Farbe, Feuchtigkeit, Turgor" },
        { key: "dekubitus", label: "Dekubitus-Check", hint: "Ferse, Steiß, Ellbogen" },
        { key: "wunden", label: "Wunden & Narben", hint: "Heilungsverlauf, Sekretion" },
        { key: "katheter", label: "Katheter / Sonde", hint: "Lage, Ausfluss, Wechseldatum" },
        { key: "oedeme", label: "Ödeme", hint: "Beine, Knöchel, Lidödeme" },
        { key: "ernaehrung", label: "Ernährung & Flüssigkeit", hint: "Gewichtsverlauf, Trinkmenge" },
        { key: "sturz", label: "Sturz-Risiko", hint: "Mobilität, Orientierung, Sturz-Tag-Intervall" },
      ],
      vitals: [
        { key: "bp", label: "Blutdruck", unit: "mmHg", hint: "RR syst/diast" },
        { key: "pulse", label: "Puls", unit: "/min" },
        { key: "temp", label: "Temp.", unit: "°C" },
        { key: "spo2", label: "SpO₂", unit: "%" },
      ],
      assessments: [],
      protokollChecks: ["Medikation besprochen", "Labor bei Bedarf angefordert"],
    },

    Nervenarzt: {
      label: "Nervenarzt",
      short: "N",
      tone: "violet",
      tagline: "Konsiliar · Demenz · BPSD · Parkinson · alle 6 Wochen",
      focus: [
        "BPSD-Symptome (Unruhe, Wahn, Aggression, Schlaf)",
        "Antipsychotika-Indikation prüfen (Leitlinie S3)",
        "Deprescribing · Dosis reduzieren wenn möglich",
        "Motorik: Rigor · Tremor · Bradykinese · Gang",
        "Kognition · Orientierung · Affekt",
      ],
      sichtung: [
        { key: "orientierung", label: "Orientierung", hint: "Zeit · Ort · Person · Situation" },
        { key: "affekt", label: "Affekt & Stimmung", hint: "GDS · niedergeschlagen · apathisch · labil" },
        { key: "bpsd", label: "BPSD-Verhalten", hint: "Unruhe · Aggression · Wahn · Halluzinationen · Wandern" },
        { key: "schlaf", label: "Schlafprofil", hint: "Einschlaf · Durchschlafen · Nacht-Unruhe" },
        { key: "motorik", label: "Motorik (Parkinsonoid)", hint: "Rigor · Tremor · Bradykinese · posturale Instabilität" },
        { key: "gang", label: "Gang & Sturz", hint: "Gangbild · Freezing · letzte Stürze" },
        { key: "neuroleptika", label: "Neuroleptika-Review", hint: "Dauer · Nebenwirkung · Indikation noch gegeben?" },
      ],
      vitals: [
        { key: "mmse", label: "MMSE", unit: "/30", hint: "letzter Wert + Datum" },
        { key: "gds", label: "GDS", unit: "/15", hint: "Depression-Skala" },
        { key: "bp", label: "Blutdruck", unit: "mmHg" },
        { key: "pulse", label: "Puls", unit: "/min" },
      ],
      assessments: [
        { key: "bpsd_aggr", label: "Aggressiv", type: "toggle" },
        { key: "bpsd_wahn", label: "Wahn/Halluz.", type: "toggle" },
        { key: "bpsd_unruhe", label: "Motor. Unruhe", type: "toggle" },
        { key: "bpsd_apathie", label: "Apathie", type: "toggle" },
        { key: "sleep_quality", label: "Schlafqualität", type: "scale", min: 1, max: 10 },
      ],
      medCategories: ["Neuroleptika", "Antidementiva", "Parkinson-Therapie", "Benzodiazepine", "SSRI/Antidepressiva"],
      medHighlightRe: /(Melperon|Quetiapin|Risperidon|Haloperidol|Olanzapin|Pipamperon|Donepezil|Memantin|Rivastigmin|Madopar|Rasagilin|Levodopa|Pramipexol|Zopiclon|Diazepam|Lorazepam|Sertralin|Citalopram|Mirtazapin)/i,
      protokollChecks: [
        "Antipsychotika-Indikation dokumentiert",
        "Reduktionsversuch geprüft",
        "BPSD-Verhaltensbeobachtung eingeleitet",
        "Nächster Konsil-Termin (6 Wo)",
      ],
    },

    Internist: {
      label: "Internist",
      short: "I",
      tone: "amber",
      tagline: "Konsiliar · Herz-Kreislauf · Lunge · Stoffwechsel",
      focus: [
        "Herzinsuffizienz-Zeichen (NYHA · Ödeme · Gewicht)",
        "Vorhofflimmern · Antikoagulation (CHA₂DS₂-VASc)",
        "COPD · Asthma · Inhalations-Technik",
        "BZ-Einstellung · HbA1c-Verlauf",
        "Elektrolyte · Nierenfunktion",
      ],
      sichtung: [
        { key: "auskult", label: "Auskultation", hint: "Herztöne · Rasselgeräusche · Atem" },
        { key: "oedeme", label: "Ödeme & Stauung", hint: "Beine · Halsvenen · Gewicht +/−" },
        { key: "atmung", label: "Atmung", hint: "Ruhe · Belastung · Atemfrequenz · SpO₂" },
        { key: "rr_verlauf", label: "RR-Verlauf", hint: "14-Tage-Trend · Morgenspitzen" },
        { key: "bz_verlauf", label: "BZ-Verlauf", hint: "Nüchtern · postprandial · HbA1c" },
        { key: "inhalation", label: "Inhalations-Technik", hint: "Hub · Koordination · Spacer?" },
      ],
      vitals: [
        { key: "bp", label: "Blutdruck", unit: "mmHg" },
        { key: "pulse", label: "Puls", unit: "/min" },
        { key: "spo2", label: "SpO₂", unit: "%" },
        { key: "weight", label: "Gewicht", unit: "kg" },
        { key: "resp", label: "Atemfreq.", unit: "/min" },
        { key: "glucose", label: "BZ", unit: "mg/dl" },
      ],
      assessments: [
        { key: "nyha", label: "NYHA-Stadium", type: "select", options: ["I","II","III","IV"] },
        { key: "ekg", label: "EKG nötig", type: "toggle" },
      ],
      medCategories: ["Antihypertonika", "Antikoagulantien", "Diuretika", "Insulin/OAD", "Inhalativa"],
      medHighlightRe: /(Ramipril|Bisoprolol|Candesartan|Amlodipin|Apixaban|Rivaroxaban|Marcumar|Torasemid|Furosemid|Metformin|Insulin|Formoterol|Budesonid|Salbutamol)/i,
      protokollChecks: [
        "Herzinsuffizienz-Status dokumentiert",
        "Antikoag.-Indikation geprüft",
        "Labor-Verordnung (Elyte, Krea, NT-proBNP)",
      ],
    },

    Geriater: {
      label: "Geriater",
      short: "G",
      tone: "teal",
      tagline: "Ganzheitliches Assessment · Multimorbidität",
      focus: [
        "Mobilität · Sturz-Risiko · Timed-Up-&-Go",
        "Kognition · Polypharmazie · FORTA-Liste",
        "Ernährung · Trinkmenge · MNA",
        "Kontinenz · Dekubitus · Hautpflege",
      ],
      sichtung: [
        { key: "mobil", label: "Mobilität & Transfer", hint: "Timed-Up-&-Go · Rollator · Hilfebedarf" },
        { key: "kognitiv", label: "Kognitiv-Screen", hint: "MMSE · Uhrentest · Orientierung" },
        { key: "ernaehrung", label: "Ernährung (MNA)", hint: "Gewicht · BMI · Trinkmenge · Schluckstörung" },
        { key: "haut_wunden", label: "Haut & Wunden", hint: "Dekubitus · Intertrigo · Pergamenthaut" },
        { key: "kontinenz", label: "Kontinenz", hint: "Urin/Stuhl · Inkontinenz-Versorgung" },
        { key: "polypharm", label: "Polypharmazie", hint: "≥5 Wirkstoffe · FORTA-Check · Interaktionen" },
      ],
      vitals: [
        { key: "bp", label: "Blutdruck", unit: "mmHg" },
        { key: "pulse", label: "Puls", unit: "/min" },
        { key: "weight", label: "Gewicht", unit: "kg" },
        { key: "tug", label: "Timed-Up-&-Go", unit: "Sek.", hint: ">14 s = Sturzgefahr" },
      ],
      assessments: [
        { key: "mmse", label: "MMSE", type: "number", suffix: "/30" },
        { key: "barthel", label: "Barthel-Index", type: "number", suffix: "/100" },
      ],
      medCategories: ["FORTA-A", "FORTA-B", "FORTA-C", "FORTA-D"],
      protokollChecks: [
        "Timed-Up-&-Go dokumentiert",
        "Polypharmazie-Review durchgeführt",
        "Assessment-Termin (nächstes Quartal)",
      ],
    },

    Palliativ: {
      label: "Palliativ",
      short: "P",
      tone: "rose",
      tagline: "Symptomkontrolle · End-of-Life-Care",
      focus: [
        "Schmerz · NRS / ECPA bei kognitiver Einschränkung",
        "Dyspnoe · Atemnot-Score",
        "Übelkeit · Obstipation · Mundpflege",
        "Patientenverfügung · Angehörigen-Gespräch",
        "BTM-Dosisanpassung · Rescue-Medikation",
      ],
      sichtung: [
        { key: "schmerz", label: "Schmerz-Assessment", hint: "NRS 0–10 · bei Demenz: ECPA · Grimassieren" },
        { key: "dyspnoe", label: "Dyspnoe", hint: "Ruhe / Belastung · RR · Atemfrequenz" },
        { key: "uebelkeit", label: "Übelkeit / Erbrechen", hint: "Appetit · Nahrungsaufnahme" },
        { key: "obstipation", label: "Obstipation", hint: "Letzter Stuhlgang · Laxans-Regime" },
        { key: "mund", label: "Mundpflege & Xerostomie", hint: "Soor · Speichel · Lippenpflege" },
        { key: "hautzehn", label: "Haut & Dekubitus", hint: "Druckstellen · feuchtwarm · Feuchtigkeit" },
        { key: "angst", label: "Angst / Unruhe", hint: "Nachts · Wahn · Lorazepam b.B.?" },
      ],
      vitals: [
        { key: "nrs", label: "NRS", unit: "/10", hint: "Schmerz-Selbstrating" },
        { key: "ecpa", label: "ECPA", unit: "/32", hint: "Fremdrating bei Demenz" },
        { key: "resp", label: "Atemfreq.", unit: "/min" },
        { key: "bp", label: "Blutdruck", unit: "mmHg" },
      ],
      assessments: [
        { key: "dyspnoe_scale", label: "Dyspnoe (NRS)", type: "scale", min: 0, max: 10 },
        { key: "sedation", label: "RASS-Sedierung", type: "select", options: ["+2","+1","0","−1","−2","−3"] },
        { key: "pv", label: "Patientenverfügung", type: "toggle", label_on: "vorhanden" },
      ],
      medCategories: ["Analgetika-Stufe-I", "Opioide", "Koanalgetika", "Antiemetika", "Laxantien", "Sedativa"],
      medHighlightRe: /(Morphin|MST|Targin|Fentanyl|Oxycodon|Buprenorphin|Novalgin|Metamizol|Paracetamol|Tramadol|Gabapentin|Pregabalin|MCP|Haloperidol|Lorazepam|Midazolam|Movicol|Laxoberal)/i,
      protokollChecks: [
        "Schmerzstärke (NRS/ECPA) dokumentiert",
        "Rescue-Medikation verfügbar",
        "Angehörigen-Kontakt informiert",
        "Patientenverfügung geprüft",
      ],
    },

    Urologe: {
      label: "Urologe",
      short: "U",
      tone: "indigo",
      tagline: "Konsiliar · Harnwege · Kontinenz",
      focus: [
        "Katheter-Lage, Wechsel-Intervall, Urin-Aspekt",
        "Restharn · Blasenentleerung",
        "Harnwegsinfekt-Zeichen",
        "Inkontinenz-Versorgung",
      ],
      sichtung: [
        { key: "katheter", label: "Katheter", hint: "DK/suprapubisch · Wechseldatum · Sekret · Urin klar?" },
        { key: "restharn", label: "Restharn-Sonografie", hint: "Ziel <100 ml nach Miktion" },
        { key: "hwi", label: "HWI-Zeichen", hint: "Dysurie · CRP · Fieber · Trübung" },
        { key: "genital", label: "Genital-Region", hint: "Rötung · Ekzem · Skrotum · Vagina" },
        { key: "kontinenz", label: "Kontinenz", hint: "Tag/Nacht · Vorlagen-Verbrauch" },
      ],
      vitals: [
        { key: "restharn_ml", label: "Restharn", unit: "ml" },
        { key: "urin_ph", label: "Urin-pH", unit: "" },
        { key: "temp", label: "Temp.", unit: "°C" },
      ],
      assessments: [
        { key: "urinaspekt", label: "Urin-Aspekt", type: "select", options: ["klar","trüb","blutig","bernsteinfarben"] },
      ],
      medCategories: ["Antibiotika (Harnwege)", "Anticholinergika"],
      medHighlightRe: /(Ciprofloxacin|Nitrofurantoin|Fosfomycin|Tamsulosin|Solifenacin|Oxybutynin|Mirabegron)/i,
      protokollChecks: [
        "Katheter-Wechsel dokumentiert",
        "Urin-Status (Stix/Kultur) veranlasst",
      ],
    },
  };

  // Kompatibilitäts-Fallback: altes SICHTUNG_ITEMS verweist jetzt auf Hausarzt.
  const SICHTUNG_ITEMS = SPECIALTY_CONFIG.Hausarzt.sichtung;

  // Spezialität aus Visit/Arzt ermitteln
  const specFromDoctor = (arztId) => {
    const d = (window.DOCTORS || []).find((x) => x.id === arztId);
    const raw = d?.spec || "Hausarzt";
    return SPECIALTY_CONFIG[raw] ? raw : "Hausarzt";
  };

  const PHASES = [
    { key: "briefing", label: "Briefing", icon: "clipboard", min: 2 },
    { key: "sichtung", label: "Sichtung", icon: "eye", min: 5 },
    { key: "gespraech", label: "Gespräch", icon: "mic", min: 8 },
    { key: "entscheidung", label: "Entscheidung", icon: "check", min: 3 },
    { key: "protokoll", label: "Protokoll", icon: "file", min: 2 },
  ];
  const PHASE_ORDER = PHASES.map((p) => p.key);

  // ---------------- Root component ----------------
  const VisiteMode = () => {
    if (window.useStoreVersion) window.useStoreVersion();

    const [open, setOpen] = useState(false);
    const [patients, setPatients] = useState([]);
    const [currentIdx, setCurrentIdx] = useState(0);
    const [mainPhase, setMainPhase] = useState("start"); // "start" | "patient" | "end"
    const [startedAt, setStartedAt] = useState(null);
    const [elapsed, setElapsed] = useState(0);
    const [specialty, setSpecialty] = useState("Hausarzt");
    const [visitArzt, setVisitArzt] = useState(null);
    const [visitAnlass, setVisitAnlass] = useState("");
    const spec = SPECIALTY_CONFIG[specialty] || SPECIALTY_CONFIG.Hausarzt;

    // Speech state
    const [listening, setListening] = useState(false);
    const [interim, setInterim] = useState("");
    const [cmdChip, setCmdChip] = useState("");
    const recognitionRef = useRef(null);
    const listeningRef = useRef(false);

    // ---------- Open / close ----------
    useEffect(() => {
      const onStart = (e) => {
        const detail = e.detail || {};
        let bewohnerIds = detail.bewohnerIds;
        let nextVisit = null;
        if (!bewohnerIds && detail.visitId) {
          nextVisit = (window.VISITEN || []).find((x) => x.id === detail.visitId);
          if (nextVisit) bewohnerIds = nextVisit.bewohner;
        }
        // Spezialität aus Visite oder aktuellem Portal-Arzt
        let nextSpec = "Hausarzt";
        let nextArzt = null;
        if (detail.arztId) nextArzt = detail.arztId;
        else if (nextVisit?.arzt) nextArzt = nextVisit.arzt;
        if (nextArzt) nextSpec = specFromDoctor(nextArzt);
        setSpecialty(nextSpec);
        setVisitArzt(nextArzt);
        setVisitAnlass(nextVisit?.anlass || "");
        const sc = SPECIALTY_CONFIG[nextSpec] || SPECIALTY_CONFIG.Hausarzt;

        if (!bewohnerIds || bewohnerIds.length === 0) {
          let state = {};
          try { state = JSON.parse(localStorage.getItem("medlink.state.v2") || "{}"); } catch {}
          const heim = state.heim || "ros";
          bewohnerIds = (window.BEWOHNER || [])
            .filter((b) => b.heim === heim)
            .slice(0, 6)
            .map((b) => b.id);
        }

        const initialPatients = bewohnerIds
          .map((id) => bewById(id))
          .filter(Boolean)
          .map((b, i) => ({
            id: b.id,
            status: i === 0 ? "current" : "pending",
            phase: "briefing",
            briefing: generateBriefing(b),
            briefingAcknowledged: false,
            sichtung: sc.sichtung.reduce((acc, it) => ({ ...acc, [it.key]: { status: "", note: "" } }), {}),
            soap: { S: "", O: "", A: "", P: "", active: "S" },
            note: "",
            vitals: ensureVitals(b.id),
            assessments: {}, // role-specific scores (MMSE, NRS, ...)
            medActions: {}, // { medName: "approve" | "modify" | "stop" | "new" }
            anfrageActions: {}, // { anfrageId: "approve" | "reject" }
            labOrdered: false,
            followUpDays: null,
            nurseRequested: false,
            signedByNurse: false,
            signedByDoctor: false,
            protokollChecks: sc.protokollChecks.reduce((a, k) => ({ ...a, [k]: false }), {}),
          }));
        setPatients(initialPatients);
        setCurrentIdx(0);
        setMainPhase("start");
        setStartedAt(null);
        setElapsed(0);
        setOpen(true);
      };
      window.addEventListener("medlink:startVisite", onStart);
      return () => window.removeEventListener("medlink:startVisite", onStart);
    }, []);

    const close = useCallback(() => {
      stopListening();
      setOpen(false);
      setMainPhase("start");
      setListening(false);
      setInterim("");
    }, []);

    // Escape + Shortcuts
    useEffect(() => {
      if (!open) return;
      const onKey = (e) => {
        if (e.key === "Escape") close();
        if (mainPhase === "start" && e.key === "Enter" && !["INPUT","TEXTAREA"].includes(e.target.tagName)) {
          e.preventDefault();
          if (patients.length > 0) startTour();
        }
        if (mainPhase === "patient") {
          if (e.key === "ArrowRight" && e.shiftKey) nextPatient();
          if (e.key === "ArrowLeft" && e.shiftKey) prevPatient();
          if (e.key === " " && e.target.tagName !== "TEXTAREA" && e.target.tagName !== "INPUT") {
            e.preventDefault();
            toggleListening();
          }
        }
      };
      window.addEventListener("keydown", onKey);
      return () => window.removeEventListener("keydown", onKey);
    }, [open, mainPhase, currentIdx]);

    // Timer
    useEffect(() => {
      if (!open || mainPhase !== "patient" || !startedAt) return;
      const t = setInterval(() => setElapsed(Date.now() - startedAt), 1000);
      return () => clearInterval(t);
    }, [open, mainPhase, startedAt]);

    // ---------- Patient-Navigation ----------
    const updateCurrent = (patcher) => {
      setPatients((ps) => {
        const next = ps.slice();
        if (next[currentIdx]) next[currentIdx] = { ...next[currentIdx], ...patcher(next[currentIdx]) };
        return next;
      });
    };

    const setPhase = (phaseKey) => {
      updateCurrent(() => ({ phase: phaseKey }));
    };

    const nextPatient = () => {
      stopListening();
      setPatients((ps) => {
        const next = ps.slice();
        if (next[currentIdx]) next[currentIdx] = { ...next[currentIdx], status: "done" };
        if (next[currentIdx + 1]) next[currentIdx + 1] = { ...next[currentIdx + 1], status: "current" };
        return next;
      });
      setInterim("");
      if (currentIdx + 1 < patients.length) setCurrentIdx((i) => i + 1);
      else finishTour();
    };

    const prevPatient = () => {
      stopListening();
      if (currentIdx > 0) {
        setPatients((ps) => {
          const next = ps.slice();
          if (next[currentIdx]) next[currentIdx] = { ...next[currentIdx], status: "pending" };
          if (next[currentIdx - 1]) next[currentIdx - 1] = { ...next[currentIdx - 1], status: "current" };
          return next;
        });
        setCurrentIdx((i) => i - 1);
        setInterim("");
      }
    };

    const skipPatient = () => {
      stopListening();
      setPatients((ps) => {
        const next = ps.slice();
        if (next[currentIdx]) next[currentIdx] = { ...next[currentIdx], status: "skip" };
        if (next[currentIdx + 1]) next[currentIdx + 1] = { ...next[currentIdx + 1], status: "current" };
        return next;
      });
      setInterim("");
      if (currentIdx + 1 < patients.length) setCurrentIdx((i) => i + 1);
      else finishTour();
    };

    const jumpTo = (idx) => {
      if (idx === currentIdx || idx < 0 || idx >= patients.length) return;
      stopListening();
      setPatients((ps) => {
        const next = ps.slice();
        if (next[currentIdx]?.status === "current") next[currentIdx] = { ...next[currentIdx], status: "pending" };
        if (next[idx]) next[idx] = { ...next[idx], status: "current" };
        return next;
      });
      setCurrentIdx(idx);
      setInterim("");
    };

    const startTour = () => {
      setStartedAt(Date.now());
      setMainPhase("patient");
    };

    const finishTour = () => {
      stopListening();
      setMainPhase("end");
    };

    // ---------- Speech Recognition ----------
    const handleFinalTranscript = useCallback((text) => {
      if (!text || !text.trim()) return;
      const cmd = parseCommand(text);
      if (cmd) {
        setCmdChip(cmd.label);
        setTimeout(() => setCmdChip(""), 1800);
        if (cmd.type === "next") nextPatient();
        else if (cmd.type === "prev") prevPatient();
        else if (cmd.type === "skip") skipPatient();
        else if (cmd.type === "end") finishTour();
        else if (cmd.type === "approve") {
          window.dispatchEvent(new CustomEvent("medlink:toast", { detail: "Medikation freigegeben" }));
          try { window.STORE?.bump?.(); } catch {}
        }
        else if (cmd.type === "stopMic") stopListening();
        else if (cmd.type === "soap") {
          updateCurrent((p) => ({ soap: { ...p.soap, active: cmd.section } }));
        }
        else if (cmd.type === "vital") {
          const m = cmd.match;
          let value = "";
          if (cmd.key === "bp") value = `${m[1]}/${m[2]}`;
          else if (cmd.key === "temp") value = m[1].replace(",", ".");
          else value = m[1];
          updateCurrent((p) => ({ vitals: { ...p.vitals, [cmd.key]: value } }));
        }
        return;
      }
      updateCurrent((p) => {
        const section = p.soap.active || "S";
        const prev = p.soap[section] || "";
        const joined = prev ? `${prev} ${text.trim()}` : text.trim();
        return { soap: { ...p.soap, [section]: joined }, note: `${p.note}${p.note ? " " : ""}${text.trim()}`.trim() };
      });
    }, [currentIdx, patients.length]);

    const startListening = useCallback(() => {
      const SR = getSR();
      if (!SR) {
        window.dispatchEvent(new CustomEvent("medlink:toast", { detail: "Spracherkennung nicht verfügbar" }));
        return;
      }
      if (listeningRef.current) return;
      try {
        const rec = new SR();
        rec.lang = "de-DE";
        rec.continuous = true;
        rec.interimResults = true;
        rec.maxAlternatives = 1;
        rec.onresult = (event) => {
          let interimStr = "";
          let finalStr = "";
          for (let i = event.resultIndex; i < event.results.length; i++) {
            const r = event.results[i];
            if (r.isFinal) finalStr += r[0].transcript;
            else interimStr += r[0].transcript;
          }
          if (finalStr) { handleFinalTranscript(finalStr); setInterim(""); }
          else setInterim(interimStr);
        };
        rec.onerror = (e) => {
          if (e.error === "not-allowed" || e.error === "service-not-allowed") {
            window.dispatchEvent(new CustomEvent("medlink:toast", { detail: "Mikrofon-Zugriff abgelehnt" }));
          }
        };
        rec.onend = () => {
          if (listeningRef.current) {
            try { rec.start(); } catch { listeningRef.current = false; setListening(false); }
          }
        };
        rec.start();
        recognitionRef.current = rec;
        listeningRef.current = true;
        setListening(true);
      } catch (err) {
        window.dispatchEvent(new CustomEvent("medlink:toast", { detail: "Diktat konnte nicht gestartet werden" }));
      }
    }, [handleFinalTranscript]);

    const stopListening = useCallback(() => {
      listeningRef.current = false;
      setListening(false);
      setInterim("");
      const rec = recognitionRef.current;
      if (rec) { try { rec.stop(); } catch {} }
      recognitionRef.current = null;
    }, []);

    const toggleListening = () => {
      if (listeningRef.current) stopListening(); else startListening();
    };

    useEffect(() => () => { stopListening(); }, [currentIdx]);
    useEffect(() => { if (!open) stopListening(); }, [open]);

    // Scroll-Detection für kompakten Patient-Header
    const stageRef = useRef(null);
    const [scrolled, setScrolled] = useState(false);
    const currentPhase = patients[currentIdx]?.phase;
    useEffect(() => {
      const el = stageRef.current;
      if (!el) return;
      el.scrollTop = 0;
      setScrolled(false);
      const onScroll = () => setScrolled(el.scrollTop > 60);
      el.addEventListener("scroll", onScroll, { passive: true });
      return () => el.removeEventListener("scroll", onScroll);
    }, [currentIdx, mainPhase, currentPhase]);

    // Progress-Ribbon: kumuliert über alle Phasen × alle Patient:innen.
    // WICHTIG: useMemo MUSS vor jedem `return` stehen (Rules of Hooks).
    const progress = useMemo(() => {
      if (mainPhase === "start" || patients.length === 0) return 0;
      if (mainPhase === "end") return 100;
      const totalSteps = patients.length * PHASE_ORDER.length;
      let done = 0;
      patients.forEach((p, i) => {
        if (i < currentIdx) done += PHASE_ORDER.length;
        else if (i === currentIdx) {
          done += PHASE_ORDER.filter((ph) => isPhaseDone(p, ph)).length;
        }
      });
      return Math.min(100, (done / totalSteps) * 100);
    }, [patients, currentIdx, mainPhase]);

    if (!open) return null;

    const current = patients[currentIdx];
    const currentBew = current ? bewById(current.id) : null;
    const doneCount = patients.filter((p) => p.status === "done").length;

    // Patient-Header kompakt wenn: Briefing abgeschlossen ODER gescrollt
    const headerCompact = mainPhase === "patient" && current && (
      !!current.briefingAcknowledged || scrolled
    );

    return (
      <>
        <div className="vt-backdrop" onClick={close} />
        <div className="vt-shell" data-mainphase={mainPhase} role="dialog" aria-label="Visite">

          {/* Progress-Ribbon — 3px sticky oben mit continuous shimmer */}
          {mainPhase === "patient" && (
            <div className="vt-progress" aria-hidden="true">
              <div className="vt-progress-fill" style={{ width: `${progress}%` }} />
            </div>
          )}

          {/* Header — merged with patient context on patient phase */}
          <div className="vt-head" data-compact={mainPhase === "patient"}>
            {mainPhase === "patient" && currentBew ? (
              <>
                <div className="vt-head-patient">
                  <div className="vt-head-avatar" aria-hidden="true">{firstInitial(currentBew.name)}</div>
                  <div className="vt-head-info">
                    <div className="vt-head-pname">
                      <span className="vt-head-pname-txt">{lastName(currentBew.name)}</span>
                      {specialty !== "Hausarzt" && (
                        <span className="vt-spec-pill" data-tone={(SPECIALTY_CONFIG[specialty] || SPECIALTY_CONFIG.Hausarzt).tone}>
                          <span className="vt-spec-pill-mark">{(SPECIALTY_CONFIG[specialty] || SPECIALTY_CONFIG.Hausarzt).short}</span>
                        </span>
                      )}
                    </div>
                    <div className="vt-head-pmeta">
                      <span className="vt-head-counter">{currentIdx + 1}/{patients.length}</span>
                      <span className="vt-head-sep" aria-hidden="true">·</span>
                      <span>Zi.&nbsp;{currentBew.zimmer}</span>
                      <span className="vt-head-sep" aria-hidden="true">·</span>
                      <span className="vt-head-heim">{heimName(currentBew.heim)}</span>
                    </div>
                  </div>
                </div>
                <div className="vt-head-spacer" />
                {startedAt && (
                  <div className="vt-timer" aria-label="Dauer">
                    <span className="vt-timer-dot" />
                    {fmtTime(elapsed)}
                  </div>
                )}
              </>
            ) : (
              <>
                <div>
                  <div className="vt-head-title">Visite</div>
                  <div className="vt-head-sub">
                    {mainPhase === "start" && "Vorbereitung"}
                    {mainPhase === "end" && "Abgeschlossen"}
                  </div>
                </div>
                <div className="vt-head-spacer" />
              </>
            )}
            <button className="vt-close-btn" onClick={close} aria-label="Schließen">
              <Icon name="x" size={14} />
            </button>
          </div>

          {/* Patient-Timeline (compact dots, nur Tablet+ während Tour) */}
          {mainPhase === "patient" && patients.length > 0 && (
            <div className="vt-timeline">
              {patients.map((p, i) => {
                const b = bewById(p.id);
                return (
                  <button key={p.id} className="vt-timeline-node" data-status={p.status} onClick={() => jumpTo(i)} title={b?.name}>
                    <span className="vt-timeline-node-dot" />
                    <span className="vt-timeline-node-lbl">{i + 1}. {b ? lastName(b.name) : "?"}</span>
                  </button>
                );
              })}
            </div>
          )}

          {/* Stage */}
          <div className="vt-stage" ref={stageRef}>
            {mainPhase === "start" && (
              <StartScreen
                patients={patients}
                onStart={startTour}
                onCancel={close}
                onRemove={(idx) => setPatients((ps) => ps.filter((_, i) => i !== idx))}
                onReorder={(from, to) => setPatients((ps) => {
                  const next = ps.slice();
                  const [item] = next.splice(from, 1);
                  next.splice(to, 0, item);
                  return next;
                })}
              />
            )}

            {mainPhase === "patient" && currentBew && current && (
              <PatientScreen
                key={current.id + "-" + currentIdx}
                bewohner={currentBew}
                patient={current}
                specialty={specialty}
                visitArzt={visitArzt}
                visitAnlass={visitAnlass}
                listening={listening}
                interim={interim}
                cmdChip={cmdChip}
                speechSupported={speechSupported}
                headerCompact={headerCompact}
                onToggleMic={toggleListening}
                onSetPhase={setPhase}
                onAckBriefing={() => updateCurrent(() => ({ briefingAcknowledged: true, phase: "sichtung" }))}
                onSetSichtung={(key, value) => updateCurrent((p) => ({ sichtung: { ...p.sichtung, [key]: { ...(p.sichtung[key] || {}), ...value } } }))}
                onSetSoapActive={(section) => updateCurrent((p) => ({ soap: { ...p.soap, active: section } }))}
                onUpdateSoap={(section, text) => updateCurrent((p) => ({ soap: { ...p.soap, [section]: text } }))}
                onUpdateVital={(key, value) => updateCurrent((p) => ({ vitals: { ...p.vitals, [key]: value } }))}
                onSetAssessment={(key, value) => updateCurrent((p) => ({ assessments: { ...(p.assessments || {}), [key]: value } }))}
                onSetMedAction={(med, action) => updateCurrent((p) => ({ medActions: { ...p.medActions, [med]: action } }))}
                onSetAnfrageAction={(aid, action) => updateCurrent((p) => ({ anfrageActions: { ...p.anfrageActions, [aid]: action } }))}
                onSetFollowUp={(days) => updateCurrent(() => ({ followUpDays: days }))}
                onToggleLab={() => updateCurrent((p) => ({ labOrdered: !p.labOrdered }))}
                onToggleNurse={() => updateCurrent((p) => ({ nurseRequested: !p.nurseRequested }))}
                onToggleProtokollCheck={(k) => updateCurrent((p) => ({ protokollChecks: { ...(p.protokollChecks || {}), [k]: !(p.protokollChecks || {})[k] } }))}
                onSignNurse={() => updateCurrent(() => ({ signedByNurse: true }))}
                onSignDoctor={() => updateCurrent(() => ({ signedByDoctor: true }))}
              />
            )}

            {mainPhase === "end" && (
              <EndScreen
                patients={patients}
                elapsed={elapsed}
                doneCount={doneCount}
                onRestart={() => {
                  setMainPhase("start");
                  setPatients((ps) => ps.map((p, i) => ({ ...p, status: i === 0 ? "current" : "pending", phase: "briefing" })));
                  setCurrentIdx(0);
                }}
                onHandoff={() => {
                  window.dispatchEvent(new CustomEvent("medlink:toast", { detail: "Protokoll an Pflege übergeben" }));
                  window.dispatchEvent(new CustomEvent("medlink:notify", { detail: {
                    kind: "approve", icon: "clipboard",
                    title: "Visite-Protokoll übermittelt",
                    sub: `${doneCount} Bewohner · gesamt ${fmtTime(elapsed)}`
                  } }));
                  close();
                }}
                onClose={close}
              />
            )}
          </div>

          {/* Ambient Floating Mic — in allen Phasen erreichbar (auch Vorbereitung/Abschluss) */}
          {speechSupported && (
            <>
              <button
                className="vt-floating-mic"
                data-live={listening}
                data-phase={mainPhase}
                onClick={toggleListening}
                aria-label={listening ? "Diktat stoppen" : "Diktat starten"}
                title={listening ? "Diktat läuft — klicken zum Stoppen" : "Sprach-Diktat"}
              >
                <Icon name={listening ? "pause" : "mic"} size={18} />
              </button>
              {listening && <div className="vt-floating-hint">Diktat läuft · DE-DE</div>}
            </>
          )}

          {/* Footer */}
          {mainPhase === "patient" && (
            <div className="vt-foot">
              <div className="vt-foot-hint">
                <kbd>Shift+←/→</kbd> Patient · <kbd>Space</kbd> Diktat · <kbd>Esc</kbd> schließen
              </div>
              <div className="vt-nav">
                <button className="vt-btn-secondary" onClick={prevPatient} disabled={currentIdx === 0}>
                  <Icon name="chevronRight" size={14} style={{ transform: "rotate(180deg)" }} /> Zurück
                </button>
                <button className="vt-btn-ghost" onClick={skipPatient}>Überspringen</button>
                <button className="vt-btn-primary" onClick={nextPatient}>
                  {currentIdx + 1 >= patients.length ? "Abschließen" : "Weiter"} <Icon name="arrowRight" size={14} />
                </button>
              </div>
            </div>
          )}
        </div>
      </>
    );
  };

  // ================================================================
  // Start Screen
  // ================================================================
  const StartScreen = ({ patients, onStart, onCancel, onRemove, onReorder }) => {
    const total = patients.length;
    const totalMin = patients.reduce((sum, p) => sum + estimateMinutes(bewById(p.id)), 0);
    const priorityCount = patients.reduce((n, p) => n + ((window.ANFRAGEN || []).filter((a) => a.bewohner === p.id && a.status === "offen" && (a.prio === "H" || a.prio === "U")).length), 0);

    // End-Zeit-Prognose: jetzt + Summe aller geschätzten Minuten
    const now = new Date();
    const endTime = new Date(now.getTime() + totalMin * 60000);
    const endStr = endTime.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" });
    const startStr = now.toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" });
    const dateStr = now.toLocaleDateString("de-DE", { weekday: "long", day: "numeric", month: "long" });
    const totalPhasesAll = total * 5;

    // Segmente für die Zeit-Budget-Bar: je ein proportionales Segment pro Bewohner
    const maxMins = Math.max(1, ...patients.map((p) => estimateMinutes(bewById(p.id))));

    return (
      <div className="vt-start-shell vt-start-reveal">
        {/* ======= Hero-Spalte ======= */}
        <div className="vt-hero-col">
          <div className="vt-hero-eyebrow">
            <span className="vt-hero-eyebrow-dot" />
            Heute live
          </div>
          <h1 className="vt-hero-title-v2">
            Bereit für die <em>Visite</em>.
          </h1>
          <div className="vt-hero-date">
            <strong>{dateStr}</strong> · Start <strong>{startStr}</strong>
          </div>
          <p className="vt-hero-lead">
            Fünf strukturierte Phasen pro Bewohner:in — nach deutschem Pflegeheim-Standard.
            Briefing von der Pflege, Sichtungs-Checkliste, Diktat per Stimme, Entscheidungen direkt freigeben, Protokoll mit Doppelsignatur.
          </p>

          {!speechSupported && (
            <div className="vt-warn" style={{ maxWidth: 480 }}>
              <Icon name="warning" size={14} />
              <div>
                <strong>Hinweis:</strong> Browser ohne Web Speech API — Tastatur-Eingabe bleibt aktiv.
                Empfohlen: Chrome, Edge oder Safari (iOS 17+).
              </div>
            </div>
          )}
        </div>

        {/* ======= Stats-Panel ======= */}
        <div className="vt-stats-panel">
          <div className="vt-stats-title">Tagesübersicht</div>
          <div className="vt-stats-hero-num">
            {total}<span className="vt-stats-hero-unit">Bewohner</span>
          </div>

          <div className="vt-budget">
            <div className="vt-budget-label">
              Zeitbudget
              <span className="vt-budget-value">~{totalMin} Min · {totalPhasesAll} Phasen</span>
            </div>
            <div className="vt-budget-bar" title="Zeit pro Bewohner:in proportional">
              {patients.map((p, i) => {
                const b = bewById(p.id);
                const mins = estimateMinutes(b);
                const pending = (window.ANFRAGEN || []).filter((a) => a.bewohner === p.id && a.status === "offen");
                const highPrio = pending.some((a) => a.prio === "H" || a.prio === "U");
                return (
                  <div
                    key={p.id}
                    className="vt-budget-seg"
                    data-tone={highPrio ? "prio" : ""}
                    style={{ flex: mins, opacity: 0.6 + 0.4 * (mins / maxMins) }}
                    title={`${b?.name} · ~${mins} Min`}
                  />
                );
              })}
            </div>
            <div className="vt-budget-end">
              <span>Voraussichtlich fertig um <strong>{endStr}</strong></span>
              {priorityCount > 0 && (
                <span className="vt-budget-priocount">
                  <span />
                  {priorityCount} Priorität
                </span>
              )}
            </div>
          </div>
        </div>

        {/* ======= Patientenliste ======= */}
        <div className="vt-queue-v2" style={{ gridColumn: "1 / -1" }}>
          <div className="vt-queue-title-v2">
            Reihenfolge
            <em>{total} Einträge · ziehen zum Umsortieren</em>
          </div>
          {patients.map((p, i) => {
            const b = bewById(p.id);
            if (!b) return null;
            const prophs = prophylaxenFor(b);
            const mins = estimateMinutes(b);
            const pending = (window.ANFRAGEN || []).filter((a) => a.bewohner === b.id && a.status === "offen");
            const highPrio = pending.some((a) => a.prio === "H" || a.prio === "U");
            const isNext = i === 0;
            return (
              <div
                key={p.id}
                className="vt-pcard"
                data-next={isNext}
                data-prio={highPrio}
                draggable
                onDragStart={(e) => { e.dataTransfer.setData("idx", String(i)); e.currentTarget.classList.add("dragging"); }}
                onDragEnd={(e) => e.currentTarget.classList.remove("dragging")}
                onDragOver={(e) => e.preventDefault()}
                onDrop={(e) => {
                  e.preventDefault();
                  const from = parseInt(e.dataTransfer.getData("idx"), 10);
                  if (!isNaN(from) && from !== i) onReorder(from, i);
                }}
              >
                {isNext && (
                  <div className="vt-pcard-next-badge">
                    Nächste
                  </div>
                )}
                <div className="vt-pcard-num">{i + 1}</div>
                <div className="vt-pcard-info">
                  <div className="vt-pcard-name-row">
                    <span className="vt-pcard-name">{b.name}</span>
                    <span className="vt-pcard-age">{b.alter} J.</span>
                  </div>
                  <div className="vt-pcard-meta">
                    <span>Zimmer <strong style={{ color: "var(--fg)" }}>{b.zimmer}</strong></span>
                    <span className="vt-pcard-meta-dot" />
                    <span>PG {b.pflegegrad}</span>
                    <span className="vt-pcard-meta-dot" />
                    <span>{heimName(b.heim).replace("Haus ", "").replace("Seniorenzentrum ", "").replace("Pflegeheim ", "")}</span>
                  </div>
                  <div className="vt-pcard-flags">
                    {highPrio && <span className="vt-pcard-prio">Priorität</span>}
                    {(b.allergien || []).length > 0 && (
                      <span className="vt-flag" data-t="allergy">Allergie: {b.allergien[0]}</span>
                    )}
                    {prophs.slice(0, 2).map((f, k) => (
                      <span key={k} className="vt-flag" data-t={f.t === "sturz" ? "alert" : "med"}>{f.l}</span>
                    ))}
                    {pending.length > 0 && (
                      <span className="vt-flag" data-t="med">{pending.length} offen</span>
                    )}
                  </div>
                </div>
                <div className="vt-pcard-right">
                  <div className="vt-pcard-time">
                    <div className="vt-pcard-time-v">{mins}'</div>
                    <div className="vt-pcard-time-l">geplant</div>
                  </div>
                  <button className="vt-icon-btn" onClick={() => onRemove(i)} aria-label="Entfernen" title="Aus der Tour entfernen">
                    <Icon name="x" size={13} />
                  </button>
                </div>
              </div>
            );
          })}
        </div>

        {/* ======= Journey-Bar ======= */}
        <div className="vt-journey" style={{ gridColumn: "1 / -1" }}>
          <div className="vt-journey-ico">
            <Icon name="clock" size={16} />
          </div>
          <div className="vt-journey-body">
            <div className="vt-journey-title">Route</div>
            <div className="vt-journey-text">
              <strong>{startStr}</strong> &nbsp;→&nbsp; {total} Bewohner × 5 Phasen &nbsp;→&nbsp; <strong>{endStr}</strong>
            </div>
          </div>
        </div>

        {/* ======= CTA ======= */}
        <div className="vt-start-cta-v2" style={{ gridColumn: "1 / -1" }}>
          <button className="vt-btn-secondary" onClick={onCancel}>Abbrechen</button>
          <button className="vt-btn-primary" onClick={onStart} disabled={total === 0}>
            <Icon name="play" size={14} /> Visite starten<span className="vt-btn-kbd">⏎</span>
          </button>
        </div>
      </div>
    );
  };

  // ================================================================
  // Patient Screen — hat Phasen-Tabs und leitet auf richtige Phase
  // ================================================================
  const PatientScreen = (props) => {
    const { bewohner, patient, headerCompact, specialty, visitArzt } = props;
    const phase = patient.phase || "briefing";
    const spec = SPECIALTY_CONFIG[specialty] || SPECIALTY_CONFIG.Hausarzt;
    const arzt = visitArzt ? (window.DOCTORS || []).find((d) => d.id === visitArzt) : null;

    // Slide-Richtung: forward (neue Phase kommt von rechts) vs. back (kommt von links)
    const prevPhaseRef = useRef(phase);
    const [direction, setDirection] = useState("forward");
    useEffect(() => {
      const prevIdx = PHASE_ORDER.indexOf(prevPhaseRef.current);
      const nextIdx = PHASE_ORDER.indexOf(phase);
      setDirection(nextIdx < prevIdx ? "back" : "forward");
      prevPhaseRef.current = phase;
    }, [phase]);

    // Patient-context ist jetzt im Top-Bar. Nur während Briefing zeigen wir
    // zusätzlich die große Name/Chips-Karte — als „Patient-Intro".
    const showIntroHead = phase === "briefing" && !patient.briefingAcknowledged;

    return (
      <div className="vt-patient">
        {/* Sticky Stepper — immer sichtbar beim Scroll */}
        <div className="vt-stepper-compact vt-stepper-sticky">
          <PhaseStepper patient={patient} onSet={props.onSetPhase} />
        </div>

        {/* Patient-Intro nur während Briefing (große Name-Karte + Chips) */}
        {showIntroHead && (
          <div className="vt-patient-head vt-patient-intro">
            <div className="vt-patient-avatar">{firstInitial(bewohner.name)}</div>
            <div className="vt-patient-id">
              <div className="vt-patient-name">
                {bewohner.name}
                {specialty !== "Hausarzt" && (
                  <span className="vt-spec-pill" data-tone={spec.tone} title={arzt ? `Konsil: ${arzt.name}` : spec.tagline}>
                    <span className="vt-spec-pill-mark">{spec.short}</span>
                    <span className="vt-spec-pill-label">{spec.label}</span>
                  </span>
                )}
              </div>
              <div className="vt-patient-meta">
                {bewohner.alter} J. · PG {bewohner.pflegegrad}
              </div>
              <div className="vt-patient-chips">
                {(bewohner.allergien || []).length > 0 && (
                  <span className="vt-flag" data-t="allergy">Allergie: {bewohner.allergien.join(", ")}</span>
                )}
                {(bewohner.diagnosen || []).slice(0, 2).map((d, i) => (
                  <span key={i} className="vt-flag" data-t="med">{d}</span>
                ))}
              </div>
            </div>
          </div>
        )}

        {/* Aktive Phase mit Slide-Transition */}
        <div className="vt-phase-content vt-phase-swap" data-direction={direction} key={phase}>
          {phase === "briefing" && <BriefingPhase {...props} />}
          {phase === "sichtung" && <SichtungPhase {...props} />}
          {phase === "gespraech" && <GespraechPhase {...props} />}
          {phase === "entscheidung" && <EntscheidungPhase {...props} />}
          {phase === "protokoll" && <ProtokollPhase {...props} />}
        </div>
      </div>
    );
  };

  // Phase-Tab-Bar
  const PhaseStepper = ({ patient, onSet }) => {
    return (
      <div className="vt-stepper">
        {PHASES.map((ph, i) => {
          const isCurrent = patient.phase === ph.key;
          const isDone = isPhaseDone(patient, ph.key);
          return (
            <button
              key={ph.key}
              className="vt-step"
              data-current={isCurrent}
              data-done={isDone}
              onClick={() => onSet(ph.key)}
            >
              <span className="vt-step-num">
                {isDone ? <Icon name="check" size={12} /> : i + 1}
              </span>
              <span className="vt-step-lbl">{ph.label}</span>
              <span className="vt-step-min">~{ph.min}'</span>
            </button>
          );
        })}
      </div>
    );
  };

  const isPhaseDone = (patient, phaseKey) => {
    if (phaseKey === "briefing") return !!patient.briefingAcknowledged;
    if (phaseKey === "sichtung") {
      const items = Object.values(patient.sichtung || {});
      return items.filter((it) => it.status).length >= 3; // min 3 von 7 bewertet
    }
    if (phaseKey === "gespraech") return !!(patient.soap.S || patient.soap.O || patient.soap.A || patient.soap.P);
    if (phaseKey === "entscheidung") return Object.keys(patient.medActions || {}).length > 0 || Object.keys(patient.anfrageActions || {}).length > 0;
    if (phaseKey === "protokoll") return !!patient.signedByDoctor;
    return false;
  };

  // ================================================================
  // Phase 1: BRIEFING
  // ================================================================
  const BriefingPhase = ({ patient, onAckBriefing, specialty, visitAnlass }) => {
    const b = patient.briefing;
    if (!b) return null;
    const spec = SPECIALTY_CONFIG[specialty] || SPECIALTY_CONFIG.Hausarzt;
    const isKonsil = specialty !== "Hausarzt";
    return (
      <div className="vt-card vt-briefing">
        {isKonsil && (
          <div className={`vt-role-focus vt-role-${spec.tone}`}>
            <div className="vt-role-focus-head">
              <span className="vt-role-badge" data-tone={spec.tone}>{spec.short}</span>
              <div>
                <div className="vt-role-focus-title">{spec.label}-Fokus</div>
                <div className="vt-role-focus-sub">{visitAnlass || spec.tagline}</div>
              </div>
            </div>
            <ul className="vt-role-focus-list">
              {spec.focus.map((f, i) => <li key={i}>{f}</li>)}
            </ul>
          </div>
        )}
        <div className="vt-card-head">
          <div>
            <div className="vt-card-title">SBAR-Briefing von der Pflege</div>
            <div style={{ fontSize: 11, color: "var(--fg-subtle)", marginTop: 3 }}>
              {b.pflegekraft} · {b.schicht} · {b.zeit}
            </div>
          </div>
          {patient.briefingAcknowledged && (
            <span className="vt-flag" data-t="med" style={{ color: "var(--success)", background: "var(--success-tint)", borderColor: "var(--success-border)" }}>
              <Icon name="check" size={10} /> Gelesen
            </span>
          )}
        </div>
        <div className="vt-card-body">
          <div className="vt-sbar">
            <div className="vt-sbar-row">
              <div className="vt-sbar-letter">S</div>
              <div className="vt-sbar-body">
                <div className="vt-sbar-name">Situation</div>
                <div className="vt-sbar-text">{b.situation}</div>
              </div>
            </div>
            <div className="vt-sbar-row">
              <div className="vt-sbar-letter">B</div>
              <div className="vt-sbar-body">
                <div className="vt-sbar-name">Background</div>
                <div className="vt-sbar-text">{b.background}</div>
              </div>
            </div>
            <div className="vt-sbar-row">
              <div className="vt-sbar-letter">A</div>
              <div className="vt-sbar-body">
                <div className="vt-sbar-name">Assessment</div>
                <div className="vt-sbar-text">{b.assessment}</div>
              </div>
            </div>
            <div className="vt-sbar-row" data-accent="true">
              <div className="vt-sbar-letter">R</div>
              <div className="vt-sbar-body">
                <div className="vt-sbar-name">Recommendation</div>
                <div className="vt-sbar-text">{b.recommendation}</div>
              </div>
            </div>
          </div>
          {!patient.briefingAcknowledged && (
            <div style={{ display: "flex", gap: 8, marginTop: 16, justifyContent: "flex-end" }}>
              <button className="vt-btn-primary" onClick={onAckBriefing}>
                <Icon name="check" size={13} /> Verstanden · weiter zur Sichtung
              </button>
            </div>
          )}
        </div>
      </div>
    );
  };

  // ================================================================
  // Phase 2: SICHTUNG (visuelle/körperliche Begutachtung)
  // ================================================================
  const SichtungPhase = ({ patient, onSetSichtung, onSetPhase, specialty }) => {
    const spec = SPECIALTY_CONFIG[specialty] || SPECIALTY_CONFIG.Hausarzt;
    const items = spec.sichtung;
    const title = specialty === "Hausarzt" ? "Körperliche Begutachtung" : `Begutachtung · ${spec.label}`;
    const quickOk = () => {
      items.forEach((it) => {
        if (!patient.sichtung[it.key]?.status) {
          onSetSichtung(it.key, { status: "ok" });
        }
      });
    };
    return (
      <div className="vt-card">
        <div className="vt-card-head">
          <div className="vt-card-title">{title}</div>
          <button className="vt-btn-ghost" style={{ minHeight: 32, fontSize: 12 }} onClick={quickOk}>
            <Icon name="check" size={12} /> Alles o.B.
          </button>
        </div>
        <div className="vt-card-body">
          <div className="vt-checklist">
            {items.map((it) => {
              const current = patient.sichtung[it.key] || { status: "", note: "" };
              return (
                <div key={it.key} className="vt-check-row" data-status={current.status}>
                  <div className="vt-check-main">
                    <div className="vt-check-label">{it.label}</div>
                    <div className="vt-check-hint">{it.hint}</div>
                  </div>
                  <div className="vt-check-seg">
                    <button
                      className="vt-check-btn"
                      data-active={current.status === "ok"}
                      data-tone="ok"
                      onClick={() => onSetSichtung(it.key, { status: "ok" })}
                      aria-label="Unauffällig"
                    ><Icon name="check" size={12} /></button>
                    <button
                      className="vt-check-btn"
                      data-active={current.status === "flag"}
                      data-tone="flag"
                      onClick={() => onSetSichtung(it.key, { status: "flag" })}
                      aria-label="Auffällig"
                    ><Icon name="warning" size={12} /></button>
                    <button
                      className="vt-check-btn"
                      data-active={current.status === "na"}
                      data-tone="na"
                      onClick={() => onSetSichtung(it.key, { status: "na" })}
                      aria-label="Nicht anwendbar"
                    >—</button>
                  </div>
                  {current.status === "flag" && (
                    <div className="vt-check-note">
                      <input
                        type="text"
                        placeholder="Details (z. B. Stelle, Größe, Heilungsverlauf) …"
                        value={current.note || ""}
                        onChange={(e) => onSetSichtung(it.key, { note: e.target.value })}
                        onBlur={(e) => onSetSichtung(it.key, { note: e.target.value })}
                      />
                    </div>
                  )}
                </div>
              );
            })}
          </div>
          <div style={{ display: "flex", gap: 8, marginTop: 16, justifyContent: "flex-end" }}>
            <button className="vt-btn-primary" onClick={() => onSetPhase("gespraech")}>
              <Icon name="arrowRight" size={13} /> Weiter zum Gespräch
            </button>
          </div>
        </div>
      </div>
    );
  };

  // ================================================================
  // Phase 3: GESPRÄCH (Dictation + Vitalwerte)
  // ================================================================
  const GespraechPhase = (props) => {
    const { bewohner, patient, listening, interim, cmdChip, speechSupported,
            onToggleMic, onSetSoapActive, onUpdateSoap, onUpdateVital, onSetPhase,
            specialty, onSetAssessment } = props;
    const spec = SPECIALTY_CONFIG[specialty] || SPECIALTY_CONFIG.Hausarzt;
    const SOAPS = [
      { key: "S", name: "Subjektiv" },
      { key: "O", name: "Objektiv" },
      { key: "A", name: "Beurteilung" },
      { key: "P", name: "Plan" },
    ];
    const vitalsTitle = specialty === "Hausarzt" ? "Vitalwerte" : `Vitalwerte · ${spec.label}`;
    return (
      <>
        {/* Vitalwerte — rolle-spezifisch */}
        <div className="vt-card" style={{ marginBottom: 12 }}>
          <div className="vt-card-head">
            <div className="vt-card-title">{vitalsTitle}</div>
            <div style={{ fontSize: 11, color: "var(--fg-subtle)" }}>Letzte Messung</div>
          </div>
          <div className="vt-card-body">
            <div className="vt-vitals">
              {spec.vitals.map((v) => (
                <VitalTile
                  key={v.key}
                  label={v.label}
                  value={patient.vitals[v.key] ?? ""}
                  unit={v.unit || ""}
                  hint={v.hint}
                  onEdit={(val) => onUpdateVital(v.key, val)}
                />
              ))}
            </div>
            {specialty === "Hausarzt" && (
              <div style={{ fontSize: 11, color: "var(--fg-subtle)", marginTop: 10, lineHeight: 1.4 }}>
                Oder sagen Sie: <em>„Blutdruck 140 zu 90"</em>, <em>„Puls 78"</em>, <em>„Temperatur 36 Komma 8"</em>.
              </div>
            )}
          </div>
        </div>

        {/* Role-spezifische Assessments */}
        {spec.assessments && spec.assessments.length > 0 && (
          <div className="vt-card" style={{ marginBottom: 12 }}>
            <div className="vt-card-head">
              <div className="vt-card-title">{spec.label}-Assessment</div>
              <span className="vt-role-badge" data-tone={spec.tone}>{spec.short}</span>
            </div>
            <div className="vt-card-body">
              <div className="vt-assess-grid">
                {spec.assessments.map((a) => (
                  <AssessmentTile
                    key={a.key}
                    config={a}
                    value={(patient.assessments || {})[a.key]}
                    onChange={(v) => onSetAssessment(a.key, v)}
                  />
                ))}
              </div>
            </div>
          </div>
        )}

        {/* Dictation */}
        <div className="vt-dict">
          {cmdChip && <div className="vt-cmd-chip" data-show="true">✓ {cmdChip}</div>}

          <div className="vt-dict-status" data-live={listening}>
            <div className="vt-dict-status-label">{listening ? "Hört zu …" : "Diktat bereit"}</div>
            <div className="vt-dict-lang">DE-DE</div>
          </div>

          <button
            className="vt-mic"
            data-live={listening}
            onClick={onToggleMic}
            aria-label={listening ? "Mikrofon stoppen" : "Mikrofon starten"}
            disabled={!speechSupported}
          >
            <Icon name={listening ? "pause" : "mic"} size={32} />
          </button>

          <div className="vt-wave" aria-hidden="true">
            {Array.from({ length: 11 }).map((_, i) => <span key={i} />)}
          </div>

          <div className="vt-transcript">
            {patient.note || interim ? (
              <>
                <span>{patient.note}</span>
                {interim && <span className="interim">{patient.note ? " " : ""}{interim}</span>}
              </>
            ) : (
              <span className="vt-transcript-hint">
                {speechSupported
                  ? `Sprechen Sie natürlich. „Objektiv" / „Beurteilung" / „Plan" wechselt die SOAP-Sektion.`
                  : "Browser ohne Spracherkennung — bitte direkt in die S/O/A/P-Felder tippen."}
              </span>
            )}
          </div>

          <div className="vt-soap">
            {SOAPS.map((s) => (
              <div
                key={s.key}
                className="vt-soap-box"
                data-active={patient.soap.active === s.key}
                onClick={() => onSetSoapActive(s.key)}
                role="button"
              >
                <div className="vt-soap-head">
                  <div className="vt-soap-letter">{s.key}</div>
                  <div className="vt-soap-name">{s.name}</div>
                </div>
                {speechSupported ? (
                  <div className="vt-soap-content">{patient.soap[s.key]}</div>
                ) : (
                  <textarea
                    value={patient.soap[s.key]}
                    onChange={(e) => onUpdateSoap(s.key, e.target.value)}
                    style={{ width: "100%", minHeight: 40, border: 0, background: "transparent", color: "var(--fg)", fontFamily: "inherit", fontSize: 12.5, resize: "vertical" }}
                  />
                )}
              </div>
            ))}
          </div>
        </div>

        <div style={{ display: "flex", gap: 8, marginTop: 16, justifyContent: "flex-end" }}>
          <button className="vt-btn-primary" onClick={() => onSetPhase("entscheidung")}>
            <Icon name="arrowRight" size={13} /> Weiter zu Entscheidungen
          </button>
        </div>
      </>
    );
  };

  // ================================================================
  // Phase 4: ENTSCHEIDUNG (Medikation + Folgetermin)
  // ================================================================
  const EntscheidungPhase = ({ bewohner, patient, onSetMedAction, onSetAnfrageAction, onSetFollowUp, onToggleLab, onToggleNurse, onSetPhase, specialty }) => {
    const spec = SPECIALTY_CONFIG[specialty] || SPECIALTY_CONFIG.Hausarzt;
    const plan = (window.MEDPLAN || {})[bewohner.id] || [];
    const pending = (window.ANFRAGEN || []).filter((a) => a.bewohner === bewohner.id && a.status === "offen");
    return (
      <>
        {pending.length > 0 && (
          <div className="vt-card" style={{ marginBottom: 12 }}>
            <div className="vt-card-head">
              <div className="vt-card-title">Offene Anfragen <em style={{ fontStyle: "normal", color: "var(--fg-subtle)", fontWeight: 500, marginLeft: 6 }}>· {pending.length}</em></div>
            </div>
            <div className="vt-card-body">
              {pending.map((a) => {
                const action = patient.anfrageActions[a.id];
                return (
                  <div key={a.id} className="vt-decision-row">
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ fontSize: 13, fontWeight: 600, letterSpacing: "-0.005em" }}>{a.med}</div>
                      <div style={{ fontSize: 11.5, color: "var(--fg-subtle)", marginTop: 2 }}>
                        {a.typ} · {a.dosis} · {a.dauer} {a.prio === "H" && " · Priorität"}
                        {a.notiz && <div style={{ marginTop: 4, color: "var(--fg-muted)" }}>„{a.notiz}"</div>}
                      </div>
                    </div>
                    <div className="vt-decision-actions">
                      <button className="vt-decision-btn" data-active={action === "reject"} data-tone="reject"
                        onClick={() => onSetAnfrageAction(a.id, action === "reject" ? null : "reject")}>
                        Ablehnen
                      </button>
                      <button className="vt-decision-btn" data-active={action === "approve"} data-tone="approve"
                        onClick={() => onSetAnfrageAction(a.id, action === "approve" ? null : "approve")}>
                        <Icon name="check" size={12} /> Freigeben
                      </button>
                    </div>
                  </div>
                );
              })}
            </div>
          </div>
        )}

        {(() => {
          // Role-priorisierte Medikationsliste: wirkstoff-relevante Medikamente zuerst
          const highlightRe = spec.medHighlightRe;
          const highlighted = highlightRe ? plan.filter((m) => highlightRe.test(m.med)) : [];
          const others = highlightRe ? plan.filter((m) => !highlightRe.test(m.med)) : plan;

          const renderRow = (m, i, flagged) => {
            const action = patient.medActions[m.med];
            return (
              <div key={`${flagged ? "h" : "o"}-${i}`} className="vt-decision-row" data-flag={flagged ? "role" : undefined}>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ fontSize: 13, fontWeight: 500, display: "flex", alignItems: "center", gap: 6 }}>
                    {flagged && <span className="vt-role-dot" data-tone={spec.tone} title={`${spec.label}-Fokus`} />}
                    {m.med}
                  </div>
                  <div style={{ fontSize: 11, color: "var(--fg-subtle)", marginTop: 2, fontFamily: "var(--font-mono)" }}>{m.dosis}{m.grund ? ` · ${m.grund}` : ""}</div>
                </div>
                <div className="vt-decision-actions">
                  <button className="vt-decision-btn" data-active={action === "continue" || !action} data-tone="approve"
                    onClick={() => onSetMedAction(m.med, "continue")}>
                    Fortsetzen
                  </button>
                  <button className="vt-decision-btn" data-active={action === "modify"} data-tone="modify"
                    onClick={() => onSetMedAction(m.med, action === "modify" ? null : "modify")}>
                    Ändern
                  </button>
                  <button className="vt-decision-btn" data-active={action === "stop"} data-tone="reject"
                    onClick={() => onSetMedAction(m.med, action === "stop" ? null : "stop")}>
                    {specialty === "Nervenarzt" ? "Reduzieren" : "Absetzen"}
                  </button>
                </div>
              </div>
            );
          };

          return (
            <>
              {highlighted.length > 0 && (
                <div className="vt-card vt-card-accent" data-tone={spec.tone} style={{ marginBottom: 12 }}>
                  <div className="vt-card-head">
                    <div className="vt-card-title">{spec.label}-relevante Medikation</div>
                    <div style={{ fontSize: 11, color: "var(--fg-subtle)" }}>{highlighted.length} Wirkstoff{highlighted.length > 1 ? "e" : ""}</div>
                  </div>
                  <div className="vt-card-body">
                    {highlighted.map((m, i) => renderRow(m, i, true))}
                  </div>
                </div>
              )}
              <div className="vt-card" style={{ marginBottom: 12 }}>
                <div className="vt-card-head">
                  <div className="vt-card-title">{highlighted.length > 0 ? "Übrige Medikation" : "Medikationsplan"}</div>
                  <div style={{ fontSize: 11, color: "var(--fg-subtle)" }}>Pro Wirkstoff entscheiden</div>
                </div>
                <div className="vt-card-body">
                  {others.length === 0 ? (
                    <div style={{ fontSize: 12.5, color: "var(--fg-subtle)", fontStyle: "italic" }}>
                      {plan.length === 0 ? "Kein aktiver Medikationsplan." : "Alle Wirkstoffe bereits oben priorisiert."}
                    </div>
                  ) : (
                    others.map((m, i) => renderRow(m, i, false))
                  )}
                </div>
              </div>
            </>
          );
        })()}

        <div className="vt-card" style={{ marginBottom: 12 }}>
          <div className="vt-card-head">
            <div className="vt-card-title">Folgetermin & Ergänzungen</div>
          </div>
          <div className="vt-card-body">
            <div className="vt-followup">
              <div className="vt-followup-label">Nächster Kontakt in</div>
              <div className="vt-followup-seg">
                {[7, 14, 30, 90].map((d) => (
                  <button key={d} className="vt-followup-btn" data-active={patient.followUpDays === d} onClick={() => onSetFollowUp(d)}>
                    {d < 30 ? `${d} Tagen` : d === 30 ? "1 Monat" : "3 Monate"}
                  </button>
                ))}
              </div>
            </div>
            <div className="vt-checkline" onClick={onToggleLab}>
              <div className={`vt-mini-check ${patient.labOrdered ? "checked" : ""}`}>
                {patient.labOrdered && <Icon name="check" size={10} />}
              </div>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13, fontWeight: 500 }}>Laborwerte anfordern</div>
                <div style={{ fontSize: 11, color: "var(--fg-subtle)" }}>BB, CRP, Krea, Elektrolyte</div>
              </div>
            </div>
            <div className="vt-checkline" onClick={onToggleNurse}>
              <div className={`vt-mini-check ${patient.nurseRequested ? "checked" : ""}`}>
                {patient.nurseRequested && <Icon name="check" size={10} />}
              </div>
              <div style={{ flex: 1 }}>
                <div style={{ fontSize: 13, fontWeight: 500 }}>Pflege-Konsil anfordern</div>
                <div style={{ fontSize: 11, color: "var(--fg-subtle)" }}>Rücksprache zur Umsetzung der Empfehlungen</div>
              </div>
            </div>
          </div>
        </div>

        <div style={{ display: "flex", gap: 8, justifyContent: "flex-end" }}>
          <button className="vt-btn-primary" onClick={() => onSetPhase("protokoll")}>
            <Icon name="arrowRight" size={13} /> Protokoll vorbereiten
          </button>
        </div>
      </>
    );
  };

  // ================================================================
  // Phase 5: PROTOKOLL (Preview + Signaturen)
  // ================================================================
  const ProtokollPhase = ({ bewohner, patient, onSignNurse, onSignDoctor, specialty, onToggleProtokollCheck }) => {
    const spec = SPECIALTY_CONFIG[specialty] || SPECIALTY_CONFIG.Hausarzt;
    const sichtungEntries = Object.entries(patient.sichtung || {})
      .map(([k, v]) => ({ key: k, ...v, label: spec.sichtung.find((x) => x.key === k)?.label }))
      .filter((e) => e.status);
    const soapLines = [
      patient.soap.S && `S: ${patient.soap.S}`,
      patient.soap.O && `O: ${patient.soap.O}`,
      patient.soap.A && `A: ${patient.soap.A}`,
      patient.soap.P && `P: ${patient.soap.P}`,
    ].filter(Boolean);
    const approvedAnfr = Object.entries(patient.anfrageActions || {}).filter(([, v]) => v === "approve").map(([k]) => k);
    const rejectedAnfr = Object.entries(patient.anfrageActions || {}).filter(([, v]) => v === "reject").map(([k]) => k);
    const medStop = Object.entries(patient.medActions || {}).filter(([, v]) => v === "stop").map(([k]) => k);
    const medMod = Object.entries(patient.medActions || {}).filter(([, v]) => v === "modify").map(([k]) => k);

    const fullySigned = patient.signedByNurse && patient.signedByDoctor;
    const openSigs = (patient.signedByNurse ? 0 : 1) + (patient.signedByDoctor ? 0 : 1);
    return (
      <>
        <div className="vt-card vt-protokoll" data-complete={fullySigned} style={{ marginBottom: 12 }}>
          <div className="vt-card-head">
            <div className="vt-card-title">Visiten-Protokoll</div>
            <div style={{ fontSize: 11, color: "var(--fg-subtle)" }}>
              {new Date().toLocaleDateString("de-DE", { weekday: "short", day: "numeric", month: "long", year: "numeric" })}
            </div>
          </div>
          <div className="vt-card-body">
            <div className="vt-protokoll-head">
              <div className="vt-protokoll-name">{bewohner.name}</div>
              <div className="vt-protokoll-meta">
                Zi. {bewohner.zimmer} · PG {bewohner.pflegegrad} · {heimName(bewohner.heim)}
              </div>
            </div>

            {/* Summary-first: Pending-Action-Banner oben, damit User ohne Scroll weiß was zu tun ist */}
            {!fullySigned ? (
              <div className="vt-protokoll-cta" data-state="pending">
                <div className="vt-protokoll-cta-icon" aria-hidden="true">
                  <Icon name="edit" size={16} />
                </div>
                <div className="vt-protokoll-cta-text">
                  <div className="vt-protokoll-cta-title">
                    {openSigs === 2 ? "Zwei Unterschriften offen" : "Eine Unterschrift offen"}
                  </div>
                  <div className="vt-protokoll-cta-sub">
                    Protokoll prüfen, dann unten signieren.
                  </div>
                </div>
                <div className="vt-protokoll-cta-dots" aria-hidden="true">
                  <span data-ok={patient.signedByNurse} title="Bezugspflege" />
                  <span data-ok={patient.signedByDoctor} title="Arzt/Ärztin" />
                </div>
              </div>
            ) : (
              <div className="vt-protokoll-cta" data-state="done">
                <div className="vt-protokoll-cta-icon" aria-hidden="true">
                  <Icon name="check" size={16} />
                </div>
                <div className="vt-protokoll-cta-text">
                  <div className="vt-protokoll-cta-title">Protokoll signiert</div>
                  <div className="vt-protokoll-cta-sub">
                    Übermittlung an Pflege erfolgt bei Tour-Ende.
                  </div>
                </div>
              </div>
            )}

            {/* Vitalwerte */}
            {Object.values(patient.vitals).some(Boolean) && (
              <ProtokollBlock title="Vitalwerte">
                <div className="vt-protokoll-vitals">
                  {patient.vitals.bp && <span><strong>RR</strong> {patient.vitals.bp} mmHg</span>}
                  {patient.vitals.pulse && <span><strong>Puls</strong> {patient.vitals.pulse}/min</span>}
                  {patient.vitals.temp && <span><strong>Temp</strong> {patient.vitals.temp} °C</span>}
                  {patient.vitals.spo2 && <span><strong>SpO₂</strong> {patient.vitals.spo2}%</span>}
                </div>
              </ProtokollBlock>
            )}

            {/* Sichtung */}
            {sichtungEntries.length > 0 && (
              <ProtokollBlock title="Sichtung">
                <ul className="vt-protokoll-list">
                  {sichtungEntries.map((e) => (
                    <li key={e.key}>
                      <strong>{e.label}</strong>{" · "}
                      {e.status === "ok" && <span style={{ color: "var(--success)" }}>unauffällig</span>}
                      {e.status === "flag" && <span style={{ color: "var(--warning)" }}>auffällig</span>}
                      {e.status === "na" && <span style={{ color: "var(--fg-muted)" }}>nicht anwendbar</span>}
                      {e.note && <span style={{ color: "var(--fg-muted)" }}> — {e.note}</span>}
                    </li>
                  ))}
                </ul>
              </ProtokollBlock>
            )}

            {/* SOAP-Notiz */}
            {soapLines.length > 0 && (
              <ProtokollBlock title="Untersuchung & Beurteilung">
                <div style={{ whiteSpace: "pre-wrap", fontSize: 13, lineHeight: 1.5, color: "var(--fg)" }}>
                  {soapLines.join("\n")}
                </div>
              </ProtokollBlock>
            )}

            {/* Entscheidungen */}
            {(approvedAnfr.length + rejectedAnfr.length + medStop.length + medMod.length > 0 || patient.followUpDays || patient.labOrdered || patient.nurseRequested) && (
              <ProtokollBlock title="Maßnahmen & Entscheidungen">
                <ul className="vt-protokoll-list">
                  {approvedAnfr.map((id) => <li key={id}><strong>Freigegeben:</strong> {id}</li>)}
                  {rejectedAnfr.map((id) => <li key={id}><strong>Abgelehnt:</strong> {id}</li>)}
                  {medMod.map((m) => <li key={m}><strong>Dosierung anpassen:</strong> {m}</li>)}
                  {medStop.map((m) => <li key={m}><strong>{specialty === "Nervenarzt" ? "Reduzieren/Absetzen" : "Absetzen"}:</strong> {m}</li>)}
                  {patient.labOrdered && <li><strong>Laborwerte angefordert</strong> (BB, CRP, Krea, Elektrolyte)</li>}
                  {patient.nurseRequested && <li><strong>Pflege-Konsil</strong> angefordert</li>}
                  {patient.followUpDays && <li><strong>Folgetermin</strong> in {patient.followUpDays} Tagen</li>}
                </ul>
              </ProtokollBlock>
            )}

            {/* Role-spezifische Pflichtpunkte */}
            {spec.protokollChecks && spec.protokollChecks.length > 0 && (
              <ProtokollBlock title={`${spec.label}-Pflichtpunkte`}>
                <div className="vt-protokoll-checks">
                  {spec.protokollChecks.map((ck) => (
                    <label key={ck} className="vt-protokoll-check">
                      <input
                        type="checkbox"
                        checked={!!(patient.protokollChecks || {})[ck]}
                        onChange={() => onToggleProtokollCheck?.(ck)}
                      />
                      <span>{ck}</span>
                    </label>
                  ))}
                </div>
              </ProtokollBlock>
            )}

            {/* Signaturen */}
            <ProtokollBlock title="Unterschriften">
              <div className="vt-signatures">
                <SignatureBox
                  role="Bezugspflegekraft"
                  name={patient.briefing?.pflegekraft || "Maria Lehmann"}
                  signed={patient.signedByNurse}
                  onSign={onSignNurse}
                />
                <SignatureBox
                  role="Arzt/Ärztin"
                  name="Dr. med. A. Schneider"
                  signed={patient.signedByDoctor}
                  onSign={onSignDoctor}
                />
              </div>
            </ProtokollBlock>

            {patient.signedByDoctor && patient.signedByNurse && (
              <div style={{ marginTop: 16, padding: 12, background: "var(--success-tint)", border: "1px solid var(--success-border)", borderRadius: 10, display: "flex", alignItems: "center", gap: 10 }}>
                <Icon name="check" size={16} style={{ color: "var(--success)" }} />
                <div style={{ fontSize: 13, color: "var(--success)", fontWeight: 600 }}>
                  Protokoll vollständig signiert · wird bei Tour-Ende an Pflege übermittelt
                </div>
              </div>
            )}
          </div>
        </div>
      </>
    );
  };

  const ProtokollBlock = ({ title, children }) => (
    <div className="vt-protokoll-block">
      <div className="vt-protokoll-block-title">{title}</div>
      <div className="vt-protokoll-block-body">{children}</div>
    </div>
  );

  const SignatureBox = ({ role, name, signed, onSign }) => (
    <div className="vt-sig" data-signed={signed}>
      <div className="vt-sig-role">{role}</div>
      <div className="vt-sig-name">{name}</div>
      {signed ? (
        <div className="vt-sig-mark">
          <Icon name="check" size={14} />
          <span>signiert · {new Date().toLocaleTimeString("de-DE", { hour: "2-digit", minute: "2-digit" })}</span>
        </div>
      ) : (
        <button className="vt-btn-secondary" style={{ minHeight: 36, fontSize: 12 }} onClick={onSign}>
          Hier signieren
        </button>
      )}
    </div>
  );

  // ---------------- Vital tile ----------------
  const VitalTile = ({ label, value, unit, hint, onEdit }) => {
    const [editing, setEditing] = useState(false);
    const [draft, setDraft] = useState(value || "");
    useEffect(() => { setDraft(value || ""); }, [value]);
    return (
      <div className="vt-vital" data-new={!!value} onClick={() => !editing && setEditing(true)} role="button" title={hint || ""}>
        <div>
          {editing ? (
            <input
              autoFocus
              value={draft}
              onChange={(e) => setDraft(e.target.value)}
              onBlur={() => { setEditing(false); onEdit?.(draft); }}
              onKeyDown={(e) => { if (e.key === "Enter") e.target.blur(); }}
              style={{ width: "100%", border: 0, background: "transparent", color: "var(--fg)", fontFamily: "var(--font-serif)", fontSize: 20, fontWeight: 500, letterSpacing: "-0.02em", outline: "none" }}
            />
          ) : (
            <span className="vt-vital-v">
              {value || "—"}
              {value && unit && <span className="vt-vital-u"> {unit}</span>}
            </span>
          )}
        </div>
        <div className="vt-vital-l">{label}</div>
        {hint && <div className="vt-vital-h">{hint}</div>}
      </div>
    );
  };

  // ---------------- AssessmentTile: role-specific score/toggle/select/scale ----------------
  const AssessmentTile = ({ config, value, onChange }) => {
    const { type, label, options, min, max, suffix } = config;
    if (type === "toggle") {
      const on = !!value;
      return (
        <button
          className="vt-assess-tile"
          data-type="toggle"
          data-on={on}
          onClick={() => onChange(!on)}
          type="button"
        >
          <div className="vt-assess-l">{label}</div>
          <div className="vt-assess-v">{on ? (config.label_on || "ja") : "–"}</div>
        </button>
      );
    }
    if (type === "scale") {
      return (
        <div className="vt-assess-tile" data-type="scale">
          <div className="vt-assess-l">{label}</div>
          <div className="vt-assess-scale">
            {Array.from({ length: (max - min + 1) }).map((_, i) => {
              const n = min + i;
              return (
                <button key={n} className="vt-assess-dot" data-active={value === n} onClick={() => onChange(n)} type="button">
                  {n}
                </button>
              );
            })}
          </div>
        </div>
      );
    }
    if (type === "select") {
      return (
        <div className="vt-assess-tile" data-type="select">
          <div className="vt-assess-l">{label}</div>
          <div className="vt-assess-pills">
            {options.map((opt) => (
              <button
                key={opt}
                className="vt-assess-pill"
                data-active={value === opt}
                onClick={() => onChange(opt)}
                type="button"
              >
                {opt}
              </button>
            ))}
          </div>
        </div>
      );
    }
    // number default
    return (
      <div className="vt-assess-tile" data-type="number">
        <div className="vt-assess-l">{label}</div>
        <input
          type="number"
          className="vt-assess-input"
          value={value || ""}
          onChange={(e) => onChange(e.target.value)}
          placeholder="—"
        />
        {suffix && <span className="vt-assess-suffix">{suffix}</span>}
      </div>
    );
  };

  // ---------------- End Screen ----------------
  const EndScreen = ({ patients, elapsed, doneCount, onRestart, onHandoff, onClose }) => {
    const skipped = patients.filter((p) => p.status === "skip").length;
    const signedCount = patients.filter((p) => p.signedByDoctor).length;
    return (
      <div className="vt-end">
        <div className="vt-end-check">
          <Icon name="check" size={28} />
        </div>
        <div className="vt-end-title">Visite abgeschlossen.</div>
        <div className="vt-end-sub">
          {doneCount} Bewohner:innen dokumentiert · {signedCount} signiert · {fmtTime(elapsed)} insgesamt
          {skipped > 0 && ` · ${skipped} übersprungen`}
        </div>

        <div className="vt-end-summary">
          {patients.filter((p) => p.status === "done").map((p) => {
            const b = bewById(p.id);
            if (!b) return null;
            const sichtungN = Object.values(p.sichtung || {}).filter((e) => e.status).length;
            const hasNote = !!(p.soap.S || p.soap.O || p.soap.A || p.soap.P);
            const decisionsN = Object.keys(p.medActions || {}).length + Object.keys(p.anfrageActions || {}).length;
            return (
              <div key={p.id} className="vt-end-row">
                <div className="vt-end-row-avatar">{firstInitial(b.name)}</div>
                <div className="vt-end-row-info">
                  <div className="vt-end-row-name">{b.name}</div>
                  <div className="vt-end-row-meta">
                    {sichtungN > 0 && `${sichtungN} Sichtung · `}
                    {hasNote && `SOAP-Notiz · `}
                    {decisionsN > 0 && `${decisionsN} Entscheidung${decisionsN > 1 ? "en" : ""} · `}
                    {p.signedByDoctor && p.signedByNurse ? "doppelt signiert" : (p.signedByDoctor ? "Arzt signiert" : "nicht signiert")}
                  </div>
                </div>
              </div>
            );
          })}
        </div>

        <div className="vt-start-cta">
          <button className="vt-btn-ghost" onClick={onRestart}>Tour wiederholen</button>
          <button className="vt-btn-secondary" onClick={onClose}>Schließen</button>
          <button className="vt-btn-primary" onClick={onHandoff}>
            <Icon name="arrowRight" size={14} /> An Pflege übergeben
          </button>
        </div>
      </div>
    );
  };

  window.VisiteMode = VisiteMode;
})();
