/* ============================================================
   FABIAN VISUALS · FINANZ OS  (Standalone HTML)
   EÜR-Dashboard für Kleinunternehmer (§19 UStG)
   ============================================================ */
/* Babel Standalone executes ES module scripts by dynamically import()-ing a Blob URL.
   Blob URLs are not a "hierarchical" base, so relative specifiers (e.g. "./lib/apiClient.js")
   fail to resolve from inside them ("Invalid relative url or base scheme isn't hierarchical").
   Resolving against location.href up front sidesteps that by importing a fully-qualified
   absolute URL instead of a relative one. */
const ApiClient = await import(new URL("./lib/apiClient.js", location.href).href);
const { entriesToCsv, entriesToJsonBackup } = await import(new URL("./lib/csvExport.js", location.href).href);

const { useState, useEffect, useMemo, useRef, useCallback } = React;
const { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, PieChart, Pie, Cell, Legend, CartesianGrid } = Recharts;

const C = {
  bg: "#0F1014", panel: "#17181E", panelSoft: "#1D1F27", border: "#2A2C36",
  text: "#F2F3F7", muted: "#878CA0",
  income: "#3DDC97", incomeDim: "rgba(61,220,151,0.14)",
  expense: "#FF6B6B", expenseDim: "rgba(255,107,107,0.13)",
  reserve: "#FFC145", reserveDim: "rgba(255,193,69,0.13)",
  accent: "#5B8CFF", accentDim: "rgba(91,140,255,0.14)",
  brand: "#E5484D",
};

const AUSGABE_KAT = [
  "Software & Abos", "Equipment & Technik", "Studio & Miete",
  "Reisekosten", "Material & Requisiten", "Marketing",
  "Fortbildung", "Sonstiges",
];
const EINNAHME_KAT = [
  "Videoproduktion", "Fotografie", "Social Media Content",
  "Beratung & Strategie", "Sonstiges",
];
const KAT_COLORS = ["#5B8CFF", "#3DDC97", "#FFC145", "#FF6B6B", "#B78CFF", "#4DD0E1", "#FF9F5B", "#8A8FA3"];
const MONATE = ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dez"];

const eur = (n) => new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }).format(n || 0);

const fmtDate = (iso) => {
  if (!iso) return "–";
  const [y, m, d] = iso.split("-");
  return `${d}.${m}.${y}`;
};

const fileToBase64 = (file) =>
  new Promise((res, rej) => {
    const r = new FileReader();
    r.onload = () => res(r.result.split(",")[1]);
    r.onerror = () => rej(new Error("Datei konnte nicht gelesen werden"));
    r.readAsDataURL(file);
  });

const compressImage = (file, maxDim = 1000, quality = 0.72) =>
  new Promise((res, rej) => {
    const img = new Image();
    const url = URL.createObjectURL(file);
    img.onload = () => {
      const scale = Math.min(1, maxDim / Math.max(img.width, img.height));
      const canvas = document.createElement("canvas");
      canvas.width = Math.round(img.width * scale);
      canvas.height = Math.round(img.height * scale);
      canvas.getContext("2d").drawImage(img, 0, 0, canvas.width, canvas.height);
      URL.revokeObjectURL(url);
      res(canvas.toDataURL("image/jpeg", quality));
    };
    img.onerror = () => { URL.revokeObjectURL(url); rej(new Error("Bild konnte nicht geladen werden")); };
    img.src = url;
  });

const emptyForm = () => ({
  typ: "ausgabe",
  datum: new Date().toISOString().slice(0, 10),
  betrag: "", name: "", kategorie: "", rechnungsnr: "",
  status: "bezahlt", beschreibung: "",
});

