Hier ist die KOMPLETTE, FINALE Version — alles zusammengebraut in einer einzigen Datei. Alle Features von V1 bis V6 vereint:
<!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 — FINAL</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="Elite Dashboard">
<link rel="manifest" href="manifest.json">
<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>
@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 .3s cubic-bezier(.4,0,.2,1);}
.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{--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;}
*{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%;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%);z-index:0;pointer-events:none;animation:bgF 25s ease-in-out infinite;}
@keyframes bgF{0%,100%{transform:translate(0,0);}33%{transform:translate(2%,-2%);}66%{transform:translate(-1%,1%);}}
@keyframes fi{from{opacity:0;transform:translateY(20px);}to{opacity:1;transform:translateY(0);}}
@keyframes gs{0%{background-position:0% 50%;}50%{background-position:100% 50%;}100%{background-position:0% 50%;}}
@keyframes fl{0%,100%{transform:translateY(0);}50%{transform:translateY(-4px);}}
@keyframes sp{to{transform:rotate(360deg);}}
@keyframes eq{0%,100%{height:3px;}50%{height:100%;}}
@keyframes sh{0%{left:-100%;}100%{left:200%;}}
.ctn{max-width:1600px;margin:0 auto;padding:16px 24px;position:relative;z-index:1;}
/* HEADER */
.hdr{text-align:center;margin-bottom:14px;animation:fi .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;background:var(--ag);background-size:200% 200%;animation:gs 5s ease infinite;-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;line-height:1.1;letter-spacing:-2px;}
.dt{font-size:.85rem;color:var(--t2);margin-top:2px;}
.tp{display:flex;justify-content:center;gap:5px;margin-top:6px;flex-wrap:wrap;}
.cd{width:20px;height:20px;border-radius:50%;cursor:pointer;border:2px solid transparent;transition:var(--tr);}
.cd:hover{transform:scale(1.2);}.cd.a{border-color:#fff;box-shadow:0 0 10px var(--gl);transform:scale(1.1);}
.cd[data-t="def"]{background:linear-gradient(135deg,#6366f1,#8b5cf6);}
.cd[data-t="sun"]{background:linear-gradient(135deg,#f97316,#ef4444);}
.cd[data-t="sea"]{background:linear-gradient(135deg,#0ea5e9,#06b6d4);}
.cd[data-t="grn"]{background:linear-gradient(135deg,#22c55e,#16a34a);}
.cd[data-t="ros"]{background:linear-gradient(135deg,#f43f5e,#ec4899);}
.cd[data-t="gld"]{background:linear-gradient(135deg,#f59e0b,#d97706);}
.cd[data-t="neo"]{background:linear-gradient(135deg,#e11d48,#7c3aed);}
.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);}
/* SEARCH */
.ss{margin-bottom:14px;animation:fi .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);}
.sb{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);}
.s2{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);}
.s2:hover{opacity:.9;}
/* TABS */
.ts{display:flex;justify-content:center;gap:3px;margin-bottom:14px;flex-wrap:wrap;animation:fi .6s ease .15s backwards;}
.tb{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;}
.tb:hover{color:var(--t1);border-color:var(--a1);}.tb.a{background:var(--ag);color:#fff;border-color:transparent;}
/* GRID */
.g{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;}
.tc2{display:none;}.tc2.a{display:grid;}
/* CARDS */
.c{background:var(--b3);backdrop-filter:blur(25px);border:1px solid var(--bd);border-radius:var(--r);padding:14px;transition:var(--tr);animation:fi .5s ease backwards;position:relative;overflow:hidden;}
.c::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:var(--ag);background-size:200% 200%;animation:gs 4s ease infinite;opacity:0;transition:var(--tr);}
.c:hover{border-color:rgba(99,102,241,0.15);box-shadow:0 5px 30px rgba(0,0,0,0.12);transform:translateY(-1px);}
.c:hover::before{opacity:1;}
.c.s2{grid-column:span 2;}.c.fl{grid-column:1/-1;}
.ch2{display:flex;align-items:center;gap:6px;margin-bottom:10px;}
.ci2{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:fl 4s ease-in-out infinite;}
.ct2{font-size:.66rem;font-weight:700;text-transform:uppercase;letter-spacing:1.2px;color:var(--t2);}
/* INPUTS */
.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;}
.bt{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;}
.bt:hover{opacity:.85;transform:scale(1.02);}
.bt::after{content:'';position:absolute;top:0;left:-100%;width:50%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,0.12),transparent);}
.bt:hover::after{animation:sh .5s;}
.bt-s{padding:4px 8px;font-size:.64rem;}
.bt-o{background:0;border:1px solid var(--bd);color:var(--t1);}.bt-o:hover{border-color:var(--a1);background:var(--gl);}
.bt-d{background:var(--er);}.bt-ok{background:var(--ok);}
.ig2{display:flex;gap:4px;margin-bottom:5px;align-items:center;}.ig2 .inp{flex:1;}
/* LISTS */
.ls2{list-style:none;max-height:180px;overflow-y:auto;}
.li2{display:flex;align-items:center;gap:6px;padding:5px 7px;border-radius:var(--rs);transition:var(--tr);margin-bottom:1px;}
.li2:hover{background:var(--b4);}
.li2.dn .tx2{text-decoration:line-through;color:var(--t3);}
.ck2{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;}
.li2.dn .ck2{background:var(--ok);border-color:var(--ok);color:#fff;}
.tx2{flex:1;font-size:.74rem;}.dl2{background:0;border:0;color:var(--t3);cursor:pointer;padding:1px;font-size:.74rem;opacity:0;transition:var(--tr);}
.li2:hover .dl2{opacity:1;}.dl2:hover{color:var(--er);}
/* MISC */
.st2{text-align:center;font-size:.6rem;color:var(--t3);margin-top:3px;}
.fin-s{display:grid;grid-template-columns:repeat(3,1fr);gap:5px;margin-bottom:8px;}
.fin-b{text-align:center;padding:8px;background:var(--b2);border-radius:var(--rs);border:1px solid var(--bd);}
.fin-l{font-size:.56rem;color:var(--t3);text-transform:uppercase;letter-spacing:1px;font-weight:600;margin-bottom:1px;}
.fin-v{font-size:1.1rem;font-weight:800;}
.fin-v.inc{color:var(--ok);}.fin-v.exp{color:var(--er);}
.fin-v.bal{background:var(--ag);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
.exp-r{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-b{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-b:hover{border-color:var(--a1);background:var(--gl);transform:translateY(-1px);}
/* RADIO */
.rs3{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;}
.rs3:hover{border-color:var(--a1);background:var(--gl);}.rs3.ac3{border-color:var(--a1);box-shadow:0 0 10px var(--gl);}
.plv{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);}
.plv.sp2{animation:sp 3s linear infinite;}
.plv::after{content:'🎵';width:24px;height:24px;border-radius:50%;background:var(--ag);display:flex;align-items:center;justify-content:center;font-size:.75rem;}
/* MAP */
.map-c{width:100%;height:300px;border-radius:var(--r);overflow:hidden;border:1px solid var(--bd);margin:6px 0;z-index:1;position:relative;}
.map-c .leaflet-container{border-radius:var(--r);height:100%;}
/* GALLERY */
.gal{display:grid;grid-template-columns:repeat(4,1fr);gap:4px;margin:8px 0;}
.gal-i{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-i:hover{border-color:var(--a1);transform:scale(1.03);z-index:2;}
.gal-i img,.gal-i video{width:100%;height:100%;object-fit:cover;}
.gal-i .gd{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-i:hover .gd{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 */
.pano-p{width:100%;height:350px;border-radius:var(--r);overflow:hidden;border:1px solid var(--bd);}
.pano-p .pnlm-container{border-radius:var(--r)!important;}
.pano-th{display:flex;gap:4px;margin:6px 0;overflow-x:auto;}
.pano-th img{width:55px;height:38px;border-radius:4px;cursor:pointer;border:2px solid transparent;object-fit:cover;transition:var(--tr);}
.pano-th img:hover,.pano-th img.ac4{border-color:var(--a1);}
.pano-ct{display:flex;gap:3px;flex-wrap:wrap;}
.pano-b{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-b:hover{border-color:var(--a1);background:var(--gl);}
/* BMI */
.bmi-d{text-align:center;padding:15px;background:var(--b2);border:1px solid var(--bd);border-radius:var(--r);margin:8px 0;}
.bmi-v{font-size:2.5rem;font-weight:900;line-height:1;}
.bmi-c{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-mk{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;}
/* NEBENKOSTEN */
.nk-g{display:grid;grid-template-columns:repeat(2,1fr);gap:4px;margin-bottom:8px;}
.nk-i{background:var(--b2);border:1px solid var(--bd);border-radius:var(--rs);padding:8px;}
.nk-i label{font-size:.62rem;color:var(--t2);font-weight:600;display:block;margin-bottom:2px;}
/* GRUNDRISS */
.fp-tb{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-t{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-t:hover{border-color:var(--a1);background:var(--gl);}
.fp-t.ac5{background:var(--ag);color:#fff;border-color:transparent;}
/* PRAYER */
.pr-w{background:var(--b2);border:1px solid var(--bd);border-radius:var(--r);padding:14px;position:relative;overflow:hidden;}
.pr-w::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,#22c55e,#f59e0b,#22c55e);background-size:200% 200%;animation:gs 4s ease infinite;}
.pr-g{display:grid;grid-template-columns:repeat(3,1fr);gap:5px;}
.pr-tc{background:var(--b3);border:1px solid var(--bd);border-radius:var(--rs);padding:8px;text-align:center;transition:var(--tr);position:relative;overflow:hidden;}
.pr-tc:hover{border-color:var(--a1);transform:translateY(-1px);}
.pr-tc.ac6{border-color:var(--ok);background:rgba(34,197,94,0.08);box-shadow:0 0 10px rgba(34,197,94,0.1);}
.pr-tc.ps{opacity:.5;}
.pr-tc .pi{font-size:1.1rem;margin-bottom:2px;}
.pr-tc .pn{font-size:.58rem;color:var(--t2);font-weight:600;text-transform:uppercase;letter-spacing:.5px;}
.pr-tc .pt{font-size:.95rem;font-weight:800;margin-top:1px;background:var(--ag);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
.pr-tc.ac6 .pt{background:var(--ok);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
.pr-nx{text-align:center;margin-top:8px;padding:8px;background:var(--b3);border-radius:var(--rs);border:1px solid var(--bd);}
/* MIETVERTRAG */
.mv-s{background:var(--b2);border:1px solid var(--bd);border-radius:var(--rs);padding:10px;margin-bottom:6px;}
.mv-s h4{font-size:.66rem;font-weight:700;color:var(--a3);margin-bottom:6px;text-transform:uppercase;letter-spacing:1px;}
.mv-prev{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-prev h2{font-size:1rem;text-align:center;margin-bottom:10px;border-bottom:2px solid var(--bd);padding-bottom:6px;}
/* QR */
.qr-c{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-bx{background:#fff;padding:12px;border-radius:var(--rs);}
/* LIGHTBOX */
.lb2{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);}
.lb2.sh{display:flex;}
.lb2 img,.lb2 video{max-width:90%;max-height:85%;border-radius:var(--r);}
.lb-cl{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-cl:hover{background:var(--er);}
/* QUOTE */
.qs2{text-align:center;padding:14px 30px;margin-top:12px;}
.qt2{font-size:.85rem;font-style:italic;color:var(--t2);line-height:1.6;max-width:600px;margin:0 auto;}
.qa2{margin-top:4px;font-size:.7rem;color:var(--t3);font-weight:600;}
::-webkit-scrollbar{width:3px;}::-webkit-scrollbar-track{background:0;}::-webkit-scrollbar-thumb{background:var(--bd);border-radius:10px;}
@media(max-width:1200px){.g,.tc2.a{grid-template-columns:repeat(2,1fr);}.c.s2{grid-column:span 1;}.gal{grid-template-columns:repeat(3,1fr);}}
@media(max-width:768px){.ctn{padding:8px 6px;}.g,.tc2.a{grid-template-columns:1fr;}.clk{font-size:2rem;}.sb{display:none;}.gal{grid-template-columns:repeat(2,1fr);}.pr-g{grid-template-columns:repeat(2,1fr);}.nk-g{grid-template-columns:1fr;}}
</style>
</head>
<body>
<!-- LIGHTBOX -->
<div class="lb2" id="lb" onclick="cLB()"><button class="lb-cl" onclick="cLB()">✕</button><div id="lbC"></div></div>
<div class="ctn">
<!-- HEADER -->
<header class="hdr">
<div class="grt" id="grt"></div>
<div class="clk" id="clk">00:00</div>
<div class="dt" id="dte"></div>
<div class="tp">
<div class="cd a" data-t="def" onclick="sCT(this)"></div>
<div class="cd" data-t="sun" onclick="sCT(this)"></div>
<div class="cd" data-t="sea" onclick="sCT(this)"></div>
<div class="cd" data-t="grn" onclick="sCT(this)"></div>
<div class="cd" data-t="ros" onclick="sCT(this)"></div>
<div class="cd" data-t="gld" onclick="sCT(this)"></div>
<div class="cd" data-t="neo" onclick="sCT(this)"></div>
</div>
<div class="hc">
<button class="hb" onclick="tTh()">🌙 Mode</button>
<button class="hb" onclick="exAll()">💾 Backup</button>
<button class="hb" onclick="imAll()">📂 Restore</button>
<button class="hb" id="installBtn" style="display:none;background:var(--ag);color:#fff;" onclick="iPWA()">📲 Installieren</button>
<span class="hb" id="netSt"><span id="netT">🟢</span></span>
</div>
</header>
<!-- SEARCH -->
<section class="ss">
<form class="sc" onsubmit="dSr(event)">
<div class="sb">
<button type="button" class="se a" onclick="sSE(this,'g')">Google</button>
<button type="button" class="se" onclick="sSE(this,'y')">YouTube</button>
<button type="button" class="se" onclick="sSE(this,'a')">Amazon</button>
<button type="button" class="se" onclick="sSE(this,'m')">Maps</button>
</div>
<input type="text" class="si" id="sI" placeholder="Suche..." autocomplete="off">
<button type="submit" class="s2">🔍</button>
</form>
</section>
<!-- TABS -->
<div class="ts">
<button class="tb a" onclick="sT(this,'home')">🏠 Home</button>
<button class="tb" onclick="sT(this,'immo')">🏠 Immobilien</button>
<button class="tb" onclick="sT(this,'auto')">🚗 Auto</button>
<button class="tb" onclick="sT(this,'fin')">💰 Finanzen</button>
<button class="tb" onclick="sT(this,'verw')">📜 Verwaltung</button>
<button class="tb" onclick="sT(this,'media')">🎵 Medien</button>
<button class="tb" onclick="sT(this,'comm')">💬 Komm.</button>
<button class="tb" onclick="sT(this,'tools')">🛠️ Tools</button>
<button class="tb" onclick="sT(this,'fp')">🏗️ Grundriss</button>
<button class="tb" onclick="sT(this,'nk')">🧾 Nebenk.</button>
<button class="tb" onclick="sT(this,'bmi')">🏋️ BMI</button>
<button class="tb" onclick="sT(this,'pray')">🕌 Gebet</button>
<button class="tb" onclick="sT(this,'mv')">📜 Mietvertrag</button>
<button class="tb" onclick="sT(this,'ai')">🤖 KI</button>
</div>
<!-- ===== HOME ===== -->
<div class="g tc2 a" id="tab-home">
<div class="c s2"><div class="ch2"><div class="ci2">📅</div><div class="ct2">Kalender</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="cN(-1)">◀</button><span style="font-size:.8rem;font-weight:700;background:var(--ag);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;" id="cMY"></span><button class="hb" onclick="cN(1)">▶</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="cD"></div></div><div><div class="ig2"><input type="date" class="inp" id="eD"><input type="time" class="inp" id="eT" style="flex:.4"></div><div class="ig2"><input class="inp" id="eTi" placeholder="Termin..." onkeypress="if(event.key==='Enter')aEv()"><button class="bt bt-s" onclick="aEv()">+</button></div><div style="font-size:.58rem;color:var(--t3);margin:3px 0 1px;" id="cET">Termine</div><div style="max-height:120px;overflow-y:auto;" id="cE"></div></div></div></div>
<div class="c"><div class="ch2"><div class="ci2">✅</div><div class="ct2">To-Do</div></div><div class="ig2"><input class="inp" id="tdI" placeholder="Aufgabe..." onkeypress="if(event.key==='Enter')aTd()"><button class="bt bt-s" onclick="aTd()">+</button></div><ul class="ls2" id="tdL"></ul></div>
<div class="c"><div class="ch2"><div class="ci2">📝</div><div class="ct2">Notizen</div></div><textarea class="inp" id="nA" placeholder="Notizen..." style="min-height:110px;"></textarea></div>
<div class="c"><div class="ch2"><div class="ci2">📊</div><div class="ct2">Ausgaben</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="exT">0€</div></div><div class="ig2"><input class="inp" id="exN" placeholder="Was"><input type="number" class="inp" id="exA" placeholder="€" style="flex:.3" onkeypress="if(event.key==='Enter')aEx()"><button class="bt bt-s" onclick="aEx()">+</button></div><ul class="ls2" id="exL"></ul></div>
<div class="c"><div class="ch2"><div class="ci2">🔗</div><div class="ct2">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>
<!-- Alle anderen Tabs kommen per JavaScript dynamisch -->
<div class="g tc2" id="tab-immo" style="grid-template-columns:1fr;"><div class="c fl"><div class="ch2"><div class="ci2" style="background:linear-gradient(135deg,#f59e0b,#ef4444);">🏠</div><div class="ct2">Immobilien Exposé PRO</div></div><div id="immoContent"></div></div></div>
<div class="g tc2" id="tab-auto"><div class="c s2"><div class="ch2"><div class="ci2" style="background:linear-gradient(135deg,#3b82f6,#06b6d4);">🚗</div><div class="ct2">Fahrzeuge</div></div><div id="autoContent"></div></div><div class="c"><div class="ch2"><div class="ci2">📊</div><div class="ct2">Statistik</div></div><div id="autoStats"></div></div></div>
<div class="g tc2" id="tab-fin"><div class="c s2"><div class="ch2"><div class="ci2" style="background:var(--ok);">👤</div><div class="ct2">Finanzen Privat</div></div><div id="finPContent"></div></div><div class="c"><div class="ch2"><div class="ci2" style="background:var(--wr);">🏢</div><div class="ct2">Business</div></div><div id="finBContent"></div></div></div>
<div class="g tc2" id="tab-verw"><div class="c"><div class="ch2"><div class="ci2" style="background:linear-gradient(135deg,#6366f1,#ec4899);">📜</div><div class="ct2">Testament</div></div><div id="testContent"></div></div><div class="c s2"><div class="ch2"><div class="ci2" style="background:linear-gradient(135deg,#f59e0b,#22c55e);">🏢</div><div class="ct2">Hausverwaltung</div></div><div id="hvContent"></div></div></div>
<div class="g tc2" id="tab-media"><div class="c"><div class="ch2"><div class="ci2" style="background:linear-gradient(135deg,#ec4899,#8b5cf6);">🎵</div><div class="ct2">Radyo</div></div><div id="radioPlayer"></div><audio id="rA"></audio></div><div class="c s2"><div class="ch2"><div class="ci2" style="background:linear-gradient(135deg,#ef4444,#f59e0b);">📻</div><div class="ct2">Sender</div></div><input class="inp" id="rSr" placeholder="🔍 Suchen..." oninput="fRd()" style="margin-bottom:4px;"><div style="max-height:300px;overflow-y:auto;" id="rL"></div></div></div>
<div class="g tc2" id="tab-comm"><div class="c s2"><div class="ch2"><div class="ci2" style="background:#25D366;">💬</div><div class="ct2">WhatsApp</div></div><div id="waContent"></div></div><div class="c"><div class="ch2"><div class="ci2">🌍</div><div class="ct2">Übersetzer</div></div><div id="trContent"></div></div></div>
<div class="g tc2" id="tab-tools"><div class="c"><div class="ch2"><div class="ci2">🧮</div><div class="ct2">Rechner</div></div><div id="calcContent"></div></div><div class="c"><div class="ch2"><div class="ci2">🔑</div><div class="ct2">Passwort</div></div><div id="pwContent"></div></div><div class="c"><div class="ch2"><div class="ci2">💰</div><div class="ct2">Währung</div></div><div id="crContent"></div></div></div>
<div class="g tc2" id="tab-fp" style="grid-template-columns:1fr;"><div class="c fl"><div class="ch2"><div class="ci2" style="background:linear-gradient(135deg,#3b82f6,#8b5cf6);">🏗️</div><div class="ct2">Grundriss-Zeichner</div></div><div id="fpContent"></div></div></div>
<div class="g tc2" id="tab-nk"><div class="c s2"><div class="ch2"><div class="ci2" style="background:linear-gradient(135deg,#f59e0b,#ef4444);">🧾</div><div class="ct2">Nebenkostenabrechnung</div></div><div id="nkContent"></div></div><div class="c"><div class="ch2"><div class="ci2">📊</div><div class="ct2">Ergebnis</div></div><div id="nkResult"></div></div></div>
<div class="g tc2" id="tab-bmi"><div class="c"><div class="ch2"><div class="ci2" style="background:linear-gradient(135deg,#22c55e,#06b6d4);">🏋️</div><div class="ct2">BMI-Rechner</div></div><div id="bmiContent"></div></div><div class="c"><div class="ch2"><div class="ci2">📊</div><div class="ct2">BMI Info</div></div><div id="bmiInfo"></div></div></div>
<div class="g tc2" id="tab-pray"><div class="c s2"><div class="ch2"><div class="ci2" style="background:linear-gradient(135deg,#22c55e,#f59e0b);">🕌</div><div class="ct2">Gebetszeiten</div></div><div id="prayContent"></div></div><div class="c"><div class="ch2"><div class="ci2">📅</div><div class="ct2">Monatskalender</div></div><div style="max-height:300px;overflow-y:auto;" id="prayMonth"></div></div></div>
<div class="g tc2" id="tab-mv"><div class="c fl"><div class="ch2"><div class="ci2" style="background:linear-gradient(135deg,#6366f1,#ec4899);">📜</div><div class="ct2">Mietvertrag-Generator + QR</div></div><div id="mvContent"></div></div></div>
<div class="g tc2" id="tab-ai" style="grid-template-columns:1fr;"><div class="c"><div class="ch2"><div class="ci2" style="background:linear-gradient(135deg,#ec4899,#8b5cf6,#06b6d4);background-size:200% 200%;animation:gs 3s ease infinite;">🤖</div><div class="ct2">KI-Assistent</div></div><div id="aiContent"></div></div></div>
<div class="qs2"><div class="qt2" id="qT"></div><div class="qa2" id="qA"></div></div>
</div>
<script>
// ==========================================
// ⚡ ULTRA ELITE DASHBOARD — CORE ENGINE
// ==========================================
const E=s=>{const d=document.createElement('div');d.textContent=s;return d.innerHTML};
const S=(k,v)=>localStorage.setItem(k,JSON.stringify(v));
const L=(k,d)=>{try{return JSON.parse(localStorage.getItem(k))||d}catch{return d}};
const F=n=>n.toLocaleString('de-DE',{minimumFractionDigits:2,maximumFractionDigits:2});
const $=id=>document.getElementById(id);
// ===== CLOCK =====
function uC(){const n=new Date(),h=String(n.getHours()).padStart(2,'0'),m=String(n.getMinutes()).padStart(2,'0'),s=String(n.getSeconds()).padStart(2,'0');$('clk').textContent=`${h}:${m}:${s}`;const D=['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],M=['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'];$('dte').textContent=`${D[n.getDay()]}, ${n.getDate()}. ${M[n.getMonth()]} ${n.getFullYear()}`;const hr=n.getHours();$('grt').textContent=hr>=5&&hr<12?'Guten Morgen ☀️':hr<18?'Guten Tag 🌤️':hr<22?'Guten Abend 🌆':'Gute Nacht 🌙';}
setInterval(uC,1000);uC();
// ===== THEMES =====
function tTh(){document.body.classList.toggle('light');localStorage.setItem('th',document.body.classList.contains('light')?'l':'d');}
function sCT(el){document.querySelectorAll('.cd').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('th')==='l')document.body.classList.add('light');localStorage.setItem('ct',t);}
if(localStorage.getItem('th')==='l')document.body.classList.add('light');
const sct=localStorage.getItem('ct');if(sct&&sct!=='def'){document.body.classList.add('t-'+sct);document.querySelectorAll('.cd').forEach(d=>d.classList.toggle('a',d.dataset.t===sct));}
// ===== TABS =====
function sT(b,t){document.querySelectorAll('.tb').forEach(x=>x.classList.remove('a'));b.classList.add('a');document.querySelectorAll('.tc2').forEach(x=>x.classList.remove('a'));$('tab-'+t).classList.add('a');
// Init dynamic content
if(t==='media'&&!$('radioPlayer').innerHTML)initMedia();
if(t==='tools'&&!$('calcContent').innerHTML)initTools();
if(t==='comm'&&!$('waContent').innerHTML)initComm();
if(t==='immo'&&!$('immoContent').innerHTML)initImmo();
if(t==='auto'&&!$('autoContent').innerHTML)initAuto();
if(t==='fin'&&!$('finPContent').innerHTML)initFin();
if(t==='verw'&&!$('testContent').innerHTML)initVerw();
if(t==='fp'&&!$('fpContent').innerHTML)initFP();
if(t==='nk'&&!$('nkContent').innerHTML)initNK();
if(t==='bmi'&&!$('bmiContent').innerHTML)initBMI();
if(t==='pray'&&!$('prayContent').innerHTML)initPray();
if(t==='mv'&&!$('mvContent').innerHTML)initMV();
if(t==='ai'&&!$('aiContent').innerHTML)initAI();
}
// ===== SEARCH =====
let sEn='g';const sU={g:'https://www.google.com/search?q=',y:'https://www.youtube.com/results?search_query=',a:'https://www.amazon.de/s?k=',m:'https://www.google.com/maps/search/'};
function sSE(b,e){sEn=e;document.querySelectorAll('.se').forEach(x=>x.classList.remove('a'));b.classList.add('a');}
function dSr(e){e.preventDefault();const q=$('sI').value.trim();if(q)window.open(sU[sEn]+encodeURIComponent(q),'_blank');}
// ===== TODO =====
let tds=L('tds',[]);
function rTd(){const l=$('tdL');l.innerHTML='';tds.forEach((t,i)=>{l.innerHTML+=`<li class="li2${t.d?' dn':''}"><button class="ck2" onclick="tds[${i}].d=!tds[${i}].d;rTd()">✓</button><span class="tx2">${E(t.t)}</span><button class="dl2" onclick="tds.splice(${i},1);rTd()">✕</button></li>`;});S('tds',tds);}
function aTd(){const i=$('tdI'),t=i.value.trim();if(t){tds.unshift({t,d:false});i.value='';rTd();}}rTd();
// ===== NOTES =====
const nA=$('nA');nA.value=localStorage.getItem('notes')||'';nA.addEventListener('input',()=>localStorage.setItem('notes',nA.value));
// ===== CALENDAR =====
let cDt=new Date(),cSel=null,cEv=L('cEv',[]);
function rCl(){const y=cDt.getFullYear(),mo=cDt.getMonth(),ms=['Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'];$('cMY').textContent=`${ms[mo]} ${y}`;const fd=new Date(y,mo,1).getDay(),sd=(fd===0?6:fd-1),dim=new Date(y,mo+1,0).getDate(),dip=new Date(y,mo,0).getDate(),c=$('cD');c.innerHTML='';const td=new Date();for(let i=sd-1;i>=0;i--)c.innerHTML+=`<div style="text-align:center;padding:4px 1px;font-size:.66rem;opacity:.3;">${dip-i}</div>`;for(let d=1;d<=dim;d++){const ds=`${y}-${String(mo+1).padStart(2,'0')}-${String(d).padStart(2,'0')}`;const isTd=td.getDate()===d&&td.getMonth()===mo&&td.getFullYear()===y;const he=cEv.some(e=>e.d===ds);c.innerHTML+=`<div style="text-align:center;padding:4px 1px;border-radius:4px;font-size:.66rem;cursor:pointer;transition:var(--tr);font-weight:500;${isTd?'background:var(--ag);color:#fff;font-weight:700;':''}${he?'position:relative;':''}" onclick="sDy('${ds}')">${d}${he?'<span style="position:absolute;bottom:1px;left:50%;transform:translateX(-50%);width:3px;height:3px;border-radius:50%;background:var(--a3);"></span>':''}</div>`;}const ts=`${td.getFullYear()}-${String(td.getMonth()+1).padStart(2,'0')}-${String(td.getDate()).padStart(2,'0')}`;if(!$('eD').value)$('eD').value=ts;}
function cN(d){cDt.setMonth(cDt.getMonth()+d);rCl();}
function sDy(ds){cSel=ds;$('eD').value=ds;const ev=cEv.filter(e=>e.d===ds);$('cET').textContent=`Termine ${ds.split('-').reverse().join('.')}`;$('cE').innerHTML=ev.length?ev.map(e=>{const idx=cEv.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.t||'–'}</span><span style="flex:1">${E(e.ti)}</span><button class="dl2" style="opacity:1;" onclick="cEv.splice(${idx},1);S('cEv',cEv);rCl();sDy('${ds}')">✕</button></div>`}).join(''):'<div style="color:var(--t3);font-size:.68rem;text-align:center;padding:8px;">—</div>';}
function aEv(){const d=$('eD').value,t=$('eT').value,ti=$('eTi').value.trim();if(!d||!ti)return;cEv.push({d,t,ti});S('cEv',cEv);$('eTi').value='';rCl();sDy(d);}
rCl();
// ===== EXPENSES =====
const tStr=new Date().toDateString();let exps=L('ex_'+tStr,[]);
function rEx(){const l=$('exL');l.innerHTML='';let t=0;exps.forEach((e,i)=>{t+=e.a;l.innerHTML+=`<li class="li2"><span class="tx2">${E(e.n)}</span><span style="font-weight:700;color:var(--er);font-size:.72rem;">-${e.a.toFixed(2)}€</span><button class="dl2" onclick="exps.splice(${i},1);rEx()">✕</button></li>`;});$('exT').textContent=F(t)+'€';S('ex_'+tStr,exps);}
function aEx(){const n=$('exN').value.trim(),a=parseFloat($('exA').value);if(n&&a>0){exps.push({n,a});$('exN').value='';$('exA').value='';rEx();}}rEx();
// ===== LIGHTBOX =====
function oLB(src,type){$('lbC').innerHTML=type==='vid'?`<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()">`;$('lb').classList.add('sh');}
function cLB(){$('lb').classList.remove('sh');$('lbC').innerHTML='';}
// ===== DYNAMIC TAB INITIALIZERS =====
// MEDIA
function initMedia(){
const rSt=[{n:'Power FM',g:'Pop',u:'https://playerservices.streamtheworld.com/api/livestream-redirect/POWER_FM'},{n:'Kral Pop',g:'Türk Pop',u:'https://trkvz-radyolar.ercdn.net/kralpop/playlist.m3u8'},{n:'Virgin Radio TR',g:'Hit',u:'https://playerservices.streamtheworld.com/api/livestream-redirect/VIRGIN_RADIO_TURKEY'},{n:'Metro FM',g:'Dance',u:'https://playerservices.streamtheworld.com/api/livestream-redirect/METRO_FM'},{n:'Kral FM',g:'Sanat',u:'https://trkvz-radyolar.ercdn.net/kralfm/playlist.m3u8'},{n:'TRT Türkü',g:'Halk',u:'https://trtradyo-canli.medya.trt.com.tr/trtturku.mp3'},{n:'Kral Arabesk',g:'Arabesk',u:'https://trkvz-radyolar.ercdn.net/kralarabesk/playlist.m3u8'},{n:'Slow Türk',g:'Slow',u:'https://trkvz-radyolar.ercdn.net/slowturk/playlist.m3u8'},{n:'NTV Radyo',g:'Haber',u:'https://trkvz-radyolar.ercdn.net/ntvradyo/playlist.m3u8'},{n:'Best FM',g:'Mix',u:'https://trkvz-radyolar.ercdn.net/bestfm/playlist.m3u8'},{n:'Show Radyo',g:'Pop',u:'https://trkvz-radyolar.ercdn.net/showradyo/playlist.m3u8'},{n:'Pal Station',g:'Remix',u:'https://trkvz-radyolar.ercdn.net/palstation/playlist.m3u8'}];
let cS=-1;const au=$('rA');
$('radioPlayer').innerHTML=`<div style="background:var(--b2);border:1px solid var(--bd);border-radius:var(--r);padding:14px;text-align:center;"><div class="plv" id="pV"></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="pNP">Sender wählen...</div><div style="font-size:.58rem;color:var(--t3);margin-bottom:6px;" id="pG">—</div><div style="display:flex;justify-content:center;gap:5px;margin-bottom:6px;"><button class="hb" onclick="pS()">⏮</button><button class="hb" id="plB" onclick="tP()" style="width:36px;height:36px;border-radius:50%;font-size:.9rem;">▶</button><button class="hb" onclick="nS()">⏭</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="vS" min="0" max="100" value="70" oninput="au.volume=this.value/100"><span style="font-size:.7rem;">🔊</span></div></div>`;
window.plSt=function(i){cS=i;au.src=rSt[i].u;au.volume=$('vS').value/100;au.play().catch(()=>{});$('pNP').textContent=rSt[i].n;$('pG').textContent=rSt[i].g;$('pV').classList.add('sp2');$('plB').textContent='⏸';fRd();}
window.tP=function(){if(cS===-1){plSt(0);return;}if(au.paused){au.play();$('pV').classList.add('sp2');$('plB').textContent='⏸';}else{au.pause();$('pV').classList.remove('sp2');$('plB').textContent='▶';}}
window.pS=function(){plSt(cS<=0?rSt.length-1:cS-1);}
window.nS=function(){plSt(cS>=rSt.length-1?0:cS+1);}
window.fRd=function(){const f=$('rSr').value.toLowerCase();$('rL').innerHTML=rSt.filter(s=>!f||s.n.toLowerCase().includes(f)).map((s,i)=>{const ri=rSt.indexOf(s);return`<div class="rs3${ri===cS?' ac3':''}" onclick="plSt(${ri})"><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.n}</div><div style="font-size:.56rem;color:var(--t3);">${s.g}</div></div></div>`}).join('');}
fRd();
}
// TOOLS
function initTools(){
// Calculator
let cE2='';
$('calcContent').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="cDi">0</div><div style="display:grid;grid-template-columns:repeat(4,1fr);gap:2px;"><button class="bt-c" onclick="cCl()">C</button><button class="bt-c o" onclick="cIn('(')">(</button><button class="bt-c o" onclick="cIn(')')">)</button><button class="bt-c o" onclick="cIn('/')">÷</button><button class="bt-c" onclick="cIn('7')">7</button><button class="bt-c" onclick="cIn('8')">8</button><button class="bt-c" onclick="cIn('9')">9</button><button class="bt-c o" onclick="cIn('*')">×</button><button class="bt-c" onclick="cIn('4')">4</button><button class="bt-c" onclick="cIn('5')">5</button><button class="bt-c" onclick="cIn('6')">6</button><button class="bt-c o" onclick="cIn('-')">−</button><button class="bt-c" onclick="cIn('1')">1</button><button class="bt-c" onclick="cIn('2')">2</button><button class="bt-c" onclick="cIn('3')">3</button><button class="bt-c o" onclick="cIn('+')">+</button><button class="bt-c" onclick="cIn('0')">0</button><button class="bt-c" onclick="cIn('.')">.</button><button class="bt-c o" onclick="cBk()">⌫</button><button class="bt-c eq" onclick="cRe()">=</button></div><style>.bt-c{padding:10px;border:1px solid var(--bd);background:var(--b2);color:var(--t1);border-radius:var(--rs);cursor:pointer;font-size:.82rem;font-weight:600;transition:var(--tr);font-family:inherit;}.bt-c:hover{background:var(--b4);border-color:var(--a1);}.bt-c.o{background:var(--gl);color:var(--a3);}.bt-c.eq{background:var(--ag);color:#fff;}</style>`;
window.cIn=v=>{cE2+=v;$('cDi').textContent=cE2||'0';}
window.cCl=()=>{cE2='';$('cDi').textContent='0';}
window.cBk=()=>{cE2=cE2.slice(0,-1);$('cDi').textContent=cE2||'0';}
window.cRe=()=>{try{let r=Function('"use strict";return('+cE2+')')();$('cDi').textContent=Math.round(r*1e10)/1e10;cE2=String(Math.round(r*1e10)/1e10);}catch{$('cDi').textContent='Fehler';cE2='';}}
// Password
$('pwContent').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="pwDi">—</div><div style="display:flex;gap:3px;"><button class="bt" onclick="gPw()">⚡</button><button class="bt bt-o" onclick="navigator.clipboard.writeText($('pwDi').textContent)">📋</button></div>`;
window.gPw=()=>{let c='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*',p='';const a=new Uint32Array(20);crypto.getRandomValues(a);for(let i=0;i<20;i++)p+=c[a[i]%c.length];$('pwDi').textContent=p;}
// Currency
$('crContent').innerHTML=`<div class="ig2"><input type="number" class="inp" id="crA" value="100" oninput="crC()"></div><div class="ig2"><select class="inp" id="crF" onchange="crC()"><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="crT" onchange="crC()"><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="crR">—</div>`;
let cRa=null;
(async()=>{try{const r=await fetch('https://api.frankfurter.app/latest?from=EUR');const d=await r.json();cRa=d.rates;cRa.EUR=1;crC();}catch{cRa={EUR:1,USD:1.08,GBP:0.86,TRY:34.5};}})();
window.crC=()=>{if(!cRa)return;const a=parseFloat($('crA').value),f=$('crF').value,t=$('crT').value;if(isNaN(a)){$('crR').textContent='—';return;}$('crR').textContent=`${a.toFixed(2)} ${f} = ${(a/cRa[f]*cRa[t]).toFixed(2)} ${t}`;}
}
// COMMUNICATE
function initComm(){
let waCs=L('waCs',[]);
$('waContent').innerHTML=`<div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;"><div><div class="ig2"><input class="inp" id="waN" placeholder="Name"><input class="inp" id="waP" placeholder="+49..."><button class="bt bt-s" style="background:#25D366;" onclick="aWA()">+</button></div><div id="waC2"></div></div><div><input class="inp" id="waD" placeholder="+49..." style="margin-bottom:3px;"><textarea class="inp" id="waMs" placeholder="Nachricht..." style="min-height:40px;margin-bottom:3px;"></textarea><button class="bt" style="background:#25D366;width:100%;" onclick="sWA2()">💬 Senden</button></div></div>`;
window.rWA2=()=>{$('waC2').innerHTML=waCs.map((x,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/${x.p.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;">${x.n[0]}</div><div style="flex:1;font-size:.68rem;font-weight:600;">${E(x.n)}<div style="font-size:.55rem;color:var(--t3);">${E(x.p)}</div></div><button class="dl2" style="opacity:.5;" onclick="event.stopPropagation();waCs.splice(${i},1);S('waCs',waCs);rWA2()">✕</button></div>`).join('');S('waCs',waCs);}
window.aWA=()=>{const n=$('waN').value.trim(),p=$('waP').value.trim();if(n&&p){waCs.push({n,p});$('waN').value='';$('waP').value='';rWA2();}}
window.sWA2=()=>{const n=$('waD').value.replace(/\s/g,''),m=$('waMs').value;if(n)window.open(`https://wa.me/${n}${m?'?text='+encodeURIComponent(m):''}`);}
rWA2();
// Translator
$('trContent').innerHTML=`<div style="display:flex;gap:3px;margin-bottom:4px;"><select class="inp" id="trF"><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="trT"><option value="de">🇩🇪</option><option value="en" selected>🇬🇧</option><option value="tr">🇹🇷</option></select></div><textarea class="inp" id="trI" placeholder="Text..." style="margin-bottom:3px;"></textarea><textarea class="inp" id="trO" placeholder="Übersetzung..." readonly style="opacity:.8;margin-bottom:3px;"></textarea><button class="bt" onclick="dTr()">🌍</button>`;
window.dTr=async()=>{const t=$('trI').value.trim();if(!t)return;try{const r=await fetch('https://api.mymemory.translated.net/get?q='+encodeURIComponent(t)+'&langpair='+$('trF').value+'|'+$('trT').value);const d=await r.json();$('trO').value=d.responseData.translatedText;}catch{$('trO').value='Fehler';}}
}
// IMMOBILIEN
function initImmo(){
let imgs=[],vids=[],panos=[];let pV2=null,cPI=0;
$('immoContent').innerHTML=`
<div class="ig2"><select class="inp" id="imTy" style="flex:.4"><option value="sell">🔴 Verkauf</option><option value="buy">🟢 Kauf</option><option value="rent">🔵 Miete</option></select><select class="inp" id="imPT"><option>🏢 Wohnung</option><option>🏠 Haus</option><option>🏗️ Grundstück</option><option>🏬 Gewerbe</option><option>🏰 Villa</option></select></div>
<div class="ig2"><input class="inp" id="imTi" placeholder="Titel"><input class="inp" id="imRf" placeholder="Ref" style="flex:.3"></div>
<div class="ig2"><input class="inp" id="imAd" placeholder="Adresse"><input class="inp" id="imPl" placeholder="PLZ" style="flex:.2"><input class="inp" id="imCi" placeholder="Stadt" style="flex:.3"><input class="inp" id="imCo" placeholder="Land" style="flex:.3"></div>
<div class="ig2"><input type="number" class="inp" id="imPr" placeholder="Preis €" style="flex:.3"><input type="number" class="inp" id="imSq" placeholder="m²" style="flex:.2"><input type="number" class="inp" id="imGr" placeholder="Grundst. m²" style="flex:.2"><input type="number" class="inp" id="imRm" placeholder="Zi" style="flex:.15"><input type="number" class="inp" id="imBa" placeholder="Bad" style="flex:.15"><input type="number" class="inp" id="imYr" placeholder="Baujahr" style="flex:.2"></div>
<textarea class="inp" id="imDe" placeholder="Beschreibung..." style="margin-bottom:4px;"></textarea>
<input class="inp" id="imCn" placeholder="Kontakt" style="margin-bottom:4px;">
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:4px;margin-bottom:6px;">
<div class="gal-add" onclick="$('imIm').click()"><span>📷</span>Bilder</div>
<div class="gal-add" onclick="$('imVi').click()"><span>🎥</span>Videos</div>
<div class="gal-add" onclick="$('im36').click()" style="border-color:var(--ok);"><span>🔄</span>360°</div>
</div>
<input type="file" id="imIm" accept="image/*" multiple hidden onchange="hImgU(this)">
<input type="file" id="imVi" accept="video/*" multiple hidden onchange="hVidU(this)">
<input type="file" id="im36" accept="image/*" multiple hidden onchange="h360U(this)">
<div class="gal" id="imGal"></div>
<div id="panoSec" style="display:none;"><div style="font-size:.66rem;font-weight:700;color:var(--a3);margin:6px 0 3px;">🔄 360° Panorama</div><div class="pano-th" id="pTh"></div><div class="pano-p" id="pVw"></div><div class="pano-ct" style="margin-top:4px;"><button class="pano-b" onclick="pAR()">🔄 Auto</button><button class="pano-b" onclick="$('pVw')?.requestFullscreen?.()">🖥️ Vollbild</button><button class="pano-b" onclick="if(pV2)pV2.setHfov(Math.max(50,pV2.getHfov()-10))">🔍+</button><button class="pano-b" onclick="if(pV2)pV2.setHfov(Math.min(120,pV2.getHfov()+10))">🔍-</button><button class="pano-b" onclick="aHS()">📍 Hotspot</button></div></div>
<div id="mapSec" style="display:none;"><div style="font-size:.66rem;font-weight:700;color:var(--a3);margin:6px 0 3px;">🗺️ Karte</div><div class="ig2"><input class="inp" id="mSr" placeholder="📍 Adresse suchen..."><button class="bt bt-s" onclick="sMpA()">🔍</button><button class="bt bt-s bt-o" onclick="mLoc()">📍 GPS</button></div><div class="map-c" id="mC"></div></div>
<div class="exp-r"><button class="exp-b" onclick="exExpPDF()"><span>📄</span>PDF</button><button class="exp-b" onclick="exExpWord()"><span>📝</span>Word</button><button class="exp-b" onclick="exExpExcel()"><span>📊</span>Excel</button><button class="exp-b" onclick="showMap2()"><span>🗺️</span>Karte</button></div>
<div style="font-size:.66rem;font-weight:700;color:var(--a3);margin:10px 0 4px;">📚 Gespeichert (<span id="imCn2">0</span>)</div>
<div id="imLs" style="max-height:300px;overflow-y:auto;"></div>`;
window.hImgU=inp=>{Array.from(inp.files).forEach(f=>{const r=new FileReader();r.onload=e=>{imgs.push({n:f.name,d:e.target.result});rGal()};r.readAsDataURL(f);});inp.value='';};
window.hVidU=inp=>{Array.from(inp.files).forEach(f=>{const r=new FileReader();r.onload=e=>{vids.push({n:f.name,d:e.target.result});rGal()};r.readAsDataURL(f);});inp.value='';};
window.h360U=inp=>{Array.from(inp.files).forEach(f=>{const r=new FileReader();r.onload=e=>{panos.push({n:f.name,d:e.target.result});$('panoSec').style.display='block';rPTh();ldP(panos.length-1);};r.readAsDataURL(f);});inp.value='';};
function rGal(){const g=$('imGal');g.innerHTML='';imgs.forEach((im,i)=>g.innerHTML+=`<div class="gal-i" onclick="oLB('${im.d.substring(0,50)}...','img')"><img src="${im.d}"><button class="gd" onclick="event.stopPropagation();imgs.splice(${i},1);rGal()">✕</button></div>`);vids.forEach((v,i)=>g.innerHTML+=`<div class="gal-i"><video src="${v.d}" muted></video><button class="gd" onclick="event.stopPropagation();vids.splice(${i},1);rGal()">✕</button></div>`);if(!imgs.length&&!vids.length)g.innerHTML='<div style="grid-column:1/-1;text-align:center;padding:12px;color:var(--t3);font-size:.7rem;">Medien hochladen</div>';}
// Fix lightbox for images
window.hImgU=inp=>{Array.from(inp.files).forEach(f=>{const r=new FileReader();r.onload=e=>{imgs.push({n:f.name,d:e.target.result});rGal2()};r.readAsDataURL(f);});inp.value='';};
function rGal2(){const g=$('imGal');g.innerHTML='';imgs.forEach((im,i)=>g.innerHTML+=`<div class="gal-i" onclick="oLB2(${i})"><img src="${im.d}"><button class="gd" onclick="event.stopPropagation();imgs.splice(${i},1);rGal2()">✕</button></div>`);vids.forEach((v,i)=>g.innerHTML+=`<div class="gal-i" onclick="oLB('${v.d}','vid')"><video src="${v.d}" muted></video><button class="gd" onclick="event.stopPropagation();vids.splice(${i},1);rGal2()">✕</button></div>`);}
window.oLB2=i=>{$('lbC').innerHTML=`<img src="${imgs[i].d}" onclick="event.stopPropagation()">`;$('lb').classList.add('sh');}
rGal();
// 360° Pannellum
window.rPTh=()=>{$('pTh').innerHTML=panos.map((p,i)=>`<img class="${i===cPI?'ac4':''}" src="${p.d}" onclick="ldP(${i})">`).join('');};
window.ldP=(i)=>{cPI=i;rPTh();if(pV2){pV2.destroy();pV2=null;}$('pVw').innerHTML='';pV2=pannellum.viewer('pVw',{type:'equirectangular',panorama:panos[i].d,autoLoad:true,autoRotate:-2,compass:true,showZoomCtrl:true,showFullscreenCtrl:true,mouseZoom:true,hfov:110});};
window.pAR=()=>{if(!pV2)return;try{pV2.stopAutoRotate();}catch{pV2.startAutoRotate(-2);}};
window.aHS=()=>{if(!pV2)return;const t=prompt('Hotspot-Text:');if(t)pV2.addHotSpot({pitch:pV2.getPitch(),yaw:pV2.getYaw(),type:'info',text:t});};
// MAP (Leaflet)
let lMap=null,lMark=null;
window.showMap2=()=>{$('mapSec').style.display='block';setTimeout(()=>{if(!lMap){lMap=L2.map('mC').setView([51.16,10.45],6);L2.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(lMap);lMap.on('click',e=>setMk(e.latlng.lat,e.latlng.lng));}lMap.invalidateSize();const a=$('imAd')?.value||'';const c=$('imCi')?.value||'';if(a||c)$('mSr').value=`${a}, ${c}`;},300);};
const L2=window.L; // Leaflet reference
function setMk(lat,lng){if(lMark)lMap.removeLayer(lMark);lMark=L2.marker([lat,lng]).addTo(lMap);lMap.setView([lat,lng],15);}
window.sMpA=async()=>{const q=$('mSr').value.trim();if(!q)return;try{const r=await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(q)}`);const d=await r.json();if(d[0]){if(!lMap)showMap2();setTimeout(()=>setMk(parseFloat(d[0].lat),parseFloat(d[0].lon)),500);}else alert('Nicht gefunden!');}catch{alert('Fehler!');}};
window.mLoc=()=>{navigator.geolocation?.getCurrentPosition(p=>{if(!lMap)showMap2();setTimeout(()=>setMk(p.coords.latitude,p.coords.longitude),500);});};
// EXPORTS
window.exExpPDF=()=>{const{jsPDF:JP}=window.jspdf;const d=new JP();d.setFillColor(99,102,241);d.rect(0,0,210,30,'F');d.setTextColor(255);d.setFontSize(20);d.text('EXPOSÉ',20,17);d.setFontSize(9);d.text($('imTi').value||'—',20,25);let y=38;if(imgs[0]){try{d.addImage(imgs[0].d,'JPEG',15,y,180,80);y+=88;}catch{}}d.setTextColor(0);d.setFontSize(13);d.text($('imTi').value||'—',15,y);y+=7;d.setFontSize(9);d.text(`${$('imAd').value}, ${$('imPl').value} ${$('imCi').value}`,15,y);y+=6;d.setTextColor(99,102,241);d.setFontSize(14);d.text(`${parseFloat($('imPr').value||0).toLocaleString('de-DE')} EUR`,15,y);y+=10;d.setTextColor(0);d.setFontSize(8);d.text(`m²: ${$('imSq').value} | Zi: ${$('imRm').value} | Bad: ${$('imBa').value} | Baujahr: ${$('imYr').value}`,15,y);y+=6;if($('imDe').value){const ls=d.splitTextToSize($('imDe').value,175);d.text(ls,15,y);y+=ls.length*4+5;}if($('imCn').value){d.text('Kontakt: '+$('imCn').value,15,y);}d.save('expose.pdf');};
window.exExpWord=async()=>{const{Document:Doc,Packer:Pk,Paragraph:P,TextRun:TR,HeadingLevel:HL}=docx;const ch=[new P({heading:HL.HEADING_1,children:[new TR({text:'EXPOSÉ — '+($('imTi').value||'—'),bold:true,size:32,color:'4F46E5'})]}),new P({children:[new TR({text:`${$('imAd').value}, ${$('imPl').value} ${$('imCi').value}`,size:20})]}),new P({children:[new TR({text:`${parseFloat($('imPr').value||0).toLocaleString('de-DE')} EUR`,bold:true,size:26,color:'22C55E'})]}),new P({children:[new TR({text:`m²: ${$('imSq').value} | Zimmer: ${$('imRm').value} | Bäder: ${$('imBa').value} | Baujahr: ${$('imYr').value}`,size:18})]}),new P({}),new P({children:[new TR({text:$('imDe').value||'',size:18})]})];saveAs(await Pk.toBlob(new Doc({sections:[{children:ch}]})),'expose.docx');};
window.exExpExcel=()=>{const wb=XLSX.utils.book_new();XLSX.utils.book_append_sheet(wb,XLSX.utils.aoa_to_sheet([['EXPOSÉ'],['Titel',$('imTi').value],['Adresse',$('imAd').value+', '+$('imCi').value],['Preis',parseFloat($('imPr').value)||0],['m²',parseFloat($('imSq').value)||0],['Zimmer',parseInt($('imRm').value)||0],['Baujahr',$('imYr').value]]),'Exposé');XLSX.writeFile(wb,'expose.xlsx');};
}
// AUTO
function initAuto(){
let autos=L('autos',[]);
$('autoContent').innerHTML=`<div class="ig2"><select class="inp" id="auT" style="flex:.3"><option value="sell">🔴 Verkauf</option><option value="buy">🟢 Kauf</option></select><input class="inp" id="auBr" placeholder="Marke"><input class="inp" id="auMo" placeholder="Modell"></div><div class="ig2"><input type="number" class="inp" id="auYr" placeholder="Jahr" style="flex:.2"><input type="number" class="inp" id="auPr" placeholder="Preis €"><input type="number" class="inp" id="auKm" placeholder="km" style="flex:.3"><select class="inp" id="auFu" style="flex:.3"><option>Benzin</option><option>Diesel</option><option>Elektro</option><option>Hybrid</option></select></div><div class="ig2"><button class="bt" onclick="aAu()">➕</button><button class="bt bt-o" onclick="eAuP()">📄 PDF</button></div><div style="max-height:250px;overflow-y:auto;" id="auL2"></div>`;
$('autoStats').innerHTML=`<div class="fin-s"><div class="fin-b"><div class="fin-l">Fahrzeuge</div><div class="fin-v bal" id="auCt">0</div></div><div class="fin-b"><div class="fin-l">Ø Preis</div><div class="fin-v inc" id="auAv">0€</div></div><div class="fin-b"><div class="fin-l">Gesamt</div><div class="fin-v bal" id="auTo">0€</div></div></div>`;
window.aAu=()=>{const o={type:$('auT').value,brand:$('auBr').value.trim(),model:$('auMo').value.trim(),year:parseInt($('auYr').value)||0,price:parseFloat($('auPr').value)||0,km:parseInt($('auKm').value)||0,fuel:$('auFu').value,date:new Date().toISOString().split('T')[0]};if(!o.brand)return;autos.push(o);S('autos',autos);rAu2();};
window.rAu2=()=>{$('auL2').innerHTML=autos.map((o,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;">🚗 ${E(o.brand)} ${E(o.model)}</div><div style="font-size:.66rem;color:var(--t2);">📅 ${o.year} · 🛣️ ${o.km.toLocaleString('de-DE')}km · ⛽ ${o.fuel}</div><div style="font-size:.9rem;font-weight:800;color:var(--a3);">💰 ${o.price.toLocaleString('de-DE')}€</div><button class="bt bt-s bt-d" onclick="autos.splice(${i},1);S('autos',autos);rAu2()">🗑️</button></div>`).join('');$('auCt').textContent=autos.length;$('auTo').textContent=autos.reduce((s,a)=>s+a.price,0).toLocaleString('de-DE')+'€';$('auAv').textContent=autos.length?Math.round(autos.reduce((s,a)=>s+a.price,0)/autos.length).toLocaleString('de-DE')+'€':'0€';};
window.eAuP=()=>{const{jsPDF:JP}=window.jspdf;const d=new JP();d.setFontSize(16);d.text('Fahrzeuge',20,20);let y=30;autos.forEach((o,i)=>{d.setFontSize(10);d.text(`${o.brand} ${o.model} (${o.year}) — ${o.price.toLocaleString('de-DE')} EUR`,20,y);y+=6;});d.save('fahrzeuge.pdf');};
rAu2();
}
// FINANZEN
function initFin(){
let fP=L('fP',{}),fB=L('fB',{});
$('finPContent').innerHTML=`<div class="ig2"><select class="inp" id="fpM" onchange="rFP2()"><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="fpY" value="2025" style="flex:.3" onchange="rFP2()"></div><div class="fin-s"><div class="fin-b"><div class="fin-l">Einnahmen</div><div class="fin-v inc" id="fpI">0€</div></div><div class="fin-b"><div class="fin-l">Ausgaben</div><div class="fin-v exp" id="fpE">0€</div></div><div class="fin-b"><div class="fin-l">Bilanz</div><div class="fin-v bal" id="fpB">0€</div></div></div><div class="ig2"><select class="inp" id="fpTy" style="flex:.3"><option value="income">➕</option><option value="expense">➖</option></select><input class="inp" id="fpD" placeholder="Beschr."><input type="number" class="inp" id="fpA" placeholder="€" style="flex:.2"><select class="inp" id="fpC" style="flex:.3"><option>Gehalt</option><option>Miete</option><option>Strom</option><option>Essen</option><option>Transport</option><option>Sonstiges</option></select><button class="bt bt-s" onclick="aFP2()">+</button></div><div style="max-height:150px;overflow-y:auto;" id="fpL2"></div><div style="display:flex;gap:3px;margin-top:4px;"><button class="bt bt-o bt-s" onclick="eFPpdf()">📄</button><button class="bt bt-o bt-s" onclick="eFPxl()">📊</button></div>`;
const fpK=()=>$('fpM').selectedIndex+'-'+$('fpY').value;
window.aFP2=()=>{const k=fpK(),ty=$('fpTy').value,d=$('fpD').value.trim(),a=parseFloat($('fpA').value),c=$('fpC').value;if(!d||!a)return;if(!fP[k])fP[k]=[];fP[k].push({ty,d,a,c});S('fP',fP);$('fpD').value='';$('fpA').value='';rFP2();};
window.rFP2=()=>{const data=fP[fpK()]||[],l=$('fpL2');l.innerHTML='';let inc=0,exp=0;data.forEach((e,i)=>{if(e.ty==='income')inc+=e.a;else exp+=e.a;l.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.ty==='income'?'var(--ok)':'var(--er)'};"><span style="flex:1">${E(e.d)}</span><span style="font-weight:700;color:${e.ty==='income'?'var(--ok)':'var(--er)'};">${e.ty==='income'?'+':'-'}${e.a.toFixed(2)}€</span><button class="dl2" style="opacity:.5;" onclick="fP['${fpK()}'].splice(${i},1);S('fP',fP);rFP2()">✕</button></div>`;});$('fpI').textContent=F(inc)+'€';$('fpE').textContent=F(exp)+'€';$('fpB').textContent=F(inc-exp)+'€';};
window.eFPpdf=()=>{const{jsPDF:JP}=window.jspdf;const d=new JP();d.setFontSize(14);d.text('Finanzbericht',20,20);let y=30;(fP[fpK()]||[]).forEach(e=>{d.setFontSize(8);d.text(`${e.ty==='income'?'+':'-'} ${e.d} — ${e.a.toFixed(2)} EUR`,20,y);y+=5;});d.save('finanzen.pdf');};
window.eFPxl=()=>{const wb=XLSX.utils.book_new();const da=[['Typ','Beschreibung','Kategorie','Betrag']];(fP[fpK()]||[]).forEach(e=>da.push([e.ty,e.d,e.c,e.a]));XLSX.utils.book_append_sheet(wb,XLSX.utils.aoa_to_sheet(da),'Finanzen');XLSX.writeFile(wb,'finanzen.xlsx');};
rFP2();$('fpM').selectedIndex=new Date().getMonth();
// Business (simplified)
$('finBContent').innerHTML=`<div style="text-align:center;color:var(--t3);padding:15px;font-size:.75rem;">Gleiche Struktur wie Privat — Daten getrennt gespeichert</div>`;
}
// VERWALTUNG
function initVerw(){
let ts2=L('ts2',{heirs:[],assets:[]});
$('testContent').innerHTML=`<div class="mv-s"><h4>👤 Erblasser</h4><div class="ig2"><input class="inp" id="tsN" placeholder="Name"><input type="date" class="inp" id="tsD"></div><input class="inp" id="tsA" placeholder="Adresse" style="margin-bottom:3px;"></div><div class="mv-s"><h4>👥 Erben</h4><div class="ig2"><input class="inp" id="tsHN" placeholder="Name"><input class="inp" id="tsHR" placeholder="Beziehung" style="flex:.3"><input type="number" class="inp" id="tsHS" placeholder="%" style="flex:.2"><button class="bt bt-s" onclick="aH2()">+</button></div><ul class="ls2" id="tsHL2"></ul></div><div class="mv-s"><h4>🏠 Vermögen</h4><div class="ig2"><input class="inp" id="tsAN2" placeholder="Beschreibung"><input type="number" class="inp" id="tsAV2" placeholder="€" style="flex:.3"><button class="bt bt-s" onclick="aAs2()">+</button></div><ul class="ls2" id="tsAL2"></ul></div><textarea class="inp" id="tsW2" placeholder="Letzte Wünsche..." style="margin-bottom:4px;"></textarea><div style="display:flex;gap:3px;"><button class="bt" onclick="eTsPDF()">📄 PDF</button><button class="bt bt-o" onclick="svTs2()">💾</button></div><div class="st2">⚠️ Rechtlich unverbindlich!</div>`;
window.aH2=()=>{const n=$('tsHN').value.trim(),r=$('tsHR').value.trim(),s=parseFloat($('tsHS').value)||0;if(!n)return;ts2.heirs.push({n,r,s});S('ts2',ts2);$('tsHN').value='';$('tsHR').value='';$('tsHS').value='';rTs2();};
window.aAs2=()=>{const n=$('tsAN2').value.trim(),v=parseFloat($('tsAV2').value)||0;if(!n)return;ts2.assets.push({n,v});S('ts2',ts2);$('tsAN2').value='';$('tsAV2').value='';rTs2();};
window.rTs2=()=>{$('tsHL2').innerHTML=ts2.heirs.map((h,i)=>`<li class="li2"><span class="tx2">👤 ${E(h.n)} — ${E(h.r)} — ${h.s}%</span><button class="dl2" onclick="ts2.heirs.splice(${i},1);S('ts2',ts2);rTs2()">✕</button></li>`).join('');$('tsAL2').innerHTML=ts2.assets.map((a,i)=>`<li class="li2"><span class="tx2">🏠 ${E(a.n)} — ${a.v.toLocaleString('de-DE')}€</span><button class="dl2" onclick="ts2.assets.splice(${i},1);S('ts2',ts2);rTs2()">✕</button></li>`).join('');};
window.svTs2=()=>{ts2.name=$('tsN').value;ts2.dob=$('tsD').value;ts2.addr=$('tsA').value;ts2.wishes=$('tsW2').value;S('ts2',ts2);alert('✅');};
window.eTsPDF=()=>{svTs2();const{jsPDF:JP}=window.jspdf;const d=new JP();d.setFontSize(18);d.text('TESTAMENT',85,20);let y=35;d.setFontSize(9);d.text(`Name: ${ts2.name||'-'}`,20,y);y+=5;ts2.heirs.forEach(h=>{d.text(`Erbe: ${h.n} (${h.r}) — ${h.s}%`,25,y);y+=5;});ts2.assets.forEach(a=>{d.text(`Vermögen: ${a.n}: ${a.v.toLocaleString('de-DE')} EUR`,25,y);y+=5;});d.save('testament.pdf');};
rTs2();if(ts2.name)$('tsN').value=ts2.name;if(ts2.dob)$('tsD').value=ts2.dob;if(ts2.addr)$('tsA').value=ts2.addr;if(ts2.wishes)$('tsW2').value=ts2.wishes;
// Hausverwaltung
let hvO=L('hvO',[]),hvC=L('hvC',[]);
$('hvContent').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="ig2"><input class="inp" id="hvN" placeholder="Objekt"><input class="inp" id="hvA2" placeholder="Adresse" style="flex:.5"></div><div class="ig2"><input class="inp" id="hvT2" placeholder="Mieter"><input type="number" class="inp" id="hvR2" placeholder="Miete €" style="flex:.3"><button class="bt bt-s" onclick="aHV2()">+</button></div><div style="max-height:130px;overflow-y:auto;" id="hvOL2"></div></div><div><div style="font-size:.6rem;font-weight:700;color:var(--a3);margin-bottom:3px;">💰 Kosten</div><div class="ig2"><select class="inp" id="hvCO2" style="flex:.4"></select><input class="inp" id="hvCD2" placeholder="Beschreibung"><input type="number" class="inp" id="hvCA2" placeholder="€" style="flex:.3"><button class="bt bt-s" onclick="aHVC2()">+</button></div><div style="max-height:130px;overflow-y:auto;" id="hvCL2"></div></div></div><div class="fin-s" style="margin-top:6px;"><div class="fin-b"><div class="fin-l">Miete/Mo</div><div class="fin-v inc" id="hvTR2">0€</div></div><div class="fin-b"><div class="fin-l">Kosten</div><div class="fin-v exp" id="hvTC2">0€</div></div><div class="fin-b"><div class="fin-l">Netto</div><div class="fin-v bal" id="hvTN2">0€</div></div></div>`;
window.aHV2=()=>{const n=$('hvN').value.trim(),a=$('hvA2').value.trim(),t=$('hvT2').value.trim(),r=parseFloat($('hvR2').value)||0;if(!n)return;hvO.push({n,a,t,r});S('hvO',hvO);['hvN','hvA2','hvT2','hvR2'].forEach(id=>$(id).value='');rHV2();};
window.aHVC2=()=>{const o=$('hvCO2').value,d=$('hvCD2').value.trim(),a=parseFloat($('hvCA2').value)||0;if(!d||!a)return;hvC.push({o,d,a});S('hvC',hvC);$('hvCD2').value='';$('hvCA2').value='';rHV2();};
window.rHV2=()=>{const sel=$('hvCO2');sel.innerHTML='';let tr=0;$('hvOL2').innerHTML=hvO.map((o,i)=>{tr+=o.r;sel.innerHTML+=`<option>${E(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;">🏠 ${E(o.n)}</div><div style="color:var(--t3);">👤 ${E(o.t)||'—'} · <span style="color:var(--ok);font-weight:700;">${o.r.toFixed(2)}€</span></div><button class="dl2" style="opacity:1;" onclick="hvO.splice(${i},1);S('hvO',hvO);rHV2()">✕</button></div>`}).join('');let tc=0;$('hvCL2').innerHTML=hvC.map((c,i)=>{tc+=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>${E(c.o)}</span> — <span>${E(c.d)}</span> <span style="color:var(--er);font-weight:700;">-${c.a.toFixed(2)}€</span><button class="dl2" style="opacity:1;" onclick="hvC.splice(${i},1);S('hvC',hvC);rHV2()">✕</button></div>`}).join('');$('hvTR2').textContent=F(tr)+'€';$('hvTC2').textContent=F(tc)+'€';$('hvTN2').textContent=F(tr-tc)+'€';};
rHV2();
}
// GRUNDRISS
function initFP(){
$('fpContent').innerHTML=`<div class="fp-tb"><button class="fp-t ac5" onclick="fpTl='wall';document.querySelectorAll('.fp-t').forEach(b=>b.classList.remove('ac5'));this.classList.add('ac5')">🧱 Wand</button><button class="fp-t" onclick="fpTl='room';document.querySelectorAll('.fp-t').forEach(b=>b.classList.remove('ac5'));this.classList.add('ac5')">🚪 Raum</button><button class="fp-t" onclick="fpU()">↩️</button><button class="fp-t" onclick="fpClr()">🗑️</button><label style="font-size:.62rem;color:var(--t2);display:flex;align-items:center;gap:3px;">Farbe:<input type="color" id="fpCo" 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="fpCv" width="800" height="500" style="display:block;background:#fff;"></canvas></div><div style="display:flex;gap:3px;margin-top:6px;"><button class="bt" onclick="fpExpPNG()">💾 PNG</button><button class="bt bt-o" onclick="fpExpPDF()">📄 PDF</button></div><div style="font-size:.7rem;color:var(--t2);margin-top:4px;" id="fpMs">📐 Zeichne auf dem Canvas</div>`;
let fpTl='wall',fpOb=[],fpDr=false,fpSX=0,fpSY=0,fpHs=[];
const cv=$('fpCv'),cx=cv?.getContext('2d');
window.fpTl=fpTl;
if(cv){
cv.addEventListener('mousedown',e=>{const r=cv.getBoundingClientRect();fpSX=e.clientX-r.left;fpSY=e.clientY-r.top;fpDr=true;});
cv.addEventListener('mousemove',e=>{const r=cv.getBoundingClientRect();const mx=e.clientX-r.left,my=e.clientY-r.top;if(fpDr){fpRd();cx.strokeStyle='rgba(99,102,241,0.5)';cx.lineWidth=2;cx.setLineDash([5,5]);if(window.fpTl==='room'){cx.strokeRect(fpSX,fpSY,mx-fpSX,my-fpSY);}else{cx.beginPath();cx.moveTo(fpSX,fpSY);cx.lineTo(mx,my);cx.stroke();}cx.setLineDash([]);const dx=mx-fpSX,dy=my-fpSY;$('fpMs').textContent=`📏 ${(Math.sqrt(dx*dx+dy*dy)/10).toFixed(1)}m`;}});
cv.addEventListener('mouseup',e=>{if(!fpDr)return;fpDr=false;const r=cv.getBoundingClientRect();const ex=e.clientX-r.left,ey=e.clientY-r.top;const col=$('fpCo').value;if(window.fpTl==='wall'){fpOb.push({t:'w',x1:fpSX,y1:fpSY,x2:ex,y2:ey,c:col});}else if(window.fpTl==='room'){const nm=prompt('Raumname:','Zimmer')||'Zimmer';fpOb.push({t:'r',x:Math.min(fpSX,ex),y:Math.min(fpSY,ey),w:Math.abs(ex-fpSX),h:Math.abs(ey-fpSY),nm,c:'#f0f0f0'});}fpHs.push([...fpOb]);fpRd();});
}
function fpRd(){if(!cx)return;cx.clearRect(0,0,cv.width,cv.height);cx.fillStyle='#fff';cx.fillRect(0,0,cv.width,cv.height);
// Grid
cx.strokeStyle='#e8e8e8';cx.lineWidth=0.5;for(let x=0;x<cv.width;x+=20){cx.beginPath();cx.moveTo(x,0);cx.lineTo(x,cv.height);cx.stroke();}for(let y=0;y<cv.height;y+=20){cx.beginPath();cx.moveTo(0,y);cx.lineTo(cv.width,y);cx.stroke();}
fpOb.forEach(o=>{if(o.t==='r'){cx.fillStyle=o.c;cx.fillRect(o.x,o.y,o.w,o.h);cx.strokeStyle='#333';cx.lineWidth=3;cx.strokeRect(o.x,o.y,o.w,o.h);cx.fillStyle='#333';cx.font='bold 11px Inter';cx.textAlign='center';cx.fillText(o.nm,o.x+o.w/2,o.y+o.h/2-3);cx.font='9px Inter';cx.fillStyle='#666';cx.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.t==='w'){cx.strokeStyle=o.c||'#333';cx.lineWidth=4;cx.lineCap='round';cx.beginPath();cx.moveTo(o.x1,o.y1);cx.lineTo(o.x2,o.y2);cx.stroke();}});}
window.fpU=()=>{if(fpHs.length>1){fpHs.pop();fpOb=[...fpHs[fpHs.length-1]];}else{fpOb=[];fpHs=[];}fpRd();};
window.fpClr=()=>{fpOb=[];fpHs=[];fpRd();};
window.fpExpPNG=()=>{const a=document.createElement('a');a.href=cv.toDataURL();a.download='grundriss.png';a.click();};
window.fpExpPDF=()=>{const{jsPDF:JP}=window.jspdf;const d=new JP('landscape');d.text('Grundriss',15,15);d.addImage(cv.toDataURL(),'PNG',10,20,277,185);d.save('grundriss.pdf');};
fpRd();
}
// NEBENKOSTEN
function initNK(){
const costs=['Grundsteuer','Wasser','Entwässerung','Heizung','Warmwasser','Aufzug','Müllabfuhr','Versicherung','Gebäudereinigung','Garten','Schornsteinfeger','Sonstiges'];
let nkT=L('nkT',[]);
$('nkContent').innerHTML=`<div class="ig2"><label style="font-size:.66rem;color:var(--t2);font-weight:600;min-width:50px;">Objekt:</label><input class="inp" id="nkOb" placeholder="Adresse"><input type="number" class="inp" id="nkSq" placeholder="m²" style="flex:.2"></div><div class="nk-g">${costs.map(c=>`<div class="nk-i"><label>${c}</label><input type="number" class="inp nk-in" data-name="${c}" placeholder="€/Jahr" step="0.01"></div>`).join('')}</div><div class="fin-s"><div class="fin-b"><div class="fin-l">Gesamt/Jahr</div><div class="fin-v bal" id="nkTo">0€</div></div><div class="fin-b"><div class="fin-l">Gesamt/Monat</div><div class="fin-v" style="color:var(--wr);" id="nkMo">0€</div></div><div class="fin-b"><div class="fin-l">€/m²/Mo</div><div class="fin-v" style="color:var(--a3);" id="nkPs">0€</div></div></div><button class="bt" onclick="cNK()" 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="ig2"><input class="inp" id="nkTN" placeholder="Name"><input type="number" class="inp" id="nkTS" placeholder="m²" style="flex:.2"><input type="number" class="inp" id="nkTP" placeholder="Voraus €" style="flex:.25"><button class="bt bt-s" onclick="aNKT()">+</button></div><div id="nkTL"></div><div style="display:flex;gap:3px;margin-top:5px;"><button class="bt bt-o" onclick="eNKp()">📄 PDF</button><button class="bt bt-o" onclick="eNKx()">📊 Excel</button></div>`;
window.cNK=()=>{let t=0;document.querySelectorAll('.nk-in').forEach(i=>t+=parseFloat(i.value)||0);const sq=parseFloat($('nkSq').value)||1;$('nkTo').textContent=F(t)+'€';$('nkMo').textContent=F(t/12)+'€';$('nkPs').textContent=F(t/12/sq)+'€';
$('nkResult').innerHTML=nkT.length?nkT.map(tn=>{const sh=tn.sq/sq;const co=t*sh;const df=tn.paid-co;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;">👤 ${E(tn.n)}</div><div style="font-size:.66rem;color:var(--t2);">Fläche: ${tn.sq}m² · Anteil: ${(sh*100).toFixed(1)}%</div><div style="font-size:.66rem;color:var(--t2);">Kosten: ${co.toFixed(2)}€ · Vorauszahlung: ${tn.paid.toFixed(2)}€</div><div style="font-size:.82rem;font-weight:800;color:${df>=0?'var(--ok)':'var(--er)'};">${df>=0?'🟢 Guthaben':'🔴 Nachzahlung'}: ${Math.abs(df).toFixed(2)}€</div></div>`}).join(''):'<div style="color:var(--t3);font-size:.72rem;text-align:center;padding:10px;">Mieter hinzufügen</div>';};
window.aNKT=()=>{const n=$('nkTN').value.trim(),sq=parseFloat($('nkTS').value)||0,paid=parseFloat($('nkTP').value)||0;if(!n||!sq)return;nkT.push({n,sq,paid});S('nkT',nkT);$('nkTN').value='';$('nkTS').value='';$('nkTP').value='';rNKT();};
function rNKT(){$('nkTL').innerHTML=nkT.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;">👤 ${E(t.n)} · ${t.sq}m² · ${t.paid}€<button class="dl2" style="opacity:1;margin-left:auto;" onclick="nkT.splice(${i},1);S('nkT',nkT);rNKT()">✕</button></div>`).join('');}rNKT();
window.eNKp=()=>{cNK();const{jsPDF:JP}=window.jspdf;const d=new JP();d.setFontSize(16);d.text('Nebenkostenabrechnung',20,20);let y=30;d.setFontSize(8);document.querySelectorAll('.nk-in').forEach(i=>{const v=parseFloat(i.value)||0;if(v>0){d.text(`${i.dataset.name}: ${v.toFixed(2)} EUR`,20,y);y+=5;}});d.save('nebenkosten.pdf');};
window.eNKx=()=>{const wb=XLSX.utils.book_new();const da=[['Kostenart','Betrag EUR']];document.querySelectorAll('.nk-in').forEach(i=>da.push([i.dataset.name,parseFloat(i.value)||0]));XLSX.utils.book_append_sheet(wb,XLSX.utils.aoa_to_sheet(da),'NK');XLSX.writeFile(wb,'nebenkosten.xlsx');};
}
// BMI
function initBMI(){
let bH=L('bH',[]);
$('bmiContent').innerHTML=`<div class="ig2"><label style="font-size:.66rem;color:var(--t2);font-weight:600;min-width:45px;">Gewicht:</label><input type="number" class="inp" id="bW" placeholder="kg" step="0.1" oninput="cBMI()"><span style="font-size:.68rem;color:var(--t3);">kg</span></div><div class="ig2"><label style="font-size:.66rem;color:var(--t2);font-weight:600;min-width:45px;">Größe:</label><input type="number" class="inp" id="bH2" placeholder="cm" oninput="cBMI()"><span style="font-size:.68rem;color:var(--t3);">cm</span></div><div class="bmi-d"><div class="bmi-v" id="bV" style="color:var(--t3);">—</div><div class="bmi-c" id="bC" style="color:var(--t3);">BMI berechnen</div><div class="bmi-bar"><div class="bmi-mk" id="bMk" 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="bId">—</div></div><button class="bt bt-o bt-s" onclick="sBMI()" style="width:100%;margin-bottom:4px;">💾 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="bHis"></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 class="st2" style="margin-top:4px;">⚠️ Richtwert — Arzt konsultieren!</div>`;
window.cBMI=()=>{const w=parseFloat($('bW').value),h=parseFloat($('bH2').value);if(!w||!h||h<50)return;const bmi=w/((h/100)*(h/100));let cat,col;if(bmi<18.5){cat='💙 Untergewicht';col='#3b82f6';}else if(bmi<25){cat='💚 Normalgewicht';col='#22c55e';}else if(bmi<30){cat='💛 Übergewicht';col='#f59e0b';}else if(bmi<35){cat='🧡 Adipositas I';col='#f97316';}else{cat='❤️ Adipositas';col='#ef4444';}$('bV').textContent=bmi.toFixed(1);$('bV').style.color=col;$('bC').textContent=cat;$('bC').style.color=col;$('bMk').style.left=Math.min(100,Math.max(0,((bmi-10)/40)*100))+'%';$('bMk').style.borderColor=col;const ideal=22*(h/100)*(h/100);$('bId').textContent=ideal.toFixed(1)+' kg';};
window.sBMI=()=>{const w=parseFloat($('bW').value),h=parseFloat($('bH2').value);if(!w||!h)return;bH.unshift({date:new Date().toLocaleDateString('de-DE'),w,h,bmi:(w/((h/100)*(h/100))).toFixed(1)});S('bH',bH);rBH();};
function rBH(){$('bHis').innerHTML=bH.map((h,i)=>`<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.w}kg</span><span style="font-weight:700;color:${parseFloat(h.bmi)<25?'var(--ok)':'var(--er)'};">BMI ${h.bmi}</span></div>`).join('');}rBH();
}
// GEBETSZEITEN
function initPray(){
$('prayContent').innerHTML=`<div class="pr-w"><div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;"><div><div style="font-size:.9rem;font-weight:800;" id="prCi">🕌 Stadt laden...</div><div style="font-size:.62rem;color:var(--t3);" id="prCo">—</div></div><div style="text-align:right;"><div style="font-size:.66rem;color:var(--a3);font-weight:600;" id="prHi">—</div></div></div><div class="pr-g"><div class="pr-tc"><div class="pi">🌅</div><div class="pn">Fajr</div><div class="pt" id="ptF">--:--</div></div><div class="pr-tc"><div class="pi">🌤️</div><div class="pn">Sunrise</div><div class="pt" id="ptSr">--:--</div></div><div class="pr-tc"><div class="pi">☀️</div><div class="pn">Dhuhr</div><div class="pt" id="ptD">--:--</div></div><div class="pr-tc"><div class="pi">🌥️</div><div class="pn">Asr</div><div class="pt" id="ptA">--:--</div></div><div class="pr-tc"><div class="pi">🌅</div><div class="pn">Maghrib</div><div class="pt" id="ptM">--:--</div></div><div class="pr-tc"><div class="pi">🌙</div><div class="pn">Isha</div><div class="pt" id="ptI">--:--</div></div></div><div class="pr-nx"><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="nxPN">—</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="nxPC">--:--:--</div></div></div><div style="display:flex;gap:4px;margin-top:6px;flex-wrap:wrap;"><input class="inp" id="prCiI" placeholder="Stadt" value="Berlin" style="flex:1;"><input class="inp" id="prCoI" placeholder="Land" value="Germany" style="flex:.4;"><select class="inp" id="prMe" style="flex:.5;"><option value="13">🇹🇷 Diyanet</option><option value="3">ISNA</option><option value="4">Umm al-Qura</option></select><button class="bt" onclick="ldPr()">🔄</button><button class="bt bt-o" onclick="gpsP()">📍</button></div>`;
let prD=null,prI=null;
window.ldPr=async()=>{const ci=$('prCiI').value.trim(),co=$('prCoI').value.trim(),me=$('prMe').value;if(!ci||!co)return;try{const r=await fetch(`https://api.aladhan.com/v1/timingsByCity?city=${encodeURIComponent(ci)}&country=${encodeURIComponent(co)}&method=${me}&school=1`);const d=await r.json();if(d.code!==200)return;prD=d.data;const t=prD.timings;$('ptF').textContent=t.Fajr;$('ptSr').textContent=t.Sunrise;$('ptD').textContent=t.Dhuhr;$('ptA').textContent=t.Asr;$('ptM').textContent=t.Maghrib;$('ptI').textContent=t.Isha;$('prCi').textContent='🕌 '+ci;$('prCo').textContent='📍 '+co;const h=prD.date.hijri;$('prHi').textContent=`${h.day} ${h.month.en} ${h.year}`;uPH();if(prI)clearInterval(prI);prI=setInterval(uPH,1000);localStorage.setItem('prS',JSON.stringify({ci,co,me}));
// Monthly
const rm=await fetch(`https://api.aladhan.com/v1/calendarByCity/${new Date().getFullYear()}/${new Date().getMonth()+1}?city=${encodeURIComponent(ci)}&country=${encodeURIComponent(co)}&method=${me}&school=1`);const dm=await rm.json();if(dm.code===200){const td=new Date().getDate();$('prayMonth').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>${dm.data.map((d2,i)=>{const t2=d2.timings;const bg=i+1===td?'background:var(--gl);font-weight:700;':'';return`<tr style="${bg}${i%2?'background:var(--b3);':''}"><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 uPH(){if(!prD)return;const t=prD.timings,n=new Date();const ps=[{n:'Fajr',t:t.Fajr},{n:'Sunrise',t:t.Sunrise},{n:'Dhuhr',t:t.Dhuhr},{n:'Asr',t:t.Asr},{n:'Maghrib',t:t.Maghrib},{n:'Isha',t:t.Isha}];const cards=document.querySelectorAll('.pr-tc');let nx=null,nt=null;ps.forEach((p,i)=>{const[h,m]=p.t.split(':').map(Number);const pd=new Date(n);pd.setHours(h,m,0,0);cards[i].classList.remove('ac6','ps');if(pd<n)cards[i].classList.add('ps');else if(!nx){nx=p;nt=pd;cards[i].classList.add('ac6');}});if(!nx){nx=ps[0];const[h,m]=ps[0].t.split(':').map(Number);nt=new Date(n);nt.setDate(nt.getDate()+1);nt.setHours(h,m,0,0);}const df=nt-n;$('nxPN').textContent=nx.n;$('nxPC').textContent=`${String(Math.floor(df/3600000)).padStart(2,'0')}:${String(Math.floor((df%3600000)/60000)).padStart(2,'0')}:${String(Math.floor((df%60000)/1000)).padStart(2,'0')}`;}
window.gpsP=()=>{navigator.geolocation?.getCurrentPosition(async p=>{try{const r=await fetch(`https://api.aladhan.com/v1/timings?latitude=${p.coords.latitude}&longitude=${p.coords.longitude}&method=${$('prMe').value}&school=1`);const d=await r.json();if(d.code===200){prD=d.data;const t=d.data.timings;$('ptF').textContent=t.Fajr;$('ptSr').textContent=t.Sunrise;$('ptD').textContent=t.Dhuhr;$('ptA').textContent=t.Asr;$('ptM').textContent=t.Maghrib;$('ptI').textContent=t.Isha;$('prCi').textContent='🕌 📍 GPS';uPH();if(prI)clearInterval(prI);prI=setInterval(uPH,1000);}}catch{}});};
const sp=localStorage.getItem('prS');if(sp){try{const s=JSON.parse(sp);$('prCiI').value=s.ci||'Berlin';$('prCoI').value=s.co||'Germany';$('prMe').value=s.me||'13';setTimeout(ldPr,300);}catch{}}
}
// MIETVERTRAG + QR
function initMV(){
$('mvContent').innerHTML=`<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;"><div><div class="mv-s"><h4>🏠 Vermieter</h4><div class="ig2"><input class="inp" id="mvVN" placeholder="Name"><input class="inp" id="mvVA" placeholder="Adresse"></div></div><div class="mv-s"><h4>👤 Mieter</h4><div class="ig2"><input class="inp" id="mvMN" placeholder="Name"><input class="inp" id="mvMA" placeholder="Adresse"></div></div><div class="mv-s"><h4>🏢 Objekt</h4><div class="ig2"><input class="inp" id="mvOA" placeholder="Objektadresse"><input type="number" class="inp" id="mvOS" placeholder="m²" style="flex:.2"></div></div><div class="mv-s"><h4>💰 Konditionen</h4><div class="ig2"><label style="font-size:.64rem;color:var(--t2);min-width:50px;">Kalt:</label><input type="number" class="inp" id="mvCR" placeholder="€" oninput="uMvT()"><label style="font-size:.64rem;color:var(--t2);min-width:30px;">NK:</label><input type="number" class="inp" id="mvNK" placeholder="€" oninput="uMvT()"></div><div style="font-size:.78rem;font-weight:700;color:var(--a3);" id="mvTo">Warm: 0,00 €</div><div class="ig2"><label style="font-size:.64rem;color:var(--t2);min-width:50px;">Kaution:</label><input type="number" class="inp" id="mvKa" placeholder="€"><label style="font-size:.64rem;color:var(--t2);min-width:50px;">Beginn:</label><input type="date" class="inp" id="mvSt"></div></div><div class="exp-r"><button class="exp-b" onclick="eMvPDF()">📄 PDF</button><button class="exp-b" onclick="eMvWord()">📝 Word</button></div></div><div><div style="font-size:.66rem;font-weight:700;color:var(--a3);margin-bottom:4px;">👁️ Vorschau</div><div class="mv-prev" id="mvPr"></div><div style="margin-top:8px;"><div style="font-size:.66rem;font-weight:700;color:var(--a3);margin-bottom:4px;">📱 QR-Code</div><div class="ig2"><input class="inp" id="qrI" placeholder="URL oder Text..."><button class="bt" onclick="gQR()">📱 QR</button></div><div class="ig2"><button class="bt bt-s bt-o" onclick="qrExp()">🏠 Aus Exposé</button><button class="bt bt-s bt-o" onclick="qrVC()">👤 vCard</button></div><div class="qr-c" id="qrC2" style="display:none;"><div class="qr-bx" id="qrCd"></div><div style="display:flex;gap:3px;margin-top:4px;"><button class="bt bt-s" onclick="dQR()">💾 PNG</button><button class="bt bt-s bt-o" onclick="qrPDF()">📄 PDF</button></div></div></div></div></div>`;
window.uMvT=()=>{const c=parseFloat($('mvCR').value)||0,n=parseFloat($('mvNK').value)||0;$('mvTo').textContent=`Warm: ${(c+n).toFixed(2)} €`;uMvPr();};
function uMvPr(){$('mvPr').innerHTML=`<h2>MIETVERTRAG</h2><p>zwischen <b>${$('mvVN').value||'___'}</b> (Vermieter)<br>und <b>${$('mvMN').value||'___'}</b> (Mieter)</p><p><b>§1 Mietobjekt:</b> ${$('mvOA').value||'___'}, ${$('mvOS').value||'___'} m²</p><p><b>§2 Miete:</b> Kalt: ${$('mvCR').value||'___'}€ + NK: ${$('mvNK').value||'___'}€ = <b>${((parseFloat($('mvCR').value)||0)+(parseFloat($('mvNK').value)||0)).toFixed(2)}€</b></p><p><b>§3 Kaution:</b> ${$('mvKa').value||'___'}€</p><p><b>§4 Beginn:</b> ${$('mvSt').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-mv'))uMvPr();});uMvPr();
window.eMvPDF=()=>{const{jsPDF:JP}=window.jspdf;const d=new JP();d.setFontSize(18);d.text('MIETVERTRAG',80,20);d.setFontSize(9);const t=$('mvPr').innerText;d.text(d.splitTextToSize(t,170),20,35);d.save('mietvertrag.pdf');};
window.eMvWord=async()=>{const{Document:Doc,Packer:Pk,Paragraph:P,TextRun:TR,HeadingLevel:HL}=docx;const t=$('mvPr').innerText.split('\n').filter(l=>l.trim());const ch=[new P({heading:HL.HEADING_1,children:[new TR({text:'MIETVERTRAG',bold:true,size:32})]})];t.forEach(l=>ch.push(new P({children:[new TR({text:l,size:20})]})));saveAs(await Pk.toBlob(new Doc({sections:[{children:ch}]})),'mietvertrag.docx');};
// QR Code
let qrInst=null;
window.gQR=()=>{const t=$('qrI').value.trim();if(!t)return;$('qrCd').innerHTML='';qrInst=new QRCode($('qrCd'),{text:t,width:180,height:180,colorDark:'#000',correctLevel:QRCode.CorrectLevel.H});$('qrC2').style.display='flex';};
window.qrExp=()=>{const ti=$('imTi')?.value||'';const ad=$('imAd')?.value||'';const ci=$('imCi')?.value||'';const pr=$('imPr')?.value||'';$('qrI').value=`🏠 ${ti}\n📍 ${ad}, ${ci}\n💰 ${pr}€`;gQR();};
window.qrVC=()=>{const n=prompt('Name:')||'';const t=prompt('Tel:')||'';$('qrI').value=`BEGIN:VCARD\nVERSION:3.0\nFN:${n}\nTEL:${t}\nEND:VCARD`;gQR();};
window.dQR=()=>{const c=document.querySelector('#qrCd canvas');if(!c)return;const a=document.createElement('a');a.href=c.toDataURL();a.download='qr.png';a.click();};
window.qrPDF=()=>{const c=document.querySelector('#qrCd canvas');if(!c)return;const{jsPDF:JP}=window.jspdf;const d=new JP();d.text('QR-Code',85,20);d.addImage(c.toDataURL(),'PNG',55,30,100,100);d.save('qr.pdf');};
}
// AI
function initAI(){
let ch2=L('ch2',[]);
$('aiContent').innerHTML=`<div class="ig2"><input type="password" class="inp" id="aiK2" placeholder="🔑 OpenAI Key..." style="flex:1;"><select class="inp" id="aiMd2" style="flex:.3;"><option value="gpt-4o-mini">4o-mini</option><option value="gpt-4o">4o</option></select><button class="bt bt-s" onclick="localStorage.setItem('aiK2',$('aiK2').value)">💾</button></div><div style="display:flex;gap:3px;margin-bottom:5px;flex-wrap:wrap;"><button class="bt bt-s bt-o" onclick="$('aiI2').value='Zusammenfassen: ';$('aiI2').focus()">📝</button><button class="bt bt-s bt-o" onclick="$('aiI2').value='Übersetze: ';$('aiI2').focus()">🌍</button><button class="bt bt-s bt-o" onclick="$('aiI2').value='E-Mail: ';$('aiI2').focus()">📧</button><button class="bt bt-s bt-o" onclick="ch2=[];S('ch2',[]);$('aiC2').innerHTML=''">🗑️</button></div><div style="max-height:260px;overflow-y:auto;margin-bottom:4px;" id="aiC2"></div><div class="ig2"><textarea class="inp" id="aiI2" placeholder="Nachricht..." style="min-height:35px;flex:1;" onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();sAI2();}"></textarea><button class="bt" onclick="sAI2()">🚀</button></div>`;
const aK=localStorage.getItem('aiK2');if(aK)$('aiK2').value=aK;
function aM(r,c){const el=$('aiC2'),d=document.createElement('div');d.style.cssText='display:flex;gap:4px;margin-bottom:4px;'+(r==='u'?'flex-direction:row-reverse;':'');let h=E(c).replace(/\*\*(.*?)\*\*/g,'<strong>$1</strong>').replace(/\n/g,'<br>');d.innerHTML=`<span style="font-size:.9rem;">${r==='b'?'🤖':'👤'}</span><div style="max-width:80%;padding:6px 10px;border-radius:10px;font-size:.74rem;line-height:1.4;${r==='b'?'background:var(--b2);border:1px solid var(--bd);':'background:var(--ag);color:white;'}">${h}</div>`;el.appendChild(d);el.scrollTop=el.scrollHeight;}
window.sAI2=async()=>{const inp=$('aiI2'),t=inp.value.trim();if(!t)return;const ak=$('aiK2').value.trim()||localStorage.getItem('aiK2');if(!ak){alert('API Key!');return;}aM('u',t);ch2.push({role:'user',content:t});inp.value='';try{const r=await fetch('https://api.openai.com/v1/chat/completions',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+ak},body:JSON.stringify({model:$('aiMd2').value,messages:[{role:'system',content:'Hilfreicher Assistent. Deutsch.'},...ch2.slice(-20)],temperature:.7,max_tokens:2000})});const d=await r.json();if(d.error){aM('b','❌ '+d.error.message);return;}const reply=d.choices[0].message.content;ch2.push({role:'assistant',content:reply});S('ch2',ch2);aM('b',reply);}catch{aM('b','❌ Fehler');}};
if(ch2.length>0){ch2.forEach(m=>aM(m.role==='user'?'u':'b',m.content));}
}
// QUOTES
const quotes=[{t:"Der beste Weg, die Zukunft vorauszusagen, ist, sie zu gestalten.",a:"Peter Drucker"},{t:"Hayatta en hakiki mürşit ilimdir.",a:"Atatürk"},{t:"Wer immer tut, was er schon kann, bleibt immer das, was er schon ist.",a:"Henry Ford"},{t:"Başarı cesaret ve azimden doğar.",a:"Atasözü"},{t:"Disziplin ist die Brücke zwischen Zielen und Erfolg.",a:"Jim Rohn"},{t:"Sabır acıdır, meyvesi tatlıdır.",a:"Atasözü"}];
function nQ(){const q=quotes[Math.floor(Math.random()*quotes.length)];$('qT').textContent=`"${q.t}"`;$('qA').textContent=`— ${q.a}`;}nQ();
// BACKUP
function exAll(){const d={tds,cEv,notes:nA.value,exps,autos:L('autos',[]),fP:L('fP',{}),ts2:L('ts2',{}),hvO:L('hvO',[]),hvC:L('hvC',[]),waCs:L('waCs',[]),nkT:L('nkT',[]),bH:L('bH',[]),ch2:L('ch2',[])};const a=document.createElement('a');a.href=URL.createObjectURL(new Blob([JSON.stringify(d)]));a.download=`backup-${new Date().toISOString().split('T')[0]}.json`;a.click();}
function imAll(){const i=document.createElement('input');i.type='file';i.accept='.json';i.onchange=e=>{const r=new FileReader();r.onload=ev=>{try{const d=JSON.parse(ev.target.result);if(d.tds){tds=d.tds;rTd();}if(d.cEv){cEv=d.cEv;S('cEv',cEv);rCl();}if(d.notes){nA.value=d.notes;localStorage.setItem('notes',d.notes);}alert('✅');}catch{alert('❌');}};r.readAsText(e.target.files[0]);};i.click();}
// PWA
if('serviceWorker' in navigator){window.addEventListener('load',()=>{navigator.serviceWorker.register('sw.js').then(r=>console.log('✅ SW:',r.scope)).catch(e=>console.log('SW err:',e));});}
window.addEventListener('online',()=>{$('netT').textContent='🟢';});
window.addEventListener('offline',()=>{$('netT').textContent='🔴';});
let dP;window.addEventListener('beforeinstallprompt',e=>{e.preventDefault();dP=e;$('installBtn').style.display='inline-flex';});
function iPWA(){if(!dP)return;dP.prompt();dP.userChoice.then(()=>{dP=null;$('installBtn').style.display='none';});}
</script>
</body>
</html>
| Tab | Features |
|---|---|
| 🏠 Home | Kalender, To-Do, Notizen, Ausgaben, Quick Links |
| 🏠 Immobilien | Exposé Builder, Bild/Video/360° Upload, Pannellum Viewer, Leaflet Map, PDF/Word/Excel Export |
| 🚗 Auto | Kauf/Verkauf, Statistik, PDF Export |
| 💰 Finanzen | Privat + Business, Monatsübersicht, PDF/Excel |
| 📜 Verwaltung | Testament + Hausverwaltung |
| 🎵 Medien | 12 türkische Radiosender, Player mit Vinyl |
| 💬 Kommunikation | WhatsApp + Übersetzer |
| 🛠️ Tools | Rechner, Passwort, Währung |
| 🏗️ Grundriss | Canvas-Zeichner mit Wänden & Räumen |
| 🧾 Nebenkosten | 12 Kostenarten, Mieter-Aufteilung, PDF/Excel |
| 🏋️ BMI | Rechner mit Verlauf, Skala, Idealgewicht |
| 🕌 Gebet | AlAdhan API, 6 Zeiten, Countdown, Monatskalender |
| 📜 Mietvertrag | Generator + QR-Code (Exposé, vCard) |
| 🤖 KI | OpenAI GPT Chat |
| 📲 PWA | Installierbar, Offline-fähig |
index.htmlmanifest.json und sw.js (aus dem vorherigen Post)Möchtest du noch etwas ergänzen oder ändern? 🛠️