import React, { useState, useRef, useEffect } from "react";
import { SIA_PHASES, DASHBOARD_WIDGETS } from "../constants.js";
import { formatCHF, formatDate, formatHours, migrateDashboardLayout, widgetsToRows, generateId } from "../utils.js";

const HEIGHT_OPTS = [
  { v: 0,   l: "Auto" },
  { v: 160, l: "S" },
  { v: 280, l: "M" },
  { v: 420, l: "L" },
];

function deepCloneLayout(layout) {
  return (layout || []).map(r => ({ ...r, widgets: [...r.widgets] }));
}

export default function Dashboard({ data, setView, currentUser, saveAll }) {
  const today = new Date().toISOString().slice(0, 10);
  const thisMonth = today.slice(0, 7);
  const thisYear = today.slice(0, 4);
  const lastMonth = (() => { const d = new Date(); d.setMonth(d.getMonth() - 1); return d.toISOString().slice(0, 7); })();

  // ─── Layout resolution ─────────────────────────────────────────────
  const myUser  = (data.users        || []).find(u => u.id === currentUser?.id);
  const myRole  = (data.appRoles     || []).find(r => r.id === (currentUser?.appRoleId || myUser?.appRoleId));
  const myTpl   = (data.dashboardTemplates || []).find(t => t.id === myRole?.dashboardTemplateId);
  const roleLayout  = myTpl
    ? migrateDashboardLayout(myTpl.layout)
    : migrateDashboardLayout(myRole?.dashboardWidgets) // fallback for old data
    || widgetsToRows(DASHBOARD_WIDGETS.map(w => w.id));
  const savedLayout = myUser?.dashboardWidgets ? migrateDashboardLayout(myUser.dashboardWidgets) : null;

  const [editMode, setEditMode]         = useState(false);
  const [layout,   setLayout]           = useState([]);
  const [dragOver, setDragOver]         = useState(null);
  const [addPopoverRowId, setAddPopoverRowId] = useState(null);
  const [saveTemplateOpen, setSaveTemplateOpen] = useState(false);
  const [newPublicName, setNewPublicName] = useState("");
  const [newPrivateName, setNewPrivateName] = useState("");
  const dragRef = useRef(null);

  const activeLayout = editMode ? layout : (savedLayout || roleLayout);

  // ─── Data ──────────────────────────────────────────────────────────
  const activeProjects   = data.projects.filter(p => p.status === "aktiv");
  const projMins  = id   => data.timeEntries.filter(e => e.projectId === id).reduce((s, e) => s + (e.minutes || 0), 0);
  const monthMins        = data.timeEntries.filter(e => (e.date||"").startsWith(thisMonth)).reduce((s,e)=>s+(e.minutes||0),0);
  const lastMoMins       = data.timeEntries.filter(e => (e.date||"").startsWith(lastMonth)).reduce((s,e)=>s+(e.minutes||0),0);
  const myEmpId          = currentUser?.employeeId;
  const myMonthMins      = data.timeEntries.filter(e => (e.date||"").startsWith(thisMonth) && e.employeeId===myEmpId).reduce((s,e)=>s+(e.minutes||0),0);
  const recentTime       = [...data.timeEntries].sort((a,b)=>(b.date||"").localeCompare(a.date||"")).slice(0,6);
  const myRecentTime     = [...data.timeEntries].filter(e=>e.employeeId===myEmpId).sort((a,b)=>(b.date||"").localeCompare(a.date||"")).slice(0,6);
  const openInvoices     = data.invoices.filter(i => i.status==="gesendet"||i.status==="überfällig");
  const overdueInvoices  = data.invoices.filter(i => i.status==="überfällig");
  const openAmount       = openInvoices.reduce((s,i)=>s+(i.total||0),0);
  const paidThisYear     = data.invoices.filter(i=>i.status==="bezahlt"&&(i.date||"").startsWith(thisYear)).reduce((s,i)=>s+(i.sub||0),0);
  const pendingQuotes    = (data.quotes||[]).filter(q=>q.status==="gesendet");
  const expiredQuotes    = (data.quotes||[]).filter(q=>q.status==="gesendet"&&q.validUntil&&q.validUntil<today);
  const unbilledProjects = activeProjects.map(p=>{
    const mins = data.timeEntries.filter(e=>e.projectId===p.id&&!e.invoiceId).reduce((s,e)=>s+(e.minutes||0),0);
    return {...p, unbilledMins:mins, unbilledAmt:(mins/60)*(p.hourlyRate||0)};
  }).filter(p=>p.unbilledMins>0&&(p.billingType||p.type)==="stundensatz").sort((a,b)=>b.unbilledMins-a.unbilledMins);
  const totalUnbilled    = unbilledProjects.reduce((s,p)=>s+p.unbilledMins,0);
  const last6Months      = Array.from({length:6},(_,i)=>{const d=new Date();d.setMonth(d.getMonth()-(5-i));return d.toISOString().slice(0,7);});
  const monthlyRevenue   = last6Months.map(m=>({m,paid:data.invoices.filter(i=>i.status==="bezahlt"&&(i.date||"").startsWith(m)).reduce((s,i)=>s+(i.sub||0),0)}));
  const maxRev           = Math.max(...monthlyRevenue.map(m=>m.paid),1);

  // ─── Permission ────────────────────────────────────────────────────
  const canSaveTemplate = !myRole || myRole.permissions === null || (myRole.permissions||[]).includes("dashboard-vorlage");

  // ─── Edit mode ─────────────────────────────────────────────────────
  const enterEdit = () => { setLayout(deepCloneLayout(savedLayout || roleLayout)); setEditMode(true); };
  const cancelEdit = () => { setEditMode(false); setAddPopoverRowId(null); setSaveTemplateOpen(false); setNewPublicName(""); setNewPrivateName(""); };
  const saveEdit = () => {
    if (currentUser && saveAll) {
      const users = (data.users||[]).map(u => u.id===currentUser.id ? {...u, dashboardWidgets: layout} : u);
      saveAll({ ...data, users });
    }
    setEditMode(false); setAddPopoverRowId(null); setSaveTemplateOpen(false); setNewPublicName(""); setNewPrivateName("");
  };
  const loadTemplate = tplId => {
    const tpl = (data.dashboardTemplates||[]).find(t=>t.id===tplId);
    if (tpl?.layout) setLayout(deepCloneLayout(migrateDashboardLayout(tpl.layout)));
  };
  const saveAsTemplate = (tplId) => {
    if (!saveAll) return;
    const dashboardTemplates = (data.dashboardTemplates||[]).map(t => t.id===tplId ? {...t, layout} : t);
    saveAll({ ...data, dashboardTemplates });
    setSaveTemplateOpen(false);
  };
  const createTemplate = (name, isPublic) => {
    if (!name.trim() || !saveAll) return;
    const tpl = { id: generateId(), name: name.trim(), isPublic, layout, ...(!isPublic ? { createdBy: currentUser?.id } : {}) };
    saveAll({ ...data, dashboardTemplates: [...(data.dashboardTemplates||[]), tpl] });
    setSaveTemplateOpen(false);
    if (isPublic) setNewPublicName(""); else setNewPrivateName("");
  };
  // Add widget to row, moving it out of any other row it's already in
  const addWidgetExclusive = (rowId, wid) => {
    setLayout(l => l.map(r => {
      if (r.id === rowId) return { ...r, widgets: r.widgets.includes(wid) ? r.widgets : [...r.widgets, wid] };
      return { ...r, widgets: r.widgets.filter(w => w !== wid) };
    }));
    setAddPopoverRowId(null);
  };
  // Close popovers on outside click
  useEffect(() => {
    if (!addPopoverRowId && !saveTemplateOpen) return;
    const close = e => { if (!e.target.closest("[data-popover]")) { setAddPopoverRowId(null); setSaveTemplateOpen(false); } };
    document.addEventListener("mousedown", close);
    return () => document.removeEventListener("mousedown", close);
  }, [addPopoverRowId, saveTemplateOpen]);

  // ─── Row operations ────────────────────────────────────────────────
  const updateRow = (rowId, patch) => setLayout(l => l.map(r => r.id===rowId ? {...r,...patch} : r));
  const addRow = (afterId) => {
    const row = { id: generateId(), cols: 2, minH: 0, widgets: [] };
    setLayout(l => {
      const i = l.findIndex(r=>r.id===afterId);
      const next = [...l];
      next.splice(i+1, 0, row);
      return next;
    });
  };
  const deleteRow = rowId => setLayout(l => l.filter(r=>r.id!==rowId));
  const moveRow = (rowId, dir) => setLayout(l => {
    const i = l.findIndex(r=>r.id===rowId);
    const j = i + dir;
    if (j<0||j>=l.length) return l;
    const next=[...l];
    [next[i],next[j]]=[next[j],next[i]];
    return next;
  });
  const addWidgetToRow = (rowId, wid) =>
    setLayout(l => l.map(r => r.id===rowId ? {...r, widgets:[...r.widgets,wid]} : r));
  const removeWidgetFromRow = (rowId, wid) =>
    setLayout(l => l.map(r => r.id===rowId ? {...r, widgets:r.widgets.filter(w=>w!==wid)} : r));

  // ─── Drag & Drop ───────────────────────────────────────────────────
  const handleDragStart = (fromRowId, widgetId) => {
    dragRef.current = { fromRowId, widgetId };
  };
  const handleDragEnd = () => {
    dragRef.current = null;
    setDragOver(null);
  };
  const handleDrop = (toRowId, beforeWidgetId) => {
    const src = dragRef.current;
    if (!src) return;
    const { fromRowId, widgetId } = src;
    setLayout(l => {
      const next = deepCloneLayout(l);
      const fromRow = next.find(r=>r.id===fromRowId);
      const toRow   = next.find(r=>r.id===toRowId);
      if (!fromRow||!toRow) return l;
      fromRow.widgets = fromRow.widgets.filter(w=>w!==widgetId);
      if (beforeWidgetId) {
        const idx = toRow.widgets.indexOf(beforeWidgetId);
        toRow.widgets.splice(idx<0 ? toRow.widgets.length : idx, 0, widgetId);
      } else {
        if (!toRow.widgets.includes(widgetId)) toRow.widgets.push(widgetId);
      }
      return next;
    });
    dragRef.current = null;
    setDragOver(null);
  };

  // ─── Styles ────────────────────────────────────────────────────────
  const ctrlBtn = "pill";
  const activeCtrlBtn = "pill active";

  // ─── Widget content renderers ──────────────────────────────────────
  const wContent = {
    "kpi-projekte": () => <KpiCard label="AKTIVE PROJEKTE" value={activeProjects.length} color="#b07848" go="projects" setView={!editMode?setView:undefined} sub={`${data.projects.filter(p=>p.status==="abgeschlossen").length} abgeschlossen`} />,
    "kpi-stunden": () => <KpiCard label={`STUNDEN ${new Date().toLocaleString("de-CH",{month:"long"}).toUpperCase()}`} value={formatHours(myEmpId?myMonthMins:monthMins)} color="#2d6a4f" go="time" setView={!editMode?setView:undefined} sub={!myEmpId&&lastMoMins>0?`Vormonat: ${formatHours(lastMoMins)}`:undefined} />,
    "kpi-ausstehend": () => <KpiCard label="AUSSTEHEND" value={formatCHF(openAmount)} color={overdueInvoices.length>0?"#8a1a1a":"#7a6a00"} go="invoices" setView={!editMode?setView:undefined} sub={overdueInvoices.length>0?`${overdueInvoices.length} überfällig`:`${openInvoices.length} gesendet`} />,
    "kpi-umsatz": () => <KpiCard label="UMSATZ DIESES JAHR" value={formatCHF(paidThisYear)} color="#2d6a4f" go="invoices" setView={!editMode?setView:undefined} sub="bezahlt (netto)" />,
    "warnungen": () => {
      const has = overdueInvoices.length>0||expiredQuotes.length>0;
      if (!editMode&&!has) return null;
      return has ? (
        <div style={{display:"flex",gap:12,flexWrap:"wrap",height:"100%",alignItems:"stretch"}}>
          {overdueInvoices.length>0&&<div onClick={!editMode?()=>setView("invoices"):undefined} style={{flex:1,minWidth:180,padding:"12px 16px",background:"#fff3f3",border:"1.5px solid #e0b0b0",borderRadius:8,cursor:editMode?"default":"pointer",display:"flex",alignItems:"center",gap:12}}>
            <div style={{fontSize:18}}>⚠</div>
            <div><div style={{fontSize:12,fontWeight:600,color:"#8a1a1a"}}>{overdueInvoices.length} überfällige Rechnung{overdueInvoices.length>1?"en":""}</div><div style={{fontSize:11,color:"#b5621e",marginTop:2}}>{formatCHF(overdueInvoices.reduce((s,i)=>s+i.total,0))} ausstehend</div></div>
          </div>}
          {expiredQuotes.length>0&&<div onClick={!editMode?()=>setView("quotes"):undefined} style={{flex:1,minWidth:180,padding:"12px 16px",background:"#fffbe8",border:"1.5px solid #e0d090",borderRadius:8,cursor:editMode?"default":"pointer",display:"flex",alignItems:"center",gap:12}}>
            <div style={{fontSize:18}}>⏱</div>
            <div><div style={{fontSize:12,fontWeight:600,color:"#7a6a00"}}>{expiredQuotes.length} Offerte{expiredQuotes.length>1?"n":""} abgelaufen</div><div style={{fontSize:11,color:"#888",marginTop:2}}>Gültigkeit überschritten</div></div>
          </div>}
        </div>
      ) : <div className="card" style={{fontSize:12,color:"var(--text5)",fontStyle:"italic"}}>Warnungen (keine aktuellen)</div>;
    },
    "aktive-projekte": () => (
      <div className="card" style={{height:"100%",boxSizing:"border-box"}}>
        <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:16}}>
          <div style={{fontSize:11,fontWeight:600,letterSpacing:"0.1em",color:"var(--text4)"}}>AKTIVE PROJEKTE</div>
          <button onClick={()=>setView("projects")} style={{background:"none",border:"none",fontSize:11,color:"var(--text4)",cursor:"pointer",fontFamily:"inherit"}}>Alle →</button>
        </div>
        {activeProjects.length===0?<div style={{fontSize:13,color:"var(--text5)",textAlign:"center",padding:"20px 0"}}>Keine aktiven Projekte</div>:activeProjects.slice(0,6).map(p=>{
          const used=projMins(p.id),budget=p.budgetHours||0,pct=budget>0?Math.min((used/60)/budget,1):0,over=budget>0&&(used/60)>budget;
          const cl=(data.persons||[]).filter(x=>x.isAuftraggeber).find(c=>c.id===p.clientId);
          return (<div key={p.id} style={{marginBottom:14,paddingBottom:14,borderBottom:"1px solid var(--border2)"}}>
            <div style={{display:"flex",justifyContent:"space-between",marginBottom:4}}>
              <div><div style={{fontSize:12,fontWeight:500,color:"var(--text)"}}>{p.name}</div>{cl&&<div style={{fontSize:10,color:"var(--text4)",marginTop:1}}>{cl.name}</div>}</div>
              <div style={{textAlign:"right",fontSize:11,color:over?"#8a1a1a":"var(--text4)",whiteSpace:"nowrap"}}>{formatHours(used)}{budget>0?` / ${budget}h`:""}</div>
            </div>
            {budget>0&&<div style={{height:3,background:"var(--border2)",borderRadius:2}}><div style={{width:`${pct*100}%`,height:"100%",background:over?"#8a1a1a":pct>0.8?"#b5621e":"#2d6a4f",borderRadius:2,transition:"width 0.3s"}}/></div>}
          </div>);
        })}
      </div>
    ),
    "unverrechnete-stunden": () => (
      <div className="card" style={{height:"100%",boxSizing:"border-box"}}>
        <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:16}}>
          <div style={{fontSize:11,fontWeight:600,letterSpacing:"0.1em",color:"var(--text4)"}}>UNVERRECHNETE STUNDEN</div>
          <button onClick={()=>setView("invoices")} style={{background:"none",border:"none",fontSize:11,color:"var(--text4)",cursor:"pointer",fontFamily:"inherit"}}>→</button>
        </div>
        {totalUnbilled===0?<div style={{fontSize:13,color:"#2d6a4f",textAlign:"center",padding:"20px 0"}}>✓ Alles verrechnet</div>:<>
          <div style={{fontSize:22,fontFamily:"'Playfair Display',serif",fontWeight:700,color:"#b5621e",marginBottom:2}}>{formatHours(totalUnbilled)}</div>
          <div style={{fontSize:11,color:"var(--text5)",marginBottom:16}}>≈ {formatCHF(unbilledProjects.reduce((s,p)=>s+p.unbilledAmt,0))}</div>
          {unbilledProjects.slice(0,5).map(p=><div key={p.id} style={{display:"flex",justifyContent:"space-between",padding:"5px 0",borderBottom:"1px solid var(--border2)",fontSize:12}}><span style={{color:"var(--text2)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",maxWidth:"60%"}}>{p.name}</span><span style={{color:"#b5621e",flexShrink:0}}>{formatHours(p.unbilledMins)}</span></div>)}
        </>}
      </div>
    ),
    "umsatz-sparkline": () => (
      <div className="card" style={{height:"100%",boxSizing:"border-box"}}>
        <div style={{fontSize:11,fontWeight:600,letterSpacing:"0.1em",color:"var(--text4)",marginBottom:14}}>UMSATZ LETZTE 6 MONATE</div>
        <div style={{display:"flex",alignItems:"flex-end",gap:6,height:60}}>
          {monthlyRevenue.map(({m,paid})=>(
            <div key={m} style={{flex:1,display:"flex",flexDirection:"column",alignItems:"center",gap:4}}>
              <div style={{width:"100%",height:paid>0?`${Math.max((paid/maxRev)*54,4)}px`:"2px",background:m===thisMonth?"#b07848":paid>0?"#2d6a4f":"var(--border2)",borderRadius:"2px 2px 0 0",transition:"height 0.3s"}} title={formatCHF(paid)}/>
              <div style={{fontSize:8,color:m===thisMonth?"#b07848":"var(--text5)"}}>{new Date(m+"-01").toLocaleString("de-CH",{month:"short"})}</div>
            </div>
          ))}
        </div>
      </div>
    ),
    "offene-offerten": () => (
      <div className="card" style={{height:"100%",boxSizing:"border-box"}}>
        <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:14}}>
          <div style={{fontSize:11,fontWeight:600,letterSpacing:"0.1em",color:"var(--text4)"}}>OFFENE OFFERTEN</div>
          <button onClick={()=>setView("quotes")} style={{background:"none",border:"none",fontSize:11,color:"var(--text4)",cursor:"pointer",fontFamily:"inherit"}}>Alle →</button>
        </div>
        {pendingQuotes.length===0?<div style={{fontSize:12,color:"var(--text5)"}}>Keine pendenten Offerten</div>:pendingQuotes.slice(0,5).map(q=>{
          const cl=(data.persons||[]).filter(p=>p.isAuftraggeber).find(c=>c.id===q.clientId);
          const expired=q.validUntil&&q.validUntil<today;
          return (<div key={q.id} style={{display:"flex",justifyContent:"space-between",padding:"5px 0",borderBottom:"1px solid var(--border2)",fontSize:12}}>
            <div><div style={{color:expired?"#b5621e":"var(--text2)"}}>{q.number}</div>{cl&&<div style={{fontSize:10,color:"var(--text5)"}}>{cl.name}</div>}</div>
            <div style={{textAlign:"right",flexShrink:0}}><div style={{color:"var(--text2)",fontWeight:500}}>{formatCHF(q.total)}</div>{expired&&<div style={{fontSize:9,color:"#b5621e"}}>abgelaufen</div>}</div>
          </div>);
        })}
      </div>
    ),
    "letzte-zeiteintraege": () => (
      <div className="card" style={{height:"100%",boxSizing:"border-box"}}>
        <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:14}}>
          <div style={{fontSize:11,fontWeight:600,letterSpacing:"0.1em",color:"var(--text4)"}}>LETZTE ZEITEINTRÄGE</div>
          <button onClick={()=>setView("time")} style={{background:"none",border:"none",fontSize:11,color:"var(--text4)",cursor:"pointer",fontFamily:"inherit"}}>Zeiterfassung →</button>
        </div>
        <TimeTable entries={recentTime} data={data}/>
      </div>
    ),
    "meine-zeiteintraege": () => (
      <div className="card" style={{height:"100%",boxSizing:"border-box"}}>
        <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:14}}>
          <div style={{fontSize:11,fontWeight:600,letterSpacing:"0.1em",color:"var(--text4)"}}>MEINE ZEITEINTRÄGE</div>
          <button onClick={()=>setView("time")} style={{background:"none",border:"none",fontSize:11,color:"var(--text4)",cursor:"pointer",fontFamily:"inherit"}}>Zeiterfassung →</button>
        </div>
        <TimeTable entries={myRecentTime} data={data}/>
      </div>
    ),

    "meine-projekte": () => {
      const myProjects = (data.projects||[]).filter(p=>p.status==="aktiv"&&(p.internalMembers||[]).includes(myEmpId));
      return (
        <div className="card" style={{height:"100%",boxSizing:"border-box"}}>
          <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:14}}>
            <div style={{fontSize:11,fontWeight:600,letterSpacing:"0.1em",color:"var(--text4)"}}>MEINE PROJEKTE</div>
            <button onClick={()=>!editMode&&setView("projects")} style={{background:"none",border:"none",fontSize:11,color:"var(--text4)",cursor:"pointer",fontFamily:"inherit"}}>Alle →</button>
          </div>
          {myProjects.length===0
            ? <div style={{fontSize:13,color:"var(--text5)",textAlign:"center",padding:"20px 0"}}>Keinen Projekten zugewiesen</div>
            : myProjects.map(p=>{
                const myMins=data.timeEntries.filter(e=>e.projectId===p.id&&e.employeeId===myEmpId).reduce((s,e)=>s+(e.minutes||0),0);
                const cl=(data.persons||[]).find(c=>c.id===p.clientId);
                return (
                  <div key={p.id} style={{marginBottom:12,paddingBottom:12,borderBottom:"1px solid var(--border2)"}}>
                    <div style={{display:"flex",justifyContent:"space-between",alignItems:"baseline"}}>
                      <div>
                        <div style={{fontSize:12,fontWeight:500,color:"var(--text)"}}>{p.name}</div>
                        {cl&&<div style={{fontSize:10,color:"var(--text4)",marginTop:1}}>{cl.name}</div>}
                      </div>
                      <div style={{fontSize:11,color:"var(--text3)",flexShrink:0,marginLeft:8}}>{formatHours(myMins)}</div>
                    </div>
                  </div>
                );
              })
          }
        </div>
      );
    },

    "meine-ferien": () => {
      const myEmp=(data.employees||[]).find(e=>e.id===myEmpId);
      if(!myEmpId||!myEmp) return <div className="card" style={{height:"100%",boxSizing:"border-box",display:"flex",alignItems:"center",justifyContent:"center",fontSize:12,color:"var(--text5)"}}>Kein Mitarbeiterprofil verknüpft</div>;
      const anspruchTage=(myEmp.ferienWochen||5)*5;
      const approvedEntries=(data.ferienEntries||[]).filter(f=>f.employeeId===myEmpId&&(f.status==="approved"||!f.status)&&(f.dateFrom||"").startsWith(thisYear));
      const countWorkdays=(from,to)=>{
        let n=0;const d=new Date(from);const end=new Date(to);
        while(d<=end){const dow=d.getDay();if(dow!==0&&dow!==6)n++;d.setDate(d.getDate()+1);}
        return n;
      };
      const bezogenTage=approvedEntries.reduce((s,f)=>s+countWorkdays(f.dateFrom,f.dateTo),0);
      const restTage=anspruchTage-bezogenTage;
      const pct=Math.min(bezogenTage/anspruchTage,1);
      const upcoming=(data.ferienEntries||[]).filter(f=>f.employeeId===myEmpId&&(f.status==="approved"||!f.status)&&f.dateFrom>today).slice(0,2);
      return (
        <div className="card" style={{height:"100%",boxSizing:"border-box"}}>
          <div style={{fontSize:11,fontWeight:600,letterSpacing:"0.1em",color:"var(--text4)",marginBottom:14}}>FERIENSTAND {thisYear}</div>
          <div style={{display:"flex",justifyContent:"space-between",marginBottom:6}}>
            <div style={{textAlign:"center"}}>
              <div style={{fontSize:22,fontFamily:"'Playfair Display',serif",fontWeight:700,color:"#2d6a4f"}}>{restTage}</div>
              <div style={{fontSize:10,color:"var(--text4)"}}>Verbleibend</div>
            </div>
            <div style={{textAlign:"center"}}>
              <div style={{fontSize:22,fontFamily:"'Playfair Display',serif",fontWeight:700,color:"var(--text)"}}>{bezogenTage}</div>
              <div style={{fontSize:10,color:"var(--text4)"}}>Bezogen</div>
            </div>
            <div style={{textAlign:"center"}}>
              <div style={{fontSize:22,fontFamily:"'Playfair Display',serif",fontWeight:700,color:"var(--text3)"}}>{anspruchTage}</div>
              <div style={{fontSize:10,color:"var(--text4)"}}>Anspruch</div>
            </div>
          </div>
          <div style={{height:4,background:"var(--border2)",borderRadius:2,margin:"12px 0 14px"}}>
            <div style={{width:`${pct*100}%`,height:"100%",background:restTage<5?"#8a1a1a":"#2d6a4f",borderRadius:2,transition:"width 0.4s"}}/>
          </div>
          {upcoming.length>0&&<>
            <div style={{fontSize:9,letterSpacing:"0.1em",color:"var(--text4)",marginBottom:6}}>NÄCHSTE FERIEN</div>
            {upcoming.map(f=><div key={f.id} style={{fontSize:11,color:"var(--text2)",marginBottom:3}}>{formatDate(f.dateFrom)} – {formatDate(f.dateTo)}</div>)}
          </>}
        </div>
      );
    },

    "ueberstunden": () => {
      const myEmp=(data.employees||[]).find(e=>e.id===myEmpId);
      if(!myEmpId||!myEmp) return <div className="card" style={{height:"100%",boxSizing:"border-box",display:"flex",alignItems:"center",justifyContent:"center",fontSize:12,color:"var(--text5)"}}>Kein Mitarbeiterprofil verknüpft</div>;
      const pensum=(myEmp.pensum||100)/100;
      const tagessollH=((myEmp.wochenstunden||35)*pensum)/5;
      const startOfYear=`${thisYear}-01-01`;
      const fts=data.feiertage||[];
      // Respect eintrittsdatum: only count from when the employee actually started
      const effectiveYearStart=myEmp.eintrittsdatum&&myEmp.eintrittsdatum>startOfYear?myEmp.eintrittsdatum:startOfYear;
      const todayD=new Date(today);
      let workdays=0;const d=new Date(effectiveYearStart);
      while(d<=todayD){const dow=d.getDay();const ds=d.toISOString().slice(0,10);const ft=fts.find(f=>f.date===ds);const isFt=ft&&(ft.stundenDelta===0||ft.stundenDelta===null||ft.stundenDelta===undefined);if(dow!==0&&dow!==6&&!isFt)workdays++;d.setDate(d.getDate()+1);}
      const sollMin=workdays*tagessollH*60;
      const istMin=data.timeEntries.filter(e=>e.employeeId===myEmpId&&(e.date||"")>=effectiveYearStart&&(e.date||"")<=today).reduce((s,e)=>s+(e.minutes||0),0);
      const deltaMin=istMin-sollMin;
      const isPos=deltaMin>=0;
      // This month — also respect eintrittsdatum
      const effectiveMonthStart=myEmp.eintrittsdatum&&myEmp.eintrittsdatum>`${thisMonth}-01`?myEmp.eintrittsdatum:`${thisMonth}-01`;
      const sollMonthMin=(() => {
        let wd=0;const me=new Date(new Date(`${thisMonth}-01`).getFullYear(),new Date(`${thisMonth}-01`).getMonth()+1,0);
        const end=me<todayD?me:todayD;const dd=new Date(effectiveMonthStart);
        while(dd<=end){const dow=dd.getDay();const ds=dd.toISOString().slice(0,10);const ft=fts.find(f=>f.date===ds);const isFt=ft&&(ft.stundenDelta===0||ft.stundenDelta===null||ft.stundenDelta===undefined);if(dow!==0&&dow!==6&&!isFt)wd++;dd.setDate(dd.getDate()+1);}
        return wd*tagessollH*60;
      })();
      const istMonthMin=data.timeEntries.filter(e=>e.employeeId===myEmpId&&(e.date||"").startsWith(thisMonth)).reduce((s,e)=>s+(e.minutes||0),0);
      const deltaMonth=istMonthMin-sollMonthMin;
      return (
        <div className="card" style={{height:"100%",boxSizing:"border-box"}}>
          <div style={{fontSize:11,fontWeight:600,letterSpacing:"0.1em",color:"var(--text4)",marginBottom:14}}>STUNDENSALDO</div>
          <div style={{marginBottom:14}}>
            <div style={{fontSize:10,color:"var(--text4)",marginBottom:4}}>JAHRESSALDO {thisYear}</div>
            <div style={{fontSize:26,fontFamily:"'Playfair Display',serif",fontWeight:700,color:isPos?"#2d6a4f":"#8a1a1a"}}>
              {isPos?"+":""}{formatHours(Math.abs(deltaMin))}
              <span style={{fontSize:13,fontWeight:400,marginLeft:4}}>{isPos?"Überstunden":"Minusstunden"}</span>
            </div>
            <div style={{fontSize:11,color:"var(--text4)",marginTop:2}}>{formatHours(istMin)} von {formatHours(sollMin)} Soll</div>
          </div>
          <div style={{paddingTop:12,borderTop:"1px solid var(--border2)"}}>
            <div style={{fontSize:10,color:"var(--text4)",marginBottom:4}}>DIESER MONAT</div>
            <div style={{fontSize:14,fontWeight:600,color:deltaMonth>=0?"#2d6a4f":"#8a1a1a"}}>
              {deltaMonth>=0?"+":""}{formatHours(Math.abs(deltaMonth))}
            </div>
            <div style={{fontSize:11,color:"var(--text4)"}}>{formatHours(istMonthMin)} von {formatHours(sollMonthMin)} Soll</div>
          </div>
        </div>
      );
    },

    "stunden-woche": () => {
      const myEmp=(data.employees||[]).find(e=>e.id===myEmpId);
      const pensum=(myEmp?.pensum||100)/100;
      const sollH=(myEmp?.wochenstunden||35)*pensum;
      const getMonday=(dateStr)=>{const d=new Date(dateStr);const day=d.getDay();d.setDate(d.getDate()-(day===0?6:day-1));return d;};
      const monday=getMonday(today);
      const weeks=Array.from({length:5},(_,i)=>{
        const mon=new Date(monday);mon.setDate(mon.getDate()-(4-i)*7);
        const sun=new Date(mon);sun.setDate(sun.getDate()+6);
        const monStr=mon.toISOString().slice(0,10);
        const sunStr=sun.toISOString().slice(0,10);
        const isCurrent=i===4;
        const mins=(myEmpId?data.timeEntries.filter(e=>e.employeeId===myEmpId&&e.date>=monStr&&e.date<=sunStr):data.timeEntries.filter(e=>e.date>=monStr&&e.date<=sunStr)).reduce((s,e)=>s+(e.minutes||0),0);
        const kw=(() => { const d2=new Date(mon);d2.setHours(0,0,0,0);d2.setDate(d2.getDate()+3-(d2.getDay()||7)+1); const w1=new Date(d2.getFullYear(),0,4);return 1+Math.round(((d2-w1)/86400000+((w1.getDay()||7)-1))/7); })();
        return {kw,mins,isCurrent};
      });
      const maxMins=Math.max(...weeks.map(w=>w.mins),sollH*60,1);
      const sollPct=(sollH*60)/maxMins;
      return (
        <div className="card" style={{height:"100%",boxSizing:"border-box"}}>
          <div style={{fontSize:11,fontWeight:600,letterSpacing:"0.1em",color:"var(--text4)",marginBottom:14}}>STUNDEN PRO WOCHE</div>
          <div style={{display:"flex",alignItems:"flex-end",gap:8,height:80,position:"relative"}}>
            <div style={{position:"absolute",bottom:`${sollPct*100}%`,left:0,right:0,borderTop:"1px dashed var(--border3)",pointerEvents:"none"}} title={`Soll: ${sollH}h`}/>
            {weeks.map(({kw,mins,isCurrent})=>{
              const pct=mins/maxMins;
              const over=mins>sollH*60;
              return (
                <div key={kw} style={{flex:1,display:"flex",flexDirection:"column",alignItems:"center",gap:3}}>
                  <div style={{fontSize:9,color:over?"#2d6a4f":"var(--text4)"}}>{mins>0?formatHours(mins):""}</div>
                  <div style={{width:"100%",height:`${Math.max(pct*72,mins>0?4:1)}px`,background:isCurrent?(over?"#2d6a4f":"#b07848"):over?"#2d6a4f33":"var(--border2)",borderRadius:"3px 3px 0 0",transition:"height 0.3s"}}/>
                  <div style={{fontSize:9,color:isCurrent?"var(--text2)":"var(--text5)",fontWeight:isCurrent?600:400}}>KW{kw}</div>
                </div>
              );
            })}
          </div>
          <div style={{marginTop:10,fontSize:10,color:"var(--text4)"}}>
            — Soll: {sollH}h / Woche
          </div>
        </div>
      );
    },

    "interner-blog": () => {
      const posts = (data.blogPosts || []);
      const recent = [...posts].sort((a,b) => {
        if (a.pinned !== b.pinned) return a.pinned ? -1 : 1;
        return b.createdAt.localeCompare(a.createdAt);
      }).slice(0, 3);
      const getMonday = d => { const dd=new Date(d); dd.setDate(dd.getDate()-(dd.getDay()===0?6:dd.getDay()-1)); return dd; };
      const weekStart = getMonday(new Date(today));
      const weekEnd = new Date(weekStart); weekEnd.setDate(weekEnd.getDate()+6);
      const feiertageWeek = (data.feiertage||[]).filter(f=>f.date>=weekStart.toISOString().slice(0,10)&&f.date<=weekEnd.toISOString().slice(0,10));
      const TYPE_COLOR = { beitrag:"#1a4e8a", ankuendigung:"#b5621e", event:"#2d6a4f" };
      const TYPE_LABEL = { beitrag:"Beitrag", ankuendigung:"Ankündigung", event:"Event" };
      return (
        <div className="card" style={{height:"100%",boxSizing:"border-box"}}>
          <div style={{display:"flex",justifyContent:"space-between",alignItems:"center",marginBottom:14}}>
            <div style={{fontSize:11,fontWeight:600,letterSpacing:"0.1em",color:"var(--text4)"}}>PINNWAND</div>
            <button onClick={()=>!editMode&&setView("pinnwand")} style={{background:"none",border:"none",fontSize:11,color:"var(--text4)",cursor:"pointer",fontFamily:"inherit"}}>Alle →</button>
          </div>
          {feiertageWeek.length>0&&(
            <div style={{padding:"8px 12px",background:"#e8f5ee",border:"1px solid #a8d8b8",borderRadius:8,marginBottom:12,fontSize:11,color:"#2d6a4f",display:"flex",gap:8,alignItems:"center"}}>
              <span>🎉</span>
              <span><b>Feiertag diese Woche:</b> {feiertageWeek.map(f=>f.name).join(", ")}</span>
            </div>
          )}
          {recent.length===0
            ? <div style={{fontSize:13,color:"var(--text5)",textAlign:"center",padding:"16px 0"}}>Keine Beiträge</div>
            : recent.map(p=>(
              <div key={p.id} style={{marginBottom:12,paddingBottom:12,borderBottom:"1px solid var(--border2)"}}>
                <div style={{display:"flex",alignItems:"center",gap:6,marginBottom:4}}>
                  <span style={{fontSize:9,fontWeight:600,color:TYPE_COLOR[p.type]||"#1a4e8a",letterSpacing:"0.06em"}}>{(TYPE_LABEL[p.type]||"").toUpperCase()}</span>
                  {p.pinned&&<span style={{fontSize:9,color:"#b07848"}}>📌</span>}
                </div>
                {p.title&&<div style={{fontSize:13,fontWeight:500,color:"var(--text)",marginBottom:2}}>{p.title}</div>}
                <div style={{fontSize:11,color:"var(--text3)",lineHeight:1.5,display:"-webkit-box",WebkitLineClamp:2,WebkitBoxOrient:"vertical",overflow:"hidden"}}>{p.body}</div>
                <div style={{fontSize:10,color:"var(--text4)",marginTop:4}}>{p.authorName} · {new Date(p.createdAt).toLocaleDateString("de-CH")}</div>
              </div>
            ))
          }
        </div>
      );
    },

    "team-auslastung": () => {
      const activeEmps=(data.employees||[]).filter(e=>e.aktiv!==false);
      const pensum=e=>(e.pensum||100)/100;
      const sollH=e=>((e.wochenstunden||35)*pensum(e))/5*(() => {
        let wd=0;const d=new Date(`${thisMonth}-01`);const end=new Date(d.getFullYear(),d.getMonth()+1,0);const todayD=new Date(today);
        const cap=end<todayD?end:todayD;const dd=new Date(d);
        while(dd<=cap){const dow=dd.getDay();if(dow!==0&&dow!==6)wd++;dd.setDate(dd.getDate()+1);}
        return wd;
      })();
      const empData=activeEmps.map(e=>{
        const istMin=data.timeEntries.filter(t=>t.employeeId===e.id&&(t.date||"").startsWith(thisMonth)).reduce((s,t)=>s+(t.minutes||0),0);
        const sollMin=sollH(e)*60;
        const pct=sollMin>0?Math.min(istMin/sollMin,1.5):0;
        return{...e,istMin,sollMin,pct};
      }).sort((a,b)=>b.istMin-a.istMin);
      return (
        <div className="card" style={{height:"100%",boxSizing:"border-box"}}>
          <div style={{fontSize:11,fontWeight:600,letterSpacing:"0.1em",color:"var(--text4)",marginBottom:14}}>TEAM-AUSLASTUNG {new Date().toLocaleString("de-CH",{month:"long"}).toUpperCase()}</div>
          {empData.length===0
            ? <div style={{fontSize:13,color:"var(--text5)"}}>Keine Mitarbeitenden</div>
            : empData.map(e=>{
                const over=e.pct>1;
                return (
                  <div key={e.id} style={{marginBottom:10}}>
                    <div style={{display:"flex",justifyContent:"space-between",marginBottom:3}}>
                      <div style={{fontSize:12,color:"var(--text)"}}>{e.name}</div>
                      <div style={{fontSize:11,color:over?"#2d6a4f":"var(--text4)",fontWeight:over?600:400}}>{formatHours(e.istMin)}{e.sollMin>0?` / ${formatHours(e.sollMin)}`:""}</div>
                    </div>
                    <div style={{height:3,background:"var(--border2)",borderRadius:2}}>
                      <div style={{width:`${Math.min(e.pct,1)*100}%`,height:"100%",background:over?"#2d6a4f":e.pct>0.8?"#b07848":"var(--border3)",borderRadius:2,transition:"width 0.3s"}}/>
                    </div>
                  </div>
                );
              })
          }
        </div>
      );
    },
  };

  // ─── Row renderer ──────────────────────────────────────────────────
  const renderRow = (row, rowIdx) => {
    const isDragOverRow = dragOver?.rowId === row.id && dragOver?.before === null;
    const content = wContent[row.id] ? null : null; // widget lookup happens below

    return (
      <div key={row.id} style={{marginBottom:16}}>
        {/* Row toolbar */}
        {editMode && (
          <div style={{display:"flex",alignItems:"center",gap:6,marginBottom:6,flexWrap:"wrap"}}>
            <span style={{fontSize:10,color:"var(--text4)",letterSpacing:"0.08em"}}>SPALTEN</span>
            {[1,2,3,4].map(n=>(
              <button key={n} onClick={()=>updateRow(row.id,{cols:n})} className={row.cols===n?activeCtrlBtn:ctrlBtn}>{n}</button>
            ))}
            <span style={{fontSize:10,color:"var(--text4)",letterSpacing:"0.08em",marginLeft:6}}>HÖHE</span>
            {HEIGHT_OPTS.map(opt=>(
              <button key={opt.v} onClick={()=>updateRow(row.id,{minH:opt.v})} className={row.minH===opt.v?activeCtrlBtn:ctrlBtn}>{opt.l}</button>
            ))}
            <div data-popover style={{position:"relative",marginLeft:6}}>
              <button onClick={()=>setAddPopoverRowId(addPopoverRowId===row.id?null:row.id)} className={addPopoverRowId===row.id?activeCtrlBtn:ctrlBtn}>+ Widget</button>
              {addPopoverRowId===row.id&&(
                <div style={{position:"absolute",top:"calc(100% + 4px)",left:0,zIndex:200,background:"var(--surface)",border:"1px solid var(--border)",borderRadius:8,padding:"6px 0",minWidth:230,boxShadow:"0 4px 20px rgba(0,0,0,0.15)"}}>
                  {DASHBOARD_WIDGETS.map(d=>{
                    const inThis=row.widgets.includes(d.id);
                    const inOther=!inThis&&layout.some(r=>r.id!==row.id&&r.widgets.includes(d.id));
                    return (
                      <button key={d.id} onClick={()=>!inThis&&addWidgetExclusive(row.id,d.id)}
                        style={{display:"flex",alignItems:"center",gap:8,width:"100%",padding:"7px 14px",background:"none",border:"none",color:inThis?"var(--text4)":"var(--text)",cursor:inThis?"default":"pointer",fontFamily:"inherit",fontSize:12,textAlign:"left"}}>
                        <span style={{width:14,textAlign:"center",fontSize:10,opacity:0.5,flexShrink:0}}>{inThis?"✓":"+"}</span>
                        <span style={{flex:1}}>{d.label}</span>
                        {inOther&&<span style={{fontSize:9,color:"var(--text5)"}}>verschieben</span>}
                      </button>
                    );
                  })}
                </div>
              )}
            </div>
            <div style={{marginLeft:"auto",display:"flex",gap:4}}>
              {rowIdx>0&&<button onClick={()=>moveRow(row.id,-1)} className={ctrlBtn}>↑</button>}
              {rowIdx<layout.length-1&&<button onClick={()=>moveRow(row.id,1)} className={ctrlBtn}>↓</button>}
              <button onClick={()=>addRow(row.id)} className={ctrlBtn}>+ Zeile</button>
              <button onClick={()=>deleteRow(row.id)} className={ctrlBtn} style={{color:"#8a1a1a"}}><span className="material-icons" style={{ fontSize: 16 }}>close</span></button>
            </div>
          </div>
        )}

        {/* Row grid */}
        <div
          style={{
            display:"grid",
            gridTemplateColumns:`repeat(${row.cols},1fr)`,
            gap:16,
            minHeight:row.minH||undefined,
            alignItems:"stretch",
            outline: isDragOverRow&&editMode ? "2px dashed var(--text)" : "none",
            borderRadius:10,
            transition:"outline 0.1s",
          }}
          onDragOver={editMode?e=>{e.preventDefault();setDragOver({rowId:row.id,before:null});}:undefined}
          onDrop={editMode?e=>{e.preventDefault();handleDrop(row.id,null);}:undefined}
        >
          {row.widgets.map(wid=>{
            const content = wContent[wid];
            if (!content) return null;
            const rendered = content();
            if (rendered===null&&!editMode) return null;
            const isBefore = dragOver?.rowId===row.id&&dragOver?.before===wid;
            const isDragging = dragRef.current?.widgetId===wid;
            return (
              <div
                key={wid}
                draggable={editMode}
                onDragStart={editMode?()=>handleDragStart(row.id,wid):undefined}
                onDragEnd={editMode?handleDragEnd:undefined}
                onDragOver={editMode?e=>{e.preventDefault();e.stopPropagation();setDragOver({rowId:row.id,before:wid});}:undefined}
                onDrop={editMode?e=>{e.preventDefault();e.stopPropagation();handleDrop(row.id,wid);}:undefined}
                style={{
                  position:"relative",
                  height:"100%",
                  opacity:isDragging?0.35:1,
                  boxShadow:isBefore?"inset 3px 0 0 var(--text)":undefined,
                  borderRadius:10,
                  cursor:editMode?"grab":"default",
                  transition:"opacity 0.15s",
                }}
              >
                {rendered===null?<div className="card" style={{fontSize:12,color:"var(--text5)",fontStyle:"italic",height:"100%",boxSizing:"border-box",display:"flex",alignItems:"center",justifyContent:"center"}}>{DASHBOARD_WIDGETS.find(d=>d.id===wid)?.label}</div>:rendered}
                {editMode&&(
                  <button
                    onClick={()=>removeWidgetFromRow(row.id,wid)}
                    className={ctrlBtn} style={{position:"absolute",top:8,right:8,zIndex:10,color:"#8a1a1a",lineHeight:1,padding:"2px 6px"}}
                    onMouseDown={e=>e.stopPropagation()}
                  >×</button>
                )}
              </div>
            );
          })}

          {/* Empty slot drop target */}
          {editMode&&(
            <div
              onDragOver={e=>{e.preventDefault();setDragOver({rowId:row.id,before:null});}}
              onDrop={e=>{e.preventDefault();handleDrop(row.id,null);}}
              style={{minHeight:80,border:"1.5px dashed var(--border3)",borderRadius:10,display:"flex",alignItems:"center",justifyContent:"center",color:"var(--text5)",fontSize:13}}
            >
              ablegen
            </div>
          )}
        </div>
      </div>
    );
  };

  // ─── Render ────────────────────────────────────────────────────────
  return (
    <div>
      {/* Header */}
      <div style={{marginBottom:28,display:"flex",justifyContent:"space-between",alignItems:"flex-start"}}>
        <div>
          <h1 style={{fontFamily:"'Playfair Display',serif",fontSize:30,fontWeight:400,letterSpacing:"-0.02em",lineHeight:1.1,color:"var(--text)"}}>
            {data.settings.name||"Studio"}
          </h1>
          <div style={{fontSize:11,color:"var(--text4)",letterSpacing:"0.1em",marginTop:6}}>
            {new Date().toLocaleDateString("de-CH",{weekday:"long",day:"numeric",month:"long",year:"numeric"}).toUpperCase()}
          </div>
        </div>
        <div style={{display:"flex",gap:8,alignItems:"center",marginTop:6,flexShrink:0}}>
          {editMode?(
            <>
              <select defaultValue="" onChange={e=>{if(e.target.value){loadTemplate(e.target.value);e.target.value="";}}} className={ctrlBtn}>
                <option value="">Vorlage laden…</option>
                {(data.dashboardTemplates||[]).filter(t=>t.isPublic).map(t=>(
                  <option key={t.id} value={t.id}>{t.name}</option>
                ))}
                {(data.dashboardTemplates||[]).filter(t=>!t.isPublic&&t.createdBy===currentUser?.id).map(t=>(
                  <option key={t.id} value={t.id}>{t.name} (persönlich)</option>
                ))}
              </select>
              <div data-popover style={{position:"relative"}}>
                <button onClick={()=>setSaveTemplateOpen(v=>!v)} className={saveTemplateOpen?activeCtrlBtn:ctrlBtn}>Vorlage speichern…</button>
                {saveTemplateOpen&&(
                  <div style={{position:"absolute",top:"calc(100% + 4px)",right:0,zIndex:200,background:"var(--surface)",border:"1px solid var(--border)",borderRadius:8,minWidth:240,boxShadow:"0 4px 20px rgba(0,0,0,0.15)",overflow:"hidden"}}>
                    {canSaveTemplate&&(<>
                      <div style={{padding:"8px 14px 4px",fontSize:9,color:"var(--text4)",letterSpacing:"0.1em",fontWeight:600}}>ÖFFENTLICHE VORLAGE</div>
                      {(data.dashboardTemplates||[]).filter(t=>t.isPublic).map(t=>(
                        <button key={t.id} onClick={()=>saveAsTemplate(t.id)} style={{display:"flex",justifyContent:"space-between",alignItems:"center",width:"100%",padding:"6px 14px",background:"none",border:"none",color:"var(--text)",cursor:"pointer",fontFamily:"inherit",fontSize:12,textAlign:"left"}}>
                          <span>{t.name}</span><span style={{fontSize:9,color:"var(--text5)"}}>überschreiben</span>
                        </button>
                      ))}
                      <div style={{padding:"6px 14px 10px"}}>
                        <div style={{display:"flex",gap:5}}>
                          <input value={newPublicName} onChange={e=>setNewPublicName(e.target.value)} placeholder="Neue öffentliche Vorlage…"
                            onKeyDown={e=>e.key==="Enter"&&createTemplate(newPublicName,true)}
                            style={{flex:1,height:26,border:"1px solid var(--border)",borderRadius:4,padding:"0 8px",fontSize:11,background:"var(--surface)",color:"var(--text)",fontFamily:"inherit",outline:"none"}} />
                          <button onClick={()=>createTemplate(newPublicName,true)} className={ctrlBtn}>+</button>
                        </div>
                      </div>
                      <div style={{height:1,background:"var(--border)"}}/>
                    </>)}
                    <div style={{padding:"8px 14px 4px",fontSize:9,color:"var(--text4)",letterSpacing:"0.1em",fontWeight:600}}>PERSÖNLICHE VORLAGE</div>
                    {(data.dashboardTemplates||[]).filter(t=>!t.isPublic&&t.createdBy===currentUser?.id).map(t=>(
                      <button key={t.id} onClick={()=>saveAsTemplate(t.id)} style={{display:"flex",justifyContent:"space-between",alignItems:"center",width:"100%",padding:"6px 14px",background:"none",border:"none",color:"var(--text)",cursor:"pointer",fontFamily:"inherit",fontSize:12,textAlign:"left"}}>
                        <span>{t.name}</span><span style={{fontSize:9,color:"var(--text5)"}}>überschreiben</span>
                      </button>
                    ))}
                    <div style={{padding:"6px 14px 10px"}}>
                      <div style={{display:"flex",gap:5}}>
                        <input value={newPrivateName} onChange={e=>setNewPrivateName(e.target.value)} placeholder="Neue persönliche Vorlage…"
                          onKeyDown={e=>e.key==="Enter"&&createTemplate(newPrivateName,false)}
                          style={{flex:1,height:26,border:"1px solid var(--border)",borderRadius:4,padding:"0 8px",fontSize:11,background:"var(--surface)",color:"var(--text)",fontFamily:"inherit",outline:"none"}} />
                        <button onClick={()=>createTemplate(newPrivateName,false)} className={ctrlBtn}>+</button>
                      </div>
                    </div>
                  </div>
                )}
              </div>
              <button onClick={cancelEdit} className={ctrlBtn}>Abbrechen</button>
              <button onClick={saveEdit} className="btn btn-primary" style={{fontSize:11}}>Speichern</button>
            </>
          ):(
            <button onClick={enterEdit} className={ctrlBtn} style={{display:"flex",alignItems:"center",gap:5}}>
              <span className="material-icons" style={{fontSize:13,verticalAlign:"middle"}}>edit</span>
              Anpassen
            </button>
          )}
        </div>
      </div>

      {/* Edit banner */}
      {editMode&&(
        <div style={{padding:"10px 16px",background:"var(--bg2)",border:"1px dashed var(--border3)",borderRadius:8,marginBottom:20,fontSize:12,color:"var(--text4)"}}>
          Dashboard anpassen — Spaltenanzahl und Höhe pro Zeile wählen. Widgets per Drag &amp; Drop verschieben oder mit × entfernen.
        </div>
      )}

      {/* Rows */}
      {activeLayout.map((row,idx) => renderRow(row,idx))}

      {/* Edit mode: add first row / add row at bottom */}
      {editMode&&(
        <div style={{marginTop:8}}>
          <button onClick={()=>addRow(layout[layout.length-1]?.id||"")} className={ctrlBtn} style={{width:"100%",padding:"10px",textAlign:"center",borderStyle:"dashed",color:"var(--text4)"}}>
            + Neue Zeile hinzufügen
          </button>
        </div>
      )}
    </div>
  );
}