/* ============================================================ */
function FabianFinanzOS() {
  const [loaded, setLoaded] = useState(false);
  const [entries, setEntries] = useState([]);
  const [taxRate, setTaxRate] = useState(30);
  const [tab, setTab] = useState("dashboard");
  const [year, setYear] = useState(new Date().getFullYear());
  const [toast, setToast] = useState(null);
  const [receiptView, setReceiptView] = useState(null);

  const showToast = (msg, isError = false) => {
    setToast({ msg, isError });
    setTimeout(() => setToast(null), 3200);
  };

  useEffect(() => {
    (async () => {
      try {
        const [entriesData, settingsData] = await Promise.all([
          ApiClient.listEntries(),
          ApiClient.getSettings(),
        ]);
        setEntries(entriesData);
        setTaxRate(settingsData.taxRate);
      } catch (err) {
        showToast("Daten konnten nicht geladen werden: " + err.message, true);
      }
      setLoaded(true);
    })();
  }, []);

  const changeTaxRate = async (rate) => {
    setTaxRate(rate);
    try {
      await ApiClient.updateSettings({ taxRate: rate });
    } catch (err) {
      showToast("Steuersatz konnte nicht gespeichert werden: " + err.message, true);
    }
  };

  const addEntry = useCallback(async (form, receiptInfo) => {
    try {
      const entry = await ApiClient.createEntry({
        typ: form.typ,
        datum: form.datum,
        betrag: Math.abs(parseFloat(String(form.betrag).replace(",", ".")) || 0),
        name: form.name.trim(),
        kategorie: form.kategorie || "Sonstiges",
        rechnungsnr: form.rechnungsnr?.trim() || "",
        status: form.typ === "einnahme" ? form.status : "bezahlt",
        beschreibung: form.beschreibung?.trim() || "",
        receiptKey: receiptInfo?.receiptKey || null,
        receiptName: receiptInfo?.receiptName || null,
        source: receiptInfo?.extracted ? "ki-upload" : "manuell",
      });
      setEntries((prev) => [entry, ...prev]);
      showToast(`${entry.typ === "einnahme" ? "Einnahme" : "Ausgabe"} gebucht: ${eur(entry.betrag)}`);
    } catch (err) {
      showToast("Speichern fehlgeschlagen: " + err.message, true);
    }
  }, []);

  const updateEntry = useCallback(async (id, patch) => {
    try {
      const updated = await ApiClient.updateEntry(id, patch);
      setEntries((prev) => prev.map((e) => (e.id === id ? updated : e)));
      showToast("Buchung aktualisiert");
    } catch (err) {
      showToast("Aktualisieren fehlgeschlagen: " + err.message, true);
    }
  }, []);

  const deleteEntry = async (id) => {
    try {
      await ApiClient.deleteEntry(id);
      setEntries((prev) => prev.filter((e) => e.id !== id));
    } catch (err) {
      showToast("Löschen fehlgeschlagen: " + err.message, true);
    }
  };

  const toggleStatus = (id) => {
    const entry = entries.find((e) => e.id === id);
    if (!entry) return;
    updateEntry(id, { status: entry.status === "bezahlt" ? "offen" : "bezahlt" });
  };

  const openReceipt = (entry) => {
    if (!entry.receiptKey) return;
    setReceiptView({ name: entry.receiptName, url: ApiClient.receiptUrl(entry.receiptKey) });
  };

  const years = useMemo(() => {
    const s = new Set(entries.map((e) => parseInt(e.datum.slice(0, 4))));
    s.add(new Date().getFullYear());
    return [...s].sort((a, b) => b - a);
  }, [entries]);

  const yearEntries = useMemo(() => entries.filter((e) => e.datum.startsWith(String(year))), [entries, year]);

  const stats = useMemo(() => {
    const ein = yearEntries.filter((e) => e.typ === "einnahme");
    const aus = yearEntries.filter((e) => e.typ === "ausgabe");
    const sumEin = ein.reduce((s, e) => s + e.betrag, 0);
    const sumAus = aus.reduce((s, e) => s + e.betrag, 0);
    const gewinn = sumEin - sumAus;
    const offen = ein.filter((e) => e.status === "offen").reduce((s, e) => s + e.betrag, 0);
    return { sumEin, sumAus, gewinn, offen, offenCount: ein.filter((e) => e.status === "offen").length };
  }, [yearEntries]);

  const monthly = useMemo(() => {
    const m = MONATE.map((name) => ({ name, Einnahmen: 0, Ausgaben: 0 }));
    yearEntries.forEach((e) => {
      const idx = parseInt(e.datum.slice(5, 7)) - 1;
      if (idx >= 0 && idx < 12) m[idx][e.typ === "einnahme" ? "Einnahmen" : "Ausgaben"] += e.betrag;
    });
    return m;
  }, [yearEntries]);

  const katData = useMemo(() => {
    const map = {};
    yearEntries.filter((e) => e.typ === "ausgabe").forEach((e) => { map[e.kategorie] = (map[e.kategorie] || 0) + e.betrag; });
    return Object.entries(map).map(([name, value]) => ({ name, value: Math.round(value * 100) / 100 })).sort((a, b) => b.value - a.value);
  }, [yearEntries]);

  const ruecklage = Math.max(0, stats.gewinn) * (taxRate / 100);

  const exportExcel = () => {
    const rows = (typ) =>
      yearEntries.filter((e) => e.typ === typ).sort((a, b) => a.datum.localeCompare(b.datum)).map((e) => ({
        Datum: fmtDate(e.datum),
        [typ === "einnahme" ? "Kunde" : "Händler"]: e.name,
        Kategorie: e.kategorie,
        "Betrag (EUR)": e.betrag,
        ...(typ === "einnahme" ? { Rechnungsnr: e.rechnungsnr, Status: e.status } : {}),
        Beschreibung: e.beschreibung,
        Beleg: e.receiptName || "",
      }));

    const wb = XLSX.utils.book_new();
    const wsEin = XLSX.utils.json_to_sheet(rows("einnahme"));
    const wsAus = XLSX.utils.json_to_sheet(rows("ausgabe"));
    const wsEuer = XLSX.utils.aoa_to_sheet([
      [`EÜR ${year} – Fabian Visuals (Kleinunternehmer §19 UStG)`], [],
      ["Summe Einnahmen", stats.sumEin],
      ["Summe Ausgaben", stats.sumAus],
      ["Gewinn / Verlust", stats.gewinn], [],
      [`Steuerrücklage (${taxRate} %)`, ruecklage],
      ["Offene Forderungen", stats.offen],
    ]);
    [wsEin, wsAus].forEach((ws) => { ws["!cols"] = [{ wch: 12 }, { wch: 26 }, { wch: 22 }, { wch: 12 }, { wch: 14 }, { wch: 10 }, { wch: 30 }, { wch: 24 }]; });
    wsEuer["!cols"] = [{ wch: 42 }, { wch: 14 }];
    XLSX.utils.book_append_sheet(wb, wsEuer, "EÜR Übersicht");
    XLSX.utils.book_append_sheet(wb, wsEin, "Einnahmen");
    XLSX.utils.book_append_sheet(wb, wsAus, "Ausgaben");

    const out = XLSX.write(wb, { bookType: "xlsx", type: "array" });
    const blob = new Blob([out], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url; a.download = `Fabian-Visuals_EUeR_${year}.xlsx`; a.click();
    URL.revokeObjectURL(url);
    showToast(`Excel-Export für ${year} erstellt`);
  };

  const downloadTextFile = (filename, content, mimeType) => {
    const blob = new Blob([content], { type: mimeType });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url; a.download = filename; a.click();
    URL.revokeObjectURL(url);
  };

  const exportCsv = () => {
    downloadTextFile(`Fabian-Visuals_Buchungen_${year}.csv`, entriesToCsv(yearEntries), "text/csv;charset=utf-8");
    showToast(`CSV-Export für ${year} erstellt`);
  };

  const exportJsonBackup = () => {
    downloadTextFile(`Fabian-Visuals_Backup.json`, entriesToJsonBackup(entries, taxRate), "application/json");
    showToast(`JSON-Backup erstellt`);
  };

  const TABS = [
    { id: "dashboard", label: "Dashboard", icon: "◧" },
    { id: "upload", label: "Beleg-Upload", icon: "⇧" },
    { id: "einnahmen", label: "Einnahmen", icon: "＋" },
    { id: "ausgaben", label: "Ausgaben", icon: "－" },
    { id: "kunden", label: "Kunden", icon: "◑" },
    { id: "steuer", label: "Steuerrücklage", icon: "◔" },
    { id: "export", label: "Export", icon: "⤓" },
  ];

  if (!loaded) {
    return (
      <div style={{ ...S.app, display: "flex", alignItems: "center", justifyContent: "center" }}>
        <div style={{ color: C.muted }}>Lade Finanzdaten …</div>
      </div>
    );
  }

  return (
    <div style={S.app}>
      <header style={S.header}>
        <div>
          <div style={S.wordmark}>
            FABIAN VISUALS <span style={{ color: C.brand }}>/</span>{" "}
            <span style={{ color: C.muted, fontWeight: 400 }}>FINANZ OS</span>
          </div>
          <div style={S.sub}>EÜR · Kleinunternehmer §19 UStG</div>
        </div>
        <select value={year} onChange={(e) => setYear(parseInt(e.target.value))} style={S.yearSelect} aria-label="Jahr wählen">
          {years.map((y) => <option key={y} value={y}>{y}</option>)}
        </select>
      </header>

      <nav style={S.tabBar}>
        {TABS.map((t) => (
          <button key={t.id} onClick={() => setTab(t.id)}
            style={{ ...S.tabBtn, color: tab === t.id ? C.text : C.muted,
              borderBottom: tab === t.id ? `2px solid ${C.brand}` : "2px solid transparent",
              background: tab === t.id ? C.panelSoft : "transparent" }}>
            <span aria-hidden="true" style={{ marginRight: 6, opacity: 0.8 }}>{t.icon}</span>{t.label}
          </button>
        ))}
      </nav>

      <main style={S.main}>
        {tab === "dashboard" && <DashboardTab stats={stats} monthly={monthly} katData={katData} ruecklage={ruecklage} taxRate={taxRate} entries={yearEntries} year={year} />}
        {tab === "upload" && <UploadTab onSave={addEntry} showToast={showToast} />}
        {tab === "einnahmen" && <ListTab typ="einnahme" entries={yearEntries} onDelete={deleteEntry} onToggle={toggleStatus} onReceipt={openReceipt} onUpdate={updateEntry} year={year} />}
        {tab === "ausgaben" && <ListTab typ="ausgabe" entries={yearEntries} onDelete={deleteEntry} onReceipt={openReceipt} onUpdate={updateEntry} year={year} />}
        {tab === "kunden" && <KundenTab entries={yearEntries} year={year} />}
        {tab === "steuer" && <SteuerTab stats={stats} taxRate={taxRate} setTaxRate={changeTaxRate} ruecklage={ruecklage} year={year} />}
        {tab === "export" && <ExportTab stats={stats} year={year} count={yearEntries.length} onExportExcel={exportExcel} onExportCsv={exportCsv} onExportJson={exportJsonBackup} taxRate={taxRate} ruecklage={ruecklage} />}
      </main>

      {receiptView && (
        <div style={S.modalBg} onClick={() => setReceiptView(null)}>
          <div style={S.modal} onClick={(e) => e.stopPropagation()}>
            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 12 }}>
              <div style={{ fontWeight: 600, fontSize: 14, wordBreak: "break-all" }}>{receiptView.name}</div>
              <button onClick={() => setReceiptView(null)} style={S.iconBtn} aria-label="Schließen">✕</button>
            </div>
            {receiptView.url ? (
              /\.pdf$/i.test(receiptView.name || "") ? (
                <iframe src={receiptView.url} title="Beleg" style={{ width: "100%", height: 420, border: `1px solid ${C.border}`, borderRadius: 8 }} />
              ) : (
                <img src={receiptView.url} alt="Beleg" style={{ width: "100%", borderRadius: 8, border: `1px solid ${C.border}` }} />
              )
            ) : (
              <div style={{ color: C.muted, padding: 32, textAlign: "center", background: C.panelSoft, borderRadius: 8 }}>
                Kein Beleg hinterlegt.
              </div>
            )}
          </div>
        </div>
      )}

      {toast && (
        <div style={{ ...S.toast, borderColor: toast.isError ? C.expense : C.income, color: toast.isError ? C.expense : C.income }}>
          {toast.msg}
        </div>
      )}
    </div>
  );
}

