⚡ ULTRA ELITE DASHBOARD — SAUBERE FINALE VERSION

Hier ist die komplette, saubere, finale Version. Folge genau diesen Schritten:


📁 Schritt 1: Ordner erstellen

Erstelle auf deinem Desktop einen Ordner namens: MeinDashboard

📄 Schritt 2: Diese Datei erstellen → index.html

Rechtsklick im Ordner → Neu → Textdokument → Umbenennen zu index.html Dann mit Editor/Notepad öffnen und ALLES hier rein kopieren:

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>⚡ Ultra Elite Dashboard</title>
<meta name="theme-color" content="#06060b">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Dashboard">
<link rel="manifest" href="manifest.json">

<!-- Externe Bibliotheken -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<script src="https://unpkg.com/docx@8.2.3/build/index.js"></script>
<script src="https://unpkg.com/file-saver@2.0.5/dist/FileSaver.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pannellum@2.5.7/build/pannellum.css">
<script src="https://cdn.jsdelivr.net/npm/pannellum@2.5.7/build/pannellum.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>

<style>
/* ============================================================
   🎨 DESIGN SYSTEM
   ============================================================ */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');

:root {
  --b1: #06060b; --b2: #0e0e16;
  --b3: rgba(255,255,255,0.025); --b4: rgba(255,255,255,0.05);
  --bd: rgba(255,255,255,0.06);
  --t1: #e4e4e7; --t2: #71717a; --t3: #52525b;
  --a1: #6366f1; --a2: #8b5cf6; --a3: #a78bfa;
  --ag: linear-gradient(135deg, #6366f1, #8b5cf6, #a78bfa);
  --gl: rgba(99,102,241,0.12);
  --ok: #22c55e; --wr: #f59e0b; --er: #ef4444; --wa: #25D366;
  --r: 14px; --rs: 9px;
  --tr: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Farb-Themes */
.t-sun { --a1:#f97316; --a2:#ef4444; --a3:#fb923c; --ag:linear-gradient(135deg,#f97316,#ef4444,#ec4899); --gl:rgba(249,115,22,0.12); }
.t-sea { --a1:#06b6d4; --a2:#0ea5e9; --a3:#22d3ee; --ag:linear-gradient(135deg,#0ea5e9,#06b6d4,#14b8a6); --gl:rgba(6,182,212,0.12); }
.t-grn { --a1:#22c55e; --a2:#16a34a; --a3:#4ade80; --ag:linear-gradient(135deg,#22c55e,#16a34a,#15803d); --gl:rgba(34,197,94,0.12); }
.t-ros { --a1:#f43f5e; --a2:#ec4899; --a3:#fb7185; --ag:linear-gradient(135deg,#f43f5e,#ec4899,#d946ef); --gl:rgba(244,63,94,0.12); }
.t-gld { --a1:#f59e0b; --a2:#d97706; --a3:#fbbf24; --ag:linear-gradient(135deg,#f59e0b,#d97706,#b45309); --gl:rgba(245,158,11,0.12); }
.t-neo { --a1:#e11d48; --a2:#7c3aed; --a3:#06b6d4; --ag:linear-gradient(135deg,#e11d48,#7c3aed,#06b6d4); --gl:rgba(124,58,237,0.12); }

/* Light Mode */
.light {
  --b1:#f0f0f3; --b2:#fff; --b3:rgba(0,0,0,0.02); --b4:rgba(0,0,0,0.04);
  --bd:rgba(0,0,0,0.07); --t1:#18181b; --t2:#52525b; --t3:#a1a1aa;
}

/* ============================================================
   📐 RESET & BASE
   ============================================================ */
* { margin:0; padding:0; box-sizing:border-box; }
html { scroll-behavior: smooth; }

body {
  font-family: 'Inter', -apple-system, sans-serif;
  background: var(--b1); color: var(--t1);
  min-height: 100vh; overflow-x: hidden;
  transition: var(--tr);
}

body::before {
  content: ''; position: fixed; top: -50%; left: -50%;
  width: 200%; height: 200%; z-index: 0; pointer-events: none;
  background: radial-gradient(ellipse at 25% 25%, var(--gl), transparent 55%),
              radial-gradient(ellipse at 75% 75%, rgba(139,92,246,0.04), transparent 55%);
  animation: bgFloat 25s ease-in-out infinite;
}

/* ============================================================
   🎬 ANIMATIONEN
   ============================================================ */
@keyframes bgFloat { 0%,100%{transform:translate(0,0);} 33%{transform:translate(2%,-2%);} 66%{transform:translate(-1%,1%);} }
@keyframes fadeIn { from{opacity:0;transform:translateY(20px);} to{opacity:1;transform:translateY(0);} }
@keyframes gradShift { 0%{background-position:0% 50%;} 50%{background-position:100% 50%;} 100%{background-position:0% 50%;} }
@keyframes float { 0%,100%{transform:translateY(0);} 50%{transform:translateY(-4px);} }
@keyframes spin { to{transform:rotate(360deg);} }
@keyframes shine { 0%{left:-100%;} 100%{left:200%;} }

/* ============================================================
   📦 CONTAINER
   ============================================================ */
.ctn { max-width:1600px; margin:0 auto; padding:16px 24px; position:relative; z-index:1; }

/* ============================================================
   🎯 HEADER
   ============================================================ */
.hdr { text-align:center; margin-bottom:14px; animation:fadeIn .6s ease; }
.grt { font-size:.8rem; font-weight:500; color:var(--t2); letter-spacing:3px; text-transform:uppercase; margin-bottom:2px; }
.clk {
  font-size:3.5rem; font-weight:900; line-height:1.1; letter-spacing:-2px;
  background:var(--ag); background-size:200% 200%; animation:gradShift 5s ease infinite;
  -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text;
}
.dte { font-size:.85rem; color:var(--t2); margin-top:2px; }

/* Theme Dots */
.tp { display:flex; justify-content:center; gap:5px; margin-top:6px; flex-wrap:wrap; }
.dot { width:20px; height:20px; border-radius:50%; cursor:pointer; border:2px solid transparent; transition:var(--tr); }
.dot:hover { transform:scale(1.2); }
.dot.a { border-color:#fff; box-shadow:0 0 10px var(--gl); transform:scale(1.1); }
.dot[data-t="def"] { background:linear-gradient(135deg,#6366f1,#8b5cf6); }
.dot[data-t="sun"] { background:linear-gradient(135deg,#f97316,#ef4444); }
.dot[data-t="sea"] { background:linear-gradient(135deg,#0ea5e9,#06b6d4); }
.dot[data-t="grn"] { background:linear-gradient(135deg,#22c55e,#16a34a); }
.dot[data-t="ros"] { background:linear-gradient(135deg,#f43f5e,#ec4899); }
.dot[data-t="gld"] { background:linear-gradient(135deg,#f59e0b,#d97706); }
.dot[data-t="neo"] { background:linear-gradient(135deg,#e11d48,#7c3aed); }

/* Header Buttons */
.hc { display:flex; justify-content:center; gap:4px; margin-top:8px; flex-wrap:wrap; }
.hb {
  background:var(--b3); border:1px solid var(--bd); color:var(--t1);
  padding:5px 11px; border-radius:50px; cursor:pointer;
  font-size:.66rem; font-weight:500; transition:var(--tr); font-family:inherit;
}
.hb:hover { background:var(--b4); border-color:var(--a1); box-shadow:0 0 15px var(--gl); }

/* ============================================================
   🔍 SUCHE
   ============================================================ */
.ss { margin-bottom:14px; animation:fadeIn .6s ease .1s backwards; }
.sc {
  display:flex; background:var(--b3); backdrop-filter:blur(25px);
  border:1px solid var(--bd); border-radius:50px; padding:3px;
  max-width:720px; margin:0 auto; transition:var(--tr);
}
.sc:focus-within { border-color:var(--a1); box-shadow:0 0 20px var(--gl); }
.seb { display:flex; gap:1px; padding:1px; }
.se {
  background:0; border:0; color:var(--t3); padding:6px 9px; border-radius:50px;
  cursor:pointer; font-size:.64rem; font-weight:600; transition:var(--tr);
  font-family:inherit; white-space:nowrap;
}
.se.a { background:var(--ag); color:#fff; }
.si {
  flex:1; background:0; border:0; color:var(--t1);
  font-size:.82rem; padding:7px 12px; outline:0; font-family:inherit;
}
.si::placeholder { color:var(--t3); }
.sbtn {
  background:var(--ag); border:0; color:#fff; padding:7px 15px;
  border-radius:50px; cursor:pointer; font-size:.72rem; font-weight:600;
  font-family:inherit; transition:var(--tr);
}
.sbtn:hover { opacity:.9; }

/* ============================================================
   📑 TABS
   ============================================================ */
.tabs {
  display:flex; justify-content:center; gap:3px; margin-bottom:14px;
  flex-wrap:wrap; animation:fadeIn .6s ease .15s backwards;
}
.tab {
  background:var(--b3); border:1px solid var(--bd); color:var(--t2);
  padding:5px 10px; border-radius:50px; cursor:pointer;
  font-size:.64rem; font-weight:600; transition:var(--tr); font-family:inherit;
}
.tab:hover { color:var(--t1); border-color:var(--a1); }
.tab.a { background:var(--ag); color:#fff; border-color:transparent; }

/* ============================================================
   📐 GRID & CARDS
   ============================================================ */
.grid { display:grid; grid-template-columns:repeat(3,1fr); gap:10px; }
.pane { display:none; }
.pane.a { display:grid; }

.card {
  background:var(--b3); backdrop-filter:blur(25px);
  border:1px solid var(--bd); border-radius:var(--r);
  padding:14px; transition:var(--tr); animation:fadeIn .5s ease backwards;
  position:relative; overflow:hidden;
}
.card::before {
  content:''; position:absolute; top:0; left:0; right:0; height:2px;
  background:var(--ag); background-size:200% 200%; animation:gradShift 4s ease infinite;
  opacity:0; transition:var(--tr);
}
.card:hover {
  border-color:rgba(99,102,241,0.15);
  box-shadow:0 5px 30px rgba(0,0,0,0.12);
  transform:translateY(-1px);
}
.card:hover::before { opacity:1; }
.card.s2 { grid-column:span 2; }
.card.full { grid-column:1 / -1; }

/* Card Header */
.card-h {
  display:flex; align-items:center; gap:6px; margin-bottom:10px;
}
.card-i {
  width:28px; height:28px; border-radius:7px; background:var(--ag);
  display:flex; align-items:center; justify-content:center;
  font-size:.85rem; flex-shrink:0; animation:float 4s ease-in-out infinite;
}
.card-t {
  font-size:.66rem; font-weight:700; text-transform:uppercase;
  letter-spacing:1.2px; color:var(--t2);
}

/* ============================================================
   📝 FORMULAR-ELEMENTE
   ============================================================ */
.inp {
  width:100%; background:var(--b2); border:1px solid var(--bd);
  color:var(--t1); padding:6px 9px; border-radius:var(--rs);
  font-size:.74rem; outline:0; transition:var(--tr); font-family:inherit;
}
.inp:focus { border-color:var(--a1); box-shadow:0 0 10px var(--gl); }
select.inp { cursor:pointer; }
textarea.inp { resize:vertical; line-height:1.5; min-height:55px; }

.btn {
  background:var(--ag); border:0; color:#fff;
  padding:6px 11px; border-radius:var(--rs); cursor:pointer;
  font-size:.68rem; font-weight:600; transition:var(--tr);
  font-family:inherit; white-space:nowrap;
  position:relative; overflow:hidden;
}
.btn:hover { opacity:.85; transform:scale(1.02); }
.btn::after {
  content:''; position:absolute; top:0; left:-100%;
  width:50%; height:100%;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,0.12),transparent);
}
.btn:hover::after { animation:shine .5s; }
.btn-s { padding:4px 8px; font-size:.64rem; }
.btn-o { background:0; border:1px solid var(--bd); color:var(--t1); }
.btn-o:hover { border-color:var(--a1); background:var(--gl); }
.btn-d { background:var(--er); }
.btn-ok { background:var(--ok); }

/* Input Group */
.ig { display:flex; gap:4px; margin-bottom:5px; align-items:center; }
.ig .inp { flex:1; }

/* ============================================================
   📋 LISTEN
   ============================================================ */
.ls { list-style:none; max-height:180px; overflow-y:auto; }
.li {
  display:flex; align-items:center; gap:6px;
  padding:5px 7px; border-radius:var(--rs);
  transition:var(--tr); margin-bottom:1px;
}
.li:hover { background:var(--b4); }
.li.dn .txt { text-decoration:line-through; color:var(--t3); }

.chk {
  width:15px; height:15px; border-radius:50%;
  border:2px solid var(--bd); cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  transition:var(--tr); flex-shrink:0;
  background:0; color:transparent; font-size:.5rem;
}
.li.dn .chk { background:var(--ok); border-color:var(--ok); color:#fff; }

.txt { flex:1; font-size:.74rem; }
.del {
  background:0; border:0; color:var(--t3); cursor:pointer;
  padding:1px; font-size:.74rem; opacity:0; transition:var(--tr);
}
.li:hover .del { opacity:1; }
.del:hover { color:var(--er); }

/* ============================================================
   📊 FINANZ-BOXEN
   ============================================================ */
.fin-row { display:grid; grid-template-columns:repeat(3,1fr); gap:5px; margin-bottom:8px; }
.fin-box {
  text-align:center; padding:8px; background:var(--b2);
  border-radius:var(--rs); border:1px solid var(--bd);
}
.fin-lbl {
  font-size:.56rem; color:var(--t3); text-transform:uppercase;
  letter-spacing:1px; font-weight:600; margin-bottom:1px;
}
.fin-val { font-size:1.1rem; font-weight:800; }
.fin-val.inc { color:var(--ok); }
.fin-val.exp { color:var(--er); }
.fin-val.bal {
  background:var(--ag); -webkit-background-clip:text;
  -webkit-text-fill-color:transparent; background-clip:text;
}

/* ============================================================
   🔘 EXPORT-BUTTONS
   ============================================================ */
.exp-row {
  display:flex; gap:4px; flex-wrap:wrap; padding:8px;
  background:var(--b3); border:1px solid var(--bd);
  border-radius:var(--rs); margin-top:8px;
}
.exp-btn {
  display:flex; align-items:center; gap:4px;
  padding:6px 12px; border-radius:var(--rs); cursor:pointer;
  font-size:.66rem; font-weight:600; transition:var(--tr);
  border:1px solid var(--bd); background:var(--b2);
  color:var(--t1); font-family:inherit;
}
.exp-btn:hover { border-color:var(--a1); background:var(--gl); transform:translateY(-1px); }

/* ============================================================
   🎵 RADIO PLAYER
   ============================================================ */
.radio-st {
  display:flex; align-items:center; gap:7px; padding:7px;
  background:var(--b2); border:1px solid var(--bd);
  border-radius:var(--rs); cursor:pointer; transition:var(--tr);
  margin-bottom:2px;
}
.radio-st:hover { border-color:var(--a1); background:var(--gl); }
.radio-st.playing { border-color:var(--a1); box-shadow:0 0 10px var(--gl); }

.vinyl {
  width:70px; height:70px; border-radius:50%;
  background:conic-gradient(#1a1a2e,#16213e,#0f3460,#1a1a2e);
  margin:0 auto 8px; display:flex; align-items:center;
  justify-content:center; transition:var(--tr);
}
.vinyl.spin { animation:spin 3s linear infinite; }
.vinyl::after {
  content:'🎵'; width:24px; height:24px; border-radius:50%;
  background:var(--ag); display:flex; align-items:center;
  justify-content:center; font-size:.75rem;
}

/* ============================================================
   🗺️ KARTE
   ============================================================ */
.map-wrap {
  width:100%; height:300px; border-radius:var(--r);
  overflow:hidden; border:1px solid var(--bd);
  margin:6px 0; z-index:1; position:relative;
}
.map-wrap .leaflet-container { border-radius:var(--r); height:100%; }

/* ============================================================
   🖼️ GALERIE
   ============================================================ */
.gallery {
  display:grid; grid-template-columns:repeat(4,1fr);
  gap:4px; margin:8px 0;
}
.gal-item {
  position:relative; border-radius:var(--rs); overflow:hidden;
  cursor:pointer; aspect-ratio:1; background:var(--b2);
  border:1px solid var(--bd); transition:var(--tr);
}
.gal-item:hover { border-color:var(--a1); transform:scale(1.03); z-index:2; }
.gal-item img, .gal-item video { width:100%; height:100%; object-fit:cover; }
.gal-item .gal-del {
  position:absolute; top:3px; left:3px; background:var(--er); color:#fff;
  width:16px; height:16px; border-radius:50%; border:0; cursor:pointer;
  font-size:.55rem; display:flex; align-items:center; justify-content:center;
  opacity:0; transition:var(--tr);
}
.gal-item:hover .gal-del { opacity:1; }
.gal-add {
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  border:2px dashed var(--bd); border-radius:var(--rs); cursor:pointer;
  transition:var(--tr); aspect-ratio:1; color:var(--t3); font-size:.62rem; gap:3px;
}
.gal-add:hover { border-color:var(--a1); background:var(--gl); color:var(--t1); }
.gal-add span { font-size:1.3rem; }

/* ============================================================
   🔄 360° PANORAMA
   ============================================================ */
.pano-view {
  width:100%; height:350px; border-radius:var(--r);
  overflow:hidden; border:1px solid var(--bd);
}
.pano-view .pnlm-container { border-radius:var(--r) !important; }
.pano-thumbs { display:flex; gap:4px; margin:6px 0; overflow-x:auto; }
.pano-thumbs img {
  width:55px; height:38px; border-radius:4px; cursor:pointer;
  border:2px solid transparent; object-fit:cover; transition:var(--tr);
}
.pano-thumbs img:hover, .pano-thumbs img.active { border-color:var(--a1); }
.pano-ctrls { display:flex; gap:3px; flex-wrap:wrap; }
.pano-btn {
  padding:3px 8px; background:var(--b2); border:1px solid var(--bd);
  border-radius:12px; font-size:.6rem; font-weight:600; cursor:pointer;
  transition:var(--tr); color:var(--t1); font-family:inherit;
}
.pano-btn:hover { border-color:var(--a1); background:var(--gl); }

/* ============================================================
   🏋️ BMI
   ============================================================ */
.bmi-display {
  text-align:center; padding:15px; background:var(--b2);
  border:1px solid var(--bd); border-radius:var(--r); margin:8px 0;
}
.bmi-val { font-size:2.5rem; font-weight:900; line-height:1; }
.bmi-cat { font-size:.82rem; font-weight:700; margin-top:3px; }
.bmi-bar {
  width:100%; height:10px; border-radius:5px; margin:10px 0; position:relative;
  background:linear-gradient(90deg,#3b82f6 0%,#22c55e 25%,#22c55e 40%,#f59e0b 55%,#ef4444 75%,#7c3aed 100%);
}
.bmi-marker {
  position:absolute; top:-3px; width:16px; height:16px; border-radius:50%;
  background:#fff; border:2px solid var(--a1); box-shadow:0 2px 6px rgba(0,0,0,.3);
  transform:translateX(-50%); transition:left .5s ease;
}

/* ============================================================
   🕌 GEBETSZEITEN
   ============================================================ */
.prayer-wrap {
  background:var(--b2); border:1px solid var(--bd);
  border-radius:var(--r); padding:14px;
  position:relative; overflow:hidden;
}
.prayer-wrap::before {
  content:''; position:absolute; top:0; left:0; right:0; height:2px;
  background:linear-gradient(90deg,#22c55e,#f59e0b,#22c55e);
  background-size:200% 200%; animation:gradShift 4s ease infinite;
}
.prayer-grid { display:grid; grid-template-columns:repeat(3,1fr); gap:5px; }
.prayer-card {
  background:var(--b3); border:1px solid var(--bd); border-radius:var(--rs);
  padding:8px; text-align:center; transition:var(--tr);
  position:relative; overflow:hidden;
}
.prayer-card:hover { border-color:var(--a1); transform:translateY(-1px); }
.prayer-card.active {
  border-color:var(--ok); background:rgba(34,197,94,0.08);
  box-shadow:0 0 10px rgba(34,197,94,0.1);
}
.prayer-card.passed { opacity:.5; }
.prayer-icon { font-size:1.1rem; margin-bottom:2px; }
.prayer-name { font-size:.58rem; color:var(--t2); font-weight:600; text-transform:uppercase; letter-spacing:.5px; }
.prayer-time {
  font-size:.95rem; font-weight:800; margin-top:1px;
  background:var(--ag); -webkit-background-clip:text;
  -webkit-text-fill-color:transparent; background-clip:text;
}
.prayer-card.active .prayer-time {
  background:var(--ok); -webkit-background-clip:text;
  -webkit-text-fill-color:transparent; background-clip:text;
}
.prayer-next {
  text-align:center; margin-top:8px; padding:8px;
  background:var(--b3); border-radius:var(--rs); border:1px solid var(--bd);
}

/* ============================================================
   📜 MIETVERTRAG
   ============================================================ */
.mv-section {
  background:var(--b2); border:1px solid var(--bd);
  border-radius:var(--rs); padding:10px; margin-bottom:6px;
}
.mv-section h4 {
  font-size:.66rem; font-weight:700; color:var(--a3);
  margin-bottom:6px; text-transform:uppercase; letter-spacing:1px;
}
.mv-preview {
  background:var(--b1); border:1px solid var(--bd);
  border-radius:var(--rs); padding:15px 18px; margin-top:8px;
  max-height:350px; overflow-y:auto; font-size:.76rem; line-height:1.7;
}
.mv-preview h2 {
  font-size:1rem; text-align:center; margin-bottom:10px;
  border-bottom:2px solid var(--bd); padding-bottom:6px;
}

/* ============================================================
   📱 QR CODE
   ============================================================ */
.qr-wrap {
  display:flex; flex-direction:column; align-items:center; gap:8px;
  padding:15px; background:var(--b2); border:1px solid var(--bd);
  border-radius:var(--r); margin-top:8px;
}
.qr-box { background:#fff; padding:12px; border-radius:var(--rs); }

/* ============================================================
   🏗️ GRUNDRISS
   ============================================================ */
.fp-toolbar {
  display:flex; gap:3px; margin-bottom:6px; flex-wrap:wrap;
  padding:6px; background:var(--b2); border:1px solid var(--bd);
  border-radius:var(--rs);
}
.fp-tool {
  padding:4px 9px; background:var(--b3); border:1px solid var(--bd);
  border-radius:var(--rs); font-size:.62rem; font-weight:600;
  cursor:pointer; transition:var(--tr); color:var(--t1);
  font-family:inherit; display:flex; align-items:center; gap:3px;
}
.fp-tool:hover { border-color:var(--a1); background:var(--gl); }
.fp-tool.active { background:var(--ag); color:#fff; border-color:transparent; }

/* ============================================================
   🧾 NEBENKOSTEN
   ============================================================ */
.nk-grid { display:grid; grid-template-columns:repeat(2,1fr); gap:4px; margin-bottom:8px; }
.nk-item {
  background:var(--b2); border:1px solid var(--bd);
  border-radius:var(--rs); padding:8px;
}
.nk-item label { font-size:.62rem; color:var(--t2); font-weight:600; display:block; margin-bottom:2px; }

/* ============================================================
   🖥️ LIGHTBOX
   ============================================================ */
.lightbox {
  display:none; position:fixed; top:0; left:0; width:100%; height:100%;
  background:rgba(0,0,0,0.92); z-index:9999;
  align-items:center; justify-content:center; backdrop-filter:blur(10px);
}
.lightbox.show { display:flex; }
.lightbox img, .lightbox video { max-width:90%; max-height:85%; border-radius:var(--r); }
.lb-close {
  position:absolute; top:15px; right:20px;
  background:rgba(255,255,255,0.1); border:1px solid rgba(255,255,255,0.2);
  color:#fff; width:36px; height:36px; border-radius:50%;
  cursor:pointer; font-size:1rem; display:flex;
  align-items:center; justify-content:center; transition:var(--tr);
}
.lb-close:hover { background:var(--er); }

/* ============================================================
   💬 ZITAT
   ============================================================ */
.quote-section { text-align:center; padding:14px 30px; margin-top:12px; }
.quote-text {
  font-size:.85rem; font-style:italic; color:var(--t2);
  line-height:1.6; max-width:600px; margin:0 auto;
}
.quote-author { margin-top:4px; font-size:.7rem; color:var(--t3); font-weight:600; }

/* ============================================================
   📜 SCROLLBAR
   ============================================================ */
::-webkit-scrollbar { width:3px; }
::-webkit-scrollbar-track { background:0; }
::-webkit-scrollbar-thumb { background:var(--bd); border-radius:10px; }

/* ============================================================
   📱 RESPONSIVE
   ============================================================ */
@media (max-width:1200px) {
  .grid, .pane.a { grid-template-columns:repeat(2,1fr); }
  .card.s2 { grid-column:span 1; }
  .gallery { grid-template-columns:repeat(3,1fr); }
}
@media (max-width:768px) {
  .ctn { padding:8px 6px; }
  .grid, .pane.a { grid-template-columns:1fr; }
  .clk { font-size:2rem; }
  .seb { display:none; }
  .gallery { grid-template-columns:repeat(2,1fr); }
  .prayer-grid { grid-template-columns:repeat(2,1fr); }
  .nk-grid { grid-template-columns:1fr; }
}
</style>
</head>
<body>

<!-- ============================================================
     🖥️ LIGHTBOX
     ============================================================ -->
<div class="lightbox" id="lightbox" onclick="closeLightbox()">
  <button class="lb-close" onclick="closeLightbox()">✕</button>
  <div id="lightboxContent"></div>
</div>

<div class="ctn">

  <!-- ============================================================
       🎯 HEADER
       ============================================================ -->
  <header class="hdr">
    <div class="grt" id="greeting"></div>
    <div class="clk" id="clock">00:00:00</div>
    <div class="dte" id="dateDisplay"></div>

    <!-- Farb-Themes -->
    <div class="tp">
      <div class="dot a" data-t="def" onclick="setThemeColor(this)"></div>
      <div class="dot" data-t="sun" onclick="setThemeColor(this)"></div>
      <div class="dot" data-t="sea" onclick="setThemeColor(this)"></div>
      <div class="dot" data-t="grn" onclick="setThemeColor(this)"></div>
      <div class="dot" data-t="ros" onclick="setThemeColor(this)"></div>
      <div class="dot" data-t="gld" onclick="setThemeColor(this)"></div>
      <div class="dot" data-t="neo" onclick="setThemeColor(this)"></div>
    </div>

    <!-- Buttons -->
    <div class="hc">
      <button class="hb" onclick="toggleDarkLight()">🌙 Dark/Light</button>
      <button class="hb" onclick="backupAll()">💾 Backup</button>
      <button class="hb" onclick="restoreAll()">📂 Restore</button>
      <button class="hb" id="installBtn" style="display:none;background:var(--ag);color:#fff;" onclick="installPWA()">📲 Installieren</button>
      <span class="hb" id="netStatus">🟢</span>
    </div>
  </header>

  <!-- ============================================================
       🔍 SUCHE
       ============================================================ -->
  <section class="ss">
    <form class="sc" onsubmit="doSearch(event)">
      <div class="seb">
        <button type="button" class="se a" onclick="setSearchEngine(this,'google')">Google</button>
        <button type="button" class="se" onclick="setSearchEngine(this,'youtube')">YouTube</button>
        <button type="button" class="se" onclick="setSearchEngine(this,'amazon')">Amazon</button>
        <button type="button" class="se" onclick="setSearchEngine(this,'maps')">Maps</button>
      </div>
      <input type="text" class="si" id="searchInput" placeholder="Suche im Web..." autocomplete="off">
      <button type="submit" class="sbtn">🔍</button>
    </form>
  </section>

  <!-- ============================================================
       📑 NAVIGATION TABS
       ============================================================ -->
  <div class="tabs">
    <button class="tab a" onclick="openTab(this,'home')">🏠 Home</button>
    <button class="tab" onclick="openTab(this,'immo')">🏠 Immobilien</button>
    <button class="tab" onclick="openTab(this,'auto')">🚗 Auto</button>
    <button class="tab" onclick="openTab(this,'finance')">💰 Finanzen</button>
    <button class="tab" onclick="openTab(this,'admin')">📜 Verwaltung</button>
    <button class="tab" onclick="openTab(this,'media')">🎵 Medien</button>
    <button class="tab" onclick="openTab(this,'comm')">💬 Kommunikation</button>
    <button class="tab" onclick="openTab(this,'tools')">🛠️ Tools</button>
    <button class="tab" onclick="openTab(this,'floorplan')">🏗️ Grundriss</button>
    <button class="tab" onclick="openTab(this,'nk')">🧾 Nebenkosten</button>
    <button class="tab" onclick="openTab(this,'bmi')">🏋️ BMI</button>
    <button class="tab" onclick="openTab(this,'prayer')">🕌 Gebet</button>
    <button class="tab" onclick="openTab(this,'contract')">📜 Mietvertrag</button>
    <button class="tab" onclick="openTab(this,'ai')">🤖 KI</button>
  </div>

  <!-- ============================================================
       🏠 TAB: HOME
       ============================================================ -->
  <div class="grid pane a" id="tab-home">

    <!-- KALENDER -->
    <div class="card s2">
      <div class="card-h"><div class="card-i">📅</div><div class="card-t">Kalender & Termine</div></div>
      <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;">
        <div>
          <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:4px;">
            <button class="hb" onclick="calPrev()">◀</button>
            <span id="calMonthYear" style="font-size:.8rem;font-weight:700;background:var(--ag);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;"></span>
            <button class="hb" onclick="calNext()">▶</button>
          </div>
          <div style="display:grid;grid-template-columns:repeat(7,1fr);gap:1px;margin-bottom:1px;">
            <div style="text-align:center;font-size:.52rem;color:var(--t3);font-weight:700;">Mo</div>
            <div style="text-align:center;font-size:.52rem;color:var(--t3);font-weight:700;">Di</div>
            <div style="text-align:center;font-size:.52rem;color:var(--t3);font-weight:700;">Mi</div>
            <div style="text-align:center;font-size:.52rem;color:var(--t3);font-weight:700;">Do</div>
            <div style="text-align:center;font-size:.52rem;color:var(--t3);font-weight:700;">Fr</div>
            <div style="text-align:center;font-size:.52rem;color:var(--t3);font-weight:700;">Sa</div>
            <div style="text-align:center;font-size:.52rem;color:var(--t3);font-weight:700;">So</div>
          </div>
          <div style="display:grid;grid-template-columns:repeat(7,1fr);gap:1px;" id="calDays"></div>
        </div>
        <div>
          <div class="ig">
            <input type="date" class="inp" id="eventDate">
            <input type="time" class="inp" id="eventTime" style="flex:.4">
          </div>
          <div class="ig">
            <input class="inp" id="eventTitle" placeholder="Termin..." onkeypress="if(event.key==='Enter')addEvent()">
            <button class="btn btn-s" onclick="addEvent()">+</button>
          </div>
          <div style="font-size:.58rem;color:var(--t3);margin:3px 0 1px;" id="calEventsTitle">Termine</div>
          <div style="max-height:120px;overflow-y:auto;" id="calEvents"></div>
        </div>
      </div>
    </div>

    <!-- TO-DO -->
    <div class="card">
      <div class="card-h"><div class="card-i">✅</div><div class="card-t">To-Do Liste</div></div>
      <div class="ig">
        <input class="inp" id="todoInput" placeholder="Neue Aufgabe..." onkeypress="if(event.key==='Enter')addTodo()">
        <button class="btn btn-s" onclick="addTodo()">+</button>
      </div>
      <ul class="ls" id="todoList"></ul>
    </div>

    <!-- NOTIZEN -->
    <div class="card">
      <div class="card-h"><div class="card-i">📝</div><div class="card-t">Notizen</div></div>
      <textarea class="inp" id="notesArea" placeholder="Notizen schreiben..." style="min-height:110px;"></textarea>
    </div>

    <!-- TAGESAUSGABEN -->
    <div class="card">
      <div class="card-h"><div class="card-i">📊</div><div class="card-t">Tagesausgaben</div></div>
      <div style="text-align:center;padding:6px;background:var(--b2);border-radius:var(--rs);margin-bottom:4px;">
        <div style="font-size:.55rem;color:var(--t3);text-transform:uppercase;letter-spacing:1px;">Heute</div>
        <div style="font-size:1.2rem;font-weight:800;background:var(--ag);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;" id="dailyTotal">0,00 €</div>
      </div>
      <div class="ig">
        <input class="inp" id="expName" placeholder="Beschreibung">
        <input type="number" class="inp" id="expAmount" placeholder="€" style="flex:.3" onkeypress="if(event.key==='Enter')addDailyExp()">
        <button class="btn btn-s" onclick="addDailyExp()">+</button>
      </div>
      <ul class="ls" id="dailyExpList"></ul>
    </div>

    <!-- QUICK LINKS -->
    <div class="card">
      <div class="card-h"><div class="card-i">🔗</div><div class="card-t">Quick Links</div></div>
      <div style="display:grid;grid-template-columns:repeat(3,1fr);gap:3px;">
        <a href="https://mail.google.com" target="_blank" style="text-align:center;padding:8px 3px;display:flex;flex-direction:column;align-items:center;gap:1px;border-radius:var(--rs);background:var(--b2);text-decoration:none;color:var(--t1);font-size:.58rem;border:1px solid var(--bd);transition:var(--tr);"><span style="font-size:.9rem;">📧</span>Gmail</a>
        <a href="https://youtube.com" target="_blank" style="text-align:center;padding:8px 3px;display:flex;flex-direction:column;align-items:center;gap:1px;border-radius:var(--rs);background:var(--b2);text-decoration:none;color:var(--t1);font-size:.58rem;border:1px solid var(--bd);transition:var(--tr);"><span style="font-size:.9rem;">🎬</span>YouTube</a>
        <a href="https://maps.google.com" target="_blank" style="text-align:center;padding:8px 3px;display:flex;flex-direction:column;align-items:center;gap:1px;border-radius:var(--rs);background:var(--b2);text-decoration:none;color:var(--t1);font-size:.58rem;border:1px solid var(--bd);transition:var(--tr);"><span style="font-size:.9rem;">🗺️</span>Maps</a>
        <a href="https://drive.google.com" target="_blank" style="text-align:center;padding:8px 3px;display:flex;flex-direction:column;align-items:center;gap:1px;border-radius:var(--rs);background:var(--b2);text-decoration:none;color:var(--t1);font-size:.58rem;border:1px solid var(--bd);transition:var(--tr);"><span style="font-size:.9rem;">☁️</span>Drive</a>
        <a href="https://web.whatsapp.com" target="_blank" style="text-align:center;padding:8px 3px;display:flex;flex-direction:column;align-items:center;gap:1px;border-radius:var(--rs);background:var(--b2);text-decoration:none;color:var(--t1);font-size:.58rem;border:1px solid var(--bd);transition:var(--tr);"><span style="font-size:.9rem;">💬</span>WhatsApp</a>
        <a href="https://translate.google.com" target="_blank" style="text-align:center;padding:8px 3px;display:flex;flex-direction:column;align-items:center;gap:1px;border-radius:var(--rs);background:var(--b2);text-decoration:none;color:var(--t1);font-size:.58rem;border:1px solid var(--bd);transition:var(--tr);"><span style="font-size:.9rem;">🌍</span>Übersetzer</a>
      </div>
    </div>

  </div>

  <!-- ============================================================
       DYNAMISCHE TABS (werden per JS gefüllt)
       ============================================================ -->
  <div class="grid pane" id="tab-immo" style="grid-template-columns:1fr;"><div class="card full"><div class="card-h"><div class="card-i" style="background:linear-gradient(135deg,#f59e0b,#ef4444);">🏠</div><div class="card-t">Immobilien Exposé Builder</div></div><div id="immoBody">Lade...</div></div></div>
  <div class="grid pane" id="tab-auto"><div class="card s2"><div class="card-h"><div class="card-i" style="background:linear-gradient(135deg,#3b82f6,#06b6d4);">🚗</div><div class="card-t">Fahrzeuge</div></div><div id="autoBody">Lade...</div></div><div class="card"><div class="card-h"><div class="card-i">📊</div><div class="card-t">Statistik</div></div><div id="autoStats">Lade...</div></div></div>
  <div class="grid pane" id="tab-finance"><div class="card s2"><div class="card-h"><div class="card-i" style="background:var(--ok);">👤</div><div class="card-t">Finanzen Privat</div></div><div id="finPrivBody">Lade...</div></div><div class="card"><div class="card-h"><div class="card-i" style="background:var(--wr);">🏢</div><div class="card-t">Business</div></div><div id="finBizBody">Lade...</div></div></div>
  <div class="grid pane" id="tab-admin"><div class="card"><div class="card-h"><div class="card-i" style="background:linear-gradient(135deg,#6366f1,#ec4899);">📜</div><div class="card-t">Testament</div></div><div id="testBody">Lade...</div></div><div class="card s2"><div class="card-h"><div class="card-i" style="background:linear-gradient(135deg,#f59e0b,#22c55e);">🏢</div><div class="card-t">Hausverwaltung</div></div><div id="hvBody">Lade...</div></div></div>
  <div class="grid pane" id="tab-media"><div class="card"><div class="card-h"><div class="card-i" style="background:linear-gradient(135deg,#ec4899,#8b5cf6);">🎵</div><div class="card-t">Radyo Player</div></div><div id="radioBody">Lade...</div><audio id="radioAudio"></audio></div><div class="card s2"><div class="card-h"><div class="card-i" style="background:linear-gradient(135deg,#ef4444,#f59e0b);">📻</div><div class="card-t">Türkische Sender</div></div><input class="inp" id="radioSearch" placeholder="🔍 Sender suchen..." oninput="filterRadio()" style="margin-bottom:4px;"><div style="max-height:300px;overflow-y:auto;" id="radioList"></div></div></div>
  <div class="grid pane" id="tab-comm"><div class="card s2"><div class="card-h"><div class="card-i" style="background:#25D366;">💬</div><div class="card-t">WhatsApp</div></div><div id="waBody">Lade...</div></div><div class="card"><div class="card-h"><div class="card-i">🌍</div><div class="card-t">Übersetzer</div></div><div id="transBody">Lade...</div></div></div>
  <div class="grid pane" id="tab-tools"><div class="card"><div class="card-h"><div class="card-i">🧮</div><div class="card-t">Taschenrechner</div></div><div id="calcBody">Lade...</div></div><div class="card"><div class="card-h"><div class="card-i">🔑</div><div class="card-t">Passwort Generator</div></div><div id="pwBody">Lade...</div></div><div class="card"><div class="card-h"><div class="card-i">💰</div><div class="card-t">Währungsrechner</div></div><div id="currBody">Lade...</div></div></div>
  <div class="grid pane" id="tab-floorplan" style="grid-template-columns:1fr;"><div class="card full"><div class="card-h"><div class="card-i" style="background:linear-gradient(135deg,#3b82f6,#8b5cf6);">🏗️</div><div class="card-t">Grundriss-Zeichner</div></div><div id="fpBody">Lade...</div></div></div>
  <div class="grid pane" id="tab-nk"><div class="card s2"><div class="card-h"><div class="card-i" style="background:linear-gradient(135deg,#f59e0b,#ef4444);">🧾</div><div class="card-t">Nebenkostenabrechnung</div></div><div id="nkBody">Lade...</div></div><div class="card"><div class="card-h"><div class="card-i">📊</div><div class="card-t">Ergebnis</div></div><div id="nkResult">Mieter hinzufügen</div></div></div>
  <div class="grid pane" id="tab-bmi"><div class="card"><div class="card-h"><div class="card-i" style="background:linear-gradient(135deg,#22c55e,#06b6d4);">🏋️</div><div class="card-t">BMI-Rechner</div></div><div id="bmiBody">Lade...</div></div><div class="card"><div class="card-h"><div class="card-i">📊</div><div class="card-t">BMI Info</div></div><div id="bmiInfo">Lade...</div></div></div>
  <div class="grid pane" id="tab-prayer"><div class="card s2"><div class="card-h"><div class="card-i" style="background:linear-gradient(135deg,#22c55e,#f59e0b);">🕌</div><div class="card-t">Gebetszeiten — Namaz Vakitleri</div></div><div id="prayerBody">Lade...</div></div><div class="card"><div class="card-h"><div class="card-i">📅</div><div class="card-t">Monatskalender</div></div><div style="max-height:300px;overflow-y:auto;" id="prayerMonthly">Klicke "Laden"</div></div></div>
  <div class="grid pane" id="tab-contract" style="grid-template-columns:1fr;"><div class="card full"><div class="card-h"><div class="card-i" style="background:linear-gradient(135deg,#6366f1,#ec4899);">📜</div><div class="card-t">Mietvertrag + QR-Code</div></div><div id="mvBody">Lade...</div></div></div>
  <div class="grid pane" id="tab-ai" style="grid-template-columns:1fr;"><div class="card"><div class="card-h"><div class="card-i" style="background:linear-gradient(135deg,#ec4899,#8b5cf6,#06b6d4);background-size:200% 200%;animation:gradShift 3s ease infinite;">🤖</div><div class="card-t">KI-Assistent (OpenAI)</div></div><div id="aiBody">Lade...</div></div></div>

  <!-- ZITAT -->
  <div class="quote-section">
    <div class="quote-text" id="quoteText"></div>
    <div class="quote-author" id="quoteAuthor"></div>
  </div>

</div>

<!-- ============================================================
     ⚡ JAVASCRIPT — CORE ENGINE
     ============================================================ -->
<script>
// ========================================
// 🔧 HILFSFUNKTIONEN
// ========================================
const esc = s => { const d = document.createElement('div'); d.textContent = s; return d.innerHTML; };
const save = (k, v) => localStorage.setItem(k, JSON.stringify(v));
const load = (k, d) => { try { return JSON.parse(localStorage.getItem(k)) || d; } catch { return d; } };
const fmt = n => n.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
const $ = id => document.getElementById(id);

// ========================================
// ⏰ UHR & DATUM
// ========================================
function updateClock() {
  const now = new Date();
  const h = String(now.getHours()).padStart(2, '0');
  const m = String(now.getMinutes()).padStart(2, '0');
  const s = String(now.getSeconds()).padStart(2, '0');
  $('clock').textContent = `${h}:${m}:${s}`;

  const days = ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'];
  const months = ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'];
  $('dateDisplay').textContent = `${days[now.getDay()]}, ${now.getDate()}. ${months[now.getMonth()]} ${now.getFullYear()}`;

  const hr = now.getHours();
  $('greeting').textContent =
    hr >= 5 && hr < 12 ? 'Guten Morgen ☀️' :
    hr < 18 ? 'Guten Tag 🌤️' :
    hr < 22 ? 'Guten Abend 🌆' : 'Gute Nacht 🌙';
}
setInterval(updateClock, 1000);
updateClock();

// ========================================
// 🎨 THEMES
// ========================================
function toggleDarkLight() {
  document.body.classList.toggle('light');
  localStorage.setItem('theme', document.body.classList.contains('light') ? 'l' : 'd');
}

function setThemeColor(el) {
  document.querySelectorAll('.dot').forEach(d => d.classList.remove('a'));
  el.classList.add('a');
  document.body.className = document.body.className.replace(/t-\S+/g, '').trim();
  const t = el.dataset.t;
  if (t !== 'def') document.body.classList.add('t-' + t);
  if (localStorage.getItem('theme') === 'l') document.body.classList.add('light');
  localStorage.setItem('colorTheme', t);
}

// Restore themes on load
if (localStorage.getItem('theme') === 'l') document.body.classList.add('light');
const savedColorTheme = localStorage.getItem('colorTheme');
if (savedColorTheme && savedColorTheme !== 'def') {
  document.body.classList.add('t-' + savedColorTheme);
  document.querySelectorAll('.dot').forEach(d =>
    d.classList.toggle('a', d.dataset.t === savedColorTheme)
  );
}

// ========================================
// 📑 TAB NAVIGATION
// ========================================
const tabInitialized = {};

function openTab(btn, tabId) {
  document.querySelectorAll('.tab').forEach(t => t.classList.remove('a'));
  btn.classList.add('a');
  document.querySelectorAll('.pane').forEach(p => p.classList.remove('a'));
  $('tab-' + tabId).classList.add('a');

  // Lazy-Init: Tabs erst laden wenn geklickt
  if (!tabInitialized[tabId]) {
    tabInitialized[tabId] = true;
    switch(tabId) {
      case 'media': initMedia(); break;
      case 'tools': initTools(); break;
      case 'comm': initComm(); break;
      case 'immo': initImmo(); break;
      case 'auto': initAuto(); break;
      case 'finance': initFinance(); break;
      case 'admin': initAdmin(); break;
      case 'floorplan': initFloorplan(); break;
      case 'nk': initNebenkosten(); break;
      case 'bmi': initBMI(); break;
      case 'prayer': initPrayer(); break;
      case 'contract': initContract(); break;
      case 'ai': initAI(); break;
    }
  }
}

// ========================================
// 🔍 SUCHE
// ========================================
let searchEngine = 'google';
const searchUrls = {
  google: 'https://www.google.com/search?q=',
  youtube: 'https://www.youtube.com/results?search_query=',
  amazon: 'https://www.amazon.de/s?k=',
  maps: 'https://www.google.com/maps/search/'
};

function setSearchEngine(btn, engine) {
  searchEngine = engine;
  document.querySelectorAll('.se').forEach(b => b.classList.remove('a'));
  btn.classList.add('a');
}

function doSearch(e) {
  e.preventDefault();
  const q = $('searchInput').value.trim();
  if (q) window.open(searchUrls[searchEngine] + encodeURIComponent(q), '_blank');
}

// ========================================
// ✅ TO-DO LISTE
// ========================================
let todos = load('todos', []);

function renderTodos() {
  const list = $('todoList');
  list.innerHTML = '';
  todos.forEach((t, i) => {
    list.innerHTML += `<li class="li${t.done ? ' dn' : ''}">
      <button class="chk" onclick="todos[${i}].done=!todos[${i}].done;renderTodos()">✓</button>
      <span class="txt">${esc(t.text)}</span>
      <button class="del" onclick="todos.splice(${i},1);renderTodos()">✕</button>
    </li>`;
  });
  save('todos', todos);
}

function addTodo() {
  const input = $('todoInput');
  const text = input.value.trim();
  if (text) {
    todos.unshift({ text, done: false });
    input.value = '';
    renderTodos();
  }
}
renderTodos();

// ========================================
// 📝 NOTIZEN
// ========================================
const notesArea = $('notesArea');
notesArea.value = localStorage.getItem('notes') || '';
notesArea.addEventListener('input', () => localStorage.setItem('notes', notesArea.value));

// ========================================
// 📅 KALENDER
// ========================================
let calDate = new Date();
let calSelectedDate = null;
let calEvents = load('calEvents', []);

function renderCalendar() {
  const year = calDate.getFullYear();
  const month = calDate.getMonth();
  const monthNames = ['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'];
  $('calMonthYear').textContent = `${monthNames[month]} ${year}`;

  const firstDay = new Date(year, month, 1).getDay();
  const startDay = firstDay === 0 ? 6 : firstDay - 1;
  const daysInMonth = new Date(year, month + 1, 0).getDate();
  const daysInPrev = new Date(year, month, 0).getDate();
  const container = $('calDays');
  container.innerHTML = '';
  const today = new Date();

  // Vorheriger Monat
  for (let i = startDay - 1; i >= 0; i--) {
    container.innerHTML += `<div style="text-align:center;padding:4px 1px;font-size:.66rem;opacity:.3;">${daysInPrev - i}</div>`;
  }

  // Aktueller Monat
  for (let day = 1; day <= daysInMonth; day++) {
    const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
    const isToday = today.getDate() === day && today.getMonth() === month && today.getFullYear() === year;
    const hasEvent = calEvents.some(e => e.date === dateStr);

    container.innerHTML += `<div style="text-align:center;padding:4px 1px;border-radius:4px;font-size:.66rem;cursor:pointer;transition:var(--tr);font-weight:500;position:relative;${isToday ? 'background:var(--ag);color:#fff;font-weight:700;' : ''}" onclick="selectCalDay('${dateStr}')">${day}${hasEvent ? '<span style="position:absolute;bottom:1px;left:50%;transform:translateX(-50%);width:3px;height:3px;border-radius:50%;background:var(--a3);"></span>' : ''}</div>`;
  }

  // Standard-Datum setzen
  const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
  if (!$('eventDate').value) $('eventDate').value = todayStr;
}

function calPrev() { calDate.setMonth(calDate.getMonth() - 1); renderCalendar(); }
function calNext() { calDate.setMonth(calDate.getMonth() + 1); renderCalendar(); }

function selectCalDay(dateStr) {
  calSelectedDate = dateStr;
  $('eventDate').value = dateStr;
  const events = calEvents.filter(e => e.date === dateStr);
  $('calEventsTitle').textContent = `Termine ${dateStr.split('-').reverse().join('.')}`;
  $('calEvents').innerHTML = events.length
    ? events.map(e => {
        const idx = calEvents.indexOf(e);
        return `<div style="display:flex;align-items:center;gap:4px;padding:4px 6px;background:var(--b2);border-radius:4px;margin-bottom:1px;font-size:.7rem;border-left:2px solid var(--a1);">
          <span style="font-weight:700;color:var(--a3);font-size:.62rem;">${e.time || '–'}</span>
          <span style="flex:1">${esc(e.title)}</span>
          <button class="del" style="opacity:1;" onclick="calEvents.splice(${idx},1);save('calEvents',calEvents);renderCalendar();selectCalDay('${dateStr}')">✕</button>
        </div>`;
      }).join('')
    : '<div style="color:var(--t3);font-size:.68rem;text-align:center;padding:8px;">Keine Termine</div>';
}

function addEvent() {
  const date = $('eventDate').value;
  const time = $('eventTime').value;
  const title = $('eventTitle').value.trim();
  if (!date || !title) return;
  calEvents.push({ date, time, title });
  save('calEvents', calEvents);
  $('eventTitle').value = '';
  renderCalendar();
  selectCalDay(date);
}
renderCalendar();

// ========================================
// 📊 TAGESAUSGABEN
// ========================================
const todayKey = new Date().toDateString();
let dailyExpenses = load('dailyExp_' + todayKey, []);

function renderDailyExp() {
  const list = $('dailyExpList');
  list.innerHTML = '';
  let total = 0;
  dailyExpenses.forEach((e, i) => {
    total += e.amount;
    list.innerHTML += `<li class="li">
      <span class="txt">${esc(e.name)}</span>
      <span style="font-weight:700;color:var(--er);font-size:.72rem;">-${e.amount.toFixed(2)}€</span>
      <button class="del" onclick="dailyExpenses.splice(${i},1);renderDailyExp()">✕</button>
    </li>`;
  });
  $('dailyTotal').textContent = fmt(total) + ' €';
  save('dailyExp_' + todayKey, dailyExpenses);
}

function addDailyExp() {
  const name = $('expName').value.trim();
  const amount = parseFloat($('expAmount').value);
  if (name && amount > 0) {
    dailyExpenses.push({ name, amount });
    $('expName').value = '';
    $('expAmount').value = '';
    renderDailyExp();
  }
}
renderDailyExp();

// ========================================
// 🖼️ LIGHTBOX
// ========================================
function openLightbox(src, type) {
  $('lightboxContent').innerHTML = type === 'video'
    ? `<video src="${src}" controls autoplay style="max-width:90%;max-height:85%;border-radius:var(--r);" onclick="event.stopPropagation()"></video>`
    : `<img src="${src}" onclick="event.stopPropagation()">`;
  $('lightbox').classList.add('show');
}
function closeLightbox() { $('lightbox').classList.remove('show'); $('lightboxContent').innerHTML = ''; }

// ========================================
// 🎵 MEDIEN — Türkische Radiosender
// ========================================
function initMedia() {
  const stations = [
    { name: 'Power FM', genre: 'Pop', url: 'https://playerservices.streamtheworld.com/api/livestream-redirect/POWER_FM' },
    { name: 'Kral Pop', genre: 'Türk Pop', url: 'https://trkvz-radyolar.ercdn.net/kralpop/playlist.m3u8' },
    { name: 'Virgin Radio TR', genre: 'Hit', url: 'https://playerservices.streamtheworld.com/api/livestream-redirect/VIRGIN_RADIO_TURKEY' },
    { name: 'Metro FM', genre: 'Dance', url: 'https://playerservices.streamtheworld.com/api/livestream-redirect/METRO_FM' },
    { name: 'Kral FM', genre: 'Sanat Müzik', url: 'https://trkvz-radyolar.ercdn.net/kralfm/playlist.m3u8' },
    { name: 'TRT Türkü', genre: 'Halk Müzik', url: 'https://trtradyo-canli.medya.trt.com.tr/trtturku.mp3' },
    { name: 'Kral Arabesk', genre: 'Arabesk', url: 'https://trkvz-radyolar.ercdn.net/kralarabesk/playlist.m3u8' },
    { name: 'Slow Türk', genre: 'Slow', url: 'https://trkvz-radyolar.ercdn.net/slowturk/playlist.m3u8' },
    { name: 'NTV Radyo', genre: 'Haber', url: 'https://trkvz-radyolar.ercdn.net/ntvradyo/playlist.m3u8' },
    { name: 'Best FM', genre: 'Mix', url: 'https://trkvz-radyolar.ercdn.net/bestfm/playlist.m3u8' },
    { name: 'Show Radyo', genre: 'Pop', url: 'https://trkvz-radyolar.ercdn.net/showradyo/playlist.m3u8' },
    { name: 'Pal Station', genre: 'Remix', url: 'https://trkvz-radyolar.ercdn.net/palstation/playlist.m3u8' }
  ];

  let currentStation = -1;
  const audio = $('radioAudio');

  $('radioBody').innerHTML = `
    <div style="background:var(--b2);border:1px solid var(--bd);border-radius:var(--r);padding:14px;text-align:center;">
      <div class="vinyl" id="vinyl"></div>
      <div style="font-size:.8rem;font-weight:700;background:var(--ag);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;" id="nowPlaying">Sender wählen...</div>
      <div style="font-size:.58rem;color:var(--t3);margin-bottom:6px;" id="nowGenre">—</div>
      <div style="display:flex;justify-content:center;gap:5px;margin-bottom:6px;">
        <button class="hb" onclick="prevStation()">⏮</button>
        <button class="hb" id="playBtn" onclick="toggleRadio()" style="width:36px;height:36px;border-radius:50%;font-size:.9rem;">▶</button>
        <button class="hb" onclick="nextStation()">⏭</button>
      </div>
      <div style="display:flex;align-items:center;justify-content:center;gap:4px;">
        <span style="font-size:.7rem;">🔈</span>
        <input type="range" style="width:80px;accent-color:var(--a1);" id="volumeSlider" min="0" max="100" value="70" oninput="audio.volume=this.value/100">
        <span style="font-size:.7rem;">🔊</span>
      </div>
    </div>`;

  window.playStation = function(idx) {
    currentStation = idx;
    audio.src = stations[idx].url;
    audio.volume = $('volumeSlider').value / 100;
    audio.play().catch(() => {});
    $('nowPlaying').textContent = stations[idx].name;
    $('nowGenre').textContent = stations[idx].genre;
    $('vinyl').classList.add('spin');
    $('playBtn').textContent = '⏸';
    filterRadio();
  };

  window.toggleRadio = function() {
    if (currentStation === -1) { playStation(0); return; }
    if (audio.paused) {
      audio.play();
      $('vinyl').classList.add('spin');
      $('playBtn').textContent = '⏸';
    } else {
      audio.pause();
      $('vinyl').classList.remove('spin');
      $('playBtn').textContent = '▶';
    }
  };

  window.prevStation = function() { playStation(currentStation <= 0 ? stations.length - 1 : currentStation - 1); };
  window.nextStation = function() { playStation(currentStation >= stations.length - 1 ? 0 : currentStation + 1); };

  window.filterRadio = function() {
    const filter = $('radioSearch').value.toLowerCase();
    $('radioList').innerHTML = stations
      .filter(s => !filter || s.name.toLowerCase().includes(filter))
      .map((s, i) => {
        const realIdx = stations.indexOf(s);
        return `<div class="radio-st${realIdx === currentStation ? ' playing' : ''}" onclick="playStation(${realIdx})">
          <div style="width:26px;height:26px;border-radius:5px;background:var(--ag);display:flex;align-items:center;justify-content:center;font-size:.7rem;">🎵</div>
          <div style="flex:1">
            <div style="font-size:.7rem;font-weight:600;">${s.name}</div>
            <div style="font-size:.56rem;color:var(--t3);">${s.genre}</div>
          </div>
        </div>`;
      }).join('');
  };
  filterRadio();
}

// ========================================
// 🛠️ TOOLS
// ========================================
function initTools() {
  // Taschenrechner
  let calcExpr = '';
  $('calcBody').innerHTML = `
    <div style="width:100%;text-align:right;background:var(--b2);border:1px solid var(--bd);color:var(--t1);padding:9px;border-radius:var(--rs);font-size:1.1rem;font-weight:700;margin-bottom:5px;" id="calcDisplay">0</div>
    <div style="display:grid;grid-template-columns:repeat(4,1fr);gap:2px;">
      <button class="btn btn-o" onclick="calcClear()">C</button>
      <button class="btn btn-o" onclick="calcInput('(')">(</button>
      <button class="btn btn-o" onclick="calcInput(')')">)</button>
      <button class="btn btn-o" onclick="calcInput('/')">÷</button>
      <button class="btn btn-o" onclick="calcInput('7')">7</button>
      <button class="btn btn-o" onclick="calcInput('8')">8</button>
      <button class="btn btn-o" onclick="calcInput('9')">9</button>
      <button class="btn btn-o" onclick="calcInput('*')">×</button>
      <button class="btn btn-o" onclick="calcInput('4')">4</button>
      <button class="btn btn-o" onclick="calcInput('5')">5</button>
      <button class="btn btn-o" onclick="calcInput('6')">6</button>
      <button class="btn btn-o" onclick="calcInput('-')">−</button>
      <button class="btn btn-o" onclick="calcInput('1')">1</button>
      <button class="btn btn-o" onclick="calcInput('2')">2</button>
      <button class="btn btn-o" onclick="calcInput('3')">3</button>
      <button class="btn btn-o" onclick="calcInput('+')">+</button>
      <button class="btn btn-o" onclick="calcInput('0')">0</button>
      <button class="btn btn-o" onclick="calcInput('.')">.</button>
      <button class="btn btn-o" onclick="calcBackspace()">⌫</button>
      <button class="btn" onclick="calcResult()">=</button>
    </div>`;

  window.calcInput = v => { calcExpr += v; $('calcDisplay').textContent = calcExpr || '0'; };
  window.calcClear = () => { calcExpr = ''; $('calcDisplay').textContent = '0'; };
  window.calcBackspace = () => { calcExpr = calcExpr.slice(0, -1); $('calcDisplay').textContent = calcExpr || '0'; };
  window.calcResult = () => {
    try {
      let r = Function('"use strict"; return (' + calcExpr + ')')();
      r = Math.round(r * 1e10) / 1e10;
      $('calcDisplay').textContent = r;
      calcExpr = String(r);
    } catch { $('calcDisplay').textContent = 'Fehler'; calcExpr = ''; }
  };

  // Passwort Generator
  $('pwBody').innerHTML = `
    <div style="background:var(--b2);border:1px solid var(--bd);padding:8px;border-radius:var(--rs);font-family:monospace;font-size:.78rem;word-break:break-all;margin-bottom:5px;color:var(--a3);font-weight:600;min-height:35px;" id="pwDisplay">—</div>
    <div style="display:flex;gap:3px;">
      <button class="btn" onclick="generatePassword()">⚡ Generieren</button>
      <button class="btn btn-o" onclick="navigator.clipboard.writeText($('pwDisplay').textContent)">📋 Kopieren</button>
    </div>`;

  window.generatePassword = () => {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*';
    let pw = '';
    const arr = new Uint32Array(20);
    crypto.getRandomValues(arr);
    for (let i = 0; i < 20; i++) pw += chars[arr[i] % chars.length];
    $('pwDisplay').textContent = pw;
  };

  // Währungsrechner
  let rates = null;
  $('currBody').innerHTML = `
    <div class="ig"><input type="number" class="inp" id="currAmount" value="100" oninput="convertCurrency()"></div>
    <div class="ig">
      <select class="inp" id="currFrom" onchange="convertCurrency()">
        <option value="EUR">🇪🇺 EUR</option><option value="USD">🇺🇸 USD</option>
        <option value="GBP">🇬🇧 GBP</option><option value="TRY">🇹🇷 TRY</option>
      </select>
      <span style="color:var(--t3);">→</span>
      <select class="inp" id="currTo" onchange="convertCurrency()">
        <option value="EUR">EUR</option><option value="USD" selected>USD</option>
        <option value="GBP">GBP</option><option value="TRY">TRY</option>
      </select>
    </div>
    <div style="text-align:center;font-size:1rem;font-weight:700;color:var(--a3);padding:8px;background:var(--b2);border-radius:var(--rs);border:1px solid var(--bd);" id="currResult">—</div>`;

  (async () => {
    try {
      const res = await fetch('https://api.frankfurter.app/latest?from=EUR');
      const data = await res.json();
      rates = data.rates;
      rates.EUR = 1;
      convertCurrency();
    } catch { rates = { EUR: 1, USD: 1.08, GBP: 0.86, TRY: 34.5 }; }
  })();

  window.convertCurrency = () => {
    if (!rates) return;
    const amount = parseFloat($('currAmount').value);
    const from = $('currFrom').value;
    const to = $('currTo').value;
    if (isNaN(amount)) { $('currResult').textContent = '—'; return; }
    $('currResult').textContent = `${amount.toFixed(2)} ${from} = ${(amount / rates[from] * rates[to]).toFixed(2)} ${to}`;
  };
}

// ========================================
// 💬 KOMMUNIKATION
// ========================================
function initComm() {
  // WhatsApp
  let waContacts = load('waContacts', []);
  $('waBody').innerHTML = `
    <div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;">
      <div>
        <div class="ig">
          <input class="inp" id="waName" placeholder="Name">
          <input class="inp" id="waPhone" placeholder="+49...">
          <button class="btn btn-s" style="background:#25D366;" onclick="addWAContact()">+</button>
        </div>
        <div id="waContactList"></div>
      </div>
      <div>
        <input class="inp" id="waDirectNum" placeholder="+49..." style="margin-bottom:3px;">
        <textarea class="inp" id="waMessage" placeholder="Nachricht..." style="min-height:40px;margin-bottom:3px;"></textarea>
        <button class="btn" style="background:#25D366;width:100%;" onclick="sendWhatsApp()">💬 Senden</button>
      </div>
    </div>`;

  window.renderWAContacts = () => {
    $('waContactList').innerHTML = waContacts.map((c, i) =>
      `<div style="display:flex;align-items:center;gap:5px;padding:5px;background:var(--b2);border:1px solid var(--bd);border-radius:var(--rs);margin-bottom:2px;cursor:pointer;" onclick="window.open('https://wa.me/${c.phone.replace(/\\s/g,'')}')">
        <div style="width:24px;height:24px;border-radius:50%;background:var(--ag);display:flex;align-items:center;justify-content:center;font-size:.6rem;font-weight:700;color:#fff;">${c.name[0]}</div>
        <div style="flex:1;font-size:.68rem;font-weight:600;">${esc(c.name)}<div style="font-size:.55rem;color:var(--t3);">${esc(c.phone)}</div></div>
        <button class="del" style="opacity:.5;" onclick="event.stopPropagation();waContacts.splice(${i},1);save('waContacts',waContacts);renderWAContacts()">✕</button>
      </div>`
    ).join('');
    save('waContacts', waContacts);
  };

  window.addWAContact = () => {
    const name = $('waName').value.trim();
    const phone = $('waPhone').value.trim();
    if (name && phone) {
      waContacts.push({ name, phone });
      $('waName').value = ''; $('waPhone').value = '';
      renderWAContacts();
    }
  };

  window.sendWhatsApp = () => {
    const num = $('waDirectNum').value.replace(/\s/g, '');
    const msg = $('waMessage').value;
    if (num) window.open(`https://wa.me/${num}${msg ? '?text=' + encodeURIComponent(msg) : ''}`);
  };

  renderWAContacts();

  // Übersetzer
  $('transBody').innerHTML = `
    <div style="display:flex;gap:3px;margin-bottom:4px;">
      <select class="inp" id="transFrom"><option value="de">🇩🇪</option><option value="en">🇬🇧</option><option value="tr">🇹🇷</option><option value="fr">🇫🇷</option><option value="ar">🇸🇦</option></select>
      <select class="inp" id="transTo"><option value="de">🇩🇪</option><option value="en" selected>🇬🇧</option><option value="tr">🇹🇷</option></select>
    </div>
    <textarea class="inp" id="transInput" placeholder="Text eingeben..." style="margin-bottom:3px;"></textarea>
    <textarea class="inp" id="transOutput" placeholder="Übersetzung..." readonly style="opacity:.8;margin-bottom:3px;"></textarea>
    <button class="btn" onclick="doTranslate()">🌍 Übersetzen</button>`;

  window.doTranslate = async () => {
    const text = $('transInput').value.trim();
    if (!text) return;
    try {
      const res = await fetch(`https://api.mymemory.translated.net/get?q=${encodeURIComponent(text)}&langpair=${$('transFrom').value}|${$('transTo').value}`);
      const data = await res.json();
      $('transOutput').value = data.responseData.translatedText;
    } catch { $('transOutput').value = 'Fehler!'; }
  };
}

// ========================================
// 🏠 IMMOBILIEN (Vereinfacht für Sauberkeit)
// ========================================
function initImmo() {
  $('immoBody').innerHTML = `
    <div class="ig"><select class="inp" id="imType" style="flex:.3"><option value="sell">🔴 Verkauf</option><option value="buy">🟢 Kauf</option><option value="rent">🔵 Miete</option></select><select class="inp" id="imPropType"><option>🏢 Wohnung</option><option>🏠 Haus</option><option>🏗️ Grundstück</option><option>🏬 Gewerbe</option><option>🏰 Villa</option></select></div>
    <div class="ig"><input class="inp" id="imTitle" placeholder="Titel"><input class="inp" id="imRef" placeholder="Ref-Nr." style="flex:.3"></div>
    <div class="ig"><input class="inp" id="imAddr" placeholder="Adresse"><input class="inp" id="imPLZ" placeholder="PLZ" style="flex:.2"><input class="inp" id="imCity" placeholder="Stadt" style="flex:.3"></div>
    <div class="ig"><input type="number" class="inp" id="imPrice" placeholder="Preis €" style="flex:.3"><input type="number" class="inp" id="imSqm" placeholder="m²" style="flex:.2"><input type="number" class="inp" id="imRooms" placeholder="Zimmer" style="flex:.15"><input type="number" class="inp" id="imBath" placeholder="Bäder" style="flex:.15"><input type="number" class="inp" id="imYear" placeholder="Baujahr" style="flex:.2"></div>
    <textarea class="inp" id="imDesc" placeholder="Beschreibung..." style="margin-bottom:4px;"></textarea>
    <input class="inp" id="imContact" placeholder="Kontakt: Name, Tel, Email" style="margin-bottom:4px;">
    <div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:4px;margin-bottom:6px;">
      <div class="gal-add" onclick="$('imImgFile').click()"><span>📷</span>Bilder</div>
      <div class="gal-add" onclick="$('imVidFile').click()"><span>🎥</span>Videos</div>
      <div class="gal-add" onclick="$('im360File').click()" style="border-color:var(--ok);"><span>🔄</span>360°</div>
    </div>
    <input type="file" id="imImgFile" accept="image/*" multiple hidden onchange="handleImmoImages(this)">
    <input type="file" id="imVidFile" accept="video/*" multiple hidden onchange="handleImmoVideos(this)">
    <input type="file" id="im360File" accept="image/*" multiple hidden onchange="handleImmo360(this)">
    <div class="gallery" id="imGallery"><div style="grid-column:1/-1;text-align:center;padding:12px;color:var(--t3);font-size:.7rem;">📷 Medien hier hochladen</div></div>
    <div id="panoSection" style="display:none;"><div style="font-size:.66rem;font-weight:700;color:var(--a3);margin:6px 0 3px;">🔄 360° Panorama</div><div class="pano-thumbs" id="panoThumbs"></div><div class="pano-view" id="panoViewer"></div><div class="pano-ctrls" style="margin-top:4px;"><button class="pano-btn" onclick="panoToggleRotate()">🔄 Auto</button><button class="pano-btn" onclick="$('panoViewer')?.requestFullscreen?.()">🖥️ Vollbild</button><button class="pano-btn" onclick="if(panoInstance)panoInstance.setHfov(Math.max(50,panoInstance.getHfov()-10))">🔍+</button><button class="pano-btn" onclick="if(panoInstance)panoInstance.setHfov(Math.min(120,panoInstance.getHfov()+10))">🔍-</button></div></div>
    <div id="mapSection" style="display:none;"><div style="font-size:.66rem;font-weight:700;color:var(--a3);margin:6px 0 3px;">🗺️ Karte</div><div class="ig"><input class="inp" id="mapSearchInput" placeholder="📍 Adresse suchen..."><button class="btn btn-s" onclick="searchMapAddress()">🔍</button><button class="btn btn-s btn-o" onclick="mapGPS()">📍 GPS</button></div><div class="map-wrap" id="mapContainer"></div></div>
    <div class="exp-row"><button class="exp-btn" onclick="exportExposePDF()"><span>📄</span>Exposé PDF</button><button class="exp-btn" onclick="exportExposeWord()"><span>📝</span>Word</button><button class="exp-btn" onclick="exportExposeExcel()"><span>📊</span>Excel</button><button class="exp-btn" onclick="showImmoMap()"><span>🗺️</span>Karte</button></div>`;

  // Bilder, Videos, 360° Upload
  let immoImages = [], immoVideos = [], panoImages = [];
  let panoInstance = null, currentPanoIdx = 0;
  window.panoInstance = null; // Global für Controls

  window.handleImmoImages = input => {
    Array.from(input.files).forEach(f => {
      const reader = new FileReader();
      reader.onload = e => { immoImages.push({ name: f.name, data: e.target.result }); renderImmoGallery(); };
      reader.readAsDataURL(f);
    }); input.value = '';
  };

  window.handleImmoVideos = input => {
    Array.from(input.files).forEach(f => {
      const reader = new FileReader();
      reader.onload = e => { immoVideos.push({ name: f.name, data: e.target.result }); renderImmoGallery(); };
      reader.readAsDataURL(f);
    }); input.value = '';
  };

  window.handleImmo360 = input => {
    Array.from(input.files).forEach(f => {
      const reader = new FileReader();
      reader.onload = e => {
        panoImages.push({ name: f.name, data: e.target.result });
        $('panoSection').style.display = 'block';
        renderPanoThumbs();
        loadPano(panoImages.length - 1);
      };
      reader.readAsDataURL(f);
    }); input.value = '';
  };

  function renderImmoGallery() {
    const g = $('imGallery'); g.innerHTML = '';
    immoImages.forEach((img, i) => {
      g.innerHTML += `<div class="gal-item" onclick="openLightbox('${img.data}','image')"><img src="${img.data}"><button class="gal-del" onclick="event.stopPropagation();immoImages.splice(${i},1);renderImmoGallery()">✕</button></div>`;
    });
    immoVideos.forEach((vid, i) => {
      g.innerHTML += `<div class="gal-item" onclick="openLightbox('${vid.data}','video')"><video src="${vid.data}" muted></video><button class="gal-del" onclick="event.stopPropagation();immoVideos.splice(${i},1);renderImmoGallery()">✕</button></div>`;
    });
    if (!immoImages.length && !immoVideos.length) {
      g.innerHTML = '<div style="grid-column:1/-1;text-align:center;padding:12px;color:var(--t3);font-size:.7rem;">📷 Medien hochladen</div>';
    }
  }

  // 360° Pannellum
  function renderPanoThumbs() {
    $('panoThumbs').innerHTML = panoImages.map((p, i) =>
      `<img class="${i === currentPanoIdx ? 'active' : ''}" src="${p.data}" onclick="loadPano(${i})">`
    ).join('');
  }

  window.loadPano = idx => {
    currentPanoIdx = idx; renderPanoThumbs();
    if (panoInstance) { panoInstance.destroy(); panoInstance = null; }
    $('panoViewer').innerHTML = '';
    panoInstance = pannellum.viewer('panoViewer', {
      type: 'equirectangular', panorama: panoImages[idx].data,
      autoLoad: true, autoRotate: -2, compass: true,
      showZoomCtrl: true, showFullscreenCtrl: true, mouseZoom: true,
      hfov: 110, minHfov: 50, maxHfov: 120
    });
    window.panoInstance = panoInstance;
  };

  window.panoToggleRotate = () => {
    if (!panoInstance) return;
    try { panoInstance.stopAutoRotate(); } catch { panoInstance.startAutoRotate(-2); }
  };

  // Leaflet Map
  let leafletMap = null, leafletMarker = null;

  window.showImmoMap = () => {
    $('mapSection').style.display = 'block';
    setTimeout(() => {
      if (!leafletMap) {
        leafletMap = L.map('mapContainer').setView([51.16, 10.45], 6);
        L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
          attribution: '© OpenStreetMap'
        }).addTo(leafletMap);
        leafletMap.on('click', e => setMarker(e.latlng.lat, e.latlng.lng));
      }
      leafletMap.invalidateSize();
      const addr = $('imAddr')?.value || '';
      const city = $('imCity')?.value || '';
      if (addr || city) $('mapSearchInput').value = `${addr}, ${city}`;
    }, 300);
  };

  function setMarker(lat, lng) {
    if (leafletMarker) leafletMap.removeLayer(leafletMarker);
    leafletMarker = L.marker([lat, lng]).addTo(leafletMap);
    leafletMap.setView([lat, lng], 15);
  }

  window.searchMapAddress = async () => {
    const q = $('mapSearchInput').value.trim();
    if (!q) return;
    try {
      const res = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(q)}`);
      const data = await res.json();
      if (data[0]) {
        if (!leafletMap) showImmoMap();
        setTimeout(() => setMarker(parseFloat(data[0].lat), parseFloat(data[0].lon)), 500);
      } else alert('Nicht gefunden!');
    } catch { alert('Fehler!'); }
  };

  window.mapGPS = () => {
    navigator.geolocation?.getCurrentPosition(pos => {
      if (!leafletMap) showImmoMap();
      setTimeout(() => setMarker(pos.coords.latitude, pos.coords.longitude), 500);
    });
  };

  // PDF Export
  window.exportExposePDF = () => {
    const { jsPDF } = window.jspdf;
    const doc = new jsPDF();
    doc.setFillColor(99, 102, 241); doc.rect(0, 0, 210, 30, 'F');
    doc.setTextColor(255); doc.setFontSize(20); doc.text('EXPOSÉ', 20, 17);
    doc.setFontSize(9); doc.text($('imTitle').value || '—', 20, 25);
    let y = 38;
    if (immoImages[0]) { try { doc.addImage(immoImages[0].data, 'JPEG', 15, y, 180, 80); y += 88; } catch {} }
    doc.setTextColor(0); doc.setFontSize(13); doc.text($('imTitle').value || '—', 15, y); y += 7;
    doc.setFontSize(9); doc.text(`${$('imAddr').value}, ${$('imPLZ').value} ${$('imCity').value}`, 15, y); y += 6;
    doc.setTextColor(99, 102, 241); doc.setFontSize(14);
    doc.text(`${parseFloat($('imPrice').value || 0).toLocaleString('de-DE')} EUR`, 15, y); y += 10;
    doc.setTextColor(0); doc.setFontSize(8);
    doc.text(`m²: ${$('imSqm').value} | Zimmer: ${$('imRooms').value} | Bäder: ${$('imBath').value} | Baujahr: ${$('imYear').value}`, 15, y); y += 6;
    if ($('imDesc').value) {
      const lines = doc.splitTextToSize($('imDesc').value, 175);
      doc.text(lines, 15, y); y += lines.length * 4 + 5;
    }
    if ($('imContact').value) doc.text('Kontakt: ' + $('imContact').value, 15, y);
    doc.save('expose.pdf');
  };

  // Word Export
  window.exportExposeWord = async () => {
    const { Document, Packer, Paragraph, TextRun, HeadingLevel } = docx;
    const children = [
      new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun({ text: 'EXPOSÉ — ' + ($('imTitle').value || '—'), bold: true, size: 32, color: '4F46E5' })] }),
      new Paragraph({ children: [new TextRun({ text: `${$('imAddr').value}, ${$('imPLZ').value} ${$('imCity').value}`, size: 20 })] }),
      new Paragraph({ children: [new TextRun({ text: `${parseFloat($('imPrice').value || 0).toLocaleString('de-DE')} EUR`, bold: true, size: 26, color: '22C55E' })] }),
      new Paragraph({ children: [new TextRun({ text: `m²: ${$('imSqm').value} | Zimmer: ${$('imRooms').value} | Bäder: ${$('imBath').value} | Baujahr: ${$('imYear').value}`, size: 18 })] }),
      new Paragraph({}),
      new Paragraph({ children: [new TextRun({ text: $('imDesc').value || '', size: 18 })] })
    ];
    saveAs(await Packer.toBlob(new Document({ sections: [{ children }] })), 'expose.docx');
  };

  // Excel Export
  window.exportExposeExcel = () => {
    const wb = XLSX.utils.book_new();
    XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet([
      ['EXPOSÉ'], ['Titel', $('imTitle').value], ['Adresse', $('imAddr').value + ', ' + $('imCity').value],
      ['Preis', parseFloat($('imPrice').value) || 0], ['m²', parseFloat($('imSqm').value) || 0],
      ['Zimmer', parseInt($('imRooms').value) || 0], ['Baujahr', $('imYear').value]
    ]), 'Exposé');
    XLSX.writeFile(wb, 'expose.xlsx');
  };
}

// ========================================
// 🚗 AUTO
// ========================================
function initAuto() {
  let autos = load('autos', []);
  $('autoBody').innerHTML = `
    <div class="ig"><select class="inp" id="autoType" style="flex:.3"><option value="sell">🔴 Verkauf</option><option value="buy">🟢 Kauf</option></select><input class="inp" id="autoBrand" placeholder="Marke"><input class="inp" id="autoModel" placeholder="Modell"></div>
    <div class="ig"><input type="number" class="inp" id="autoYear" placeholder="Jahr" style="flex:.2"><input type="number" class="inp" id="autoPrice" placeholder="Preis €"><input type="number" class="inp" id="autoKm" placeholder="km" style="flex:.3"><select class="inp" id="autoFuel" style="flex:.3"><option>Benzin</option><option>Diesel</option><option>Elektro</option><option>Hybrid</option></select></div>
    <div class="ig"><button class="btn" onclick="addAutoEntry()">➕ Hinzufügen</button><button class="btn btn-o" onclick="exportAutoPDF()">📄 PDF</button></div>
    <div style="max-height:250px;overflow-y:auto;" id="autoList"></div>`;

  $('autoStats').innerHTML = `
    <div class="fin-row">
      <div class="fin-box"><div class="fin-lbl">Fahrzeuge</div><div class="fin-val bal" id="autoCount">0</div></div>
      <div class="fin-box"><div class="fin-lbl">Ø Preis</div><div class="fin-val inc" id="autoAvg">0€</div></div>
      <div class="fin-box"><div class="fin-lbl">Gesamtwert</div><div class="fin-val bal" id="autoTotal">0€</div></div>
    </div>`;

  window.addAutoEntry = () => {
    const entry = {
      type: $('autoType').value, brand: $('autoBrand').value.trim(),
      model: $('autoModel').value.trim(), year: parseInt($('autoYear').value) || 0,
      price: parseFloat($('autoPrice').value) || 0, km: parseInt($('autoKm').value) || 0,
      fuel: $('autoFuel').value, date: new Date().toISOString().split('T')[0]
    };
    if (!entry.brand) return;
    autos.push(entry); save('autos', autos); renderAutos();
  };

  function renderAutos() {
    $('autoList').innerHTML = autos.map((a, i) =>
      `<div style="background:var(--b2);border:1px solid var(--bd);border-radius:var(--rs);padding:7px;margin-bottom:3px;">
        <div style="font-weight:700;font-size:.78rem;">🚗 ${esc(a.brand)} ${esc(a.model)}</div>
        <div style="font-size:.66rem;color:var(--t2);">📅 ${a.year} · 🛣️ ${a.km.toLocaleString('de-DE')}km · ⛽ ${a.fuel}</div>
        <div style="font-size:.9rem;font-weight:800;color:var(--a3);">💰 ${a.price.toLocaleString('de-DE')}€</div>
        <button class="btn btn-s btn-d" onclick="autos.splice(${i},1);save('autos',autos);renderAutos()">🗑️</button>
      </div>`
    ).join('');
    $('autoCount').textContent = autos.length;
    $('autoTotal').textContent = autos.reduce((s, a) => s + a.price, 0).toLocaleString('de-DE') + '€';
    $('autoAvg').textContent = autos.length ? Math.round(autos.reduce((s, a) => s + a.price, 0) / autos.length).toLocaleString('de-DE') + '€' : '0€';
  }

  window.exportAutoPDF = () => {
    const { jsPDF } = window.jspdf;
    const doc = new jsPDF();
    doc.setFontSize(16); doc.text('Fahrzeug-Portfolio', 20, 20);
    let y = 30;
    autos.forEach((a, i) => {
      doc.setFontSize(10); doc.text(`${a.brand} ${a.model} (${a.year}) — ${a.price.toLocaleString('de-DE')} EUR`, 20, y); y += 6;
    });
    doc.save('fahrzeuge.pdf');
  };

  renderAutos();
}

// ========================================
// 💰 FINANZEN
// ========================================
function initFinance() {
  let finPriv = load('finPriv', {});
  $('finPrivBody').innerHTML = `
    <div class="ig"><select class="inp" id="fpMonth" onchange="renderFinPriv()"><option>Jan</option><option>Feb</option><option>Mär</option><option>Apr</option><option>Mai</option><option>Jun</option><option>Jul</option><option>Aug</option><option>Sep</option><option>Okt</option><option>Nov</option><option>Dez</option></select><input type="number" class="inp" id="fpYear" value="2025" style="flex:.3" onchange="renderFinPriv()"></div>
    <div class="fin-row"><div class="fin-box"><div class="fin-lbl">Einnahmen</div><div class="fin-val inc" id="fpIncome">0€</div></div><div class="fin-box"><div class="fin-lbl">Ausgaben</div><div class="fin-val exp" id="fpExpense">0€</div></div><div class="fin-box"><div class="fin-lbl">Bilanz</div><div class="fin-val bal" id="fpBalance">0€</div></div></div>
    <div class="ig"><select class="inp" id="fpType" style="flex:.3"><option value="income">➕</option><option value="expense">➖</option></select><input class="inp" id="fpDesc" placeholder="Beschreibung"><input type="number" class="inp" id="fpAmt" placeholder="€" style="flex:.2"><select class="inp" id="fpCat" style="flex:.3"><option>Gehalt</option><option>Miete</option><option>Strom</option><option>Essen</option><option>Transport</option><option>Sonstiges</option></select><button class="btn btn-s" onclick="addFinPriv()">+</button></div>
    <div style="max-height:150px;overflow-y:auto;" id="fpList"></div>
    <div style="display:flex;gap:3px;margin-top:4px;"><button class="btn btn-o btn-s" onclick="exportFinPDF()">📄 PDF</button><button class="btn btn-o btn-s" onclick="exportFinExcel()">📊 Excel</button></div>`;

  const fpKey = () => $('fpMonth').selectedIndex + '-' + $('fpYear').value;

  window.addFinPriv = () => {
    const k = fpKey();
    const type = $('fpType').value, desc = $('fpDesc').value.trim();
    const amt = parseFloat($('fpAmt').value), cat = $('fpCat').value;
    if (!desc || !amt) return;
    if (!finPriv[k]) finPriv[k] = [];
    finPriv[k].push({ type, desc, amt, cat });
    save('finPriv', finPriv);
    $('fpDesc').value = ''; $('fpAmt').value = '';
    renderFinPriv();
  };

  window.renderFinPriv = () => {
    const data = finPriv[fpKey()] || [];
    const list = $('fpList'); list.innerHTML = '';
    let inc = 0, exp = 0;
    data.forEach((e, i) => {
      if (e.type === 'income') inc += e.amt; else exp += e.amt;
      list.innerHTML += `<div style="display:flex;align-items:center;gap:4px;padding:4px 6px;background:var(--b2);border-radius:var(--rs);margin-bottom:1px;font-size:.7rem;border-left:2px solid ${e.type === 'income' ? 'var(--ok)' : 'var(--er)'};">
        <span style="flex:1">${esc(e.desc)}</span>
        <span style="font-weight:700;color:${e.type === 'income' ? 'var(--ok)' : 'var(--er)'};">${e.type === 'income' ? '+' : '-'}${e.amt.toFixed(2)}€</span>
        <button class="del" style="opacity:.5;" onclick="finPriv['${fpKey()}'].splice(${i},1);save('finPriv',finPriv);renderFinPriv()">✕</button>
      </div>`;
    });
    $('fpIncome').textContent = fmt(inc) + '€';
    $('fpExpense').textContent = fmt(exp) + '€';
    $('fpBalance').textContent = fmt(inc - exp) + '€';
  };

  window.exportFinPDF = () => {
    const { jsPDF } = window.jspdf; const doc = new jsPDF();
    doc.setFontSize(14); doc.text('Finanzbericht', 20, 20);
    let y = 30;
    (finPriv[fpKey()] || []).forEach(e => {
      doc.setFontSize(8); doc.text(`${e.type === 'income' ? '+' : '-'} ${e.desc} — ${e.amt.toFixed(2)} EUR`, 20, y); y += 5;
    });
    doc.save('finanzen.pdf');
  };

  window.exportFinExcel = () => {
    const wb = XLSX.utils.book_new();
    const data = [['Typ', 'Beschreibung', 'Kategorie', 'Betrag']];
    (finPriv[fpKey()] || []).forEach(e => data.push([e.type, e.desc, e.cat, e.amt]));
    XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(data), 'Finanzen');
    XLSX.writeFile(wb, 'finanzen.xlsx');
  };

  renderFinPriv();
  $('fpMonth').selectedIndex = new Date().getMonth();

  // Business (vereinfacht)
  $('finBizBody').innerHTML = '<div style="text-align:center;color:var(--t3);padding:15px;font-size:.75rem;">Gleiche Struktur wie Privat</div>';
}

// ========================================
// 📜 VERWALTUNG
// ========================================
function initAdmin() {
  // Testament
  let testament = load('testament', { heirs: [], assets: [] });
  $('testBody').innerHTML = `
    <div class="mv-section"><h4>👤 Erblasser</h4><div class="ig"><input class="inp" id="testName" placeholder="Name"><input type="date" class="inp" id="testDOB"></div><input class="inp" id="testAddr" placeholder="Adresse" style="margin-bottom:3px;"></div>
    <div class="mv-section"><h4>👥 Erben</h4><div class="ig"><input class="inp" id="heirName" placeholder="Name"><input class="inp" id="heirRel" placeholder="Beziehung" style="flex:.3"><input type="number" class="inp" id="heirShare" placeholder="%" style="flex:.2"><button class="btn btn-s" onclick="addHeir()">+</button></div><ul class="ls" id="heirList"></ul></div>
    <div class="mv-section"><h4>🏠 Vermögen</h4><div class="ig"><input class="inp" id="assetName" placeholder="Beschreibung"><input type="number" class="inp" id="assetVal" placeholder="€" style="flex:.3"><button class="btn btn-s" onclick="addAsset()">+</button></div><ul class="ls" id="assetList"></ul></div>
    <textarea class="inp" id="testWishes" placeholder="Letzte Wünsche..." style="margin-bottom:4px;"></textarea>
    <div style="display:flex;gap:3px;"><button class="btn" onclick="exportTestamentPDF()">📄 PDF</button><button class="btn btn-o" onclick="saveTestament()">💾</button></div>
    <div style="text-align:center;font-size:.6rem;color:var(--t3);margin-top:3px;">⚠️ Rechtlich unverbindlich!</div>`;

  window.addHeir = () => {
    const n = $('heirName').value.trim(), r = $('heirRel').value.trim(), s = parseFloat($('heirShare').value) || 0;
    if (!n) return; testament.heirs.push({ n, r, s }); save('testament', testament);
    $('heirName').value = ''; $('heirRel').value = ''; $('heirShare').value = ''; renderTestament();
  };
  window.addAsset = () => {
    const n = $('assetName').value.trim(), v = parseFloat($('assetVal').value) || 0;
    if (!n) return; testament.assets.push({ n, v }); save('testament', testament);
    $('assetName').value = ''; $('assetVal').value = ''; renderTestament();
  };

  function renderTestament() {
    $('heirList').innerHTML = testament.heirs.map((h, i) => `<li class="li"><span class="txt">👤 ${esc(h.n)} — ${esc(h.r)} — ${h.s}%</span><button class="del" onclick="testament.heirs.splice(${i},1);save('testament',testament);renderTestament()">✕</button></li>`).join('');
    $('assetList').innerHTML = testament.assets.map((a, i) => `<li class="li"><span class="txt">🏠 ${esc(a.n)} — ${a.v.toLocaleString('de-DE')}€</span><button class="del" onclick="testament.assets.splice(${i},1);save('testament',testament);renderTestament()">✕</button></li>`).join('');
  }

  window.saveTestament = () => {
    testament.name = $('testName').value; testament.dob = $('testDOB').value;
    testament.addr = $('testAddr').value; testament.wishes = $('testWishes').value;
    save('testament', testament); alert('✅ Gespeichert!');
  };

  window.exportTestamentPDF = () => {
    saveTestament();
    const { jsPDF } = window.jspdf; const doc = new jsPDF();
    doc.setFontSize(18); doc.text('TESTAMENT', 85, 20);
    let y = 35; doc.setFontSize(9);
    doc.text(`Name: ${testament.name || '-'}`, 20, y); y += 5;
    testament.heirs.forEach(h => { doc.text(`Erbe: ${h.n} (${h.r}) — ${h.s}%`, 25, y); y += 5; });
    testament.assets.forEach(a => { doc.text(`Vermögen: ${a.n}: ${a.v.toLocaleString('de-DE')} EUR`, 25, y); y += 5; });
    doc.save('testament.pdf');
  };

  renderTestament();
  if (testament.name) $('testName').value = testament.name;
  if (testament.dob) $('testDOB').value = testament.dob;
  if (testament.addr) $('testAddr').value = testament.addr;
  if (testament.wishes) $('testWishes').value = testament.wishes;

  // Hausverwaltung
  let hvObjects = load('hvObjects', []), hvCosts = load('hvCosts', []);
  $('hvBody').innerHTML = `
    <div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;">
      <div>
        <div style="font-size:.6rem;font-weight:700;color:var(--a3);margin-bottom:3px;">🏠 Objekte</div>
        <div class="ig"><input class="inp" id="hvObjName" placeholder="Objekt"><input class="inp" id="hvObjAddr" placeholder="Adresse" style="flex:.5"></div>
        <div class="ig"><input class="inp" id="hvTenant" placeholder="Mieter"><input type="number" class="inp" id="hvRent" placeholder="Miete €" style="flex:.3"><button class="btn btn-s" onclick="addHVObject()">+</button></div>
        <div style="max-height:130px;overflow-y:auto;" id="hvObjList"></div>
      </div>
      <div>
        <div style="font-size:.6rem;font-weight:700;color:var(--a3);margin-bottom:3px;">💰 Kosten</div>
        <div class="ig"><select class="inp" id="hvCostObj" style="flex:.4"></select><input class="inp" id="hvCostDesc" placeholder="Beschreibung"><input type="number" class="inp" id="hvCostAmt" placeholder="€" style="flex:.3"><button class="btn btn-s" onclick="addHVCost()">+</button></div>
        <div style="max-height:130px;overflow-y:auto;" id="hvCostList"></div>
      </div>
    </div>
    <div class="fin-row" style="margin-top:6px;">
      <div class="fin-box"><div class="fin-lbl">Miete/Mo</div><div class="fin-val inc" id="hvTotalRent">0€</div></div>
      <div class="fin-box"><div class="fin-lbl">Kosten</div><div class="fin-val exp" id="hvTotalCost">0€</div></div>
      <div class="fin-box"><div class="fin-lbl">Netto</div><div class="fin-val bal" id="hvNet">0€</div></div>
    </div>`;

  window.addHVObject = () => {
    const n = $('hvObjName').value.trim(), a = $('hvObjAddr').value.trim();
    const t = $('hvTenant').value.trim(), r = parseFloat($('hvRent').value) || 0;
    if (!n) return; hvObjects.push({ n, a, t, r }); save('hvObjects', hvObjects);
    ['hvObjName', 'hvObjAddr', 'hvTenant', 'hvRent'].forEach(id => $(id).value = '');
    renderHV();
  };

  window.addHVCost = () => {
    const o = $('hvCostObj').value, d = $('hvCostDesc').value.trim(), a = parseFloat($('hvCostAmt').value) || 0;
    if (!d || !a) return; hvCosts.push({ o, d, a }); save('hvCosts', hvCosts);
    $('hvCostDesc').value = ''; $('hvCostAmt').value = ''; renderHV();
  };

  function renderHV() {
    const sel = $('hvCostObj'); sel.innerHTML = ''; let totalRent = 0;
    $('hvObjList').innerHTML = hvObjects.map((o, i) => {
      totalRent += o.r;
      sel.innerHTML += `<option>${esc(o.n)}</option>`;
      return `<div style="background:var(--b2);border:1px solid var(--bd);border-radius:var(--rs);padding:5px;margin-bottom:2px;font-size:.68rem;">
        <div style="font-weight:700;">🏠 ${esc(o.n)}</div>
        <div style="color:var(--t3);">👤 ${esc(o.t) || '—'} · <span style="color:var(--ok);font-weight:700;">${o.r.toFixed(2)}€</span></div>
        <button class="del" style="opacity:1;" onclick="hvObjects.splice(${i},1);save('hvObjects',hvObjects);renderHV()">✕</button>
      </div>`;
    }).join('');

    let totalCost = 0;
    $('hvCostList').innerHTML = hvCosts.map((c, i) => {
      totalCost += c.a;
      return `<div style="background:var(--b2);border:1px solid var(--bd);border-radius:var(--rs);padding:4px;margin-bottom:1px;font-size:.65rem;">
        <span>${esc(c.o)}</span> — <span>${esc(c.d)}</span>
        <span style="color:var(--er);font-weight:700;">-${c.a.toFixed(2)}€</span>
        <button class="del" style="opacity:1;" onclick="hvCosts.splice(${i},1);save('hvCosts',hvCosts);renderHV()">✕</button>
      </div>`;
    }).join('');

    $('hvTotalRent').textContent = fmt(totalRent) + '€';
    $('hvTotalCost').textContent = fmt(totalCost) + '€';
    $('hvNet').textContent = fmt(totalRent - totalCost) + '€';
  }
  renderHV();
}

// ========================================
// 🏗️ GRUNDRISS
// ========================================
function initFloorplan() {
  $('fpBody').innerHTML = `
    <div class="fp-toolbar">
      <button class="fp-tool active" onclick="fpSetTool('wall',this)">🧱 Wand</button>
      <button class="fp-tool" onclick="fpSetTool('room',this)">🚪 Raum</button>
      <button class="fp-tool" onclick="fpUndo()">↩️ Undo</button>
      <button class="fp-tool" onclick="fpClear()">🗑️ Löschen</button>
      <label style="font-size:.62rem;color:var(--t2);display:flex;align-items:center;gap:3px;">
        Farbe: <input type="color" id="fpColor" value="#333333" style="width:22px;height:20px;border:none;cursor:pointer;">
      </label>
    </div>
    <div style="border:1px solid var(--bd);border-radius:var(--rs);overflow:hidden;background:#fff;cursor:crosshair;">
      <canvas id="fpCanvas" width="800" height="500" style="display:block;background:#fff;"></canvas>
    </div>
    <div style="display:flex;gap:3px;margin-top:6px;">
      <button class="btn" onclick="fpExportPNG()">💾 PNG</button>
      <button class="btn btn-o" onclick="fpExportPDF()">📄 PDF</button>
    </div>
    <div style="font-size:.7rem;color:var(--t2);margin-top:4px;" id="fpMeasure">📐 Zeichne auf dem Canvas</div>`;

  let fpTool = 'wall', fpObjects = [], fpDrawing = false, fpStartX = 0, fpStartY = 0, fpHistory = [];
  const canvas = $('fpCanvas');
  const ctx = canvas ? canvas.getContext('2d') : null;

  window.fpSetTool = (tool, btn) => {
    fpTool = tool;
    document.querySelectorAll('.fp-tool').forEach(b => b.classList.remove('active'));
    btn.classList.add('active');
  };

  if (canvas) {
    canvas.addEventListener('mousedown', e => {
      const rect = canvas.getBoundingClientRect();
      fpStartX = e.clientX - rect.left; fpStartY = e.clientY - rect.top;
      fpDrawing = true;
    });

    canvas.addEventListener('mousemove', e => {
      const rect = canvas.getBoundingClientRect();
      const mx = e.clientX - rect.left, my = e.clientY - rect.top;
      if (fpDrawing) {
        fpRedraw();
        ctx.strokeStyle = 'rgba(99,102,241,0.5)'; ctx.lineWidth = 2; ctx.setLineDash([5, 5]);
        if (fpTool === 'room') { ctx.strokeRect(fpStartX, fpStartY, mx - fpStartX, my - fpStartY); }
        else { ctx.beginPath(); ctx.moveTo(fpStartX, fpStartY); ctx.lineTo(mx, my); ctx.stroke(); }
        ctx.setLineDash([]);
        const dx = mx - fpStartX, dy = my - fpStartY;
        $('fpMeasure').textContent = `📏 ${(Math.sqrt(dx * dx + dy * dy) / 10).toFixed(1)}m`;
      }
    });

    canvas.addEventListener('mouseup', e => {
      if (!fpDrawing) return; fpDrawing = false;
      const rect = canvas.getBoundingClientRect();
      const ex = e.clientX - rect.left, ey = e.clientY - rect.top;
      const color = $('fpColor').value;

      if (fpTool === 'wall') {
        fpObjects.push({ type: 'wall', x1: fpStartX, y1: fpStartY, x2: ex, y2: ey, color });
      } else if (fpTool === 'room') {
        const name = prompt('Raumname:', 'Zimmer') || 'Zimmer';
        fpObjects.push({
          type: 'room', x: Math.min(fpStartX, ex), y: Math.min(fpStartY, ey),
          w: Math.abs(ex - fpStartX), h: Math.abs(ey - fpStartY), name
        });
      }
      fpHistory.push([...fpObjects]);
      fpRedraw();
    });
  }

  function fpRedraw() {
    if (!ctx) return;
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.fillStyle = '#fff'; ctx.fillRect(0, 0, canvas.width, canvas.height);

    // Grid
    ctx.strokeStyle = '#e8e8e8'; ctx.lineWidth = 0.5;
    for (let x = 0; x < canvas.width; x += 20) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, canvas.height); ctx.stroke(); }
    for (let y = 0; y < canvas.height; y += 20) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(canvas.width, y); ctx.stroke(); }

    fpObjects.forEach(o => {
      if (o.type === 'room') {
        ctx.fillStyle = '#f0f0f0'; ctx.fillRect(o.x, o.y, o.w, o.h);
        ctx.strokeStyle = '#333'; ctx.lineWidth = 3; ctx.strokeRect(o.x, o.y, o.w, o.h);
        ctx.fillStyle = '#333'; ctx.font = 'bold 11px Inter'; ctx.textAlign = 'center';
        ctx.fillText(o.name, o.x + o.w / 2, o.y + o.h / 2 - 3);
        ctx.font = '9px Inter'; ctx.fillStyle = '#666';
        ctx.fillText(`${(o.w / 10).toFixed(1)}×${(o.h / 10).toFixed(1)}m`, o.x + o.w / 2, o.y + o.h / 2 + 10);
      } else if (o.type === 'wall') {
        ctx.strokeStyle = o.color || '#333'; ctx.lineWidth = 4; ctx.lineCap = 'round';
        ctx.beginPath(); ctx.moveTo(o.x1, o.y1); ctx.lineTo(o.x2, o.y2); ctx.stroke();
      }
    });
  }

  window.fpUndo = () => {
    if (fpHistory.length > 1) { fpHistory.pop(); fpObjects = [...fpHistory[fpHistory.length - 1]]; }
    else { fpObjects = []; fpHistory = []; }
    fpRedraw();
  };
  window.fpClear = () => { fpObjects = []; fpHistory = []; fpRedraw(); };
  window.fpExportPNG = () => { const a = document.createElement('a'); a.href = canvas.toDataURL(); a.download = 'grundriss.png'; a.click(); };
  window.fpExportPDF = () => {
    const { jsPDF } = window.jspdf;
    const doc = new jsPDF('landscape');
    doc.text('Grundriss', 15, 15);
    doc.addImage(canvas.toDataURL(), 'PNG', 10, 20, 277, 185);
    doc.save('grundriss.pdf');
  };

  fpRedraw();
}

// ========================================
// 🧾 NEBENKOSTEN
// ========================================
function initNebenkosten() {
  const costTypes = ['Grundsteuer','Wasser','Entwässerung','Heizung','Warmwasser','Aufzug','Müllabfuhr','Versicherung','Gebäudereinigung','Garten','Schornsteinfeger','Sonstiges'];
  let nkTenants = load('nkTenants', []);

  $('nkBody').innerHTML = `
    <div class="ig"><label style="font-size:.66rem;color:var(--t2);font-weight:600;min-width:50px;">Objekt:</label><input class="inp" id="nkObject" placeholder="Adresse"><input type="number" class="inp" id="nkTotalSqm" placeholder="Gesamt m²" style="flex:.2"></div>
    <div class="nk-grid">${costTypes.map(c => `<div class="nk-item"><label>${c}</label><input type="number" class="inp nk-cost-input" data-name="${c}" placeholder="€/Jahr" step="0.01"></div>`).join('')}</div>
    <div class="fin-row">
      <div class="fin-box"><div class="fin-lbl">Gesamt/Jahr</div><div class="fin-val bal" id="nkTotalYear">0€</div></div>
      <div class="fin-box"><div class="fin-lbl">Gesamt/Monat</div><div class="fin-val" style="color:var(--wr);" id="nkTotalMonth">0€</div></div>
      <div class="fin-box"><div class="fin-lbl">€/m²/Monat</div><div class="fin-val" style="color:var(--a3);" id="nkPerSqm">0€</div></div>
    </div>
    <button class="btn" onclick="calculateNK()" style="width:100%;margin-bottom:6px;">🧮 Berechnen</button>
    <div style="font-size:.66rem;font-weight:700;color:var(--a3);margin:6px 0 3px;">👥 Mieter</div>
    <div class="ig"><input class="inp" id="nkTenantName" placeholder="Name"><input type="number" class="inp" id="nkTenantSqm" placeholder="m²" style="flex:.2"><input type="number" class="inp" id="nkTenantPaid" placeholder="Vorauszahlung €" style="flex:.25"><button class="btn btn-s" onclick="addNKTenant()">+</button></div>
    <div id="nkTenantList"></div>
    <div style="display:flex;gap:3px;margin-top:5px;"><button class="btn btn-o" onclick="exportNKPDF()">📄 PDF</button><button class="btn btn-o" onclick="exportNKExcel()">📊 Excel</button></div>`;

  window.calculateNK = () => {
    let total = 0;
    document.querySelectorAll('.nk-cost-input').forEach(inp => total += parseFloat(inp.value) || 0);
    const sqm = parseFloat($('nkTotalSqm').value) || 1;
    $('nkTotalYear').textContent = fmt(total) + '€';
    $('nkTotalMonth').textContent = fmt(total / 12) + '€';
    $('nkPerSqm').textContent = fmt(total / 12 / sqm) + '€';

    $('nkResult').innerHTML = nkTenants.length
      ? nkTenants.map(t => {
          const share = t.sqm / sqm;
          const cost = total * share;
          const diff = t.paid - cost;
          return `<div style="background:var(--b2);border:1px solid var(--bd);border-radius:var(--rs);padding:8px;margin-bottom:4px;">
            <div style="font-weight:700;font-size:.78rem;">👤 ${esc(t.name)}</div>
            <div style="font-size:.66rem;color:var(--t2);">Fläche: ${t.sqm}m² · Anteil: ${(share * 100).toFixed(1)}%</div>
            <div style="font-size:.66rem;color:var(--t2);">Kosten: ${cost.toFixed(2)}€ · Vorauszahlung: ${t.paid.toFixed(2)}€</div>
            <div style="font-size:.82rem;font-weight:800;color:${diff >= 0 ? 'var(--ok)' : 'var(--er)'};">
              ${diff >= 0 ? '🟢 Guthaben' : '🔴 Nachzahlung'}: ${Math.abs(diff).toFixed(2)}€
            </div>
          </div>`;
        }).join('')
      : '<div style="color:var(--t3);font-size:.72rem;text-align:center;padding:10px;">Mieter hinzufügen</div>';
  };

  window.addNKTenant = () => {
    const name = $('nkTenantName').value.trim();
    const sqm = parseFloat($('nkTenantSqm').value) || 0;
    const paid = parseFloat($('nkTenantPaid').value) || 0;
    if (!name || !sqm) return;
    nkTenants.push({ name, sqm, paid }); save('nkTenants', nkTenants);
    $('nkTenantName').value = ''; $('nkTenantSqm').value = ''; $('nkTenantPaid').value = '';
    renderNKTenants();
  };

  function renderNKTenants() {
    $('nkTenantList').innerHTML = nkTenants.map((t, i) =>
      `<div style="display:flex;align-items:center;gap:5px;padding:4px 6px;background:var(--b2);border-radius:var(--rs);margin-bottom:2px;font-size:.7rem;">
        👤 ${esc(t.name)} · ${t.sqm}m² · ${t.paid}€
        <button class="del" style="opacity:1;margin-left:auto;" onclick="nkTenants.splice(${i},1);save('nkTenants',nkTenants);renderNKTenants()">✕</button>
      </div>`
    ).join('');
  }
  renderNKTenants();

  window.exportNKPDF = () => {
    calculateNK();
    const { jsPDF } = window.jspdf; const doc = new jsPDF();
    doc.setFontSize(16); doc.text('Nebenkostenabrechnung', 20, 20);
    let y = 30; doc.setFontSize(8); let total = 0;
    document.querySelectorAll('.nk-cost-input').forEach(inp => {
      const val = parseFloat(inp.value) || 0;
      if (val > 0) { doc.text(`${inp.dataset.name}: ${val.toFixed(2)} EUR`, 20, y); y += 5; total += val; }
    });
    doc.setFontSize(11); doc.text(`Gesamt: ${total.toFixed(2)} EUR`, 20, y);
    doc.save('nebenkosten.pdf');
  };

  window.exportNKExcel = () => {
    const wb = XLSX.utils.book_new();
    const data = [['Kostenart', 'Betrag EUR']];
    document.querySelectorAll('.nk-cost-input').forEach(inp => data.push([inp.dataset.name, parseFloat(inp.value) || 0]));
    XLSX.utils.book_append_sheet(wb, XLSX.utils.aoa_to_sheet(data), 'Nebenkosten');
    XLSX.writeFile(wb, 'nebenkosten.xlsx');
  };
}

// ========================================
// 🏋️ BMI RECHNER
// ========================================
function initBMI() {
  let bmiHistory = load('bmiHistory', []);

  $('bmiBody').innerHTML = `
    <div class="ig"><label style="font-size:.66rem;color:var(--t2);font-weight:600;min-width:45px;">Gewicht:</label><input type="number" class="inp" id="bmiWeight" placeholder="kg" step="0.1" oninput="calculateBMI()"><span style="font-size:.68rem;color:var(--t3);">kg</span></div>
    <div class="ig"><label style="font-size:.66rem;color:var(--t2);font-weight:600;min-width:45px;">Größe:</label><input type="number" class="inp" id="bmiHeight" placeholder="cm" oninput="calculateBMI()"><span style="font-size:.68rem;color:var(--t3);">cm</span></div>
    <div class="bmi-display">
      <div class="bmi-val" id="bmiValue" style="color:var(--t3);">—</div>
      <div class="bmi-cat" id="bmiCategory" style="color:var(--t3);">BMI berechnen</div>
      <div class="bmi-bar"><div class="bmi-marker" id="bmiMarker" style="left:0%;"></div></div>
      <div style="display:flex;justify-content:space-between;font-size:.55rem;color:var(--t3);"><span>Unter</span><span>Normal</span><span>Über</span><span>Adipositas</span></div>
    </div>
    <div style="background:var(--b2);border:1px solid var(--bd);border-radius:var(--rs);padding:8px;margin-bottom:5px;">
      <div style="font-size:.6rem;color:var(--t3);font-weight:600;">Idealgewicht</div>
      <div style="font-size:.9rem;font-weight:700;color:var(--a3);" id="bmiIdeal">—</div>
    </div>
    <button class="btn btn-o btn-s" onclick="saveBMIEntry()" style="width:100%;margin-bottom:4px;">💾 Eintrag speichern</button>
    <div style="font-size:.62rem;font-weight:700;color:var(--a3);margin-bottom:3px;">📈 Verlauf</div>
    <div style="max-height:120px;overflow-y:auto;" id="bmiHistoryList"></div>`;

  $('bmiInfo').innerHTML = `
    <table style="width:100%;border-collapse:collapse;font-size:.66rem;">
      <thead><tr style="background:var(--ag);color:#fff;"><th style="padding:4px;">Kategorie</th><th style="padding:4px;">BMI</th></tr></thead>
      <tbody>
        <tr style="background:var(--b3);"><td style="padding:3px;">💙 Unter</td><td>< 18.5</td></tr>
        <tr><td style="padding:3px;">💚 Normal</td><td>18.5–24.9</td></tr>
        <tr style="background:var(--b3);"><td style="padding:3px;">💛 Über</td><td>25–29.9</td></tr>
        <tr><td style="padding:3px;">🧡 Adip. I</td><td>30–34.9</td></tr>
        <tr style="background:var(--b3);"><td style="padding:3px;">❤️ Adip. II</td><td>35–39.9</td></tr>
        <tr><td style="padding:3px;">💜 Adip. III</td><td>≥ 40</td></tr>
      </tbody>
    </table>
    <div style="text-align:center;font-size:.6rem;color:var(--t3);margin-top:4px;">⚠️ Richtwert — Arzt konsultieren!</div>`;

  window.calculateBMI = () => {
    const weight = parseFloat($('bmiWeight').value);
    const height = parseFloat($('bmiHeight').value);
    if (!weight || !height || height < 50) return;

    const bmi = weight / ((height / 100) * (height / 100));
    let cat, color;
    if (bmi < 18.5) { cat = '💙 Untergewicht'; color = '#3b82f6'; }
    else if (bmi < 25) { cat = '💚 Normalgewicht'; color = '#22c55e'; }
    else if (bmi < 30) { cat = '💛 Übergewicht'; color = '#f59e0b'; }
    else if (bmi < 35) { cat = '🧡 Adipositas I'; color = '#f97316'; }
    else { cat = '❤️ Adipositas'; color = '#ef4444'; }

    $('bmiValue').textContent = bmi.toFixed(1);
    $('bmiValue').style.color = color;
    $('bmiCategory').textContent = cat;
    $('bmiCategory').style.color = color;
    $('bmiMarker').style.left = Math.min(100, Math.max(0, ((bmi - 10) / 40) * 100)) + '%';
    $('bmiMarker').style.borderColor = color;

    const idealWeight = 22 * (height / 100) * (height / 100);
    $('bmiIdeal').textContent = idealWeight.toFixed(1) + ' kg';
  };

  window.saveBMIEntry = () => {
    const weight = parseFloat($('bmiWeight').value);
    const height = parseFloat($('bmiHeight').value);
    if (!weight || !height) return;
    bmiHistory.unshift({
      date: new Date().toLocaleDateString('de-DE'),
      weight, height,
      bmi: (weight / ((height / 100) * (height / 100))).toFixed(1)
    });
    save('bmiHistory', bmiHistory);
    renderBMIHistory();
  };

  function renderBMIHistory() {
    $('bmiHistoryList').innerHTML = bmiHistory.map((h, i) => {
      const color = parseFloat(h.bmi) < 25 ? 'var(--ok)' : 'var(--er)';
      return `<div style="display:flex;justify-content:space-between;padding:3px 6px;background:var(--b2);border-radius:var(--rs);margin-bottom:1px;font-size:.66rem;">
        <span>${h.date}</span><span>${h.weight}kg</span><span style="font-weight:700;color:${color};">BMI ${h.bmi}</span>
      </div>`;
    }).join('');
  }
  renderBMIHistory();
}

// ========================================
// 🕌 GEBETSZEITEN
// ========================================
function initPrayer() {
  let prayerData = null, prayerInterval = null;

  $('prayerBody').innerHTML = `
    <div class="prayer-wrap">
      <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">
        <div>
          <div style="font-size:.9rem;font-weight:800;" id="prayerCity">🕌 Stadt laden...</div>
          <div style="font-size:.62rem;color:var(--t3);" id="prayerCountry">—</div>
        </div>
        <div style="text-align:right;">
          <div style="font-size:.66rem;color:var(--a3);font-weight:600;" id="prayerHijri">—</div>
        </div>
      </div>
      <div class="prayer-grid">
        <div class="prayer-card"><div class="prayer-icon">🌅</div><div class="prayer-name">Fajr / İmsak</div><div class="prayer-time" id="ptFajr">--:--</div></div>
        <div class="prayer-card"><div class="prayer-icon">🌤️</div><div class="prayer-name">Sunrise / Güneş</div><div class="prayer-time" id="ptSunrise">--:--</div></div>
        <div class="prayer-card"><div class="prayer-icon">☀️</div><div class="prayer-name">Dhuhr / Öğle</div><div class="prayer-time" id="ptDhuhr">--:--</div></div>
        <div class="prayer-card"><div class="prayer-icon">🌥️</div><div class="prayer-name">Asr / İkindi</div><div class="prayer-time" id="ptAsr">--:--</div></div>
        <div class="prayer-card"><div class="prayer-icon">🌅</div><div class="prayer-name">Maghrib / Akşam</div><div class="prayer-time" id="ptMaghrib">--:--</div></div>
        <div class="prayer-card"><div class="prayer-icon">🌙</div><div class="prayer-name">Isha / Yatsı</div><div class="prayer-time" id="ptIsha">--:--</div></div>
      </div>
      <div class="prayer-next">
        <div style="font-size:.58rem;color:var(--t3);text-transform:uppercase;letter-spacing:1px;font-weight:600;">Nächstes Gebet</div>
        <div style="font-size:.82rem;font-weight:700;color:var(--ok);" id="nextPrayerName">—</div>
        <div style="font-size:1.2rem;font-weight:900;background:var(--ag);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;" id="nextPrayerCountdown">--:--:--</div>
      </div>
    </div>
    <div style="display:flex;gap:4px;margin-top:6px;flex-wrap:wrap;">
      <input class="inp" id="prayerCityInput" placeholder="Stadt" value="Berlin" style="flex:1;">
      <input class="inp" id="prayerCountryInput" placeholder="Land" value="Germany" style="flex:.4;">
      <select class="inp" id="prayerMethod" style="flex:.5;">
        <option value="13">🇹🇷 Diyanet</option><option value="3">ISNA</option><option value="4">Umm al-Qura</option>
      </select>
      <button class="btn" onclick="loadPrayerTimes()">🔄 Laden</button>
      <button class="btn btn-o" onclick="prayerGPS()">📍 GPS</button>
    </div>`;

  window.loadPrayerTimes = async () => {
    const city = $('prayerCityInput').value.trim();
    const country = $('prayerCountryInput').value.trim();
    const method = $('prayerMethod').value;
    if (!city || !country) return;

    try {
      const res = await fetch(`https://api.aladhan.com/v1/timingsByCity?city=${encodeURIComponent(city)}&country=${encodeURIComponent(country)}&method=${method}&school=1`);
      const data = await res.json();
      if (data.code !== 200) return;

      prayerData = data.data;
      const t = prayerData.timings;
      $('ptFajr').textContent = t.Fajr;
      $('ptSunrise').textContent = t.Sunrise;
      $('ptDhuhr').textContent = t.Dhuhr;
      $('ptAsr').textContent = t.Asr;
      $('ptMaghrib').textContent = t.Maghrib;
      $('ptIsha').textContent = t.Isha;
      $('prayerCity').textContent = '🕌 ' + city;
      $('prayerCountry').textContent = '📍 ' + country;
      const hijri = prayerData.date.hijri;
      $('prayerHijri').textContent = `${hijri.day} ${hijri.month.en} ${hijri.year}`;

      updatePrayerHighlight();
      if (prayerInterval) clearInterval(prayerInterval);
      prayerInterval = setInterval(updatePrayerHighlight, 1000);
      localStorage.setItem('prayerSettings', JSON.stringify({ city, country, method }));

      // Monthly calendar
      const monthRes = await fetch(`https://api.aladhan.com/v1/calendarByCity/${new Date().getFullYear()}/${new Date().getMonth() + 1}?city=${encodeURIComponent(city)}&country=${encodeURIComponent(country)}&method=${method}&school=1`);
      const monthData = await monthRes.json();
      if (monthData.code === 200) {
        const today = new Date().getDate();
        $('prayerMonthly').innerHTML = `<table style="width:100%;border-collapse:collapse;font-size:.6rem;">
          <thead><tr style="background:var(--ag);color:#fff;"><th style="padding:4px;">Tag</th><th>Fajr</th><th>Dhuhr</th><th>Asr</th><th>Maghrib</th><th>Isha</th></tr></thead>
          <tbody>${monthData.data.map((d, i) => {
            const t2 = d.timings;
            const bg = i + 1 === today ? 'background:var(--gl);font-weight:700;' : (i % 2 ? 'background:var(--b3);' : '');
            return `<tr style="${bg}"><td style="padding:3px;text-align:center;">${i + 1}</td><td style="text-align:center;">${t2.Fajr}</td><td style="text-align:center;">${t2.Dhuhr}</td><td style="text-align:center;">${t2.Asr}</td><td style="text-align:center;">${t2.Maghrib}</td><td style="text-align:center;">${t2.Isha}</td></tr>`;
          }).join('')}</tbody></table>`;
      }
    } catch (e) { alert('Fehler: ' + e.message); }
  };

  function updatePrayerHighlight() {
    if (!prayerData) return;
    const t = prayerData.timings;
    const now = new Date();
    const prayers = [
      { name: 'Fajr / İmsak', time: t.Fajr },
      { name: 'Sunrise / Güneş', time: t.Sunrise },
      { name: 'Dhuhr / Öğle', time: t.Dhuhr },
      { name: 'Asr / İkindi', time: t.Asr },
      { name: 'Maghrib / Akşam', time: t.Maghrib },
      { name: 'Isha / Yatsı', time: t.Isha }
    ];

    const cards = document.querySelectorAll('.prayer-card');
    let nextPrayer = null, nextTime = null;

    prayers.forEach((p, i) => {
      const [h, m] = p.time.split(':').map(Number);
      const pDate = new Date(now);
      pDate.setHours(h, m, 0, 0);
      cards[i].classList.remove('active', 'passed');
      if (pDate < now) { cards[i].classList.add('passed'); }
      else if (!nextPrayer) { nextPrayer = p; nextTime = pDate; cards[i].classList.add('active'); }
    });

    if (!nextPrayer) {
      nextPrayer = prayers[0];
      const [h, m] = prayers[0].time.split(':').map(Number);
      nextTime = new Date(now);
      nextTime.setDate(nextTime.getDate() + 1);
      nextTime.setHours(h, m, 0, 0);
    }

    const diff = nextTime - now;
    const hours = Math.floor(diff / 3600000);
    const mins = Math.floor((diff % 3600000) / 60000);
    const secs = Math.floor((diff % 60000) / 1000);
    $('nextPrayerName').textContent = nextPrayer.name;
    $('nextPrayerCountdown').textContent = `${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;
  }

  window.prayerGPS = () => {
    navigator.geolocation?.getCurrentPosition(async pos => {
      try {
        const res = await fetch(`https://api.aladhan.com/v1/timings?latitude=${pos.coords.latitude}&longitude=${pos.coords.longitude}&method=${$('prayerMethod').value}&school=1`);
        const data = await res.json();
        if (data.code === 200) {
          prayerData = data.data;
          const t = data.data.timings;
          $('ptFajr').textContent = t.Fajr; $('ptSunrise').textContent = t.Sunrise;
          $('ptDhuhr').textContent = t.Dhuhr; $('ptAsr').textContent = t.Asr;
          $('ptMaghrib').textContent = t.Maghrib; $('ptIsha').textContent = t.Isha;
          $('prayerCity').textContent = '🕌 📍 GPS';
          updatePrayerHighlight();
          if (prayerInterval) clearInterval(prayerInterval);
          prayerInterval = setInterval(updatePrayerHighlight, 1000);
        }
      } catch {}
    });
  };

  // Restore settings
  const savedPrayer = localStorage.getItem('prayerSettings');
  if (savedPrayer) {
    try {
      const s = JSON.parse(savedPrayer);
      $('prayerCityInput').value = s.city || 'Berlin';
      $('prayerCountryInput').value = s.country || 'Germany';
      $('prayerMethod').value = s.method || '13';
      setTimeout(loadPrayerTimes, 300);
    } catch {}
  }
}

// ========================================
// 📜 MIETVERTRAG + QR-CODE
// ========================================
function initContract() {
  $('mvBody').innerHTML = `
    <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;">
      <div>
        <div class="mv-section"><h4>🏠 Vermieter</h4><div class="ig"><input class="inp" id="mvLandlord" placeholder="Name"><input class="inp" id="mvLandlordAddr" placeholder="Adresse"></div></div>
        <div class="mv-section"><h4>👤 Mieter</h4><div class="ig"><input class="inp" id="mvTenant" placeholder="Name"><input class="inp" id="mvTenantAddr" placeholder="Adresse"></div></div>
        <div class="mv-section"><h4>🏢 Objekt</h4><div class="ig"><input class="inp" id="mvObjAddr" placeholder="Objektadresse"><input type="number" class="inp" id="mvObjSqm" placeholder="m²" style="flex:.2"></div></div>
        <div class="mv-section"><h4>💰 Konditionen</h4>
          <div class="ig"><label style="font-size:.64rem;color:var(--t2);min-width:50px;">Kalt:</label><input type="number" class="inp" id="mvColdRent" placeholder="€" oninput="updateContractPreview()"><label style="font-size:.64rem;color:var(--t2);min-width:30px;">NK:</label><input type="number" class="inp" id="mvUtilities" placeholder="€" oninput="updateContractPreview()"></div>
          <div style="font-size:.78rem;font-weight:700;color:var(--a3);" id="mvTotalRent">Warmmiete: 0,00 €</div>
          <div class="ig"><label style="font-size:.64rem;color:var(--t2);min-width:50px;">Kaution:</label><input type="number" class="inp" id="mvDeposit" placeholder="€"><label style="font-size:.64rem;color:var(--t2);min-width:50px;">Beginn:</label><input type="date" class="inp" id="mvStartDate"></div>
        </div>
        <div class="exp-row">
          <button class="exp-btn" onclick="exportContractPDF()"><span>📄</span>Vertrag PDF</button>
          <button class="exp-btn" onclick="exportContractWord()"><span>📝</span>Word</button>
        </div>
      </div>
      <div>
        <div style="font-size:.66rem;font-weight:700;color:var(--a3);margin-bottom:4px;">👁️ Vorschau</div>
        <div class="mv-preview" id="contractPreview"></div>
        <div style="margin-top:8px;">
          <div style="font-size:.66rem;font-weight:700;color:var(--a3);margin-bottom:4px;">📱 QR-Code Generator</div>
          <div class="ig"><input class="inp" id="qrInput" placeholder="URL oder Text..."><button class="btn" onclick="generateQR()">📱 QR</button></div>
          <div class="ig">
            <button class="btn btn-s btn-o" onclick="qrFromExpose()">🏠 Aus Exposé</button>
            <button class="btn btn-s btn-o" onclick="qrVCard()">👤 vCard</button>
          </div>
          <div class="qr-wrap" id="qrContainer" style="display:none;">
            <div class="qr-box" id="qrCode"></div>
            <div style="display:flex;gap:3px;margin-top:4px;">
              <button class="btn btn-s" onclick="downloadQR()">💾 PNG</button>
              <button class="btn btn-s btn-o" onclick="qrToPDF()">📄 PDF</button>
            </div>
          </div>
        </div>
      </div>
    </div>`;

  window.updateContractPreview = () => {
    const cold = parseFloat($('mvColdRent').value) || 0;
    const util = parseFloat($('mvUtilities').value) || 0;
    $('mvTotalRent').textContent = `Warmmiete: ${(cold + util).toFixed(2)} €`;

    $('contractPreview').innerHTML = `
      <h2>MIETVERTRAG</h2>
      <p>zwischen <b>${$('mvLandlord').value || '___'}</b> (Vermieter)<br>und <b>${$('mvTenant').value || '___'}</b> (Mieter)</p>
      <p><b>§1 Mietobjekt:</b> ${$('mvObjAddr').value || '___'}, ${$('mvObjSqm').value || '___'} m²</p>
      <p><b>§2 Miete:</b> Kalt: ${$('mvColdRent').value || '___'}€ + NK: ${$('mvUtilities').value || '___'}€ = <b>${(cold + util).toFixed(2)}€</b></p>
      <p><b>§3 Kaution:</b> ${$('mvDeposit').value || '___'}€</p>
      <p><b>§4 Beginn:</b> ${$('mvStartDate').value || '___'}</p>
      <div style="display:flex;justify-content:space-between;margin-top:20px;padding-top:10px;border-top:1px solid var(--bd);">
        <div style="text-align:center;width:40%;"><div style="border-top:1px solid var(--t2);margin-top:30px;padding-top:3px;font-size:.6rem;">Vermieter</div></div>
        <div style="text-align:center;width:40%;"><div style="border-top:1px solid var(--t2);margin-top:30px;padding-top:3px;font-size:.6rem;">Mieter</div></div>
      </div>`;
  };

  document.addEventListener('input', e => { if (e.target.closest('#tab-contract')) updateContractPreview(); });
  updateContractPreview();

  window.exportContractPDF = () => {
    const { jsPDF } = window.jspdf; const doc = new jsPDF();
    doc.setFontSize(18); doc.text('MIETVERTRAG', 80, 20);
    doc.setFontSize(9);
    const text = $('contractPreview').innerText;
    doc.text(doc.splitTextToSize(text, 170), 20, 35);
    doc.save('mietvertrag.pdf');
  };

  window.exportContractWord = async () => {
    const { Document, Packer, Paragraph, TextRun, HeadingLevel } = docx;
    const text = $('contractPreview').innerText.split('\n').filter(l => l.trim());
    const children = [new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun({ text: 'MIETVERTRAG', bold: true, size: 32 })] })];
    text.forEach(l => children.push(new Paragraph({ children: [new TextRun({ text: l, size: 20 })] })));
    saveAs(await Packer.toBlob(new Document({ sections: [{ children }] })), 'mietvertrag.docx');
  };

  // QR Code
  window.generateQR = () => {
    const text = $('qrInput').value.trim();
    if (!text) return;
    $('qrCode').innerHTML = '';
    new QRCode($('qrCode'), { text, width: 180, height: 180, colorDark: '#000', correctLevel: QRCode.CorrectLevel.H });
    $('qrContainer').style.display = 'flex';
  };

  window.qrFromExpose = () => {
    const title = $('imTitle')?.value || '';
    const addr = $('imAddr')?.value || '';
    const city = $('imCity')?.value || '';
    const price = $('imPrice')?.value || '';
    $('qrInput').value = `🏠 ${title}\n📍 ${addr}, ${city}\n💰 ${price}€`;
    generateQR();
  };

  window.qrVCard = () => {
    const name = prompt('Name:') || '';
    const tel = prompt('Telefon:') || '';
    $('qrInput').value = `BEGIN:VCARD\nVERSION:3.0\nFN:${name}\nTEL:${tel}\nEND:VCARD`;
    generateQR();
  };

  window.downloadQR = () => {
    const canvas = document.querySelector('#qrCode canvas');
    if (!canvas) return;
    const a = document.createElement('a'); a.href = canvas.toDataURL(); a.download = 'qr-code.png'; a.click();
  };

  window.qrToPDF = () => {
    const canvas = document.querySelector('#qrCode canvas');
    if (!canvas) return;
    const { jsPDF } = window.jspdf; const doc = new jsPDF();
    doc.text('QR-Code', 85, 20);
    doc.addImage(canvas.toDataURL(), 'PNG', 55, 30, 100, 100);
    doc.save('qr-code.pdf');
  };
}

// ========================================
// 🤖 KI-ASSISTENT
// ========================================
function initAI() {
  let chatHistory = load('chatHistory', []);

  $('aiBody').innerHTML = `
    <div class="ig">
      <input type="password" class="inp" id="aiKey" placeholder="🔑 OpenAI API Key (sk-...)" style="flex:1;">
      <select class="inp" id="aiModel" style="flex:.3;">
        <option value="gpt-4o-mini">GPT-4o Mini</option><option value="gpt-4o">GPT-4o</option>
      </select>
      <button class="btn btn-s" onclick="localStorage.setItem('aiKey',$('aiKey').value);alert('✅')">💾</button>
    </div>
    <div style="display:flex;gap:3px;margin-bottom:5px;flex-wrap:wrap;">
      <button class="btn btn-s btn-o" onclick="$('aiInput').value='Zusammenfassen: ';$('aiInput').focus()">📝</button>
      <button class="btn btn-s btn-o" onclick="$('aiInput').value='Übersetze: ';$('aiInput').focus()">🌍</button>
      <button class="btn btn-s btn-o" onclick="$('aiInput').value='E-Mail schreiben: ';$('aiInput').focus()">📧</button>
      <button class="btn btn-s btn-o" onclick="$('aiInput').value='Code: ';$('aiInput').focus()">💻</button>
      <button class="btn btn-s btn-o" onclick="chatHistory=[];save('chatHistory',[]);$('aiChat').innerHTML=''">🗑️</button>
    </div>
    <div style="max-height:260px;overflow-y:auto;margin-bottom:4px;" id="aiChat"></div>
    <div class="ig">
      <textarea class="inp" id="aiInput" placeholder="Nachricht an die KI..." style="min-height:35px;flex:1;" onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();sendAIMessage();}"></textarea>
      <button class="btn" onclick="sendAIMessage()">🚀</button>
    </div>`;

  // Restore API key
  const savedKey = localStorage.getItem('aiKey');
  if (savedKey) $('aiKey').value = savedKey;

  function addAIChatMessage(role, content) {
    const chat = $('aiChat');
    const div = document.createElement('div');
    div.style.cssText = 'display:flex;gap:4px;margin-bottom:4px;' + (role === 'user' ? 'flex-direction:row-reverse;' : '');
    let html = esc(content)
      .replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
      .replace(/\n/g, '<br>');
    div.innerHTML = `<span style="font-size:.9rem;">${role === 'bot' ? '🤖' : '👤'}</span>
      <div style="max-width:80%;padding:6px 10px;border-radius:10px;font-size:.74rem;line-height:1.4;${role === 'bot' ? 'background:var(--b2);border:1px solid var(--bd);' : 'background:var(--ag);color:white;'}">${html}</div>`;
    chat.appendChild(div);
    chat.scrollTop = chat.scrollHeight;
  }

  window.sendAIMessage = async () => {
    const input = $('aiInput');
    const text = input.value.trim();
    if (!text) return;
    const apiKey = $('aiKey').value.trim() || localStorage.getItem('aiKey');
    if (!apiKey) { alert('⚠️ Bitte OpenAI API Key eingeben!'); return; }

    addAIChatMessage('user', text);
    chatHistory.push({ role: 'user', content: text });
    input.value = '';

    try {
      const res = await fetch('https://api.openai.com/v1/chat/completions', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + apiKey },
        body: JSON.stringify({
          model: $('aiModel').value,
          messages: [
            { role: 'system', content: 'Du bist ein hilfreicher Assistent. Antworte auf Deutsch. Formatiere mit **fett**.' },
            ...chatHistory.slice(-20)
          ],
          temperature: 0.7, max_tokens: 2000
        })
      });
      const data = await res.json();
      if (data.error) { addAIChatMessage('bot', '❌ ' + data.error.message); return; }
      const reply = data.choices[0].message.content;
      chatHistory.push({ role: 'assistant', content: reply });
      save('chatHistory', chatHistory);
      addAIChatMessage('bot', reply);
    } catch { addAIChatMessage('bot', '❌ Verbindungsfehler'); }
  };

  // Restore chat history
  if (chatHistory.length > 0) {
    chatHistory.forEach(m => addAIChatMessage(m.role === 'user' ? 'user' : 'bot', m.content));
  }
}

// ========================================
// 💬 ZITATE
// ========================================
const quotes = [
  { text: "Der beste Weg, die Zukunft vorauszusagen, ist, sie zu gestalten.", author: "Peter Drucker" },
  { text: "Hayatta en hakiki mürşit ilimdir.", author: "Atatürk" },
  { text: "Wer immer tut, was er schon kann, bleibt immer das, was er schon ist.", author: "Henry Ford" },
  { text: "Başarı cesaret ve azimden doğar.", author: "Türk Atasözü" },
  { text: "Disziplin ist die Brücke zwischen Zielen und Erfolg.", author: "Jim Rohn" },
  { text: "Sabır acıdır, meyvesi tatlıdır.", author: "Türk Atasözü" }
];

function showRandomQuote() {
  const q = quotes[Math.floor(Math.random() * quotes.length)];
  $('quoteText').textContent = `"${q.text}"`;
  $('quoteAuthor').textContent = `— ${q.author}`;
}
showRandomQuote();

// ========================================
// 💾 BACKUP & RESTORE
// ========================================
function backupAll() {
  const data = {
    todos, calEvents, dailyExpenses, chatHistory: load('chatHistory', []),
    notes: notesArea.value, autos: load('autos', []),
    finPriv: load('finPriv', {}), testament: load('testament', {}),
    hvObjects: load('hvObjects', []), hvCosts: load('hvCosts', []),
    waContacts: load('waContacts', []), nkTenants: load('nkTenants', []),
    bmiHistory: load('bmiHistory', [])
  };
  const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.download = `dashboard-backup-${new Date().toISOString().split('T')[0]}.json`;
  a.click();
}

function restoreAll() {
  const input = document.createElement('input');
  input.type = 'file'; input.accept = '.json';
  input.onchange = e => {
    const reader = new FileReader();
    reader.onload = ev => {
      try {
        const data = JSON.parse(ev.target.result);
        if (data.todos) { todos = data.todos; renderTodos(); }
        if (data.calEvents) { calEvents = data.calEvents; save('calEvents', calEvents); renderCalendar(); }
        if (data.notes) { notesArea.value = data.notes; localStorage.setItem('notes', data.notes); }
        alert('✅ Backup wiederhergestellt!');
      } catch { alert('❌ Fehler beim Laden!'); }
    };
    reader.readAsText(e.target.files[0]);
  };
  input.click();
}

// ========================================
// 📲 PWA (Progressive Web App)
// ========================================
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('sw.js')
      .then(reg => console.log('✅ Service Worker registriert'))
      .catch(err => console.log('SW:', err));
  });
}

window.addEventListener('online', () => { $('netStatus').textContent = '🟢'; });
window.addEventListener('offline', () => { $('netStatus').textContent = '🔴'; });

let deferredPrompt;
window.addEventListener('beforeinstallprompt', e => {
  e.preventDefault(); deferredPrompt = e;
  $('installBtn').style.display = 'inline-flex';
});

function installPWA() {
  if (!deferredPrompt) return;
  deferredPrompt.prompt();
  deferredPrompt.userChoice.then(() => {
    deferredPrompt = null;
    $('installBtn').style.display = 'none';
  });
}
</script>

</body>
</html>

📄 Schritt 3: Datei manifest.json erstellen (im selben Ordner):

{
  "name": "Ultra Elite Dashboard",
  "short_name": "Dashboard",
  "start_url": "./index.html",
  "display": "standalone",
  "background_color": "#06060b",
  "theme_color": "#6366f1",
  "icons": [
    { "src": "icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "icon-512.png", "sizes": "512x512", "type": "image/png" }
  ]
}

⚙️ Schritt 4: Datei sw.js erstellen:

const CACHE = 'dashboard-v1';
const ASSETS = ['./', './index.html', './manifest.json'];

self.addEventListener('install', e => {
  e.waitUntil(caches.open(CACHE).then(c => c.addAll(ASSETS)).then(() => self.skipWaiting()));
});

self.addEventListener('activate', e => {
  e.waitUntil(caches.keys().then(keys => Promise.all(keys.filter(k => k !== CACHE).map(k => caches.delete(k)))).then(() => self.clients.claim()));
});

self.addEventListener('fetch', e => {
  if (e.request.method !== 'GET') return;
  e.respondWith(
    caches.match(e.request).then(cached => {
      const network = fetch(e.request).then(res => {
        if (res && res.status === 200) {
          const clone = res.clone();
          caches.open(CACHE).then(c => c.put(e.request, clone));
        }
        return res;
      }).catch(() => cached);
      return cached || network;
    })
  );
});

🏁 Schritt 5: STARTEN!

Doppelklick auf index.html → Fertig! 🎉

✅ Dein Ordner sieht so aus:

📁 MeinDashboard/
├── 📄 index.html      ← Das Dashboard
├── 📄 manifest.json   ← PWA-Config
└── 📄 sw.js           ← Offline-Support

Kein PIN, kein Login, kein Account — einfach Doppelklick und los! 🚀