function KpiCard({label,value,sub,color,go,setView}) {
  return (
    <div className="card"
      onClick={go&&setView?()=>setView(go):undefined}
      style={{borderTop:`3px solid ${color||"var(--border)"}`,cursor:go&&setView?"pointer":"default",transition:"transform 0.15s",height:"100%",boxSizing:"border-box"}}
      onMouseEnter={go&&setView?e=>{e.currentTarget.style.transform="translateY(-2px)";}:undefined}
      onMouseLeave={go&&setView?e=>{e.currentTarget.style.transform="";}:undefined}
    >
      <div style={{fontSize:10,color:"var(--text4)",letterSpacing:"0.12em",marginBottom:8}}>{label}</div>
      <div style={{fontSize:24,fontFamily:"'Playfair Display',serif",fontWeight:700,color:color||"var(--text)",marginBottom:3}}>{value}</div>
      {sub&&<div style={{fontSize:11,color:"var(--text5)"}}>{sub}</div>}
    </div>
  );
}

function TimeTable({entries,data}) {
  if (!entries.length) return <div style={{fontSize:13,color:"var(--text5)",padding:"8px 0"}}>Noch keine Zeiteinträge</div>;
  return (
    <table>
      <thead><tr><th>Datum</th><th>Projekt</th><th>Beschreibung</th><th style={{textAlign:"right"}}>Dauer</th></tr></thead>
      <tbody>
        {entries.map(e=>{
          const proj=data.projects.find(p=>p.id===e.projectId);
          const phase=SIA_PHASES.find(ph=>ph.id===e.phaseId);
          return (<tr key={e.id}>
            <td>{formatDate(e.date)}</td>
            <td><div style={{color:"var(--text)"}}>{proj?.name||"—"}</div>{phase&&<div style={{fontSize:10,color:"var(--text5)"}}>Phase {phase.id}</div>}</td>
            <td style={{color:"var(--text3)"}}>{e.description||"—"}</td>
            <td style={{textAlign:"right",fontWeight:500}}>{formatHours(e.minutes)}</td>
          </tr>);
        })}
      </tbody>
    </table>
  );
}