/* ---------- DASHBOARD ---------- */
function DashboardTab({ stats, monthly, katData, ruecklage, taxRate, entries, year }) {
  const latest = [...entries].sort((a, b) => b.datum.localeCompare(a.datum)).slice(0, 6);
  const quarters = useMemo(() => {
    const q = ["Q1", "Q2", "Q3", "Q4"].map((name) => ({ name, Einnahmen: 0, Ausgaben: 0 }));
    entries.forEach((e) => {
      const m = parseInt(e.datum.slice(5, 7)) - 1;
      const qi = Math.floor(m / 3);
      if (qi >= 0 && qi < 4) q[qi][e.typ === "einnahme" ? "Einnahmen" : "Ausgaben"] += e.betrag;
    });
    return q;
  }, [entries]);

  return (
    <div>
      <div style={S.kpiGrid}>
        <Kpi label={`Einnahmen ${year}`} value={eur(stats.sumEin)} color={C.income} bg={C.incomeDim} />
        <Kpi label={`Ausgaben ${year}`} value={eur(stats.sumAus)} color={C.expense} bg={C.expenseDim} />
        <Kpi label="Gewinn (EÜR)" value={eur(stats.gewinn)} color={stats.gewinn >= 0 ? C.income : C.expense} bg={C.accentDim} />
        <Kpi label={`Steuerrücklage (${taxRate} %)`} value={eur(ruecklage)} color={C.reserve} bg={C.reserveDim} />
      </div>

      {stats.offenCount > 0 && (
        <div style={S.warnBanner}>
          ⚠ {stats.offenCount} offene Rechnung{stats.offenCount > 1 ? "en" : ""} über {eur(stats.offen)} – noch nicht bezahlt.
        </div>
      )}

      <div style={S.panel}>
        <div style={S.panelTitle}>Cashflow-Timeline {year}</div>
        <ResponsiveContainer width="100%" height={240}>
          <BarChart data={monthly} barGap={3}>
            <CartesianGrid stroke={C.border} strokeDasharray="2 6" vertical={false} />
            <XAxis dataKey="name" stroke={C.muted} tick={{ fontSize: 11, fontFamily: "'JetBrains Mono', monospace" }} axisLine={false} tickLine={false} />
            <YAxis stroke={C.muted} tick={{ fontSize: 11, fontFamily: "'JetBrains Mono', monospace" }} axisLine={false} tickLine={false} tickFormatter={(v) => `${v}€`} width={54} />
            <Tooltip formatter={(v) => eur(v)} contentStyle={{ background: C.panelSoft, border: `1px solid ${C.border}`, borderRadius: 8, fontSize: 13 }} labelStyle={{ color: C.text }} cursor={{ fill: "rgba(255,255,255,0.04)" }} />
            <Bar dataKey="Einnahmen" fill={C.income} radius={[4, 4, 0, 0]} />
            <Bar dataKey="Ausgaben" fill={C.expense} radius={[4, 4, 0, 0]} />
          </BarChart>
        </ResponsiveContainer>
      </div>

      <div style={S.panel}>
        <div style={S.panelTitle}>Quartals-Vergleich {year}</div>
        <ResponsiveContainer width="100%" height={210}>
          <BarChart data={quarters} barGap={4}>
            <CartesianGrid stroke={C.border} strokeDasharray="2 6" vertical={false} />
            <XAxis dataKey="name" stroke={C.muted} tick={{ fontSize: 12, fontFamily: "'JetBrains Mono', monospace" }} axisLine={false} tickLine={false} />
            <YAxis stroke={C.muted} tick={{ fontSize: 11, fontFamily: "'JetBrains Mono', monospace" }} axisLine={false} tickLine={false} tickFormatter={(v) => `${v}€`} width={54} />
            <Tooltip formatter={(v) => eur(v)} contentStyle={{ background: C.panelSoft, border: `1px solid ${C.border}`, borderRadius: 8, fontSize: 13 }} labelStyle={{ color: C.text }} cursor={{ fill: "rgba(255,255,255,0.04)" }} />
            <Legend wrapperStyle={{ fontSize: 12 }} />
            <Bar dataKey="Einnahmen" fill={C.income} radius={[4, 4, 0, 0]} />
            <Bar dataKey="Ausgaben" fill={C.expense} radius={[4, 4, 0, 0]} />
          </BarChart>
        </ResponsiveContainer>
      </div>

      <div style={S.twoCol}>
        <div style={S.panel}>
          <div style={S.panelTitle}>Ausgaben nach Kategorie</div>
          {katData.length === 0 ? <Empty text="Noch keine Ausgaben erfasst." /> : (
            <ResponsiveContainer width="100%" height={230}>
              <PieChart>
                <Pie data={katData} dataKey="value" nameKey="name" innerRadius={52} outerRadius={82} paddingAngle={2}>
                  {katData.map((_, i) => <Cell key={i} fill={KAT_COLORS[i % KAT_COLORS.length]} stroke={C.bg} />)}
                </Pie>
                <Tooltip formatter={(v) => eur(v)} contentStyle={{ background: C.panelSoft, border: `1px solid ${C.border}`, borderRadius: 8, fontSize: 13 }} />
                <Legend wrapperStyle={{ fontSize: 12 }} />
              </PieChart>
            </ResponsiveContainer>
          )}
        </div>
        <div style={S.panel}>
          <div style={S.panelTitle}>Letzte Buchungen</div>
          {latest.length === 0 ? <Empty text="Lade deinen ersten Beleg im Tab „Beleg-Upload“ hoch." /> : (
            latest.map((e) => (
              <div key={e.id} style={S.miniRow}>
                <span style={{ color: C.muted, fontFamily: "'JetBrains Mono', monospace", fontSize: 12 }}>{fmtDate(e.datum)}</span>
                <span style={{ flex: 1, marginLeft: 10, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{e.name}</span>
                <span style={{ fontFamily: "'JetBrains Mono', monospace", fontWeight: 600, color: e.typ === "einnahme" ? C.income : C.expense }}>
                  {e.typ === "einnahme" ? "+" : "−"}{eur(e.betrag)}
                </span>
              </div>
            ))
          )}
        </div>
      </div>
    </div>
  );
}

/* ---------- BELEG-UPLOAD ---------- */
function UploadTab({ onSave, showToast }) {
  const [mode, setMode] = useState("ki");
  const [form, setForm] = useState(emptyForm());
  const [receipt, setReceipt] = useState(null);
  const [busy, setBusy] = useState(false);
  const [dragOver, setDragOver] = useState(false);
  const [confirming, setConfirming] = useState(false);
  const fileRef = useRef(null);

  const handleFile = async (file) => {
    if (!file) return;
    const okTypes = ["image/jpeg", "image/png", "image/webp", "application/pdf"];
    if (!okTypes.includes(file.type)) { showToast("Nur JPG, PNG, WebP oder PDF möglich", true); return; }
    setBusy(true);
    try {
      const base64 = await fileToBase64(file);
      let thumb = null;
      if (file.type !== "application/pdf") { try { thumb = await compressImage(file); } catch {} }
      const { receiptKey, extracted } = await ApiClient.uploadReceipt(base64, file.type, file.name, mode === "ki");
      setReceipt({ name: file.name, thumb, receiptKey, receiptName: file.name, extracted });

      if (mode === "ki" && extracted) {
        setForm({
          typ: extracted.typ === "einnahme" ? "einnahme" : "ausgabe",
          datum: /^\d{4}-\d{2}-\d{2}$/.test(extracted.datum || "") ? extracted.datum : new Date().toISOString().slice(0, 10),
          betrag: extracted.betrag != null ? String(extracted.betrag) : "",
          name: extracted.name || "",
          kategorie: extracted.kategorie || "",
          rechnungsnr: extracted.rechnungsnr && extracted.rechnungsnr !== "null" ? extracted.rechnungsnr : "",
          status: "bezahlt",
          beschreibung: extracted.beschreibung || "",
        });
        showToast("Beleg ausgelesen – bitte kurz prüfen");
      } else if (mode === "ki" && !extracted) {
        showToast("Auslesen fehlgeschlagen – trag die Daten manuell ein", true);
      }
      setConfirming(true);
    } catch (err) {
      console.error("Belegverarbeitung:", err);
      showToast("Upload fehlgeschlagen: " + err.message, true);
      setConfirming(true);
    }
    setBusy(false);
  };

  const save = () => {
    if (!form.betrag || !form.name) { showToast("Betrag und Name sind Pflicht", true); return; }
    onSave(form, receipt);
    setForm(emptyForm()); setReceipt(null); setConfirming(false);
    if (fileRef.current) fileRef.current.value = "";
  };

  return (
    <div style={{ maxWidth: 720 }}>
      <div style={{ display: "flex", gap: 8, marginBottom: 18 }}>
        <ModeBtn active={mode === "ki"} onClick={() => setMode("ki")} title="🤖 KI liest aus" desc="Hochladen, prüfen, fertig" />
        <ModeBtn active={mode === "manuell"} onClick={() => setMode("manuell")} title="✍️ Manuell" desc="Selbst eintragen, Beleg optional" />
      </div>

      {!confirming && (
        <div
          onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}
          onDragLeave={() => setDragOver(false)}
          onDrop={(e) => { e.preventDefault(); setDragOver(false); handleFile(e.dataTransfer.files[0]); }}
          style={{ ...S.dropzone, borderColor: dragOver ? C.accent : C.border, background: dragOver ? C.accentDim : C.panel }}
        >
          {busy ? (
            <>
              <div style={{ fontSize: 28, marginBottom: 8 }}>🔍</div>
              <div style={{ fontWeight: 600 }}>{mode === "ki" ? "KI liest deinen Beleg aus …" : "Verarbeite Datei …"}</div>
              <div style={{ color: C.muted, fontSize: 13, marginTop: 4 }}>Einen Moment</div>
            </>
          ) : (
            <>
              <div style={{ fontSize: 28, marginBottom: 8 }}>📤</div>
              <div style={{ fontWeight: 600 }}>Beleg hier reinziehen</div>
              <div style={{ color: C.muted, fontSize: 13, margin: "4px 0 14px" }}>JPG, PNG, WebP oder PDF</div>
              <button onClick={() => fileRef.current?.click()} style={S.primaryBtn}>Datei wählen</button>
              {mode === "manuell" && (
                <button onClick={() => setConfirming(true)} style={{ ...S.ghostBtn, marginLeft: 8 }}>Ohne Beleg eintragen</button>
              )}
            </>
          )}
          <input ref={fileRef} type="file" accept="image/jpeg,image/png,image/webp,application/pdf" style={{ display: "none" }} onChange={(e) => handleFile(e.target.files[0])} />
        </div>
      )}

      {confirming && (
        <div style={S.panel}>
          <div style={S.panelTitle}>{receipt ? `Buchung prüfen · ${receipt.name}` : "Buchung eintragen"}</div>
          {receipt?.thumb && <img src={receipt.thumb} alt="Beleg-Vorschau" style={{ maxHeight: 140, borderRadius: 8, border: `1px solid ${C.border}`, marginBottom: 14 }} />}
          <EntryForm
            form={form}
            setForm={setForm}
            onSubmit={save}
            onCancel={() => { setConfirming(false); setReceipt(null); setForm(emptyForm()); if (fileRef.current) fileRef.current.value = ""; }}
            submitLabel="Buchung speichern"
          />
        </div>
      )}
    </div>
  );
}

/* ---------- EINNAHMEN / AUSGABEN LISTE ---------- */
function ListTab({ typ, entries, onDelete, onToggle, onReceipt, onUpdate, year }) {
  const [confirmId, setConfirmId] = useState(null);
  const [query, setQuery] = useState("");
  const [editEntry, setEditEntry] = useState(null);
  const [editForm, setEditForm] = useState(null);
  const q = query.trim().toLowerCase();
  const list = entries
    .filter((e) => e.typ === typ)
    .filter((e) => !q || [e.name, e.kategorie, e.rechnungsnr, e.beschreibung].some((f) => (f || "").toLowerCase().includes(q)))
    .sort((a, b) => b.datum.localeCompare(a.datum));
  const sum = list.reduce((s, e) => s + e.betrag, 0);
  const color = typ === "einnahme" ? C.income : C.expense;

  return (
    <div>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "baseline", marginBottom: 14, flexWrap: "wrap", gap: 8 }}>
        <div style={{ fontSize: 18, fontWeight: 700 }}>
          {typ === "einnahme" ? "Einnahmen" : "Ausgaben"} {year}
          <span style={{ color: C.muted, fontWeight: 400, fontSize: 14, marginLeft: 10 }}>{list.length} Buchungen</span>
        </div>
        <div style={{ fontFamily: "'JetBrains Mono', monospace", fontWeight: 700, fontSize: 18, color }}>
          {typ === "einnahme" ? "+" : "−"}{eur(sum)}
        </div>
      </div>

      <input
        type="text"
        placeholder="Suchen nach Name, Kategorie, Rechnungsnr. …"
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        style={{ ...S.input, marginBottom: 14 }}
      />

      {list.length === 0 ? (
        <div style={S.panel}><Empty text={`Noch keine ${typ === "einnahme" ? "Einnahmen" : "Ausgaben"} für ${year}. Ab in den Beleg-Upload!`} /></div>
      ) : (
        <div style={S.panel}>
          {list.map((e) => (
            <div key={e.id} style={S.entryRow}>
              <div style={{ minWidth: 78, fontFamily: "'JetBrains Mono', monospace", fontSize: 12, color: C.muted }}>{fmtDate(e.datum)}</div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  {e.name}
                  {e.rechnungsnr && <span style={{ color: C.muted, fontWeight: 400, fontSize: 12, marginLeft: 8 }}>#{e.rechnungsnr}</span>}
                </div>
                <div style={{ fontSize: 12, color: C.muted, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  <span style={{ ...S.katPill }}>{e.kategorie}</span>
                  {e.beschreibung && <span style={{ marginLeft: 8 }}>{e.beschreibung}</span>}
                </div>
              </div>
              {typ === "einnahme" && (
                <button onClick={() => onToggle(e.id)}
                  style={{ ...S.statusPill, color: e.status === "bezahlt" ? C.income : C.reserve, borderColor: e.status === "bezahlt" ? C.income : C.reserve }}
                  title="Status umschalten">
                  {e.status === "bezahlt" ? "✓ bezahlt" : "○ offen"}
                </button>
              )}
              {e.receiptKey && (
                <button onClick={() => onReceipt(e)} style={S.iconBtn} title={`Beleg anzeigen: ${e.receiptName || e.receiptKey}`}>📄</button>
              )}
              <div style={{ minWidth: 96, textAlign: "right", fontFamily: "'JetBrains Mono', monospace", fontWeight: 600, color }}>
                {typ === "einnahme" ? "+" : "−"}{eur(e.betrag)}
              </div>
              <button
                onClick={() => {
                  setEditEntry(e);
                  setEditForm({
                    typ: e.typ, datum: e.datum, betrag: String(e.betrag).replace(".", ","), name: e.name,
                    kategorie: e.kategorie, rechnungsnr: e.rechnungsnr, status: e.status, beschreibung: e.beschreibung,
                  });
                }}
                style={S.iconBtn}
                title="Bearbeiten"
                aria-label="Buchung bearbeiten"
              >
                ✎
              </button>
              {confirmId === e.id ? (
                <button onClick={() => { onDelete(e.id); setConfirmId(null); }} style={{ ...S.iconBtn, color: C.expense, borderColor: C.expense }} title="Wirklich löschen">Sicher?</button>
              ) : (
                <button onClick={() => setConfirmId(e.id)} style={S.iconBtn} title="Löschen" aria-label="Buchung löschen">✕</button>
              )}
            </div>
          ))}
        </div>
      )}

      {editEntry && (
        <div style={S.modalBg} onClick={() => setEditEntry(null)}>
          <div style={S.modal} onClick={(e) => e.stopPropagation()}>
            <div style={S.panelTitle}>Buchung bearbeiten</div>
            <EntryForm
              form={editForm}
              setForm={setEditForm}
              submitLabel="Änderungen speichern"
              onCancel={() => setEditEntry(null)}
              onSubmit={() => {
                onUpdate(editEntry.id, {
                  typ: editForm.typ, datum: editForm.datum,
                  betrag: Math.abs(parseFloat(String(editForm.betrag).replace(",", ".")) || 0),
                  name: editForm.name.trim(), kategorie: editForm.kategorie || "Sonstiges",
                  rechnungsnr: editForm.rechnungsnr?.trim() || "", status: editForm.typ === "einnahme" ? editForm.status : "bezahlt",
                  beschreibung: editForm.beschreibung?.trim() || "",
                });
                setEditEntry(null);
              }}
            />
          </div>
        </div>
      )}
    </div>
  );
}

/* ---------- KUNDEN-ÜBERSICHT ---------- */
function KundenTab({ entries, year }) {
  const ein = entries.filter((e) => e.typ === "einnahme");
  const kunden = useMemo(() => {
    const map = {};
    ein.forEach((e) => {
      const key = e.name || "Unbenannt";
      if (!map[key]) map[key] = { name: key, total: 0, bezahlt: 0, offen: 0, count: 0 };
      map[key].total += e.betrag;
      map[key][e.status === "offen" ? "offen" : "bezahlt"] += e.betrag;
      map[key].count += 1;
    });
    return Object.values(map).sort((a, b) => b.total - a.total);
  }, [ein]);

  const offeneRechnungen = ein.filter((e) => e.status === "offen").sort((a, b) => a.datum.localeCompare(b.datum));
  const sumTotal = kunden.reduce((s, k) => s + k.total, 0);
  const sumOffen = kunden.reduce((s, k) => s + k.offen, 0);
  const chartData = kunden.slice(0, 8).map((k) => ({ name: k.name, Umsatz: Math.round(k.total * 100) / 100 }));

  if (ein.length === 0) {
    return <div style={S.panel}><Empty text={`Noch keine Einnahmen für ${year}. Sobald du Ausgangsrechnungen buchst, erscheint hier dein Umsatz pro Kunde.`} /></div>;
  }

  return (
    <div>
      <div style={S.kpiGrid}>
        <Kpi label={`Kunden ${year}`} value={String(kunden.length)} color={C.text} bg={C.accentDim} />
        <Kpi label="Umsatz gesamt" value={eur(sumTotal)} color={C.income} bg={C.incomeDim} />
        <Kpi label="Top-Kunde" value={kunden[0]?.name || "–"} color={C.accent} bg={C.accentDim} />
        <Kpi label="Offene Forderungen" value={eur(sumOffen)} color={C.reserve} bg={C.reserveDim} />
      </div>

      <div style={S.panel}>
        <div style={S.panelTitle}>Umsatz pro Kunde · Top {chartData.length}</div>
        <ResponsiveContainer width="100%" height={Math.max(160, chartData.length * 44)}>
          <BarChart data={chartData} layout="vertical" margin={{ left: 8, right: 16, top: 4, bottom: 4 }}>
            <CartesianGrid stroke={C.border} strokeDasharray="2 6" horizontal={false} />
            <XAxis type="number" stroke={C.muted} tick={{ fontSize: 11, fontFamily: "'JetBrains Mono', monospace" }} axisLine={false} tickLine={false} tickFormatter={(v) => `${v}€`} />
            <YAxis type="category" dataKey="name" stroke={C.muted} tick={{ fontSize: 12 }} axisLine={false} tickLine={false} width={130} />
            <Tooltip formatter={(v) => eur(v)} contentStyle={{ background: C.panelSoft, border: `1px solid ${C.border}`, borderRadius: 8, fontSize: 13 }} cursor={{ fill: "rgba(255,255,255,0.04)" }} />
            <Bar dataKey="Umsatz" fill={C.income} radius={[0, 4, 4, 0]} />
          </BarChart>
        </ResponsiveContainer>
      </div>

      <div style={S.panel}>
        <div style={S.panelTitle}>Alle Kunden</div>
        {kunden.map((k) => (
          <div key={k.name} style={S.entryRow}>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{k.name}</div>
              <div style={{ fontSize: 12, color: C.muted }}>
                {k.count} Rechnung{k.count > 1 ? "en" : ""}
                {k.offen > 0 && <span style={{ color: C.reserve, marginLeft: 8 }}>· {eur(k.offen)} offen</span>}
              </div>
            </div>
            <div style={{ minWidth: 110, textAlign: "right", fontFamily: "'JetBrains Mono', monospace", fontWeight: 600, color: C.income }}>{eur(k.total)}</div>
          </div>
        ))}
      </div>

      {offeneRechnungen.length > 0 && (
        <div style={{ ...S.panel, borderColor: C.reserve }}>
          <div style={{ ...S.panelTitle, color: C.reserve }}>⚠ Offene Forderungen · {eur(sumOffen)}</div>
          {offeneRechnungen.map((e) => (
            <div key={e.id} style={S.entryRow}>
              <div style={{ minWidth: 78, fontFamily: "'JetBrains Mono', monospace", fontSize: 12, color: C.muted }}>{fmtDate(e.datum)}</div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontWeight: 600, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                  {e.name}
                  {e.rechnungsnr && <span style={{ color: C.muted, fontWeight: 400, fontSize: 12, marginLeft: 8 }}>#{e.rechnungsnr}</span>}
                </div>
                {e.beschreibung && <div style={{ fontSize: 12, color: C.muted, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{e.beschreibung}</div>}
              </div>
              <div style={{ minWidth: 96, textAlign: "right", fontFamily: "'JetBrains Mono', monospace", fontWeight: 600, color: C.reserve }}>{eur(e.betrag)}</div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

/* ---------- STEUERRÜCKLAGE ---------- */
function SteuerTab({ stats, taxRate, setTaxRate, ruecklage, year }) {
  const monatlich = ruecklage / Math.max(1, new Date().getFullYear() === year ? new Date().getMonth() + 1 : 12);
  return (
    <div style={{ maxWidth: 720 }}>
      <div style={{ ...S.panel, borderColor: C.reserve, background: `linear-gradient(180deg, ${C.reserveDim}, ${C.panel})` }}>
        <div style={{ fontSize: 13, color: C.muted, textTransform: "uppercase", letterSpacing: 1 }}>Empfohlene Rücklage {year}</div>
        <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 42, fontWeight: 700, color: C.reserve, margin: "6px 0" }}>{eur(ruecklage)}</div>
        <div style={{ color: C.muted, fontSize: 13 }}>= {taxRate} % von {eur(Math.max(0, stats.gewinn))} Gewinn · entspricht ø {eur(monatlich)} pro Monat bisher</div>
      </div>
      <div style={S.panel}>
        <div style={S.panelTitle}>Rücklagen-Satz: {taxRate} %</div>
        <input type="range" min="0" max="45" step="1" value={taxRate} onChange={(e) => setTaxRate(parseInt(e.target.value))} style={{ width: "100%", accentColor: C.reserve }} aria-label="Steuerrücklagen-Satz" />
        <div style={{ display: "flex", justifyContent: "space-between", fontSize: 11, color: C.muted, fontFamily: "'JetBrains Mono', monospace" }}>
          <span>0 %</span><span>25 %</span><span>45 %</span>
        </div>
      </div>
      <div style={S.panel}>
        <div style={S.panelTitle}>Warum 30 % als Standard?</div>
        <ul style={{ margin: 0, paddingLeft: 18, color: C.text, fontSize: 14, lineHeight: 1.7 }}>
          <li>Als <b>Kleinunternehmer (§19 UStG)</b> zahlst du keine Umsatzsteuer – aber <b>Einkommensteuer auf deinen Gewinn</b>.</li>
          <li>Dein <b>Angestellten-Gehalt zählt oben drauf</b>: Jeder Euro Freelance-Gewinn wird mit deinem persönlichen Grenzsteuersatz besteuert – der liegt durch das Gehalt schnell bei 25–35 %.</li>
          <li>Bei ~2.000–2.500 € Umsatz/Monat sind <b>30 % vom Gewinn</b> (nicht vom Umsatz!) ein sicherer Puffer inkl. ggf. Kirchensteuer/Soli.</li>
          <li>Was übrig bleibt, ist dein Bonus – umgekehrt tut eine Nachzahlung richtig weh.</li>
        </ul>
        <div style={{ marginTop: 12, fontSize: 12, color: C.muted }}>Hinweis: Das ist eine Faustregel, keine Steuerberatung. Den exakten Satz kennt dein Steuerberater bzw. dein ELSTER-Bescheid.</div>
      </div>
    </div>
  );
}

/* ---------- EXPORT ---------- */
function ExportTab({ stats, year, count, onExportExcel, onExportCsv, onExportJson, taxRate, ruecklage }) {
  return (
    <div style={{ maxWidth: 720 }}>
      <div style={S.panel}>
        <div style={S.panelTitle}>Excel-Export · {year}</div>
        <p style={{ color: C.muted, fontSize: 14, lineHeight: 1.6, marginTop: 0 }}>
          Erstellt eine <b style={{ color: C.text }}>.xlsx-Datei</b> mit drei Tabellenblättern – bereit für den Import in dein Buchhaltungsprogramm oder für den Steuerberater:
        </p>
        <div style={{ display: "grid", gap: 8, marginBottom: 18 }}>
          {[
            ["EÜR Übersicht", `Einnahmen, Ausgaben, Gewinn, Rücklage (${taxRate} %)`],
            ["Einnahmen", "Alle Ausgangsrechnungen mit Kunde, Nr., Status"],
            ["Ausgaben", "Alle Belege mit Händler, Kategorie, Beleg-Referenz"],
          ].map(([t, d]) => (
            <div key={t} style={{ display: "flex", gap: 10, alignItems: "baseline", background: C.panelSoft, borderRadius: 8, padding: "10px 14px", border: `1px solid ${C.border}` }}>
              <span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: 12, color: C.accent }}>▸</span>
              <div><b>{t}</b> <span style={{ color: C.muted, fontSize: 13 }}>– {d}</span></div>
            </div>
          ))}
        </div>
        <div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
          <button onClick={onExportExcel} disabled={count === 0} style={{ ...S.primaryBtn, opacity: count === 0 ? 0.5 : 1 }}>
            ⤓ Excel (.xlsx)
          </button>
          <button onClick={onExportCsv} disabled={count === 0} style={{ ...S.ghostBtn, opacity: count === 0 ? 0.5 : 1 }}>
            ⤓ CSV (für andere Software)
          </button>
          <button onClick={onExportJson} disabled={count === 0} style={{ ...S.ghostBtn, opacity: count === 0 ? 0.5 : 1 }}>
            ⤓ JSON-Backup
          </button>
        </div>
        {count === 0 && <div style={{ color: C.muted, fontSize: 12, marginTop: 8 }}>Noch keine Buchungen für {year} vorhanden.</div>}
      </div>
      <div style={S.panel}>
        <div style={S.panelTitle}>Enthaltene Zahlen</div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr auto", rowGap: 8, fontSize: 14 }}>
          <span style={{ color: C.muted }}>Buchungen gesamt</span><b style={{ fontFamily: "'JetBrains Mono', monospace" }}>{count}</b>
          <span style={{ color: C.muted }}>Summe Einnahmen</span><b style={{ fontFamily: "'JetBrains Mono', monospace", color: C.income }}>{eur(stats.sumEin)}</b>
          <span style={{ color: C.muted }}>Summe Ausgaben</span><b style={{ fontFamily: "'JetBrains Mono', monospace", color: C.expense }}>{eur(stats.sumAus)}</b>
          <span style={{ color: C.muted }}>Gewinn (EÜR)</span><b style={{ fontFamily: "'JetBrains Mono', monospace" }}>{eur(stats.gewinn)}</b>
          <span style={{ color: C.muted }}>Steuerrücklage</span><b style={{ fontFamily: "'JetBrains Mono', monospace", color: C.reserve }}>{eur(ruecklage)}</b>
        </div>
      </div>
    </div>
  );
}

/* ---------- KLEINE BAUSTEINE ---------- */
function Kpi({ label, value, color, bg }) {
  return (
    <div style={{ ...S.kpi, background: `linear-gradient(180deg, ${bg}, ${C.panel})` }}>
      <div style={{ fontSize: 11, color: C.muted, textTransform: "uppercase", letterSpacing: 1, marginBottom: 6 }}>{label}</div>
      <div style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: "clamp(18px, 2.4vw, 26px)", fontWeight: 700, color, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{value}</div>
    </div>
  );
}
function Field({ label, children, full }) {
  return (
    <label style={{ display: "block", gridColumn: full ? "1 / -1" : "auto" }}>
      <div style={{ fontSize: 11, color: C.muted, textTransform: "uppercase", letterSpacing: 0.8, marginBottom: 5 }}>{label}</div>
      {children}
    </label>
  );
}
function ModeBtn({ active, onClick, title, desc }) {
  return (
    <button onClick={onClick} style={{ flex: 1, textAlign: "left", padding: "12px 14px", borderRadius: 10, border: `1px solid ${active ? C.accent : C.border}`, background: active ? C.accentDim : C.panel, color: C.text }}>
      <div style={{ fontWeight: 600, fontSize: 14 }}>{title}</div>
      <div style={{ fontSize: 12, color: C.muted, marginTop: 2 }}>{desc}</div>
    </button>
  );
}
function Empty({ text }) {
  return <div style={{ color: C.muted, fontSize: 13, padding: "18px 0", textAlign: "center" }}>{text}</div>;
}
function EntryForm({ form, setForm, onSubmit, onCancel, submitLabel }) {
  const set = (k, v) => setForm((f) => ({ ...f, [k]: v }));
  const kats = form.typ === "einnahme" ? EINNAHME_KAT : AUSGABE_KAT;
  return (
    <>
      <div style={S.formGrid}>
        <Field label="Typ">
          <select value={form.typ} onChange={(e) => set("typ", e.target.value)} style={S.input}>
            <option value="ausgabe">Ausgabe</option>
            <option value="einnahme">Einnahme (Ausgangsrechnung)</option>
          </select>
        </Field>
        <Field label="Datum"><input type="date" value={form.datum} onChange={(e) => set("datum", e.target.value)} style={S.input} /></Field>
        <Field label="Betrag (EUR)"><input type="text" inputMode="decimal" placeholder="z. B. 149,90" value={form.betrag} onChange={(e) => set("betrag", e.target.value)} style={S.input} /></Field>
        <Field label={form.typ === "einnahme" ? "Kunde" : "Händler"}>
          <input type="text" placeholder={form.typ === "einnahme" ? "z. B. 1Studio GmbH" : "z. B. Adobe"} value={form.name} onChange={(e) => set("name", e.target.value)} style={S.input} />
        </Field>
        <Field label="Kategorie">
          <select value={form.kategorie} onChange={(e) => set("kategorie", e.target.value)} style={S.input}>
            <option value="">– wählen –</option>
            {kats.map((k) => <option key={k} value={k}>{k}</option>)}
          </select>
        </Field>
        {form.typ === "einnahme" && (
          <>
            <Field label="Rechnungsnr."><input type="text" placeholder="z. B. 2026-014" value={form.rechnungsnr} onChange={(e) => set("rechnungsnr", e.target.value)} style={S.input} /></Field>
            <Field label="Status">
              <select value={form.status} onChange={(e) => set("status", e.target.value)} style={S.input}>
                <option value="bezahlt">Bezahlt</option>
                <option value="offen">Offen</option>
              </select>
            </Field>
          </>
        )}
        <Field label="Beschreibung" full><input type="text" placeholder="Kurz notieren, worum es geht" value={form.beschreibung} onChange={(e) => set("beschreibung", e.target.value)} style={S.input} /></Field>
      </div>
      <div style={{ display: "flex", gap: 8, marginTop: 16 }}>
        <button onClick={onSubmit} style={S.primaryBtn}>{submitLabel}</button>
        <button onClick={onCancel} style={S.ghostBtn}>Abbrechen</button>
      </div>
    </>
  );
}

const S = {
  app: { minHeight: "100vh", background: C.bg, color: C.text, fontFamily: "'Space Grotesk', system-ui, sans-serif" },
  header: { display: "flex", justifyContent: "space-between", alignItems: "center", padding: "18px 22px 12px", flexWrap: "wrap", gap: 10 },
  wordmark: { fontWeight: 700, fontSize: 17, letterSpacing: 1.5 },
  sub: { fontSize: 11, color: C.muted, letterSpacing: 0.6, marginTop: 2 },
  yearSelect: { background: C.panel, color: C.text, border: `1px solid ${C.border}`, borderRadius: 8, padding: "8px 12px", fontSize: 14, fontWeight: 600, fontFamily: "'JetBrains Mono', monospace" },
  tabBar: { display: "flex", gap: 2, padding: "0 14px", borderBottom: `1px solid ${C.border}`, overflowX: "auto", position: "sticky", top: 0, background: C.bg, zIndex: 5 },
  tabBtn: { background: "transparent", border: "none", padding: "12px 14px", fontSize: 13, fontWeight: 600, whiteSpace: "nowrap", borderRadius: "8px 8px 0 0", transition: "color 0.15s" },
  main: { padding: "20px 22px 60px", maxWidth: 1100, margin: "0 auto" },
  kpiGrid: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(190px, 1fr))", gap: 12, marginBottom: 16 },
  kpi: { border: `1px solid ${C.border}`, borderRadius: 12, padding: "16px 18px" },
  warnBanner: { border: `1px solid ${C.reserve}`, background: C.reserveDim, color: C.reserve, borderRadius: 10, padding: "10px 14px", fontSize: 13, fontWeight: 600, marginBottom: 16 },
  panel: { background: C.panel, border: `1px solid ${C.border}`, borderRadius: 14, padding: 18, marginBottom: 16 },
  panelTitle: { fontSize: 14, fontWeight: 700, marginBottom: 14, letterSpacing: 0.3 },
  twoCol: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(300px, 1fr))", gap: 16 },
  miniRow: { display: "flex", alignItems: "center", padding: "8px 0", borderBottom: `1px solid ${C.border}`, fontSize: 13 },
  entryRow: { display: "flex", alignItems: "center", gap: 10, padding: "11px 4px", borderBottom: `1px solid ${C.border}`, flexWrap: "wrap" },
  katPill: { display: "inline-block", background: C.panelSoft, border: `1px solid ${C.border}`, borderRadius: 20, padding: "1px 8px", fontSize: 11 },
  statusPill: { background: "transparent", border: "1px solid", borderRadius: 20, padding: "3px 10px", fontSize: 11, fontWeight: 700, whiteSpace: "nowrap" },
  iconBtn: { background: C.panelSoft, border: `1px solid ${C.border}`, color: C.muted, borderRadius: 8, padding: "5px 9px", fontSize: 12 },
  primaryBtn: { background: C.accent, color: "#0B0C10", border: "none", borderRadius: 10, padding: "10px 18px", fontWeight: 700, fontSize: 14 },
  ghostBtn: { background: "transparent", color: C.muted, border: `1px solid ${C.border}`, borderRadius: 10, padding: "10px 16px", fontWeight: 600, fontSize: 14 },
  dropzone: { border: "2px dashed", borderRadius: 16, padding: "44px 20px", textAlign: "center", transition: "all 0.15s", marginBottom: 16 },
  formGrid: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(200px, 1fr))", gap: 12 },
  input: { width: "100%", background: C.panelSoft, color: C.text, border: `1px solid ${C.border}`, borderRadius: 8, padding: "9px 12px", fontSize: 14 },
  modalBg: { position: "fixed", inset: 0, background: "rgba(0,0,0,0.7)", zIndex: 50, display: "flex", alignItems: "center", justifyContent: "center", padding: 20 },
  modal: { background: C.panel, border: `1px solid ${C.border}`, borderRadius: 14, padding: 18, maxWidth: 560, width: "100%", maxHeight: "85vh", overflowY: "auto" },
  toast: { position: "fixed", bottom: 22, left: "50%", transform: "translateX(-50%)", background: C.panel, border: "1px solid", borderRadius: 10, padding: "10px 18px", fontSize: 13, fontWeight: 600, zIndex: 60, boxShadow: "0 8px 30px rgba(0,0,0,0.5)", maxWidth: "90vw", textAlign: "center" },
};

ReactDOM.createRoot(document.getElementById("root")).render(<FabianFinanzOS />);
