"use client";

import React, {
    useState,
    useEffect,
    useRef,
    useCallback,
    useMemo,
    DragEvent,
} from "react";
import { useSession, signOut } from "next-auth/react";
import CalendarEventModal from "./CalendarEventModal";
import TaskRecurrenceModal from "./RecurrenceModal";
import { GridTaskBlock } from "./GridTaskBlock";
import dynamic from "next/dynamic";
const IconPicker = dynamic(() => import("./IconPicker"), { ssr: false });
import { allIcons } from "./iconRegistry";
import MdiIcon from "@mdi/react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faApple, faGoogle, faMicrosoft, faNotion } from "@fortawesome/free-brands-svg-icons";
import {
    faServer, faFolder, faBriefcase, faBullseye, faRocket, faStar,
    faLightbulb, faFire, faPalette, faMusic, faMobileScreen, faLaptop,
    faGlobe, faHouse, faBuilding, faChartBar, faChartLine, faWrench,
    faBolt, faGamepad, faPen, faBook, faGraduationCap, faFlask,
    faMicroscope, faDumbbell, faUtensils, faPlane, faLeaf, faHeart,
    faCartShopping, faCoins, faGift, faCamera, faFilm, faBroom,
    faPaw, faEarthAmericas, faLock, faCheck, faCode, faCube,
    faUsers, faCar, faMountain, faUmbrella, faClock, faTag,
    IconDefinition,
} from "@fortawesome/free-solid-svg-icons";

import FocusModeOverlay from "./FocusModeOverlay";
import {
    LayoutGrid,
    LayoutPanelLeft,
    LayoutPanelTop,
    Calendar,
    ChevronDown,
    ChevronLeft,
    ChevronRight,
    ChevronsLeft,
    ChevronsRight,
    Search,
    Settings,
    User,
    Clock,
    Menu,
    Target,
    Sun,
    Moon,
    Repeat,
    GripVertical,
    Play,
    Zap,
    Plus,
    RefreshCcw,
    Layout,
    Palette,
    Sparkles,
    Info,
    Trash2,
    Undo2,
    Redo2,
    AlertCircle,
    MoreVertical,
    Check,
    Eye,
    EyeOff,
    PanelLeftClose,
    PanelLeftOpen,
    Type,
    FolderOpen,
    FolderPlus,
    ListPlus,
    Circle,
    X,
    Cable,
    Link,
    Globe,
    Tag,
    Kanban,
    CalendarDays,
    ListTodo,
    Filter,
    Pencil,
    FileText,
    ArrowLeftRight,
    CalendarClock,
    CornerUpRight,
    Archive,
    Bot,
    Printer,
    Star,
    LogOut,
    Briefcase,
    SlidersHorizontal,
} from "lucide-react";

const stripHtml = (html: string) => html.replace(/<[^>]*>/g, '').trim();

// Types
import UserMenu from "./UserMenu";
import SearchModal from "./SearchModal";
import SimpleDatePicker from "./SimpleDatePicker";
import RecurringTasksManager from "./RecurringTasksManager";
import WeekPrintModal from "./WeekPrintModal";
export interface RecurringTaskException { id: string; taskId: string; originalDate: string; newDate?: string | null; isCancelled: boolean; createdAt: Date; updatedAt: Date; }
import { ImportListModal } from "./ImportListModal";
import OnboardingWizard from "./OnboardingWizard";
import CalendarSyncRulesPanel from "./CalendarSyncRulesPanel";
import { getRandomLocalQuote } from "@/lib/quotes";
import { AVAILABLE_FONTS, isCustomFont } from "../lib/fontConstants";
import { translations } from "../lib/weeklyViewTranslations";
import { TIMEZONE_OPTIONS as TIMEZONE_OPTIONS_LOCAL } from "../lib/timezones";
import { WeatherDisplayKey, WEATHER_DISPLAY_DEFAULTS } from "../lib/weeklyViewConstants";
const SettingsSidebar = dynamic(() => import("./SettingsSidebar"), { ssr: false });
const RichTextEditor = dynamic(() => import("./RichTextEditor"), { ssr: false });
const PriorityView = dynamic(() => import("./PriorityView"), { ssr: false });

// Cookie helpers for per-device settings
// Keys here bypass the DB and save/load from cookie only — each device keeps its own value
const DEVICE_SETTINGS_KEYS = ["viewDays", "cellDuration", "startHour", "endHour", "fontSize", "showSubHourSlots"];

// Per-view toggle keys that are also device-specific (sidebar eye toggles)
const DEVICE_VIEW_SETTINGS_KEYS = ["showSomeday", "showAllDayEvents", "showTaskCheckboxes", "showProjectIcons", "showPriorityIcons", "weatherEnabled"] as const;
type DeviceViewSettingKey = typeof DEVICE_VIEW_SETTINGS_KEYS[number];

// Settings that save to DB (cross-device default) AND to cookie (device override wins on load)
const DEVICE_ALSO_COOKIE_KEYS = ["viewStyle", "showTimeGrid", "startDayOffset"];

function getCookie(name: string): string | null {
    if (typeof document === "undefined") return null;
    const match = document.cookie.match(new RegExp(`(?:^|; )${name}=([^;]*)`));
    return match ? decodeURIComponent(match[1]) : null;
}

function setCookie(name: string, value: string, days: number = 365) {
    if (typeof document === "undefined") return;
    const expires = new Date(Date.now() + days * 864e5).toUTCString();
    document.cookie = `${name}=${encodeURIComponent(value)}; expires=${expires}; path=/; SameSite=Lax`;
}

function readDeviceViewCookie(): Record<string, Record<string, any>> {
    const raw = getCookie("device_view_settings");
    if (!raw) return {};
    try { return JSON.parse(raw); } catch { return {}; }
}

function writeDeviceViewCookie(settings: Record<string, Record<string, any>>) {
    setCookie("device_view_settings", JSON.stringify(settings));
}

export type ViewStyle = "simple" | "calendar" | "list" | "grid" | "kanban" | "priority";

export interface KanbanStage {
    id: string;
    name: string;
    color: string;
}

export interface Task {
    id: string;
    title: string;
    completed: boolean;
    dayOfWeek?: number | null;
    scheduledDate?: string | null;
    markdownContent?: string | null;
    createdAt?: Date;
    updatedAt: Date;
    order: number;
    completedAt?: Date | null;
    externalId?: string | null;
    externalProvider?: string | null;
    lastSyncedAt?: Date | null;
    syncStatus?: string | null;
    subTasks?: Task[];
    parentId?: string | null;
    isRolling?: boolean;
    isRecurring?: boolean;
    somedayListId?: string | null;
    somedaySlotIndex?: number | null;
    repeatPattern?: string | null;
    repeatEndDate?: string | null;
    repeatStartDate?: string | null;
    originalRecurringId?: string | null;
    baseRecurringTask?: Task | null;
    recurringExceptions?: RecurringTaskException[];
    startTime?: string | null;
    duration?: number | null;
    parentTaskId?: string | null;
    userId: string;
    recurrenceInterval?: number | null;
    recurrenceUnit?: string | null;
    recurrenceTime?: string | null;
    recurrenceEndDate?: Date | null;
    recurrenceDays?: number[] | null;
    externalListId?: string | null;
    projectId?: string | null;
    project?: { id: string; name: string; icon?: string | null; color?: string | null } | null;
    kanbanStage?: string | null;
    url?: string | null;
    urgency?: boolean | null;
    importance?: boolean | null;
    priority?: string | null;
    delegatedTo?: string | null;
    delegationNote?: string | null;
}

interface CalendarEvent {
    id: string;
    title: string;
    startTime: string;
    endTime: string;
    source: "google" | "apple" | "outlook" | "synology" | "notion";
    calendarId?: string;
    calendarTitle?: string;
    calendarColor?: string;
    editable?: boolean;
    recurringEventId?: string;
    isRecurring?: boolean;
    description?: string;
    location?: string;
    url?: string;
}

export interface SomedayList {
    id: string;
    title: string;
    tasks: Task[];
    tab?: string | null;
    color?: string | null;
    icon?: string | null;
    externalProvider?: string | null;
    externalId?: string | null;
    externalListId?: string | null;
}

// Time grid configuration options
export type CellDuration = 15 | 20 | 30 | 60;
const DEFAULT_SOMEDAY_SLOT_COUNT = 5;

const getSomedaySlotCount = (tasks: Task[]) => {
    const maxIdx = tasks.reduce((max, t) => {
        if (t.somedaySlotIndex !== null && t.somedaySlotIndex !== undefined) {
            return Math.max(max, t.somedaySlotIndex);
        }
        return max;
    }, -1);
    // Add 1 extra slot if more than 4 tasks exist, or at least 5 slots total.
    // "add 5 rows and then when 4 are taken add another row"
    // Let's ensure there's always at least one empty slot at the bottom.
    return Math.max(DEFAULT_SOMEDAY_SLOT_COUNT, maxIdx + 2);
};

// Helper to load Google Fonts
const useGoogleFonts = (fonts: string[]) => {
    useEffect(() => {
        if (typeof window === "undefined") return;
        const fontsToLoad = fonts.filter((f) => f && f !== "Inter");
        if (fontsToLoad.length === 0) return;

        const linkId = "google-fonts-link";
        let link = document.getElementById(linkId) as HTMLLinkElement;

        const fontQuery = fontsToLoad.map((f) => f.replace(" ", "+")).join("|");
        const href = `https://fonts.googleapis.com/css2?family=${fontsToLoad.map((f) => `${f.replace(" ", "+")}:wght@300;400;500;700`).join("&family=")}&subset=latin,latin-ext&display=swap`;

        if (!link) {
            link = document.createElement("link");
            link.id = linkId;
            link.rel = "stylesheet";
            document.head.appendChild(link);
        }
        link.href = href;
    }, [fonts]);
};

// Date utilities
function getStartOfWeek(date: Date, startDay: number = 0): Date {
    const d = new Date(date);
    const day = d.getDay();
    const diff = d.getDate() - day + (day < startDay ? -7 : 0) + startDay; // if today is sun(0) and start is mon(1), day < start (0 < 1) -> -7 + 1 = -6. 0 - 6 = -6. Correct.
    // Wait, let's re-verify:
    // Start Mon(1). Today Sun(0). day=0. diff = date - 0 + (-7) + 1 = date - 6. Correct (last Monday).
    // Start Mon(1). Today Mon(1). day=1. diff = date - 1 + (0) + 1 = date. Correct.
    // Start Sun(0). Today Mon(1). day=1. diff = date - 1 + (0) + 0 = date - 1. Correct (last Sunday).
    // Start Sun(0). Today Sun(0). day=0. diff = date - 0 + (0) + 0 = date. Correct.
    // What if Start Mon(1), Today Tue(2). day=2. diff = date - 2 + 0 + 1 = date - 1. Correct.

    // Better logic:
    // const day = d.getDay();
    // const diff = (day < startDay ? 7 : 0) + day - startDay;
    // d.setDate(d.getDate() - diff);
    //
    // Let's stick to a robust one:
    const currentDay = d.getDay();
    const distance = (currentDay - startDay + 7) % 7;
    d.setDate(d.getDate() - distance);
    return d;
}

function formatDateHeader(date: Date, locale: string = "en-US"): string {
    return date.toLocaleDateString(locale, { day: "numeric", month: "short" }); // e.g. 12. Feb.
}

function getDayName(date: Date, locale: string = "en-US", format?: string, customNames?: string, weekStartDay: number = 0, dayCase: string = "capitalize"): string {
    let name: string;
    if (format === "custom" && customNames) {
        // Split by comma or semicolon to allow spaces in names
        const names = customNames.split(/[,;]+/).map(s => s.trim()).filter(Boolean);
        if (names.length === 7) {
            // Adjust index based on weekStartDay (0=Sun, 1=Mon)
            const index = (date.getDay() - weekStartDay + 7) % 7;
            name = names[index];
        } else {
            name = date.toLocaleDateString(locale, { weekday: "long" });
        }
    } else {
        const weekdayOption = format === "narrow" ? "narrow" : (format === "short" ? "short" : "long");
        try {
            name = date.toLocaleDateString(locale, { weekday: weekdayOption });
        } catch (e) {
            name = date.toLocaleDateString("en-US", { weekday: weekdayOption });
        }
    }
    if (dayCase === "uppercase") return name.toUpperCase();
    if (dayCase === "normal") return name.toLowerCase();
    // capitalize: first letter uppercase, rest lowercase
    return name.charAt(0).toUpperCase() + name.slice(1).toLowerCase();
}

function isSameDay(d1: Date, d2: Date): boolean {
    return d1.toDateString() === d2.toDateString();
}

function formatDateToISO(date: Date): string {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");
    return `${year}-${month}-${day}`;
}

/**
 * Parses a date string from a calendar event.
 * If strictly a date (YYYY-MM-DD), it's parsed as local mid-night.
 * If an ISO string with time, it's parsed regularly.
 */
function parseCalendarDate(dateStr: string): Date {
    if (!dateStr) return new Date();
    // If it's date-only (YYYY-MM-DD), parse as local midnight
    if (!dateStr.includes("T")) {
        const parts = dateStr.split("-").map(Number);
        if (parts.length === 3) {
            return new Date(parts[0], parts[1] - 1, parts[2], 0, 0, 0);
        }
    }
    // If it's an ISO string but we want local midnight (e.g. from cache or older backend)
    // we still parse it. The fix in the backend should reduce this.
    return new Date(dateStr);
}

function formatHour(hour: number, minutes: number = 0, format: "short" | "full" = "short", timeFormat: string = "24h"): string {
    if (timeFormat === "12h") {
        const h = hour % 12 || 12;
        const ampm = hour >= 12 ? "PM" : "AM";
        const m = minutes > 0 ? `:${minutes.toString().padStart(2, "0")}` : "";
        return format === "full" || minutes > 0 ? `${h}:${minutes.toString().padStart(2, "0")} ${ampm}` : `${h}${m} ${ampm}`;
    }
    // 24h format
    if (format === "short" && minutes === 0) {
        return `${hour}`;
    }
    return `${hour.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`;
}

function getTimeSlots(
    cellDuration: CellDuration,
    startHour: number,
    endHour: number,
): string[] {
    const slots: string[] = [];
    const startMins = startHour * 60;
    const endMins = endHour * 60;
    for (let mins = startMins; mins < endMins; mins += cellDuration) {
        const h = Math.floor(mins / 60);
        const m = mins % 60;
        slots.push(`${h.toString().padStart(2, "0")}:${m.toString().padStart(2, "0")}`);
    }
    return slots;
}

function getHourFromSlot(slot: string): number {
    return parseInt(slot.split(":")[0], 10);
}

function getWeekNumber(date: Date): number {
    // ISO 8601 week number: weeks start on Monday
    const d = new Date(
        Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()),
    );
    const dayNum = d.getUTCDay() || 7;
    d.setUTCDate(d.getUTCDate() + 4 - dayNum);
    const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
    return Math.ceil(((d.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
}

// Get the Monday of the ISO week that the first visible day belongs to.
// This ensures CW changes when the first visible day crosses into a new ISO week.
function getCWReferenceDate(days: Date[]): Date {
    if (days.length === 0) return new Date();
    const first = days[0];
    const dow = first.getDay(); // 0=Sun, 1=Mon, ..., 6=Sat
    // Calculate distance back to Monday (ISO week start)
    // Sunday (0) → go back 6 days to previous Monday
    // Monday (1) → 0, Tuesday (2) → 1, etc.
    const distToMonday = dow === 0 ? 6 : dow - 1;
    return new Date(first.getTime() - distToMonday * 86400000);
}

// Format a custom header string using tokens
function formatCustomHeader(format: string, days: Date[], language: string, t: any, refDateOverride?: Date): string {
    if (!format) return "";

    // Choose the reference date: if today is within the visible days, use today.
    // Otherwise, use the standard CW reference date (start of week).
    const today = new Date();
    const isTodayInWeek = days.some(d =>
        d.getDate() === today.getDate() &&
        d.getMonth() === today.getMonth() &&
        d.getFullYear() === today.getFullYear()
    );
    const refDate = refDateOverride ?? (isTodayInWeek ? today : getCWReferenceDate(days));
    
    // Define token mappings
    const tokens: Record<string, string> = {
        "YYYY": refDate.getFullYear().toString(),
        "WW": getWeekNumber(refDate).toString().padStart(2, '0'),
        "MMMM": refDate.toLocaleDateString(language, { month: 'long' }),
        "MMM": refDate.toLocaleDateString(language, { month: 'short' }),
        "MM": (refDate.getMonth() + 1).toString().padStart(2, '0'),
        "M": (refDate.getMonth() + 1).toString(),
        "DDDD": refDate.toLocaleDateString(language, { weekday: 'long' }),
        "DDD": refDate.toLocaleDateString(language, { weekday: 'short' }),
        "DD": refDate.getDate().toString().padStart(2, '0'),
        "D": refDate.getDate().toString(),
        "[TODAY]": today.toLocaleDateString(language, { day: '2-digit', month: '2-digit', year: 'numeric' })
    };

    // Single-pass replacement using regex to avoid nested replacements (e.g. M in MMMM)
    // Standalone 'W' removed to allow literal 'W' (like in 'KW')
    const regex = /\[TODAY\]|YYYY|WW|MMMM|MMM|MM|M|DDDD|DDD|DD|D/g;
    
    return format.replace(regex, (match) => tokens[match] || match);
}

// Get the "selected" day for current_day header.
// Priority: explicit selection → today if visible → first visible day
function getSelectedDay(days: Date[], explicitSelection?: Date | null): Date {
    if (explicitSelection) return explicitSelection;
    const today = new Date();
    return days.some(d =>
        d.getDate() === today.getDate() &&
        d.getMonth() === today.getMonth() &&
        d.getFullYear() === today.getFullYear()
    ) ? today : days[0];
}

// Check if an event is an all-day event
// Defined outside component to avoid stale closure issues in useCallbacks
const isAllDayEvent = (event: CalendarEvent): boolean => {
    if (!event.startTime) return false;

    // Date-only format (YYYY-MM-DD)
    if (!event.startTime.includes("T")) return true;

    const start = parseCalendarDate(event.startTime);
    const end = parseCalendarDate(event.endTime);
    const durationHours = (end.getTime() - start.getTime()) / (1000 * 60 * 60);

    // Check if strictly midnight to midnight in local time
    const isLocalMidnight = start.getHours() === 0 && start.getMinutes() === 0;

    // Check if UTC midnight (common for API-converted date strings)
    const isUTCMidnight =
        start.getUTCHours() === 0 && start.getUTCMinutes() === 0;

    // If it's effectively 24h+ and starts at midnight (local or UTC), treat as all-day
    return durationHours >= 24 && (isLocalMidnight || isUTCMidnight);
};

// Helper to invert colors for dark mode
function invertColor(hex: string): string {
    if (!hex) return hex;
    let color = hex.startsWith("#") ? hex.slice(1) : hex;
    if (color.length === 3) {
        color = color
            .split("")
            .map((c) => c + c)
            .join("");
    }
    if (color.length !== 6) return hex;

    try {
        const r = (255 - parseInt(color.slice(0, 2), 16))
            .toString(16)
            .padStart(2, "0");
        const g = (255 - parseInt(color.slice(2, 4), 16))
            .toString(16)
            .padStart(2, "0");
        const b = (255 - parseInt(color.slice(4, 6), 16))
            .toString(16)
            .padStart(2, "0");
        return `#${r}${g}${b}`;
    } catch (e) {
        return hex;
    }
}

// Helper to lighten color for dark mode
function adjustColorForDarkMode(hex: string, isDarkMode: boolean): string {
    if (!isDarkMode || !hex || !hex.startsWith("#")) return hex;

    // Simple hex to RGB
    let r = parseInt(hex.slice(1, 3), 16);
    let g = parseInt(hex.slice(3, 5), 16);
    let b = parseInt(hex.slice(5, 7), 16);

    // Calculate brightness (0-255)
    const brightness = (r * 299 + g * 587 + b * 114) / 1000;

    // If it's too dark for dark mode, lighten it
    if (brightness < 120) {
        r = Math.min(255, r + 100);
        g = Math.min(255, g + 100);
        b = Math.min(255, b + 100);
        return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
    }

    return hex;
}

// Main Component
export default function WeeklyView() {
    const { data: session } = useSession();
    const [tasks, setTasks] = useState<Task[]>([]);
    const [connections, setConnections] = useState<any[]>([]); // Lifted state
    const [rawCalendarEvents, setRawCalendarEvents] = useState<CalendarEvent[]>(
        [],
    );

    // Weather data: { "2026-03-17T08:00": { temp: 5, code: 2, wind: 12, ... }, ... }
    type WeatherHour = { temp: number; code: number; feelsLike?: number; wind?: number; gusts?: number; precipProb?: number; precip?: number; humidity?: number; uv?: number };
    const [weatherData, setWeatherData] = useState<Record<string, WeatherHour>>({});

    // Extend events with editable flag from connections, deduplicate by id
    // Also deduplicate recurring series masters vs expanded instances:
    // When a recurring event is created, the master is cached. Then the sync
    // returns expanded instances with different IDs but the same recurringEventId.
    // We keep instances and discard masters that overlap with them.

    // Build calendarId → editable map once per connections change (O(connections × calendars))
    const calendarEditabilityMap = useMemo(() => {
        const map = new Map<string, boolean>();
        for (const conn of connections) {
            if (conn.calendars && Array.isArray(conn.calendars)) {
                for (const cal of conn.calendars as any[]) {
                    if (cal.id && !map.has(cal.id)) {
                        map.set(cal.id, !!cal.editable);
                    }
                }
            }
        }
        return map;
    }, [connections]);

    const calendarEvents = useMemo(() => {
        const seen = new Set<string>();
        const seenSlot = new Set<string>();
        // Collect recurring event IDs that have expanded instances
        const seriesWithInstances = new Set<string>();
        for (const event of rawCalendarEvents) {
            if (event.recurringEventId && event.id !== event.recurringEventId) {
                seriesWithInstances.add(event.recurringEventId);
            }
        }
        return rawCalendarEvents.filter((event) => {
            if (seen.has(event.id)) return false;
            seen.add(event.id);
            // Skip series master if expanded instances exist for this series
            if (seriesWithInstances.has(event.id)) return false;
            // Deduplicate by title+startTime+calendarId (catches optimistic add + cache read)
            const slotKey = `${event.title}|${event.startTime}|${event.calendarId}`;
            if (seenSlot.has(slotKey)) return false;
            seenSlot.add(slotKey);
            return true;
        }).map((event) => ({
            ...event,
            editable: event.calendarId ? (calendarEditabilityMap.get(event.calendarId) ?? false) : false,
        }));
    }, [rawCalendarEvents, calendarEditabilityMap]);
    const [currentWeekStart, setCurrentWeekStart] = useState(() => {
        const d = new Date();
        d.setHours(0, 0, 0, 0);
        return d;
    });
    const [viewDays, setViewDays] = useState(7);
    const savedViewDaysRef = useRef(7); // Track user's saved preference for restoring on resize
    const [isLoading, setIsLoading] = useState(true);

    // Responsive: auto-adjust viewDays based on screen orientation / width
    useEffect(() => {
        const getResponsiveViewDays = (width: number, height: number): number => {
            if (width <= 768) {
                // Mobile: portrait → 1 day, landscape → 3 days
                return height > width ? 1 : 3;
            }
            if (width <= 1024) return Math.min(savedViewDaysRef.current, 5);
            return savedViewDaysRef.current;
        };

        const handleResize = () => {
            const responsiveDays = getResponsiveViewDays(window.innerWidth, window.innerHeight);
            setViewDays(responsiveDays);
        };

        // Set initial value
        handleResize();

        window.addEventListener('resize', handleResize);
        return () => window.removeEventListener('resize', handleResize);
    }, []); // savedViewDaysRef is a ref, so no dependency needed
    const [isSyncing, setIsSyncing] = useState(false);
    const [isFetchingCalendar, setIsFetchingCalendar] = useState(false);
    const [syncError, setSyncError] = useState<string | null>(null);
    const syncCountRef = useRef(0);
    const startSync = useCallback(() => { syncCountRef.current++; setIsSyncing(true); }, []);
    const endSync = useCallback(() => { syncCountRef.current = Math.max(0, syncCountRef.current - 1); if (syncCountRef.current === 0) setIsSyncing(false); }, []);
    const [darkMode, setDarkMode] = useState(false);
    const [timeFormat, setTimeFormat] = useState("24h");
    const [dateFormat, setDateFormat] = useState("yyyy-MM-dd");
    const [hourLabelFormat, setHourLabelFormat] = useState<"short" | "full">("short");
    const [showSubHourSlots, setShowSubHourSlots] = useState<boolean>(() => {
        const c = getCookie("setting_showSubHourSlots");
        return c !== null ? c === "true" : true;
    });
    const [allDayPosition, setAllDayPosition] = useState<"above" | "below">("below");

    const [somedayExpanded, setSomedayExpanded] = useState(true);
    const [isAllDayExpanded, setIsAllDayExpanded] = useState(true);
    const [somedayHeight, setSomedayHeight] = useState<number | null>(() => {
        if (typeof document !== 'undefined') {
            const c = document.cookie.match(/somedayHeight=(\d+)/);
            return c ? parseInt(c[1]) : null;
        }
        return null;
    });
    const [allDayHeight, setAllDayHeight] = useState<number | null>(() => {
        if (typeof document !== 'undefined') {
            const c = document.cookie.match(/allDayHeight=(\d+)/);
            return c ? parseInt(c[1]) : null;
        }
        return null;
    });
    const [priorityViewHeight, setPriorityViewHeight] = useState<number>(() => {
        if (typeof document !== 'undefined') {
            const c = document.cookie.match(/priorityViewHeight=(\d+)/);
            return c ? parseInt(c[1]) : 340;
        }
        return 340;
    });
    const priorityViewRef = useRef<HTMLDivElement | null>(null);

    const resizingRef = useRef<{ target: 'someday' | 'allday' | 'priority'; startY: number; startHeight: number; handleOnTop: boolean } | null>(null);

    const startResize = useCallback((e: React.MouseEvent | React.TouchEvent, target: 'someday' | 'allday' | 'priority', handleOnTop = false) => {
        e.preventDefault();
        e.stopPropagation();
        const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY;
        const section = target === 'someday' ? somedaySectionRef.current : target === 'priority' ? priorityViewRef.current : (document.querySelector('.all-day-events-section') as HTMLElement);
        if (!section) return;
        resizingRef.current = { target, startY: clientY, startHeight: section.getBoundingClientRect().height, handleOnTop };

        const onMove = (ev: MouseEvent | TouchEvent) => {
            if (!resizingRef.current) return;
            const y = 'touches' in ev ? ev.touches[0].clientY : ev.clientY;
            const rawDelta = y - resizingRef.current.startY;
            // Top handle: dragging up = increase height (invert delta); bottom handle: normal
            const delta = resizingRef.current.handleOnTop ? -rawDelta : rawDelta;
            if (resizingRef.current.target === 'priority') {
                setPriorityViewHeight(Math.max(80, Math.min(800, resizingRef.current.startHeight + delta)));
            } else {
                const newHeight = Math.max(40, Math.min(600, resizingRef.current.startHeight + delta));
                if (resizingRef.current.target === 'someday') setSomedayHeight(newHeight);
                else setAllDayHeight(newHeight);
            }
        };
        const onEnd = () => {
            if (resizingRef.current) {
                const cookieKey = resizingRef.current.target === 'someday' ? 'somedayHeight' : resizingRef.current.target === 'priority' ? 'priorityViewHeight' : 'allDayHeight';
                const section2 = resizingRef.current.target === 'someday' ? somedaySectionRef.current : resizingRef.current.target === 'priority' ? priorityViewRef.current : (document.querySelector('.all-day-events-section') as HTMLElement);
                if (section2) {
                    const h = Math.round(section2.getBoundingClientRect().height);
                    document.cookie = `${cookieKey}=${h};path=/;max-age=31536000`;
                }
            }
            resizingRef.current = null;
            window.removeEventListener('mousemove', onMove);
            window.removeEventListener('mouseup', onEnd);
            window.removeEventListener('touchmove', onMove);
            window.removeEventListener('touchend', onEnd);
        };
        window.addEventListener('mousemove', onMove);
        window.addEventListener('mouseup', onEnd);
        window.addEventListener('touchmove', onMove);
        window.addEventListener('touchend', onEnd);
    }, []);

    const [somedayLists, setSomedayLists] = useState<SomedayList[]>([]);
    const [projects, setProjects] = useState<{ id: string; name: string; icon?: string | null; color?: string | null }[]>([]);
    const [editingTaskId, setEditingTaskId] = useState<string | null>(null);
    const [draggingListId, setDraggingListId] = useState<string | null>(null);
    const [listToDelete, setListToDelete] = useState<string | null>(null);
    const [menuOpenListId, setMenuOpenListId] = useState<string | null>(null);
    // Punkt 7+8: per-list color/icon edit popover, and per-tab settings popover
    const [editingListVisualsId, setEditingListVisualsId] = useState<string | null>(null);
    const [editingListVisualsRect, setEditingListVisualsRect] = useState<DOMRect | null>(null);
    const [editingTabVisualsName, setEditingTabVisualsName] = useState<string | null>(null);
    const [editingTabVisualsRect, setEditingTabVisualsRect] = useState<DOMRect | null>(null);
    const [activeSomedayTab, setActiveSomedayTab] = useState<string | null>(null);
    const [editingTabName, setEditingTabName] = useState<string | null>(null);
    const [renamingTabValue, setRenamingTabValue] = useState("");
    const [newTabForListId, setNewTabForListId] = useState<string | null>(null);
    const [newTabNameValue, setNewTabNameValue] = useState("");
    const [creatingNewTab, setCreatingNewTab] = useState(false);
    const [creatingNewTabName, setCreatingNewTabName] = useState("");
    const [dragOverTab, setDragOverTab] = useState<string | null>(null);
    const [customTabs, setCustomTabs] = useState<string[]>([]);

    useEffect(() => {
        const email = session?.user?.email;
        if (typeof window !== "undefined" && email) {
            const saved = localStorage.getItem(`weekly_active_someday_tab_${email}`);
            if (saved) setActiveSomedayTab(saved === "__all__" ? null : saved);
            try {
                const savedTabs = localStorage.getItem(`weekly_custom_tabs_${email}`);
                if (savedTabs) setCustomTabs(JSON.parse(savedTabs));
            } catch { /* ignore */ }
            // Migrate old non-namespaced keys (one-time cleanup)
            if (localStorage.getItem("weekly_custom_tabs") && !localStorage.getItem(`weekly_custom_tabs_${email}_migrated`)) {
                const oldTabs = localStorage.getItem("weekly_custom_tabs");
                const oldActive = localStorage.getItem("weekly_active_someday_tab");
                if (oldTabs && !localStorage.getItem(`weekly_custom_tabs_${email}`)) {
                    localStorage.setItem(`weekly_custom_tabs_${email}`, oldTabs);
                    try { setCustomTabs(JSON.parse(oldTabs)); } catch { /* ignore */ }
                }
                if (oldActive && !localStorage.getItem(`weekly_active_someday_tab_${email}`)) {
                    localStorage.setItem(`weekly_active_someday_tab_${email}`, oldActive);
                    setActiveSomedayTab(oldActive === "__all__" ? null : oldActive);
                }
                localStorage.removeItem("weekly_custom_tabs");
                localStorage.removeItem("weekly_active_someday_tab");
                localStorage.setItem(`weekly_custom_tabs_${email}_migrated`, "1");
            }
        }
    }, [session?.user?.email]);

    const saveCustomTabs = (tabs: string[]) => {
        setCustomTabs(tabs);
        const email = session?.user?.email;
        if (email) localStorage.setItem(`weekly_custom_tabs_${email}`, JSON.stringify(tabs));
        // Also persist to DB so tabs survive on other devices and reconnects
        const updated = { ...(viewSettingsRef.current as any), somedayCustomTabs: tabs };
        viewSettingsRef.current = updated;
        setViewSettings(updated);
        fetch("/api/user/profile", {
            method: "PATCH",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ viewSettings: updated }),
        }).catch(e => console.error("[tabs] Failed to save custom tabs to DB:", e));
    };

    const somedayTabs = useMemo(() => {
        const tabs = new Set<string>();
        somedayLists.forEach(l => { if (l.tab) tabs.add(l.tab); });
        customTabs.forEach(t => tabs.add(t));
        return Array.from(tabs).sort();
    }, [somedayLists, customTabs]);

    const setSomedayTab = (tab: string | null) => {
        setActiveSomedayTab(tab);
        const email = session?.user?.email;
        if (email) localStorage.setItem(`weekly_active_someday_tab_${email}`, tab ?? "__all__");
    };

    const assignListToTab = async (listId: string, tab: string | null) => {
        setSomedayLists(prev => prev.map(l => l.id === listId ? { ...l, tab } : l));
        // Persist title→tab preference so it survives reconnects
        const list = somedayLists.find(l => l.id === listId);
        if (list) {
            const prefs: Record<string, string> = { ...((viewSettingsRef.current as any).somedayTabPrefs || {}) };
            if (tab) { prefs[list.title] = tab; } else { delete prefs[list.title]; }
            const updated = { ...(viewSettingsRef.current as any), somedayTabPrefs: prefs };
            viewSettingsRef.current = updated;
            setViewSettings(updated);
            fetch("/api/user/profile", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ viewSettings: updated }),
            }).catch(e => console.error("[tabs] Failed to save tab pref:", e));
        }
        try {
            await fetch("/api/someday-lists", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ id: listId, tab }),
            });
        } catch (e) {
            console.error("Failed to update list tab:", e);
        }
    };

    const renameTab = async (oldName: string, newName: string) => {
        if (!newName.trim() || newName === oldName) return;
        const trimmed = newName.trim();
        const listsToUpdate = somedayLists.filter(l => l.tab === oldName);
        setSomedayLists(prev => prev.map(l => l.tab === oldName ? { ...l, tab: trimmed } : l));
        if (customTabs.includes(oldName)) {
            saveCustomTabs(customTabs.map(t => t === oldName ? trimmed : t));
        }
        if (activeSomedayTab === oldName) setSomedayTab(trimmed);
        for (const list of listsToUpdate) {
            try {
                await fetch("/api/someday-lists", {
                    method: "PATCH",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ id: list.id, tab: trimmed }),
                });
            } catch (e) {
                console.error("Failed to rename tab for list:", e);
            }
        }
    };

    // Update a list's color or icon, and persist to the API.
    const updateListVisuals = async (listId: string, updates: { color?: string | null; icon?: string | null }) => {
        setSomedayLists(prev => prev.map(l => l.id === listId ? { ...l, ...updates } : l));
        try {
            await fetch("/api/someday-lists", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ id: listId, ...updates }),
            });
        } catch (e) {
            console.error("Failed to update list visuals:", e);
        }
    };

    // Tab visuals are not first-class entities — store color/icon in user.viewSettings JSON.
    const getTabVisuals = (tabName: string): { color?: string; icon?: string } => {
        const cfg = (viewSettingsRef.current as any).somedayTabConfig || {};
        return cfg[tabName] || {};
    };

    const updateTabVisuals = (tabName: string, updates: { color?: string | null; icon?: string | null }) => {
        const cfg = { ...((viewSettingsRef.current as any).somedayTabConfig || {}) };
        const existing = cfg[tabName] || {};
        const next: any = { ...existing, ...updates };
        if (!next.color) delete next.color;
        if (!next.icon) delete next.icon;
        if (Object.keys(next).length === 0) delete cfg[tabName];
        else cfg[tabName] = next;
        const updated = { ...(viewSettingsRef.current as any), somedayTabConfig: cfg };
        viewSettingsRef.current = updated;
        setViewSettings(updated);
        fetch("/api/user/profile", {
            method: "PATCH",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ viewSettings: updated }),
        }).catch(e => console.error("[tabs] Failed to save tab visuals:", e));
    };

    const dissolveTab = async (tabName: string) => {
        const listsToUpdate = somedayLists.filter(l => l.tab === tabName);
        setSomedayLists(prev => prev.map(l => l.tab === tabName ? { ...l, tab: null } : l));
        if (customTabs.includes(tabName)) {
            saveCustomTabs(customTabs.filter(t => t !== tabName));
        }
        if (activeSomedayTab === tabName) setSomedayTab(null);
        for (const list of listsToUpdate) {
            try {
                await fetch("/api/someday-lists", {
                    method: "PATCH",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ id: list.id, tab: null }),
                });
            } catch (e) {
                console.error("Failed to dissolve tab for list:", e);
            }
        }
    };

    const filteredSomedayLists = useMemo(() => {
        if (activeSomedayTab === null) return somedayLists;
        return somedayLists.filter(l => (l.tab || null) === activeSomedayTab);
    }, [somedayLists, activeSomedayTab]);
    const [dropTargetListIndex, setDropTargetListIndex] = useState<number | null>(null);
    const [activeAddSlot, setActiveAddSlot] = useState<{ listId: string; slotIdx: number } | null>(null);
    const isDragFromHandle = useRef(false);

    // Undo/Redo state
    const undoStackRef = useRef<{ tasks: Task[]; somedayLists: SomedayList[] }[]>([]);
    const redoStackRef = useRef<{ tasks: Task[]; somedayLists: SomedayList[] }[]>([]);
    const [undoCount, setUndoCount] = useState(0);
    const [redoCount, setRedoCount] = useState(0);
    const skipSnapshotRef = useRef(false);

    // Mobile detection
    const [isMobile, setIsMobile] = useState(false);
    const [isPortrait, setIsPortrait] = useState(false);

    // Tracks the last day column the user interacted with (for "selected day" header display)
    const [selectedDay, setSelectedDay] = useState<Date | null>(null);

    const [showMobileFabSheet, setShowMobileFabSheet] = useState(false);
    const [showMobileRail, setShowMobileRail] = useState(false);
    const [showMobileFabMenu, setShowMobileFabMenu] = useState(false);
    const [mobileStickyDay, setMobileStickyDay] = useState<string | null>(null);
    const [mobileStickyDayVisible, setMobileStickyDayVisible] = useState(false);
    const [showHeaderMore, setShowHeaderMore] = useState(false);
    const [fabTaskTitle, setFabTaskTitle] = useState("");

    const fabTextareaRef = useRef<HTMLTextAreaElement>(null);

    // Moved state definitions to the top
    const [showSettings, setShowSettings] = useState(false);
    const [showOnboarding, setShowOnboarding] = useState(false);
    const [activeTab, setActiveTab] = useState<
        "calendar" | "general" | "account" | "styling" | "motivation" | "about"
    >("general");
    const [exportStartDate, setExportStartDate] = useState("");
    const [exportEndDate, setExportEndDate] = useState("");
    const [showWeekPrintModal, setShowWeekPrintModal] = useState(false);
    const [passwords, setPasswords] = useState({ new: "", confirm: "" });
    const [accountMsg, setAccountMsg] = useState<string>("");
    const [importingTasksState, setImportingTasksState] =
        useState<boolean>(false);
    const [importStatusMsg, setImportStatusMsg] = useState<{
        type: "success" | "error";
        text: string;
    } | null>(null);
    const [unsyncConfirm, setUnsyncConfirm] = useState<{
        provider: "google" | "apple" | "outlook" | "synology";
        list: { id: string; title: string };
    } | null>(null);
    const [isImportModalOpen, setIsImportModalOpen] = useState(false);
    const [importProvider, setImportProvider] = useState<
        "google" | "apple" | "outlook" | "synology" | null
    >(null);
    const [importLists, setImportLists] = useState<
        { id: string; title: string }[]
    >([]);
    const [isFetchingLists, setIsFetchingLists] = useState(false);
    const [availableTaskLists, setAvailableTaskLists] = useState<{
        [key in "google" | "apple" | "outlook" | "synology"]?: { id: string; title: string }[];
    }>({});
    const [isFetchingProviderLists, setIsFetchingProviderLists] = useState<
        Record<string, boolean>
    >({});
    const [isVisible, setIsVisible] = useState(false);
    const [profile, setProfile] = useState<any>({
        name: session?.user?.name || "",
        email: session?.user?.email || "",
        timezone: "UTC",
        language: "de",
        dateFormat: "yyyy-MM-dd",
        timeFormat: "24h",
        startHour: 8,
        endHour: 18,
        autoRolling: false,
        protectEventTimes: false,
        showTimeGrid: true,
        cellDuration: 30,
        viewStyle: "simple",
        fontSize: "M",
        showNextTask: false,
        showSomeday: true,
        showAllDayEvents: true,
        showSchedule: true,
        hourLabelFormat: "short",
        showSubHourSlots: true,
        dayHeaderGap: "0.75em",
        dateVerticalAlign: "middle",
        allDayPosition: "above",
        weekStartDay: 1,
        focusTimerDuration: 25,
        focusBreakDuration: 5,
        headlineFont: "Oswald",
        headlineFontSize: "1.5rem",
        headlineFontWeight: "900",
        weekdayColor: "#0ea5e9",
        dateFontFamily: "Inter",
        dateFontSize: "0.65rem",
        dateFontWeight: "400",
        timeTaskFontFamily: "Inter",
        timeTaskFontSize: "0.75rem",
        timeTaskFontWeight: "500",
        bodyFont: "Inter",
        taskFontFamily: "Inter",
        taskFontSize: "0.9rem",
        taskFontWeight: "400",
        eventFontFamily: "Inter",
        eventFontSize: "0.85rem",
        eventFontWeight: "400",
        goalFallbackType: "quote",
        goalFontFamily: "Lato",
        goalFontSize: "1rem",
        goalFontWeight: "500",
        goalScope: "week",
        dateLayout: "right",
        mobileDateLayout: "below",
        dateAlignment: "center",
        weekendColorSat: "#ffc107",
        weekendColorSun: "#dc2626",
        pastDayColor: "#a6a6a7",
        cwFontFamily: "Oswald",
        cwFontSize: "1.5rem",
        cwFontWeight: "700",
        yearFontFamily: "Oswald",
        yearFontSize: "1.5rem",
        yearFontWeight: "700",
        quoteSourceUrl: "",
        quoteSourceUrls: [],
        quoteLanguages: ["en", "de"],
        weatherEnabled: false,
        weatherLat: null,
        weatherLon: null,
        weatherLocation: "",
        showCalendarProviderIcon: false,
    });
    const [motivationalQuote, setMotivationalQuote] = useState("");
    const [showSummary, setShowSummary] = useState(false);

    const [isAddingSomedayList, setIsAddingSomedayList] = useState(false);
    const [newSomedayListName, setNewSomedayListName] = useState("");
    const [selectedSomedayProvider, setSelectedSomedayProvider] = useState<
        string | null
    >(null);
    const [language, setLanguage] = useState("de");
    const [syncStatus, setSyncStatus] = useState<"idle" | "syncing" | "synced">(
        "idle",
    );
    const [announceMsg, setAnnounceMsg] = useState('');
    const announceTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
    const announce = (msg: string) => {
        if (announceTimeout.current) clearTimeout(announceTimeout.current);
        setAnnounceMsg(msg);
        announceTimeout.current = setTimeout(() => setAnnounceMsg(''), 3000);
    };
    const [cellDuration, setCellDuration] = useState<CellDuration>(30);
    const [draggedTask, setDraggedTask] = useState<Task | null>(null);
    const [showTimeGrid, setShowTimeGrid] = useState<boolean>(() => {
        const c = getCookie("setting_showTimeGrid");
        return c !== null ? c === "true" : true;
    });
    const [slideDirection, setSlideDirection] = useState<"next" | "prev" | null>(
        null,
    );
    const [activeSlot, setActiveSlot] = useState<{
        day: number;
        slot: string;
    } | null>(null);
    const [newSlotTask, setNewSlotTask] = useState("");
    const [selectedTaskForNotes, setSelectedTaskForNotes] = useState<Task | null>(
        null,
    );
    const [currentTime, setCurrentTime] = useState(new Date());
    const [dropPreview, setDropPreview] = useState<{
        day?: number;
        slot?: string;
        listId?: string;
        slotIdx?: number;
    } | null>(null);
    const [viewStyle, setViewStyle] = useState<ViewStyle>(() => {
        const c = getCookie("setting_viewStyle");
        return (c as ViewStyle) || "simple";
    });

    // Per-view settings: overrides that apply only to a specific view
    type PerViewOverrides = {
        hourLabelFormat?: "short" | "full";
        showSubHourSlots?: boolean;
        weatherEnabled?: boolean;
        weatherDisplay?: WeatherDisplayKey[];
        showTaskCheckboxes?: boolean;
        showProjectIcons?: boolean;
        showPriorityIcons?: boolean;
        showSomeday?: boolean;
        showAllDayEvents?: boolean;
        allDayPosition?: "above" | "below";
        showCompletedTasks?: boolean;
        cellDuration?: number;
        startHour?: number;
        endHour?: number;
    };
    const PER_VIEW_KEYS = ["hourLabelFormat", "showSubHourSlots", "weatherEnabled", "weatherDisplay", "showTaskCheckboxes", "showProjectIcons", "showPriorityIcons", "showSomeday", "showAllDayEvents", "allDayPosition", "showCompletedTasks", "cellDuration", "startHour", "endHour"] as const;
    const [viewSettings, setViewSettings] = useState<Record<string, PerViewOverrides>>({});
    const viewSettingsRef = useRef<Record<string, PerViewOverrides>>({});
    viewSettingsRef.current = viewSettings;

    // Device-local per-view overrides (cookie-based, not synced to DB)
    const [deviceViewSettings, setDeviceViewSettings] = useState<Record<string, Record<string, any>>>(() => readDeviceViewCookie());
    const deviceViewSettingsRef = useRef<Record<string, Record<string, any>>>({});
    deviceViewSettingsRef.current = deviceViewSettings;

    const getEffective = <K extends keyof PerViewOverrides>(key: K, globalVal: PerViewOverrides[K]): PerViewOverrides[K] => {
        // Device-specific settings take priority (cookie-based, not synced across devices)
        if ((DEVICE_VIEW_SETTINGS_KEYS as readonly string[]).includes(key)) {
            const dvs = deviceViewSettingsRef.current[profile.viewStyle];
            if (dvs && dvs[key] !== undefined) return dvs[key] as PerViewOverrides[K];
        }
        const vs = viewSettingsRef.current[profile.viewStyle];
        if (vs && vs[key] !== undefined) return vs[key] as PerViewOverrides[K];
        return globalVal;
    };
    const isPerView = (key: keyof PerViewOverrides): boolean => {
        const vs = viewSettingsRef.current[profile.viewStyle];
        return !!(vs && vs[key] !== undefined);
    };
    const saveViewSetting = async <K extends keyof PerViewOverrides>(key: K, value: PerViewOverrides[K], perView: boolean) => {
        // Device-specific keys: save to cookie only, not DB
        if ((DEVICE_VIEW_SETTINGS_KEYS as readonly string[]).includes(key) && perView) {
            const dvs = { ...deviceViewSettingsRef.current };
            dvs[profile.viewStyle] = { ...(dvs[profile.viewStyle] || {}), [key]: value };
            deviceViewSettingsRef.current = dvs;
            setDeviceViewSettings(dvs);
            writeDeviceViewCookie(dvs);
            return;
        }
        const updated = { ...viewSettingsRef.current };
        if (perView) {
            updated[profile.viewStyle] = { ...(updated[profile.viewStyle] || {}), [key]: value };
        } else {
            // Remove per-view overrides for this key from ALL views and set globally
            for (const v of Object.keys(updated)) {
                if (updated[v] && updated[v][key] !== undefined) {
                    const { [key]: _, ...rest } = updated[v] as any;
                    updated[v] = rest;
                }
            }
        }
        viewSettingsRef.current = updated;
        setViewSettings(updated);
        // Save to DB
        try {
            await fetch("/api/user/profile", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ viewSettings: updated }),
            });
        } catch (e) { console.error("Failed to save view settings:", e); }
    };
    const togglePerView = async (key: keyof PerViewOverrides, globalVal: any) => {
        if (isPerView(key)) {
            // Remove per-view override (revert to global)
            const updated = { ...viewSettingsRef.current };
            if (updated[profile.viewStyle]) {
                const { [key]: _, ...rest } = updated[profile.viewStyle] as any;
                updated[profile.viewStyle] = rest;
            }
            viewSettingsRef.current = updated;
            setViewSettings(updated);
            try {
                await fetch("/api/user/profile", {
                    method: "PATCH",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ viewSettings: updated }),
                });
            } catch (e) { console.error("Failed to save view settings:", e); }
        } else {
            // Set per-view override to current global value
            saveViewSetting(key, globalVal, true);
        }
    };

    // State declarations needed before effective per-view values
    const [showSomeday, setShowSomeday] = useState(true);
    const [showAllDay, setShowAllDay] = useState(true);

    // Effective per-view values (override if set for current view, else global)
    const effectiveHourLabelFormat = getEffective("hourLabelFormat", profile.hourLabelFormat ?? "short");
    const effectiveShowSubHourSlots = getEffective("showSubHourSlots", profile.showSubHourSlots ?? true);
    const effectiveWeatherEnabled = getEffective("weatherEnabled", profile.weatherEnabled);
    const effectiveWeatherDisplay = (getEffective("weatherDisplay", WEATHER_DISPLAY_DEFAULTS) || WEATHER_DISPLAY_DEFAULTS) as WeatherDisplayKey[];
    const effectiveShowTaskCheckboxes = getEffective("showTaskCheckboxes", profile.showTaskCheckboxes);
    const effectiveShowProjectIcons = getEffective("showProjectIcons", profile.showProjectIcons);
    const effectiveShowPriorityIcons = getEffective("showPriorityIcons", profile.showPriorityIcons !== false) as boolean;
    const effectivePriorityStyle = (profile.priorityStyle || "eisenhower") as string;
    const effectiveShowSomeday = getEffective("showSomeday", profile.showSomeday ?? true);
    const effectiveShowAllDay = getEffective("showAllDayEvents", profile.showAllDayEvents ?? true);
    const effectiveAllDayPosition = getEffective("allDayPosition", profile.allDayPosition ?? "above") || "above";
    const effectiveShowCompletedTasks = getEffective("showCompletedTasks", profile.showCompletedTasks !== false);
    const effectiveCellDuration = getEffective("cellDuration", cellDuration) as CellDuration;
    const effectiveStartHour = getEffective("startHour", profile.startHour ?? 8) ?? 8;
    const effectiveEndHour = getEffective("endHour", profile.endHour ?? 18) ?? 18;

    const defaultKanbanStages: KanbanStage[] = [
        { id: "backlog", name: "Backlog", color: "#94a3b8" },
        { id: "todo", name: "To Do", color: "#3b82f6" },
        { id: "in-progress", name: "In Progress", color: "#f59e0b" },
        { id: "review", name: "Review", color: "#8b5cf6" },
        { id: "done", name: "Done", color: "#22c55e" },
    ];
    const [kanbanStages, setKanbanStages] = useState<KanbanStage[]>(defaultKanbanStages);
    const saveKanbanStages = async (stages: KanbanStage[]) => {
        setKanbanStages(stages);
        try {
            await fetch("/api/user/profile", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ kanbanStages: JSON.stringify(stages) }),
            });
        } catch (e) { console.error("Failed to save kanban stages:", e); }
    };
    // Kanban filters
    const [kanbanFilterProject, setKanbanFilterProject] = useState<string>("");
    const [kanbanFilterList, setKanbanFilterList] = useState<string>("");
    const [kanbanFilterWeek, setKanbanFilterWeek] = useState<string>("");
    const [kanbanSearch, setKanbanSearch] = useState("");
    const [kanbanDeleteStageId, setKanbanDeleteStageId] = useState<string | null>(null);
    const [kanbanAddingStageId, setKanbanAddingStageId] = useState<string | null>(null);
    const [kanbanNewTaskTitle, setKanbanNewTaskTitle] = useState("");
    const [kanbanDetailTask, setKanbanDetailTask] = useState<Task | null>(null);
    const [kanbanExpandedCards, setKanbanExpandedCards] = useState<Set<string>>(new Set());

    const [protectEventTimes, setProtectEventTimes] = useState(false);
    const [unlockedEvents, setUnlockedEvents] = useState<Set<string>>(new Set());

    const [startHour, setStartHour] = useState(8);
    const [endHour, setEndHour] = useState(18);
    const [weekStartDay, setWeekStartDay] = useState(1); // 1 = Monday, 0 = Sunday
    const [goal, setGoal] = useState("your goal of this week");
    const [isEditingGoal, setIsEditingGoal] = useState(false);
    const [showNextTask, setShowNextTask] = useState(false);
    const [calendarEditMode, setCalendarEditMode] = useState(false);
    const [selectedTaskForRecurrence, setSelectedTaskForRecurrence] =
        useState<Task | null>(null);
    const [showFocusMode, setShowFocusMode] = useState(false);
    const [showSchedule, setShowSchedule] = useState(true);
    const [focusBreakDuration, setFocusBreakDuration] = useState(5);
    const [weekdayFormat, setWeekdayFormat] = useState<"long" | "short" | "narrow" | "custom">("long");
    const [weekdayCase, setWeekdayCase] = useState<"normal" | "capitalize" | "uppercase">("capitalize");
    const [customWeekdayNames, setCustomWeekdayNames] = useState("");

    // New UI State
    const [isSearchOpen, setIsSearchOpen] = useState(false);
    const [isRecurringTasksOpen, setIsRecurringTasksOpen] = useState(false);
    const [showDatePicker, setShowDatePicker] = useState(false);
    const datePickerBtnRef = useRef<HTMLDivElement>(null);
    const [showQuickSettings, setShowQuickSettings] = useState(false);
    const [leftRailExpanded, setLeftRailExpanded] = useState(false);
    const [flyoutSection, setFlyoutSection] = useState<string | null>(null);
    const [showRailUserMenu, setShowRailUserMenu] = useState(false);
    const [flyoutY, setFlyoutY] = useState(0);
    const flyoutTimerRef = useRef<NodeJS.Timeout | null>(null);
    const [showProjectsSidebar, setShowProjectsSidebar] = useState(false);
    const [activeProjectFilter, setActiveProjectFilter] = useState<string | null>(null);
    const [showIntroHints, setShowIntroHints] = useState(true);

    const [focusTimerDuration, setFocusTimerDuration] = useState(25);
    const [fontSize, setFontSize] = useState<"S" | "M" | "L">(() => {
        const c = getCookie("setting_fontSize");
        return (c as "S" | "M" | "L") || "M";
    });
    const [headlineFont, setHeadlineFont] = useState("Inter");
    const [headlineFontSize, setHeadlineFontSize] = useState("1.25rem");
    const [headlineFontWeight, setHeadlineFontWeight] = useState("900");
    const [dateFontFamily, setDateFontFamily] = useState("Inter");
    const [dateFontSize, setDateFontSize] = useState("0.65rem");
    const [dateFontWeight, setDateFontWeight] = useState("400");
    const [timeTaskFontFamily, setTimeTaskFontFamily] = useState("Inter");
    const [timeTaskFontSize, setTimeTaskFontSize] = useState("0.75rem");
    const [timeTaskFontWeight, setTimeTaskFontWeight] = useState("500");
    const [bodyFont, setBodyFont] = useState("Inter");
    const [taskFontFamily, setTaskFontFamily] = useState("Inter");
    const [taskFontSize, setTaskFontSize] = useState("0.9rem");
    const [taskFontWeight, setTaskFontWeight] = useState("400");
    const [eventFontFamily, setEventFontFamily] = useState("Inter");
    const [eventFontSize, setEventFontSize] = useState("0.85rem");
    const [eventFontWeight, setEventFontWeight] = useState("400");
    const [fontWeight, setFontWeight] = useState("400");
    const [weekendColorSat, setWeekendColorSat] = useState("#666666");
    const [weekendColorSun, setWeekendColorSun] = useState("#dc2626");

    // Load fonts
    // Dynamic font loading is handled by the main useGoogleFonts hook call below

    // Collect custom font names from profile settings
    const customFonts = useMemo(() => {
        const fontProps = [
            profile.headlineFont, profile.dateFontFamily, profile.taskFontFamily,
            profile.timeTaskFontFamily, profile.eventFontFamily, profile.goalFontFamily,
            profile.cwFontFamily, profile.yearFontFamily, profile.bodyFont,
        ];
        return fontProps.filter((f): f is string => !!f && isCustomFont(f));
    }, [profile.headlineFont, profile.dateFontFamily, profile.taskFontFamily,
        profile.timeTaskFontFamily, profile.eventFontFamily, profile.goalFontFamily,
        profile.cwFontFamily, profile.yearFontFamily, profile.bodyFont]);

    // Load ALL available fonts + any custom fonts at the top level
    useGoogleFonts([
        ...AVAILABLE_FONTS.filter((f) => f.value !== "__custom__").map((f) => f.value),
        ...customFonts,
    ]);

    // Dynamic font loading is handled by useGoogleFonts hook call above

    // Calendar Event Modal State
    const [calendarEventModal, setCalendarEventModal] = useState<{
        isOpen: boolean;
        event?: CalendarEvent;
        initialDate?: Date;
        initialStartTime?: string;
        initialEndTime?: string;
    }>({ isOpen: false });

    // Slot drag-to-create calendar event state (mouse + touch)
    const slotDragJustEndedRef = useRef(false);
    const slotDragRef = useRef<{
        active: boolean;
        date: Date;
        startSlot: string;
        currentSlot: string;
        startY: number;
    } | null>(null);
    const [slotDragSelection, setSlotDragSelection] = useState<{
        dateStr: string;
        startSlot: string;
        endSlot: string;
    } | null>(null);
    // Touch long-press state for mobile drag-to-create
    const touchLongPressRef = useRef<{
        timerId: ReturnType<typeof setTimeout>;
        startX: number;
        startY: number;
        date: Date;
        slot: string;
        activated: boolean;
    } | null>(null);

    // Calendar event resize/drag state
    const [eventDragState, setEventDragState] = useState<{
        eventId: string;
        mode: 'move' | 'resize-top' | 'resize-bottom';
        startY: number;
        startX: number;
        originalStartTime: string;
        originalEndTime: string;
        currentStartTime: string;
        currentEndTime: string;
        calendarId?: string;
        source?: string;
        hasMoved?: boolean;
    } | null>(null);

    // Pending recurring event edit after drag/resize — asks "this" or "all"
    const [pendingRecurringDrag, setPendingRecurringDrag] = useState<{
        eventId: string;
        calendarId: string;
        recurringEventId?: string;
        startTime: string;
        endTime: string;
        originalStartTime: string;
        originalEndTime: string;
    } | null>(null);
    const [recurringDragEditMode, setRecurringDragEditMode] = useState<'this' | 'future' | 'all'>('this');

    // Dark Mode Persistence & Class Toggle
    const [mounted, setMounted] = useState(false);

    const [recurringDeleteModal, setRecurringDeleteModal] = useState<{
        isOpen: boolean;
        taskId: string | null;
    }>({ isOpen: false, taskId: null });

    useEffect(() => {
        setMounted(true);
        const savedDarkMode = localStorage.getItem("weekly-dark-mode");
        if (savedDarkMode) {
            setDarkMode(JSON.parse(savedDarkMode));
        }
        const savedWeekStart = localStorage.getItem("weekly-week-start");
        if (savedWeekStart) {
            setWeekStartDay(Number(savedWeekStart));
        }
    }, []);

    // Mobile detection — track viewport width and orientation
    useEffect(() => {
        const check = () => {
            setIsMobile(window.innerWidth <= 768);
            setIsPortrait(window.innerHeight > window.innerWidth);
        };
        check();
        window.addEventListener("resize", check);
        return () => window.removeEventListener("resize", check);
    }, []);

    const profileLoadedRef = useRef(false);
    const autoSaveTimerRef = useRef<NodeJS.Timeout | null>(null);
    const dragJustEndedRef = useRef(false);

    const fetchProfile = async () => {
        try {
            const res = await fetch("/api/user/profile");
            if (res.ok) {
                const data = await res.json();
                if (data && data.user) {
                    const profileData = data.user;
                    setProfile(profileData);
                    
                    // Sync individual states to profile data
                    if (profileData.viewStyle) setViewStyle(profileData.viewStyle);
                    if (profileData.viewDays) {
                        savedViewDaysRef.current = profileData.viewDays;
                        const w = window.innerWidth, h = window.innerHeight;
                        if (w <= 768) setViewDays(h > w ? 1 : 3);
                        else if (w <= 1024) setViewDays(Math.min(profileData.viewDays, 5));
                        else setViewDays(profileData.viewDays);
                    }
                    if (profileData.showTimeGrid !== undefined) setShowTimeGrid(profileData.showTimeGrid);
                    if (profileData.showSomeday !== undefined) setShowSomeday(profileData.showSomeday);
                    if (profileData.showAllDayEvents !== undefined) setShowAllDay(profileData.showAllDayEvents);
                    if (profileData.showSchedule !== undefined) setShowSchedule(profileData.showSchedule);
                    if (profileData.cellDuration) setCellDuration(profileData.cellDuration);
                    if (profileData.language) setLanguage(profileData.language);
                    if (profileData.dateFormat) setDateFormat(profileData.dateFormat);
                    if (profileData.timeFormat) setTimeFormat(profileData.timeFormat);
                    if (profileData.startHour !== undefined) setStartHour(profileData.startHour);
                    if (profileData.endHour !== undefined) setEndHour(profileData.endHour);
                    if (profileData.fontSize) setFontSize(profileData.fontSize);
                    if (profileData.showNextTask !== undefined) setShowNextTask(profileData.showNextTask);
                    if (profileData.protectEventTimes !== undefined) setProtectEventTimes(profileData.protectEventTimes);
                    if (profileData.headlineFont) setHeadlineFont(profileData.headlineFont);
                    if (profileData.headlineFontSize) setHeadlineFontSize(profileData.headlineFontSize);
                    if (profileData.headlineFontWeight) setHeadlineFontWeight(profileData.headlineFontWeight);
                    if (profileData.dateFontFamily) setDateFontFamily(profileData.dateFontFamily);
                    if (profileData.dateFontSize) setDateFontSize(profileData.dateFontSize);
                    if (profileData.dateFontWeight) setDateFontWeight(profileData.dateFontWeight);
                    if (profileData.timeTaskFontFamily) setTimeTaskFontFamily(profileData.timeTaskFontFamily);
                    if (profileData.timeTaskFontSize) setTimeTaskFontSize(profileData.timeTaskFontSize);
                    if (profileData.timeTaskFontWeight) setTimeTaskFontWeight(profileData.timeTaskFontWeight);
                    if (profileData.bodyFont) setBodyFont(profileData.bodyFont);
                    if (profileData.taskFontFamily) setTaskFontFamily(profileData.taskFontFamily);
                    if (profileData.taskFontSize) setTaskFontSize(profileData.taskFontSize);
                    if (profileData.taskFontWeight) setTaskFontWeight(profileData.taskFontWeight);
                    if (profileData.fontWeight) setFontWeight(profileData.fontWeight);
                    if (profileData.weekendColorSat) setWeekendColorSat(profileData.weekendColorSat);
                    if (profileData.weekendColorSun) setWeekendColorSun(profileData.weekendColorSun);
                    if (profileData.hourLabelFormat) setHourLabelFormat(profileData.hourLabelFormat);
                    if (profileData.showSubHourSlots !== undefined) setShowSubHourSlots(profileData.showSubHourSlots);
                    if (profileData.allDayPosition) setAllDayPosition(profileData.allDayPosition);
                    if (profileData.viewSettings) {
                        setViewSettings(profileData.viewSettings);
                        // Load customTabs from DB (cross-device, survives reconnects)
                        const dbTabs = (profileData.viewSettings as any).somedayCustomTabs;
                        if (Array.isArray(dbTabs) && dbTabs.length > 0) {
                            setCustomTabs(prev => {
                                const merged = new Set([...dbTabs, ...prev]);
                                return Array.from(merged);
                            });
                        }
                    }

                    // Re-apply per-device cookie overrides — these always win over DB values
                    const _cFS = getCookie("setting_fontSize");
                    if (_cFS) setFontSize(_cFS as "S" | "M" | "L");
                    const _cSH = getCookie("setting_showSubHourSlots");
                    if (_cSH !== null) setShowSubHourSlots(_cSH === "true");
                    const _cCD = getCookie("setting_cellDuration");
                    if (_cCD) setCellDuration(Number(_cCD) as CellDuration);
                    const _cStart = getCookie("setting_startHour");
                    if (_cStart) setStartHour(Number(_cStart));
                    const _cEnd = getCookie("setting_endHour");
                    if (_cEnd) setEndHour(Number(_cEnd));
                    const _cVS = getCookie("setting_viewStyle");
                    if (_cVS) { setViewStyle(_cVS as ViewStyle); setProfile((p: any) => ({ ...p, viewStyle: _cVS })); }
                    const _cTG = getCookie("setting_showTimeGrid");
                    if (_cTG !== null) { const v = _cTG === "true"; setShowTimeGrid(v); setProfile((p: any) => ({ ...p, showTimeGrid: v })); }
                    const _cSDO = getCookie("setting_startDayOffset");
                    if (_cSDO !== null) setProfile((p: any) => ({ ...p, startDayOffset: Number(_cSDO) }));

                    // Show onboarding wizard for new users
                    if (profileData.hasCompletedOnboarding === false) {
                        setShowOnboarding(true);
                    }
                }
            }
        } catch (err) {
            console.error("Failed to fetch profile:", err);
        } finally {
            profileLoadedRef.current = true;
            setIsLoading(false);
        }
    };

    useEffect(() => {
        fetchProfile();
    }, []);

    useEffect(() => {
        if (!profileLoadedRef.current) return;
        if (autoSaveTimerRef.current) clearTimeout(autoSaveTimerRef.current);
        autoSaveTimerRef.current = setTimeout(async () => {
            try {
                await fetch("/api/user/profile", {
                    method: "PATCH",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify(profile),
                });
                console.log("[SETTINGS] Auto-saved profile");
            } catch (err) {
                console.error("[SETTINGS] Auto-save failed:", err);
            }
        }, 800);
        return () => {
            if (autoSaveTimerRef.current) clearTimeout(autoSaveTimerRef.current);
        };
    }, [profile]);

    // Auto-focus FAB bottom sheet textarea
    useEffect(() => {
        if (showMobileFabSheet && fabTextareaRef.current) {
            setTimeout(() => fabTextareaRef.current?.focus(), 100);
        }
    }, [showMobileFabSheet]);

    useEffect(() => {
        if (!mounted) return;
        localStorage.setItem("weekly-dark-mode", JSON.stringify(darkMode));
        if (darkMode) {
            document.documentElement.classList.add("dark");
        } else {
            document.documentElement.classList.remove("dark");
        }
    }, [darkMode, mounted]);

    useEffect(() => {
        if (!mounted) return;
        localStorage.setItem("weekly-week-start", String(profile.weekStartDay ?? 1));
        // REMOVED: Re-align current week start when start day changes
        // This was forcing the view to snap to Monday, breaking the "Yesterday as first column" setting.
        // setCurrentWeekStart(prev => getStartOfWeek(prev, weekStartDay));
    }, [profile.weekStartDay, mounted]);

    // Translation helper
    const t = translations[profile.language] || translations["en"];

    // Refs for scroll
    const dayColumnsRef = useRef<HTMLDivElement[]>([]);
    const isScrollSyncing = useRef(false);
    const isInitialScrollDone = useRef(false);
    const intendedScrollTop = useRef<number | null>(null);
    const [measuredHeaderHeight, setMeasuredHeaderHeight] = useState(65);
    const dayHeaderRef = useRef<HTMLElement>(null);
    const somedayGridRef = useRef<HTMLDivElement>(null);

    useEffect(() => {
        const updateHeight = () => {
            if (dayHeaderRef.current) {
                const height = dayHeaderRef.current.offsetHeight;
                // Allow some tolerance to avoid infinite loops across various browsers
                if (height > 0 && Math.abs(height - measuredHeaderHeight) > 1) {
                    setMeasuredHeaderHeight(height);
                }
            }
        };

        // Initial measurement
        updateHeight();

        // Measurement after a short delay for layout stabilization
        const timer = setTimeout(updateHeight, 800);

        // Also track window resize
        window.addEventListener('resize', updateHeight);

        // ResizeObserver for more robust tracking of layout shifts
        let resizeObserver: ResizeObserver | null = null;
        if (typeof window !== 'undefined' && 'ResizeObserver' in window && dayHeaderRef.current) {
            resizeObserver = new ResizeObserver(updateHeight);
            resizeObserver.observe(dayHeaderRef.current);
        }

        return () => {
            clearTimeout(timer);
            window.removeEventListener('resize', updateHeight);
            if (resizeObserver) resizeObserver.disconnect();
        };
    }, [dayHeaderRef.current, profile.cellDuration, viewDays, isMobile, profile.mobileDateLayout, profile.dateLayout, profile.dateAlignment, profile.dayHeaderGap, profile.headlineFontSize, profile.headlineFontWeight, profile.dateFontSize, profile.dateVerticalAlign, profile.headerDisplay, profile.weekdayFormat, profile.viewStyle]);
    const somedaySectionRef = useRef<HTMLElement | null>(null);

    // Unified scroll sync handlers
    // handleTimeColumnScroll no longer needed — single scroll container via time-grid-wrapper

    const handleGridScroll = (_e: React.UIEvent<HTMLElement>) => {
        // Single scroll container — no sync needed
        // Mobile sticky day is handled by the native scroll listener in the useEffect
    };

    const jumpToHour = (hour: number) => {
        const slotsPerHour = 60 / effectiveCellDuration;
        const slotHeight = getSlotHeight(effectiveCellDuration);
        const scrollOffset = hour * slotsPerHour * slotHeight;
        
        console.log(`[SCROLL] Jumping to hour ${hour} (offset ${scrollOffset}px)`);
        
        // Clear old stabilization
        isInitialScrollDone.current = true; 
        isScrollSyncing.current = true;
        intendedScrollTop.current = scrollOffset;

        const perform = () => {
            if (gridRef.current) gridRef.current.scrollTop = scrollOffset;
        };

        // Repeated enforcement
        perform();
        requestAnimationFrame(perform);
        setTimeout(perform, 50);
        setTimeout(perform, 100);
        setTimeout(perform, 250);
        
        setTimeout(() => {
            isScrollSyncing.current = false;
        }, 500);
    };

    // Slot and Header height based on cell duration
    // WMO weather code → emoji icon
    const getWeatherIcon = (code: number): string => {
        if (code === 0) return "☀️";
        if (code <= 3) return "⛅";
        if (code >= 45 && code <= 48) return "🌫️";
        if (code >= 51 && code <= 55) return "🌦️";
        if (code >= 56 && code <= 57) return "🌧️";
        if (code >= 61 && code <= 65) return "🌧️";
        if (code >= 66 && code <= 67) return "🌨️";
        if (code >= 71 && code <= 77) return "❄️";
        if (code >= 80 && code <= 82) return "🌧️";
        if (code >= 85 && code <= 86) return "❄️";
        if (code >= 95) return "⛈️";
        return "☁️";
    };

    const getSlotHeight = (duration: number) => {
        switch (duration) {
            case 15: return 25;
            case 20: return 30;
            case 30: return 35;
            case 60: return 50;
            default: return 50;
        }
    };

    const getHeaderHeight = (duration: number) => {
        if (measuredHeaderHeight > 0) return measuredHeaderHeight;
        switch (duration) {
            case 15: return 65;
            case 30: return 55;
            case 60: return 50;
            case 120: return 50;
            default: return 50;
        }
    };

    // Working hours range (configurable)
    const workingHoursStart = profile.startHour ?? 8;
    const workingHoursEnd = profile.endHour ?? 18;

    // Fetch calendar events
    // Find connectionId for a given calendarId
    const getConnectionIdForCalendar = useCallback((calId?: string) => {
        if (!calId) return undefined;
        const conn = connections.find((c: any) =>
            (c.calendars || []).some((cal: any) => cal.id === calId)
        );
        return conn?.id;
    }, [connections]);

    const fetchCalendarEvents = useCallback(async (forceRefresh = false, connectionId?: string) => {
        startSync();
        setIsFetchingCalendar(true);
        try {
            const response = await fetch("/api/calendar/sync", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    timeMin: new Date(
                        currentWeekStart.getTime() - 7 * 24 * 60 * 60 * 1000,
                    ).toISOString(),
                    timeMax: new Date(
                        currentWeekStart.getTime() + 14 * 24 * 60 * 60 * 1000,
                    ).toISOString(),
                    forceRefresh,
                    ...(connectionId ? { connectionId } : {}),
                }),
            });

            if (response.ok) {
                const text = await response.text();
                try {
                    const data = JSON.parse(text);
                    if (data.events) {
                        setRawCalendarEvents(data.events);
                    }
                    // If stale connections were refreshing in background, re-fetch after they finish
                    if (data.staleConnectionCount > 0 && !forceRefresh) {
                        setTimeout(() => {
                            fetch("/api/calendar/sync", {
                                method: "POST",
                                headers: { "Content-Type": "application/json" },
                                body: JSON.stringify({
                                    timeMin: new Date(currentWeekStart.getTime() - 7 * 24 * 60 * 60 * 1000).toISOString(),
                                    timeMax: new Date(currentWeekStart.getTime() + 14 * 24 * 60 * 60 * 1000).toISOString(),
                                }),
                            }).then(r => r.json()).then(d => {
                                if (d.events) setRawCalendarEvents(d.events);
                            }).catch(() => {});
                        }, 5000); // 5s delay for background refresh to finish
                    }
                } catch (e) {
                    console.error(
                        "Failed to parse calendar sync response:",
                        text.substring(0, 100),
                    );
                }
            }
        } catch (error) {
            console.error("Error fetching calendar events:", error);
        } finally {
            setIsFetchingCalendar(false);
            endSync();
        }
    }, [currentWeekStart, startSync, endSync]);

    // Weather fetch
    const fetchWeather = useCallback(async () => {
        if (!effectiveWeatherEnabled) return;
        if (!profile.weatherLat || !profile.weatherLon) return;
        try {
            const start = new Date(currentWeekStart.getTime() - 1 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
            const end = new Date(currentWeekStart.getTime() + 8 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
            const res = await fetch(`/api/weather?start=${start}&end=${end}`);
            if (res.ok) {
                const data = await res.json();
                if (data.hourly) setWeatherData(data.hourly);
            }
        } catch (e) {
            console.error("Weather fetch failed:", e);
        }
    }, [currentWeekStart, effectiveWeatherEnabled, profile.weatherLat, profile.weatherLon]);

    useEffect(() => {
        if (effectiveWeatherEnabled) fetchWeather();
    }, [fetchWeather, effectiveWeatherEnabled]);

    // Calendar Event Handlers
    const handleEventSave = async (eventData: any) => {
        const controller = new AbortController();
        const timeoutId = setTimeout(() => controller.abort(), 15000); // 15s timeout

        try {
            const method = eventData.id ? "PATCH" : "POST";
            const body = {
                ...eventData,
                eventId: eventData.id, // For PATCH
            };

            const res = await fetch("/api/calendar/events", {
                method,
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify(body),
                signal: controller.signal,
            });

            if (!res.ok) {
                const err = await res.json();
                throw new Error(err.error || "Failed to save event");
            }

            // Optimistically add/update from API response, then force refresh cache
            const data = await res.json();
            const isRecurring = !!(eventData.recurrence);
            if (data.event && !isRecurring) {
                // For non-recurring events: optimistic update before sync
                // For recurring events: skip — sync will fetch all expanded instances
                const ev = data.event;
                // Find calendar info from connections to fill in missing color/title
                const calInfo = connections.flatMap((c: any) =>
                    (c.calendars || []).map((cal: any) => ({ ...cal, provider: c.provider }))
                ).find((c: any) => c.id === (ev.calendarId || eventData.calendarId));
                const frontendEvent: CalendarEvent = {
                    id: ev.id,
                    title: ev.title,
                    startTime: ev.start?.dateTime || ev.start?.date || ev.startTime || '',
                    endTime: ev.end?.dateTime || ev.end?.date || ev.endTime || '',
                    source: ev.source || calInfo?.provider || 'google',
                    calendarId: ev.calendarId || eventData.calendarId,
                    calendarTitle: ev.calendarTitle || calInfo?.summary || calInfo?.title || '',
                    calendarColor: ev.backgroundColor || ev.calendarColor || calInfo?.backgroundColor || calInfo?.color || '#3b82f6',
                };
                setRawCalendarEvents(prev => {
                    if (eventData.id) {
                        return prev.map(e => e.id === eventData.id ? frontendEvent : e);
                    }
                    return [...prev, frontendEvent];
                });
            } else if (data.event && eventData.id) {
                // Recurring update: keep optimistic update for the edited instance only
                const ev = data.event;
                const calInfo = connections.flatMap((c: any) =>
                    (c.calendars || []).map((cal: any) => ({ ...cal, provider: c.provider }))
                ).find((c: any) => c.id === (ev.calendarId || eventData.calendarId));
                const frontendEvent: CalendarEvent = {
                    id: ev.id,
                    title: ev.title,
                    startTime: ev.start?.dateTime || ev.start?.date || ev.startTime || '',
                    endTime: ev.end?.dateTime || ev.end?.date || ev.endTime || '',
                    source: ev.source || calInfo?.provider || 'google',
                    calendarId: ev.calendarId || eventData.calendarId,
                    calendarTitle: ev.calendarTitle || calInfo?.summary || calInfo?.title || '',
                    calendarColor: ev.backgroundColor || ev.calendarColor || calInfo?.backgroundColor || calInfo?.color || '#3b82f6',
                };
                setRawCalendarEvents(prev => prev.map(e => e.id === eventData.id ? frontendEvent : e));
            }
            // Force refresh only the affected provider
            const connId = getConnectionIdForCalendar(eventData.calendarId);
            await fetchCalendarEvents(true, connId);
        } catch (error: any) {
            console.error("Error saving event:", error);
            if (error.name === "AbortError") {
                throw new Error("Request timed out. Please try again.");
            }
            throw error;
        } finally {
            clearTimeout(timeoutId);
        }
    };

    const handleEventDelete = async (eventId: string, calendarId: string, deleteMode?: string) => {
        try {
            const params = new URLSearchParams({ calendarId, eventId });
            if (deleteMode) params.set('deleteMode', deleteMode);

            const res = await fetch(
                `/api/calendar/events?${params.toString()}`,
                {
                    method: "DELETE",
                },
            );

            if (!res.ok) {
                const err = await res.json();
                throw new Error(err.error || "Failed to delete event");
            }

            // Optimistically remove affected events
            if (deleteMode === 'this') {
                setRawCalendarEvents(prev => prev.filter(e => e.id !== eventId));
            } else if (deleteMode === 'past') {
                // Remove this and past instances of the same recurring series
                const targetEvent = calendarEvents.find(e => e.id === eventId);
                if (targetEvent) {
                    const targetTime = new Date(targetEvent.startTime).getTime();
                    const seriesId = targetEvent.recurringEventId || eventId;
                    setRawCalendarEvents(prev => prev.filter(e => {
                        if (e.recurringEventId !== seriesId && e.id !== seriesId) return true;
                        return new Date(e.startTime).getTime() > targetTime;
                    }));
                } else {
                    setRawCalendarEvents(prev => prev.filter(e => e.id !== eventId));
                }
            } else if (deleteMode === 'future') {
                // Remove this and future instances of the same recurring series
                const targetEvent = calendarEvents.find(e => e.id === eventId);
                if (targetEvent) {
                    const targetTime = new Date(targetEvent.startTime).getTime();
                    const seriesId = targetEvent.recurringEventId || eventId;
                    setRawCalendarEvents(prev => prev.filter(e => {
                        if (e.recurringEventId !== seriesId && e.id !== seriesId) return true;
                        return new Date(e.startTime).getTime() < targetTime;
                    }));
                } else {
                    setRawCalendarEvents(prev => prev.filter(e => e.id !== eventId));
                }
            } else {
                // 'all' — remove all instances of the series
                const targetEvent = calendarEvents.find(e => e.id === eventId);
                const seriesId = targetEvent?.recurringEventId || eventId;
                setRawCalendarEvents(prev => prev.filter(e =>
                    e.id !== eventId && e.recurringEventId !== seriesId && e.id !== seriesId
                ));
            }
            // Force refresh only the affected provider
            const connId = getConnectionIdForCalendar(calendarId);
            await fetchCalendarEvents(true, connId);
        } catch (error) {
            console.error("Error deleting event:", error);
            throw error;
        }
    };

    const handleRecurrenceSave = async (taskId: string, recurrence: any) => {
        try {
            const res = await fetch("/api/tasks", {
                // Uses PATCH endpoint which handles ID in body
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    id: taskId,
                    ...recurrence,
                }),
            });

            if (!res.ok) {
                throw new Error("Failed to update recurrence");
            }

            const data = await res.json();

            // Update local state and REFRESH all tasks to show virtual instances
            setTasks((prev) => prev.map((t) => (t.id === taskId ? data.task : t)));
            await fetchTasks();
        } catch (error) {
            console.error(error);
            alert("Failed to save recurrence settings");
        }
    };

    const fetchMotivationalQuote = useCallback(async () => {
        if (profile.goalFallbackType !== "quote") return;

        const urls = profile.quoteSourceUrls && profile.quoteSourceUrls.length > 0
            ? profile.quoteSourceUrls
            : profile.quoteSourceUrl ? [profile.quoteSourceUrl] : [];

        // Strategy: try sources until one works
        for (const url of urls) {
            try {
                const res = await fetch(url);
                if (!res.ok) continue;
                const contentType = res.headers.get("content-type") || "";
                if (!contentType.includes("application/json")) continue;
                // Ensure proper UTF-8 decoding for quotes with special characters
                const rawText = await res.text();
                const data = JSON.parse(rawText);

                let quoteText = "";
                if (Array.isArray(data) && data.length > 0) {
                    const item = data[0];
                    quoteText = item.quote || item.text || item.content || (typeof item === 'string' ? item : "");
                    if (item.author) quoteText += ` - ${item.author}`;
                } else if (data && typeof data === 'object') {
                    quoteText = data.quote || data.text || data.content || "";
                    if (data.author) quoteText += ` - ${data.author}`;
                } else if (typeof data === 'string') {
                    quoteText = data;
                }

                if (quoteText) {
                    setMotivationalQuote(quoteText);
                    return; // Success!
                }
            } catch (error) {
                console.error(`Error fetching quote from ${url}:`, error);
            }
        }

        // Final fallback: use local curated quotes in user-selected languages
        const quoteLangs = profile.quoteLanguages && profile.quoteLanguages.length > 0
            ? profile.quoteLanguages
            : [profile.language || "en"];
        const randomLang = quoteLangs[Math.floor(Math.random() * quoteLangs.length)];
        const localQuote = getRandomLocalQuote(randomLang);
        if (localQuote) {
            setMotivationalQuote(`${localQuote.text} — ${localQuote.author}`);
        } else {
            setMotivationalQuote(randomLang === "de" ? "Bleib fokussiert und produktiv." : "Stay focused and productive.");
        }
    }, [profile.goalFallbackType, profile.quoteSourceUrl, profile.quoteSourceUrls, profile.language, profile.quoteLanguages]);

    // Fetch tasks on mount
    useEffect(() => {
        if (session) {
            fetchTasks();
            fetchConnections();
            fetchCalendarEvents();
            fetchMotivationalQuote();
        }
    }, [session]); // Removed fetchMotivationalQuote from deps to avoid re-runs

    // Auto-open settings to calendar tab after OAuth redirect
    useEffect(() => {
        const params = new URLSearchParams(window.location.search);
        if (params.get('openSettings') === 'calendars') {
            setShowSettings(true);
            setActiveTab('calendar');
            // Clean up URL
            const url = new URL(window.location.href);
            url.searchParams.delete('openSettings');
            url.searchParams.delete('calendar');
            window.history.replaceState({}, '', url.pathname);
            // Refresh connections to pick up the new one
            fetchConnections();
        }
    }, []);

    // Pull-sync from external task providers.
    //
    // Strategy: trigger on user-visible moments (tab gains focus, page becomes
    // visible, app mounts) plus a slow safety-net interval. The pull uses the
    // Microsoft Graph delta endpoint where possible, so each call is a few hundred
    // bytes when nothing changed — cheap to run on every focus event.
    //
    // Throttle: at most one pull every 5 seconds to absorb rapid focus toggles.
    useEffect(() => {
        if (!session) return;

        let lastSyncAt = 0;
        const MIN_INTERVAL_MS = 5_000;

        const runPullSync = async (reason: string) => {
            const now = Date.now();
            if (now - lastSyncAt < MIN_INTERVAL_MS) return;
            lastSyncAt = now;
            try {
                const res = await fetch("/api/tasks/sync");
                if (res.ok) {
                    const data = await res.json();
                    if (data.updated > 0 || data.deleted > 0 || data.created > 0) {
                        console.log(
                            `[SYNC] (${reason}) Pulled ${data.updated} updates, ${data.deleted} deletions, ${data.created || 0} new tasks`,
                        );
                        fetchTasks();
                    }
                }
            } catch (e) {
                console.error("[SYNC] Task sync error:", e);
            }
        };

        // Eager pull on mount
        runPullSync('mount');

        // Pull when the tab becomes visible or the window regains focus —
        // this is when the user actually expects fresh data.
        const onVisible = () => {
            if (document.visibilityState === 'visible') runPullSync('visibility');
        };
        const onFocus = () => runPullSync('focus');
        document.addEventListener('visibilitychange', onVisible);
        window.addEventListener('focus', onFocus);

        // Slow safety-net interval (covers the case of the tab being open & focused
        // for a long time while changes happen on another device).
        const interval = setInterval(() => runPullSync('interval'), 15 * 60 * 1000);

        return () => {
            document.removeEventListener('visibilitychange', onVisible);
            window.removeEventListener('focus', onFocus);
            clearInterval(interval);
        };
    }, [session]);

    // SSE real-time sync: listen for server-pushed task/list changes
    useEffect(() => {
        if (!session) return;
        let eventSource: EventSource | null = null;
        let reconnectTimeout: NodeJS.Timeout | null = null;

        const connect = () => {
            eventSource = new EventSource("/api/events/stream");

            eventSource.addEventListener("connected", () => {
                console.log("[SSE] Connected for real-time sync");
            });

            eventSource.addEventListener("tasks-changed", () => {
                console.log("[SSE] Tasks changed remotely, refetching...");
                fetchTasks();
            });

            eventSource.addEventListener("list-changed", () => {
                console.log("[SSE] Lists changed remotely, refetching...");
                fetchTasks();
            });

            eventSource.onerror = () => {
                console.log("[SSE] Connection lost, reconnecting in 5s...");
                eventSource?.close();
                reconnectTimeout = setTimeout(connect, 5000);
            };
        };

        connect();

        return () => {
            eventSource?.close();
            if (reconnectTimeout) clearTimeout(reconnectTimeout);
        };
    }, [session]);

    // Periodic background calendar cache refresh (every 2 minutes)
    useEffect(() => {
        if (!session) return;
        const interval = setInterval(
            async () => {
                try {
                    const now = new Date();
                    const res = await fetch("/api/calendar/background-sync", {
                        method: "POST",
                        headers: { "Content-Type": "application/json" },
                        body: JSON.stringify({
                            timeMin: new Date(
                                now.getTime() - 7 * 24 * 60 * 60 * 1000,
                            ).toISOString(),
                            timeMax: new Date(
                                now.getTime() + 14 * 24 * 60 * 60 * 1000,
                            ).toISOString(),
                        }),
                    });
                    if (res.ok) {
                        const data = await res.json();
                        if (data.queued > 0) {
                            // Stale connections are refreshing in background; re-read cache after delay
                            setTimeout(() => fetchCalendarEvents(), 10000);
                        }
                    }
                } catch (e) {
                    console.error("[SYNC] Calendar sync error:", e);
                }
            },
            15 * 60 * 1000, // 15 min — avoid iCloud rate limiting
        );
        return () => clearInterval(interval);
    }, [session, fetchCalendarEvents]);

    // Sync when tab regains focus (catches external changes in other apps)
    // Throttled: at most once per 5 minutes to avoid iCloud rate limiting
    const lastFocusSyncRef = useRef(0);
    useEffect(() => {
        if (!session) return;
        const handleVisibility = () => {
            if (!document.hidden) {
                const now = Date.now();
                if (now - lastFocusSyncRef.current < 5 * 60 * 1000) return; // throttle
                lastFocusSyncRef.current = now;
                fetchCalendarEvents();
                fetchTasks();
            }
        };
        document.addEventListener('visibilitychange', handleVisibility);
        return () => document.removeEventListener('visibilitychange', handleVisibility);
    }, [session, fetchCalendarEvents]);

    async function fetchConnections() {
        try {
            setIsLoading(true);
            const response = await fetch("/api/calendar/connections");
            if (response.ok) {
                const data = await response.json();
                setConnections(data.connections || []);
            }
        } catch (error) {
            console.error("Error fetching connections:", error);
        } finally {
            setIsLoading(false);
        }
    }

    const handleRemoveConnection = async (connectionId: string) => {
        console.log("Disconnecting connection:", connectionId);
        const res = await fetch(`/api/calendar/connections?id=${connectionId}`, {
            method: "DELETE",
        });

        if (res.ok) {
            // Update state immediately
            setConnections((prev) => prev.filter((c) => c.id !== connectionId));
            // Refresh connections to be sure
            fetchConnections();
            // Optionally refresh events too as they might be gone
            fetchCalendarEvents();
        } else {
            const err = await res.json();
            console.error("Failed to disconnect calendar", err);
            throw new Error(err.error || "Unknown error");
        }
    };

    // Refetch calendar events when week changes
    useEffect(() => {
        if (session) {
            fetchCalendarEvents();
        }
    }, [currentWeekStart, session, fetchCalendarEvents]);

    // Disable browser scroll restoration so Safari doesn't fight our initial scroll position
    useEffect(() => {
        if (typeof window !== 'undefined' && window.history.scrollRestoration) {
            window.history.scrollRestoration = 'manual';
        }
    }, []);

    // Scroll to preferred start hour (initial load + when user changes startHour)
    useEffect(() => {
        if (!isLoading) {
            const slotsPerHour = 60 / cellDuration;
            const slotHeight = getSlotHeight(cellDuration);
            const scrollOffset = workingHoursStart * slotsPerHour * slotHeight;

            // Single scroll — no interval, no enforcement loop.
            // We set scrollRestoration='manual' so the browser won't override this.
            const delay = isInitialScrollDone.current ? 50 : 300;
            const timer = setTimeout(() => {
                if (gridRef.current) gridRef.current.scrollTop = scrollOffset;
                intendedScrollTop.current = scrollOffset;
                isInitialScrollDone.current = true;
            }, delay);
            return () => clearTimeout(timer);
        }
    }, [isLoading, workingHoursStart, cellDuration]);

    // Update current time every 30 seconds for the "Now" line and clock
    useEffect(() => {
        const interval = setInterval(() => {
            setCurrentTime(new Date());
        }, 30000);
        return () => clearInterval(interval);
    }, []);

    // Intro hint: briefly reveal hidden header controls and bounce-scroll the main grid on first load
    useEffect(() => {
        const headerTimer = setTimeout(() => setShowIntroHints(false), 2200);

        const scrollTimer = setTimeout(() => {
            const grid = gridRef.current;
            if (!grid || grid.scrollHeight <= grid.clientHeight + 20) return;
            const baseTop = grid.scrollTop;
            const peek = Math.min(80, grid.scrollHeight - grid.clientHeight - baseTop);
            if (peek <= 10) return;
            const prevBehavior = grid.style.scrollBehavior;
            grid.style.scrollBehavior = "smooth";
            grid.scrollTo({ top: baseTop + peek });
            const back = setTimeout(() => {
                grid.scrollTo({ top: baseTop });
                setTimeout(() => { grid.style.scrollBehavior = prevBehavior; }, 600);
            }, 700);
            return () => { clearTimeout(back); grid.style.scrollBehavior = prevBehavior; };
        }, 900);

        return () => { clearTimeout(headerTimer); clearTimeout(scrollTimer); };
    }, []);

    // Mobile: show a sticky day bar by reading scroll position on the actual grid scroll container
    useEffect(() => {
        if (!isMobile || !profile.showTimeGrid) return;
        const grid = gridRef.current;
        if (!grid) return;

        const updateStickyDay = () => {
            const scrollTop = grid.scrollTop;
            setMobileStickyDayVisible(scrollTop > 40);

            // Find which day column header is at the top of the scroll container
            const columns = grid.querySelectorAll('.weekly-day-column[data-date]');
            let currentCol: Element | null = null;
            const gridTop = grid.getBoundingClientRect().top;

            columns.forEach(col => {
                const rect = col.getBoundingClientRect();
                // Column whose top is at or above the grid's top edge
                if (rect.top <= gridTop + 60) {
                    currentCol = col;
                }
            });

            if (currentCol) {
                const dateStr = (currentCol as Element).getAttribute('data-date');
                if (dateStr) {
                    const d = new Date(dateStr + 'T00:00:00');
                    const dayNames = profile.language === 'de'
                        ? ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa']
                        : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
                    const label = `${dayNames[d.getDay()]} ${d.getDate()}.${d.getMonth() + 1}.`;
                    setMobileStickyDay(label);
                }
            }
        };

        grid.addEventListener('scroll', updateStickyDay, { passive: true });
        updateStickyDay();
        return () => grid.removeEventListener('scroll', updateStickyDay);
    }, [isMobile, profile.showTimeGrid, currentWeekStart, viewDays, profile.language]);

    // Compute the goal date key: for "week" scope, normalize to Monday of that week; for "day", use the exact date
    const getGoalDateKey = useCallback(
        (date: Date): string => {
            const scope = profile.goalScope || "week";
            if (scope === "day") {
                const d = new Date(date);
                d.setHours(0, 0, 0, 0);
                return d.toISOString();
            }
            // Normalize to Monday of the week containing this date
            const d = new Date(date);
            d.setHours(0, 0, 0, 0);
            const day = d.getDay(); // 0=Sun, 1=Mon, ...
            const diff = day === 0 ? -6 : 1 - day; // Monday offset
            d.setDate(d.getDate() + diff);
            return d.toISOString();
        },
        [profile.goalScope],
    );

    const goalDateKey = useMemo(
        () => getGoalDateKey(currentWeekStart),
        [currentWeekStart, getGoalDateKey],
    );

    // Fetch goal for current week/day
    useEffect(() => {
        const fetchGoal = async () => {
            try {
                const res = await fetch(`/api/goal?weekStart=${goalDateKey}`);
                if (res.ok) {
                    const data = await res.json();
                    setGoal(data.goal);
                }
            } catch (err) {
                console.error("Failed to fetch goal:", err);
            }
        };
        fetchGoal();
    }, [goalDateKey]);

    const saveGoal = async (newGoal: string) => {
        setGoal(newGoal);
        try {
            const res = await fetch("/api/goal", {
                method: "PUT",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    weekStart: goalDateKey,
                    text: newGoal,
                }),
            });
            if (!res.ok) {
                console.error("Goal save failed:", res.status);
            }
        } catch (error) {
            console.error("Error saving goal:", error);
        }
    };



    // Horizontal scroll: convert vertical wheel to horizontal in someday area
    // Callback ref ensures handler is attached as soon as element mounts
    const somedayWheelCleanup = useRef<(() => void) | null>(null);
    const somedaySectionRefCb = useCallback((node: HTMLElement | null) => {
        // Cleanup previous
        if (somedayWheelCleanup.current) {
            somedayWheelCleanup.current();
            somedayWheelCleanup.current = null;
        }
        somedaySectionRef.current = node;
        if (!node) return;

        const handler = (e: WheelEvent) => {
            const grid = somedayGridRef.current;
            if (!grid) return;

            // Let native horizontal scroll (trackpad) pass through
            if (Math.abs(e.deltaX) > Math.abs(e.deltaY)) return;
            if (e.deltaY === 0) return;

            // Only convert if grid has horizontal overflow
            if (grid.scrollWidth <= grid.clientWidth + 1) return;

            // Check boundaries - allow page scroll when at edges
            const atLeft = grid.scrollLeft <= 0;
            const atRight = grid.scrollLeft + grid.clientWidth >= grid.scrollWidth - 1;
            if (e.deltaY < 0 && atLeft) return;
            if (e.deltaY > 0 && atRight) return;

            e.preventDefault();
            grid.scrollLeft += e.deltaY;
        };

        node.addEventListener("wheel", handler, { passive: false });
        somedayWheelCleanup.current = () => node.removeEventListener("wheel", handler);
    }, []);
    const saveSetting = async (key: string, value: any) => {
        // Per-device settings: save to cookie ONLY (not DB) so each device keeps its own value
        if (DEVICE_SETTINGS_KEYS.includes(key)) {
            setCookie(`setting_${key}`, String(value));
            setProfile((p: any) => ({ ...p, [key]: value })); // still update profile so rendering reacts immediately
            return; // Don't write to DB — that would overwrite other devices
        }
        // Also persist to device cookie so this device remembers its own preference on reload
        if (DEVICE_ALSO_COOKIE_KEYS.includes(key)) {
            setCookie(`setting_${key}`, String(value));
        }
        // Keep profile object in sync so the debounced auto-save never sends stale values
        setProfile((p: any) => ({ ...p, [key]: value }));
        try {
            await fetch("/api/user/profile", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ [key]: value }),
            });
        } catch (err) {
            console.error(`Failed to save setting ${key}:`, err);
        }
    };

    const handleSettingsChanged = (newSettings: any) => {
        setShowTimeGrid(newSettings.showTimeGrid);
        setCellDuration(newSettings.cellDuration);
        setViewStyle(newSettings.viewStyle);
        setLanguage(newSettings.language);
        setDateFormat(newSettings.dateFormat);
        setTimeFormat(newSettings.timeFormat);
        setStartHour(newSettings.startHour);
        setEndHour(newSettings.endHour);
        setFontSize(newSettings.fontSize);
        setShowNextTask(newSettings.showNextTask);
        setShowSomeday(newSettings.showSomeday);
        setShowAllDay(newSettings.showAllDayEvents);
        setShowSchedule(newSettings.showSchedule);
        if (newSettings.weekdayFormat) setWeekdayFormat(newSettings.weekdayFormat);
        if (newSettings.weekdayCase) setWeekdayCase(newSettings.weekdayCase);
        if (newSettings.customWeekdayNames !== undefined) setCustomWeekdayNames(newSettings.customWeekdayNames);
        setHeadlineFont(newSettings.headlineFont);
        setHeadlineFontSize(newSettings.headlineFontSize);
        setHeadlineFontWeight(newSettings.headlineFontWeight);
        setDateFontFamily(newSettings.dateFontFamily);
        setDateFontSize(newSettings.dateFontSize);
        setDateFontWeight(newSettings.dateFontWeight);
        setTimeTaskFontFamily(newSettings.timeTaskFontFamily);
        setTimeTaskFontSize(newSettings.timeTaskFontSize);
        setTimeTaskFontWeight(newSettings.timeTaskFontWeight);
        setBodyFont(newSettings.bodyFont);
        setTaskFontFamily(newSettings.taskFontFamily);
        setTaskFontSize(newSettings.taskFontSize);
        setTaskFontWeight(newSettings.taskFontWeight);
        if (newSettings.eventFontFamily)
            setEventFontFamily(newSettings.eventFontFamily);
        if (newSettings.eventFontSize) setEventFontSize(newSettings.eventFontSize);
        if (newSettings.eventFontWeight)
            setEventFontWeight(newSettings.eventFontWeight);
        if (newSettings.fontWeight) setFontWeight(newSettings.fontWeight);
        if (newSettings.weekendColorSat)
            setWeekendColorSat(newSettings.weekendColorSat);
        if (newSettings.weekendColorSun)
            setWeekendColorSun(newSettings.weekendColorSun);

        setProfile((prev: any) => ({
            ...prev,
            ...newSettings,
            weekdayColor: newSettings.weekdayColor || prev.weekdayColor,
            dateColor: newSettings.dateColor || prev.dateColor,
            taskColor: newSettings.taskColor || prev.taskColor,
            todayHighlightColor:
                newSettings.todayHighlightColor || prev.todayHighlightColor,
            eventFontFamily: newSettings.eventFontFamily || prev.eventFontFamily,
            eventFontSize: newSettings.eventFontSize || prev.eventFontSize,
            eventFontWeight: newSettings.eventFontWeight || prev.eventFontWeight,
        }));

        // Custom start/end hours might affect task placement if we filter strictly
        fetchTasks();
    };

    const fetchUserInfo = async () => {
        try {
            const res = await fetch("/api/user/profile");
            if (res.ok) {
                const data = await res.json();
                if (data.user) {
                    setProtectEventTimes(data.user.protectEventTimes || false);
                    setTimeFormat(data.user.timeFormat || "12h");
                    setDateFormat(data.user.dateFormat || "MM/dd/yyyy");
                    setLanguage(data.user.language || "en");
                    if (data.user.startHour !== undefined)
                        setStartHour(data.user.startHour);
                    if (data.user.endHour !== undefined)
                        setEndHour(data.user.endHour);
                    if (data.user.viewStyle !== undefined) {
                        setViewStyle(data.user.viewStyle as ViewStyle);
                        setShowTimeGrid(data.user.showTimeGrid ?? true);
                    }
                    if (data.user.kanbanStages) {
                        try {
                            const parsed = JSON.parse(data.user.kanbanStages);
                            if (Array.isArray(parsed) && parsed.length > 0) setKanbanStages(parsed);
                        } catch { /* use defaults */ }
                    }
                    if (data.user.viewDays !== undefined) {
                        savedViewDaysRef.current = data.user.viewDays;
                        const w = window.innerWidth, h = window.innerHeight;
                        if (w <= 768) setViewDays(h > w ? 1 : 3);
                        else if (w <= 1024) setViewDays(Math.min(data.user.viewDays, 5));
                        else setViewDays(data.user.viewDays);
                    }
                    if (data.user.cellDuration !== undefined)
                        setCellDuration(data.user.cellDuration as CellDuration);

                    // Cookie overrides for per-device settings (always apply, even if DB has no value)
                    const cookieViewDays = getCookie("setting_viewDays");
                    if (cookieViewDays) {
                        const v = Number(cookieViewDays);
                        savedViewDaysRef.current = v;
                        const w = window.innerWidth, h = window.innerHeight;
                        if (w <= 768) setViewDays(h > w ? 1 : 3);
                        else if (w <= 1024) setViewDays(Math.min(v, 5));
                        else setViewDays(v);
                    }
                    if (data.user.weekdayFormat) {
                        setProfile((prev: any) => ({ ...prev, weekdayFormat: data.user.weekdayFormat }));
                    }
                    if (data.user.customWeekdayNames) {
                        setProfile((prev: any) => ({ ...prev, customWeekdayNames: data.user.customWeekdayNames }));
                    }
                    const cookieCellDuration = getCookie("setting_cellDuration");
                    if (cookieCellDuration) setCellDuration(Number(cookieCellDuration) as CellDuration);
                    const cookieStartHour = getCookie("setting_startHour");
                    if (cookieStartHour) setStartHour(Number(cookieStartHour));
                    const cookieEndHour = getCookie("setting_endHour");
                    if (cookieEndHour) setEndHour(Number(cookieEndHour));
                    setShowNextTask(data.user.showNextTask || false);
                    setCalendarEditMode(data.user.calendarEditMode || false);
                    if (data.user.fontSize)
                        setFontSize(data.user.fontSize as "S" | "M" | "L");
                    // Cookie wins over DB for per-device settings
                    const cookieFontSize2 = getCookie("setting_fontSize");
                    if (cookieFontSize2) setFontSize(cookieFontSize2 as "S" | "M" | "L");

                    if (data.user.showSomeday !== undefined)
                        setShowSomeday(data.user.showSomeday);
                    if (data.user.showAllDayEvents !== undefined)
                        setShowAllDay(data.user.showAllDayEvents);
                    if (data.user.showSchedule !== undefined)
                        setShowSchedule(data.user.showSchedule);
                    if (data.user.weekdayFormat)
                        setWeekdayFormat(data.user.weekdayFormat as any);
                    if (data.user.weekdayCase)
                        setWeekdayCase(data.user.weekdayCase as any);
                    if (data.user.customWeekdayNames)
                        setCustomWeekdayNames(data.user.customWeekdayNames);
                    if (data.user.hourLabelFormat)
                        setHourLabelFormat(data.user.hourLabelFormat as "short" | "full");
                    if (data.user.showSubHourSlots !== undefined)
                        setShowSubHourSlots(data.user.showSubHourSlots);
                    // Cookie wins over DB for showSubHourSlots (per-device)
                    const _cSH2 = getCookie("setting_showSubHourSlots");
                    if (_cSH2 !== null) setShowSubHourSlots(_cSH2 === "true");
                    if (data.user.allDayPosition)
                        setAllDayPosition(data.user.allDayPosition as "above" | "below");
                    if (data.user.viewSettings) setViewSettings(data.user.viewSettings);
                    if (data.user.headlineFont) setHeadlineFont(data.user.headlineFont);
                    if (data.user.headlineFontSize)
                        setHeadlineFontSize(data.user.headlineFontSize);
                    if (data.user.headlineFontWeight)
                        setHeadlineFontWeight(data.user.headlineFontWeight);
                    if (data.user.dateFontFamily)
                        setDateFontFamily(data.user.dateFontFamily);
                    if (data.user.dateFontSize) setDateFontSize(data.user.dateFontSize);
                    if (data.user.dateFontWeight)
                        setDateFontWeight(data.user.dateFontWeight);
                    if (data.user.timeTaskFontFamily)
                        setTimeTaskFontFamily(data.user.timeTaskFontFamily);
                    if (data.user.timeTaskFontSize)
                        setTimeTaskFontSize(data.user.timeTaskFontSize);
                    if (data.user.timeTaskFontWeight)
                        setTimeTaskFontWeight(data.user.timeTaskFontWeight);
                    if (data.user.bodyFont) setBodyFont(data.user.bodyFont);
                    if (data.user.taskFontFamily)
                        setTaskFontFamily(data.user.taskFontFamily);
                    if (data.user.taskFontSize) setTaskFontSize(data.user.taskFontSize);
                    if (data.user.taskFontWeight)
                        setTaskFontWeight(data.user.taskFontWeight);
                    if (data.user.eventFontFamily)
                        setEventFontFamily(data.user.eventFontFamily);
                    if (data.user.eventFontSize)
                        setEventFontSize(data.user.eventFontSize);
                    if (data.user.eventFontWeight)
                        setEventFontWeight(data.user.eventFontWeight);
                    if (data.user.fontWeight) setFontWeight(data.user.fontWeight);
                    if (data.user.weekendColorSat)
                        setWeekendColorSat(data.user.weekendColorSat);
                    if (data.user.weekendColorSun)
                        setWeekendColorSun(data.user.weekendColorSun);

                    setProfile((prev: any) => ({
                        ...prev,
                        ...data.user,
                        name: data.user.name || prev.name,
                        email: data.user.email || prev.email,
                        weekdayColor: data.user.weekdayColor || "#888888",
                        dateColor: data.user.dateColor || "#888888",
                        taskColor: data.user.taskColor || "#333333",
                        todayHighlightColor: data.user.todayHighlightColor || "#f0fafa",
                    }));

                    // Apply start day offset (e.g. -1 for yesterday) — only for multi-day views
                    // On single-day view (phones), always start on today
                    const effectiveViewDays = (() => {
                        const width = window.innerWidth;
                        if (width <= 480) return 1;
                        if (width <= 768) return 3;
                        if (width <= 1024) return Math.min(data.user.viewDays || 7, 5);
                        return data.user.viewDays || 7;
                    })();
                    if (data.user.startDayOffset && data.user.startDayOffset !== 0 && effectiveViewDays > 1) {
                        const d = new Date();
                        d.setHours(0, 0, 0, 0);
                        d.setDate(d.getDate() + data.user.startDayOffset);
                        setCurrentWeekStart(d);
                    }

                    if (data.user.focusTimerDuration)
                        setFocusTimerDuration(data.user.focusTimerDuration);
                    if (data.user.focusBreakDuration)
                        setFocusBreakDuration(data.user.focusBreakDuration);
                    if (data.user.showTimeGrid !== undefined)
                        setShowTimeGrid(data.user.showTimeGrid);
                    if (data.user.cellDuration)
                        setCellDuration(data.user.cellDuration as CellDuration);
                    if (data.user.viewStyle)
                        setViewStyle(data.user.viewStyle as ViewStyle);

                    // Cookie overrides for settings that are also device-local
                    const _cVS2 = getCookie("setting_viewStyle");
                    if (_cVS2) { setViewStyle(_cVS2 as ViewStyle); setProfile((p: any) => ({ ...p, viewStyle: _cVS2, showTimeGrid: _cVS2 === "simple" || _cVS2 === "calendar" })); }
                    const _cTG2 = getCookie("setting_showTimeGrid");
                    if (_cTG2 !== null) setShowTimeGrid(_cTG2 === "true");
                    const _cSDO2 = getCookie("setting_startDayOffset");
                    if (_cSDO2 !== null) {
                        const offset = Number(_cSDO2);
                        setProfile((p: any) => ({ ...p, startDayOffset: offset }));
                        if (offset !== 0) {
                            const d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() + offset);
                            setCurrentWeekStart(d);
                        }
                    }
                }
            }
        } catch (e) {
            console.error(e);
        }
    };

    useEffect(() => {
        fetchUserInfo();
    }, []);

    async function fetchSomedayLists() {
        try {
            const response = await fetch("/api/someday-lists");
            if (response.ok) {
                const data = await response.json();
                // Map tasks is handled in fetchTasks or we can merge here if needed.
                // But fetchTasks fetches ALL tasks.
                // Optimally we fetch lists, then tasks, then merge.
                // For now, let's just set the lists structure.
                setSomedayLists(
                    data.lists.map((l: any) => ({
                        id: l.id,
                        title: l.title,
                        tab: l.tab || null,
                        color: l.color || null,
                        icon: l.icon || null,
                        tasks: l.tasks || [],
                        externalId: l.externalId || null,
                        externalProvider: l.externalProvider || null,
                    })),
                );
                return data.lists;
            }
        } catch (error) {
            console.error("Error fetching someday lists:", error);
            return [];
        }
    }

    async function fetchProjects() {
        try {
            const res = await fetch("/api/projects");
            if (res.ok) {
                const data = await res.json();
                const updatedProjects = data.projects || [];
                setProjects(updatedProjects);

                // Update project references on tasks so color changes take effect immediately
                const projectMap = new Map<string, { id: string; name: string; icon?: string | null; color?: string | null }>(
                    updatedProjects.map((p: any) => [p.id, p])
                );
                setTasks(prev => prev.map(t => {
                    if (t.projectId && projectMap.has(t.projectId)) {
                        return { ...t, project: projectMap.get(t.projectId) || null };
                    }
                    return t;
                }));
                setSomedayLists(prev => prev.map(list => ({
                    ...list,
                    tasks: list.tasks.map(t => {
                        if (t.projectId && projectMap.has(t.projectId)) {
                            return { ...t, project: projectMap.get(t.projectId) || null };
                        }
                        return t;
                    }),
                })));
            }
        } catch (error) {
            console.error("Error fetching projects:", error);
        }
    }

    async function fetchTasks() {
        startSync();
        try {
            const [tasksResponse, listsResponse] = await Promise.all([
                fetch("/api/tasks"),
                fetch("/api/someday-lists"), // Fetch lists in parallel
            ]);
            // Also fetch projects in background
            fetchProjects();

            let fetchedLists: SomedayList[] = [];
            if (listsResponse.ok) {
                const listData = await listsResponse.json();
                fetchedLists = listData.lists.map((l: any) => ({
                    id: l.id,
                    title: l.title,
                    tab: l.tab || null,
                    color: l.color || null,
                    icon: l.icon || null,
                    tasks: [],
                    externalId: l.externalId || null,
                    externalProvider: l.externalProvider || null,
                }));
            }

            // If no lists exist, maybe create default 'Someday'?
            // TeuxDeux usually starts with one.
            // If DB is empty, maybe create one?
            // For now, if empty, we might show empty.
            if (fetchedLists.length === 0) {
                // Optionally create default list if none exist?
                // Let's stick to what's in DB.
            }

            if (tasksResponse.ok) {
                const data = await tasksResponse.json();
                const fetchedTasks = data.tasks.map((t: any) => ({
                    ...t,
                    createdAt: new Date(t.createdAt),
                    updatedAt: new Date(t.updatedAt),
                    recurrenceDays: t.recurrenceDays ? (typeof t.recurrenceDays === 'string' ? JSON.parse(t.recurrenceDays) : t.recurrenceDays) : null,
                }));

                // Calendar tasks: anything NOT in a someday list (includes tasks with scheduledDate OR dayOfWeek)
                const dayTasks = fetchedTasks.filter((t: Task) => !t.somedayListId);
                const somedayTasks = fetchedTasks.filter((t: Task) => t.somedayListId);

                setTasks(dayTasks);

                // Populate lists with tasks
                const listIds = new Set(fetchedLists.map((l: SomedayList) => l.id));
                const orphanedSomedayTasks = somedayTasks.filter(
                    (t: Task) => !listIds.has(t.somedayListId || ""),
                );

                const populatedLists = fetchedLists.map((list) => ({
                    ...list,
                    tasks: somedayTasks.filter((t: Task) => t.somedayListId === list.id && !t.parentTaskId),
                }));

                // Rescue orphaned someday tasks: if their list was deleted, move them to calendar
                if (orphanedSomedayTasks.length > 0) {
                    console.warn(
                        `[RESCUE] Found ${orphanedSomedayTasks.length} orphaned someday tasks, recovering to calendar`,
                    );
                    const rescuedTasks = orphanedSomedayTasks.map((t: Task) => ({
                        ...t,
                        somedayListId: null,
                        scheduledDate: t.scheduledDate || new Date().toISOString(),
                    }));
                    setTasks((prev) => [...prev, ...rescuedTasks]);
                    // Persist the rescue to DB
                    for (const t of orphanedSomedayTasks) {
                        fetch("/api/tasks", {
                            method: "PATCH",
                            headers: { "Content-Type": "application/json" },
                            body: JSON.stringify({
                                id: t.id,
                                somedayListId: null,
                                scheduledDate: new Date().toISOString(),
                            }),
                        }).catch((e) =>
                            console.error("Failed to rescue orphaned task:", e),
                        );
                    }
                }

                setSomedayLists(populatedLists);
            }
        } catch (error) {
            console.error("Error fetching data:", error);
        } finally {
            setIsLoading(false);
            endSync();
        }
    }

    // Get visible days based on current view setting
    const getVisibleDays = useCallback(() => {
        const days: Date[] = [];
        for (let i = 0; i < viewDays; i++) {
            days.push(new Date(currentWeekStart.getTime() + i * 24 * 60 * 60 * 1000));
        }
        return days;
    }, [currentWeekStart, viewDays]);

    // Get tasks for a specific date
    const getTasksForDate = useCallback(
        (date: Date): Task[] => {
            const dateStr = formatDateToISO(date); // Use local date formatting
            return tasks
                .filter((task) => {
                    if (!task.scheduledDate) return false;
                    // Exclude sub-tasks from top-level list (they render inside their parent)
                    if (task.parentTaskId) return false;
                    // Hide completed tasks if setting is off
                    if (!effectiveShowCompletedTasks && task.completed) return false;
                    if (activeProjectFilter && task.projectId !== activeProjectFilter) return false;
                    // Use string comparison to avoid timezone shifts
                    const taskDateStr =
                        typeof task.scheduledDate === "string"
                            ? task.scheduledDate.substring(0, 10)
                            : formatDateToISO(new Date(task.scheduledDate));
                    return taskDateStr === dateStr;
                })
                .sort((a, b) => {
                    // Sort by time if available
                    if (a.startTime && b.startTime) {
                        return a.startTime.localeCompare(b.startTime);
                    }
                    if (a.startTime) return -1;
                    if (b.startTime) return 1;
                    return a.order - b.order;
                });
        },
        [tasks, effectiveShowCompletedTasks, activeProjectFilter],
    );

    // Get tasks for a specific time slot
    const getTasksForSlot = useCallback(
        (date: Date, slot: string): Task[] => {
            const dateStr = formatDateToISO(date);
            return tasks.filter((task) => {
                if (!task.scheduledDate) return false;
                // Exclude sub-tasks from top-level list
                if (task.parentTaskId) return false;
                // Hide completed tasks if setting is off
                if (!effectiveShowCompletedTasks && task.completed) return false;
                if (activeProjectFilter && task.projectId !== activeProjectFilter) return false;
                // Use string comparison to avoid timezone shifts
                const taskDateStr =
                    typeof task.scheduledDate === "string"
                        ? task.scheduledDate.substring(0, 10)
                        : formatDateToISO(new Date(task.scheduledDate));
                if (taskDateStr !== dateStr || !task.startTime) return false;

                // Extract hour:minute from task start time and compare with slot
                const [taskHour, taskMinute] = task.startTime.split(":").map(Number);
                const taskStart = taskHour * 60 + taskMinute;

                const [slotHour, slotMinute] = slot.split(":").map(Number);
                const slotStart = slotHour * 60 + slotMinute;
                const slotEnd = slotStart + effectiveCellDuration;

                return taskStart >= slotStart && taskStart < slotEnd;
            });
        },
        [tasks, effectiveCellDuration, effectiveShowCompletedTasks, activeProjectFilter],
    );

    // Get calendar events for a specific date
    const getEventsForDate = useCallback(
        (date: Date): CalendarEvent[] => {
            return calendarEvents.filter((event) => {
                // Skip all-day events (handled separately)
                if (isAllDayEvent(event)) return false;

                const eventDate = new Date(event.startTime);
                return isSameDay(eventDate, date);
            });
        },
        [calendarEvents],
    );

    // Get calendar events for a specific time slot
    const getEventsForSlot = useCallback(
        (date: Date, slot: string): CalendarEvent[] => {
            return calendarEvents.filter((event) => {
                // Skip all-day events (handled separately)
                const isAllDay = isAllDayEvent(event);
                if (isAllDay) return false;

                // During drag, use the drag state's current start time for slot assignment
                const isDraggedEvent = eventDragState?.eventId === event.id && eventDragState?.hasMoved && eventDragState?.mode === 'move';
                const startTime = isDraggedEvent ? eventDragState!.currentStartTime : event.startTime;

                const eventDate = new Date(startTime);
                if (!isSameDay(eventDate, date)) return false;

                // Extract hour:minute from event start time and compare with slot
                const eventHour = eventDate.getHours();
                const eventMinute = eventDate.getMinutes();

                // Match if event starts within this slot
                const [slotHour, slotMinute] = slot.split(":").map(Number);
                const slotStart = slotHour * 60 + slotMinute;
                const slotEnd = slotStart + effectiveCellDuration;
                const eventStart = eventHour * 60 + eventMinute;

                return eventStart >= slotStart && eventStart < slotEnd;
            });
        },
        [calendarEvents, effectiveCellDuration, eventDragState],
    );

    // Precompute overlap layout: { [eventId]: { column, totalColumns } }
    const eventOverlapLayout = useMemo(() => {
        const layout: Record<string, { column: number; totalColumns: number }> = {};
        // Group events by day
        const dayMap = new Map<string, CalendarEvent[]>();
        for (const event of calendarEvents) {
            if (isAllDayEvent(event)) continue;
            const d = new Date(event.startTime);
            const key = `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
            if (!dayMap.has(key)) dayMap.set(key, []);
            dayMap.get(key)!.push(event);
        }
        for (const events of dayMap.values()) {
            // Sort by start time, then by duration (longer first)
            events.sort((a, b) => {
                const diff = new Date(a.startTime).getTime() - new Date(b.startTime).getTime();
                if (diff !== 0) return diff;
                return (new Date(b.endTime).getTime() - new Date(b.startTime).getTime()) -
                       (new Date(a.endTime).getTime() - new Date(a.startTime).getTime());
            });
            // Build overlap groups using a greedy column assignment
            const columns: { end: number; eventId: string }[][] = [];
            for (const event of events) {
                const start = new Date(event.startTime).getTime();
                const end = new Date(event.endTime).getTime();
                // Find first column where this event doesn't overlap
                let placed = false;
                for (let col = 0; col < columns.length; col++) {
                    const lastInCol = columns[col][columns[col].length - 1];
                    if (lastInCol.end <= start) {
                        columns[col].push({ end, eventId: event.id });
                        placed = true;
                        break;
                    }
                }
                if (!placed) {
                    columns.push([{ end, eventId: event.id }]);
                }
            }
            // Now find the max columns each event actually shares with
            // For each event, find all events that overlap it and determine the group width
            for (const event of events) {
                const start = new Date(event.startTime).getTime();
                const end = new Date(event.endTime).getTime();
                // Count how many columns have events overlapping this time range
                let overlappingCols = 0;
                for (const col of columns) {
                    for (const item of col) {
                        const itemStart = calendarEvents.find(e => e.id === item.eventId);
                        if (itemStart) {
                            const iStart = new Date(itemStart.startTime).getTime();
                            const iEnd = new Date(itemStart.endTime).getTime();
                            if (iStart < end && iEnd > start) {
                                overlappingCols++;
                                break;
                            }
                        }
                    }
                }
                // Find which column this event is in
                let eventCol = 0;
                for (let col = 0; col < columns.length; col++) {
                    if (columns[col].some(item => item.eventId === event.id)) {
                        eventCol = col;
                        break;
                    }
                }
                layout[event.id] = { column: eventCol, totalColumns: Math.max(overlappingCols, 1) };
            }
        }
        return layout;
    }, [calendarEvents]);

    // Calculate event duration in pixels for proper height display
    const getEventDuration = (event: CalendarEvent): number => {
        if (isAllDayEvent(event)) return 0; // All-day events handled separately

        const start = new Date(event.startTime);
        const end = new Date(event.endTime);
        const durationMinutes = (end.getTime() - start.getTime()) / (1000 * 60);

        // Guard against NaN or negative durations (missing/invalid end time)
        if (!isFinite(durationMinutes) || durationMinutes <= 0) {
            return getSlotHeight(effectiveCellDuration); // Default to one slot height
        }

        // Calculate height based on duration and slot height
        const pixelsPerMinute = getSlotHeight(effectiveCellDuration) / effectiveCellDuration;
        return Math.max(
            durationMinutes * pixelsPerMinute,
            getSlotHeight(effectiveCellDuration),
        );
    };

    // Snap minutes to nearest 5-minute increment
    const snapMinutes = (mins: number) => Math.round(mins / 5) * 5;

    // Handle calendar event drag/resize
    const handleEventDragStart = (e: React.MouseEvent, event: CalendarEvent, mode: 'move' | 'resize-top' | 'resize-bottom') => {
        if (!event.editable) return;
        e.preventDefault();
        e.stopPropagation();
        setEventDragState({
            eventId: event.id,
            mode,
            startY: e.clientY,
            startX: e.clientX,
            originalStartTime: event.startTime,
            originalEndTime: event.endTime,
            currentStartTime: event.startTime,
            currentEndTime: event.endTime,
            calendarId: event.calendarId,
            source: event.source,
        });
    };

    useEffect(() => {
        if (!eventDragState) return;
        const pixelsPerMinute = getSlotHeight(effectiveCellDuration) / effectiveCellDuration;

        const handleMouseMove = (e: MouseEvent) => {
            const deltaY = e.clientY - eventDragState.startY;
            const deltaX = e.clientX - eventDragState.startX;
            // Require minimum 3px movement to start actual drag
            if (!eventDragState.hasMoved && Math.abs(deltaY) < 3 && Math.abs(deltaX) < 3) return;
            if (!eventDragState.hasMoved) {
                setEventDragState(prev => prev ? { ...prev, hasMoved: true } : null);
            }
            const deltaMinutes = snapMinutes(deltaY / pixelsPerMinute);
            const origStart = new Date(eventDragState.originalStartTime);
            const origEnd = new Date(eventDragState.originalEndTime);

            if (eventDragState.mode === 'move') {
                // Detect day column under cursor for cross-day drag
                let dayOffset = 0;
                const dayColumns = document.querySelectorAll('.weekly-day-column');
                if (dayColumns.length > 0) {
                    const origDate = `${origStart.getFullYear()}-${String(origStart.getMonth() + 1).padStart(2, '0')}-${String(origStart.getDate()).padStart(2, '0')}`;
                    let origColIndex = -1;
                    let hoverColIndex = -1;
                    dayColumns.forEach((col, i) => {
                        const rect = col.getBoundingClientRect();
                        const colDate = col.getAttribute('data-date');
                        if (colDate === origDate) origColIndex = i;
                        if (e.clientX >= rect.left && e.clientX <= rect.right) hoverColIndex = i;
                    });
                    if (origColIndex >= 0 && hoverColIndex >= 0) {
                        dayOffset = hoverColIndex - origColIndex;
                    }
                }
                const newStart = new Date(origStart.getTime() + deltaMinutes * 60000 + dayOffset * 86400000);
                const newEnd = new Date(origEnd.getTime() + deltaMinutes * 60000 + dayOffset * 86400000);
                setEventDragState(prev => prev ? { ...prev, currentStartTime: newStart.toISOString(), currentEndTime: newEnd.toISOString() } : null);
            } else if (eventDragState.mode === 'resize-bottom') {
                const newEnd = new Date(origEnd.getTime() + deltaMinutes * 60000);
                if (newEnd.getTime() > origStart.getTime() + 5 * 60000) {
                    setEventDragState(prev => prev ? { ...prev, currentEndTime: newEnd.toISOString() } : null);
                }
            } else if (eventDragState.mode === 'resize-top') {
                const newStart = new Date(origStart.getTime() + deltaMinutes * 60000);
                if (newStart.getTime() < origEnd.getTime() - 5 * 60000) {
                    setEventDragState(prev => prev ? { ...prev, currentStartTime: newStart.toISOString() } : null);
                }
            }
        };

        const handleMouseUp = async () => {
            if (!eventDragState) return;
            const startChanged = eventDragState.currentStartTime !== eventDragState.originalStartTime;
            const endChanged = eventDragState.currentEndTime !== eventDragState.originalEndTime;
            // Set drag-ended ref immediately (before async) to prevent click from opening popup
            if (eventDragState.hasMoved) {
                dragJustEndedRef.current = true;
                setTimeout(() => { dragJustEndedRef.current = false; }, 300);
            }
            if (eventDragState.hasMoved && (startChanged || endChanged)) {
                // Optimistically update the UI
                setRawCalendarEvents(prev => prev.map(ev =>
                    ev.id === eventDragState.eventId
                        ? { ...ev, startTime: eventDragState.currentStartTime, endTime: eventDragState.currentEndTime }
                        : ev
                ));

                // Check if this is a recurring event — if so, ask before saving
                const draggedEvent = calendarEvents.find(e => e.id === eventDragState.eventId);
                if (draggedEvent?.isRecurring) {
                    setRecurringDragEditMode('this');
                    setPendingRecurringDrag({
                        eventId: eventDragState.eventId,
                        calendarId: eventDragState.calendarId || '',
                        recurringEventId: draggedEvent.recurringEventId,
                        startTime: eventDragState.currentStartTime,
                        endTime: eventDragState.currentEndTime,
                        originalStartTime: eventDragState.originalStartTime,
                        originalEndTime: eventDragState.originalEndTime,
                    });
                } else {
                    // Non-recurring: save immediately
                    try {
                        const res = await fetch("/api/calendar/events", {
                            method: "PATCH",
                            headers: { "Content-Type": "application/json" },
                            body: JSON.stringify({
                                calendarId: eventDragState.calendarId,
                                eventId: eventDragState.eventId,
                                start: { dateTime: eventDragState.currentStartTime },
                                end: { dateTime: eventDragState.currentEndTime },
                            }),
                        });
                        if (!res.ok) {
                            setRawCalendarEvents(prev => prev.map(ev =>
                                ev.id === eventDragState.eventId
                                    ? { ...ev, startTime: eventDragState.originalStartTime, endTime: eventDragState.originalEndTime }
                                    : ev
                            ));
                        }
                    } catch {
                        setRawCalendarEvents(prev => prev.map(ev =>
                            ev.id === eventDragState.eventId
                                ? { ...ev, startTime: eventDragState.originalStartTime, endTime: eventDragState.originalEndTime }
                                : ev
                        ));
                    }
                }
            }
            setEventDragState(null);
        };

        document.addEventListener('mousemove', handleMouseMove);
        document.addEventListener('mouseup', handleMouseUp);
        return () => {
            document.removeEventListener('mousemove', handleMouseMove);
            document.removeEventListener('mouseup', handleMouseUp);
        };
    }, [eventDragState, effectiveCellDuration, calendarEvents]);

    // Slot drag-to-create: mousemove + mouseup on document (always active, ref-gated)
    const effectiveCellDurationRef = useRef(effectiveCellDuration);
    effectiveCellDurationRef.current = effectiveCellDuration;
    useEffect(() => {
        const handleMouseMove = (e: MouseEvent) => {
            const drag = slotDragRef.current;
            if (!drag) return;
            // Require minimum movement to distinguish from click
            if (!drag.active && Math.abs(e.clientY - drag.startY) < 5) return;
            if (!drag.active) {
                drag.active = true;
                document.body.style.userSelect = 'none';
            }

            // Find which slot the mouse is over
            const el = document.elementFromPoint(e.clientX, e.clientY);
            const slotEl = el?.closest('[data-slot]') as HTMLElement | null;
            if (slotEl) {
                const slot = slotEl.getAttribute('data-slot');
                if (slot) {
                    drag.currentSlot = slot;
                    const dateStr = `${drag.date.getFullYear()}-${String(drag.date.getMonth() + 1).padStart(2, '0')}-${String(drag.date.getDate()).padStart(2, '0')}`;
                    // Determine visual range (start <= end)
                    const startSlot = drag.startSlot <= slot ? drag.startSlot : slot;
                    const endSlot = drag.startSlot <= slot ? slot : drag.startSlot;
                    setSlotDragSelection({ dateStr, startSlot, endSlot });
                }
            }
        };

        const handleMouseUp = () => {
            const drag = slotDragRef.current;
            slotDragRef.current = null;
            if (!drag || !drag.active) {
                setSlotDragSelection(null);
                document.body.style.userSelect = '';
                return;
            }
            setSlotDragSelection(null);
            document.body.style.userSelect = '';
            // Suppress the click event that follows mouseup
            slotDragJustEndedRef.current = true;
            setTimeout(() => { slotDragJustEndedRef.current = false; }, 300);

            // Calculate start and end times
            const startSlot = drag.startSlot <= drag.currentSlot ? drag.startSlot : drag.currentSlot;
            const endSlot = drag.startSlot <= drag.currentSlot ? drag.currentSlot : drag.startSlot;

            // End time = endSlot + cellDuration
            const [eh, em] = endSlot.split(':').map(Number);
            const endMinutes = eh * 60 + em + effectiveCellDurationRef.current;
            const endH = Math.floor(endMinutes / 60);
            const endM = endMinutes % 60;
            const endTime = `${String(endH).padStart(2, '0')}:${String(endM).padStart(2, '0')}`;

            setCalendarEventModal({
                isOpen: true,
                initialDate: drag.date,
                initialStartTime: startSlot,
                initialEndTime: endTime,
            });
        };

        document.addEventListener('mousemove', handleMouseMove);
        document.addEventListener('mouseup', handleMouseUp);
        return () => {
            document.removeEventListener('mousemove', handleMouseMove);
            document.removeEventListener('mouseup', handleMouseUp);
        };
    }, []); // eslint-disable-line react-hooks/exhaustive-deps

    // Touch long-press drag-to-create: listeners are attached ONCE at mount (not per-slot-touch).
    // This avoids any DOM manipulation inside onTouchStart on slot divs, which can
    // confuse iOS Safari's scroll-intent detection and block vertical scrolling.
    // The slot onTouchStart only updates touchLongPressRef (pure ref, no DOM side effects).
    const longPressDragActiveRef = useRef(false); // true when non-passive drag listener is attached

    const upgradeToDragListeners = useCallback(() => {
        if (longPressDragActiveRef.current) return;
        longPressDragActiveRef.current = true;
        // Non-passive listener added only when drag is actually active (500ms hold)
        const handleDragMove = (e: TouchEvent) => {
            if (!longPressDragActiveRef.current) return;
            e.preventDefault();
            const touch = e.touches[0];
            const el = document.elementFromPoint(touch.clientX, touch.clientY);
            const slotEl = el?.closest('[data-slot]') as HTMLElement | null;
            if (slotEl) {
                const slot = slotEl.getAttribute('data-slot');
                if (slot) {
                    const drag = slotDragRef.current;
                    if (drag) {
                        drag.currentSlot = slot;
                        const dateStr = `${drag.date.getFullYear()}-${String(drag.date.getMonth() + 1).padStart(2, '0')}-${String(drag.date.getDate()).padStart(2, '0')}`;
                        const startSlot = drag.startSlot <= slot ? drag.startSlot : slot;
                        const endSlot = drag.startSlot <= slot ? slot : drag.startSlot;
                        setSlotDragSelection({ dateStr, startSlot, endSlot });
                    }
                }
            }
        };
        document.addEventListener('touchmove', handleDragMove, { passive: false });
        // Store for cleanup
        (upgradeToDragListeners as any)._handler = handleDragMove;
    }, []);

    const cancelDragListeners = useCallback(() => {
        if (!longPressDragActiveRef.current) return;
        longPressDragActiveRef.current = false;
        const handler = (upgradeToDragListeners as any)._handler;
        if (handler) {
            document.removeEventListener('touchmove', handler);
            (upgradeToDragListeners as any)._handler = null;
        }
    }, [upgradeToDragListeners]);

    // All touch listeners for the time-grid are attached ONCE at mount as native listeners.
    // CRITICAL: do NOT use React onTouchStart on slot divs — React registers those as
    // non-passive at the app root, causing iOS Safari to wait for JS before committing
    // a scroll gesture, which blocks vertical scrolling on day columns entirely.
    useEffect(() => {
        // TOUCHSTART — passive, on document. Reads data attributes from slot element.
        // Slot divs must have data-slot, data-slot-blocked, and their column must have data-date.
        const handleTouchStart = (e: TouchEvent) => {
            const target = e.target as Element;
            const slotEl = target.closest('[data-slot]') as HTMLElement | null;
            if (!slotEl) return;
            if (slotEl.dataset.slotBlocked) return;
            if (target.closest('.calendar-event-block, .grid-task-block, .task-input-slot')) return;

            const touch = e.touches[0];
            const colEl = slotEl.closest('[data-date]') as HTMLElement | null;
            if (!colEl?.dataset.date) return;
            const slotDate = new Date(colEl.dataset.date);
            const slotName = slotEl.dataset.slot!;

            if (touchLongPressRef.current) {
                clearTimeout(touchLongPressRef.current.timerId);
            }
            const timerId = setTimeout(() => {
                if (navigator.vibrate) navigator.vibrate(50);
                slotDragRef.current = {
                    active: true,
                    date: slotDate,
                    startSlot: slotName,
                    currentSlot: slotName,
                    startY: touch.clientY,
                };
                if (touchLongPressRef.current) {
                    touchLongPressRef.current.activated = true;
                }
                upgradeToDragListeners();
                const ds = `${slotDate.getFullYear()}-${String(slotDate.getMonth() + 1).padStart(2, '0')}-${String(slotDate.getDate()).padStart(2, '0')}`;
                setSlotDragSelection({ dateStr: ds, startSlot: slotName, endSlot: slotName });
            }, 500);
            touchLongPressRef.current = {
                timerId,
                startX: touch.clientX,
                startY: touch.clientY,
                date: slotDate,
                slot: slotName,
                activated: false,
            };
        };

        // TOUCHMOVE — passive, cancels long-press if finger moves (user is scrolling)
        const handlePassiveTouchMove = (e: TouchEvent) => {
            const lp = touchLongPressRef.current;
            if (!lp || lp.activated) return;
            const touch = e.touches[0];
            if (Math.abs(touch.clientX - lp.startX) > 10 || Math.abs(touch.clientY - lp.startY) > 10) {
                clearTimeout(lp.timerId);
                touchLongPressRef.current = null;
            }
        };

        // TOUCHEND — passive, completes drag or cancels
        const handleTouchEnd = () => {
            const lp = touchLongPressRef.current;
            if (lp) {
                clearTimeout(lp.timerId);
                touchLongPressRef.current = null;
            }
            cancelDragListeners();

            const drag = slotDragRef.current;
            slotDragRef.current = null;
            if (!drag || !drag.active) {
                setSlotDragSelection(null);
                return;
            }
            setSlotDragSelection(null);
            slotDragJustEndedRef.current = true;
            setTimeout(() => { slotDragJustEndedRef.current = false; }, 300);

            const startSlot = drag.startSlot <= drag.currentSlot ? drag.startSlot : drag.currentSlot;
            const endSlot = drag.startSlot <= drag.currentSlot ? drag.currentSlot : drag.startSlot;

            const [eh, em] = endSlot.split(':').map(Number);
            const endMinutes = eh * 60 + em + effectiveCellDurationRef.current;
            const endH = Math.floor(endMinutes / 60);
            const endM = endMinutes % 60;
            const endTime = `${String(endH).padStart(2, '0')}:${String(endM).padStart(2, '0')}`;

            setCalendarEventModal({
                isOpen: true,
                initialDate: drag.date,
                initialStartTime: startSlot,
                initialEndTime: endTime,
            });
        };

        document.addEventListener('touchstart', handleTouchStart, { passive: true });
        document.addEventListener('touchmove', handlePassiveTouchMove, { passive: true });
        document.addEventListener('touchend', handleTouchEnd, { passive: true });
        document.addEventListener('touchcancel', handleTouchEnd, { passive: true });
        return () => {
            document.removeEventListener('touchstart', handleTouchStart);
            document.removeEventListener('touchmove', handlePassiveTouchMove);
            document.removeEventListener('touchend', handleTouchEnd);
            document.removeEventListener('touchcancel', handleTouchEnd);
        };
    }, [cancelDragListeners, upgradeToDragListeners]); // eslint-disable-line react-hooks/exhaustive-deps

    const attachTouchListeners = useCallback(() => { /* no-op — all listeners are permanent */ }, []);

    // Handle recurring event drag confirm (this/all)
    const handleRecurringDragConfirm = async (editMode: 'this' | 'future' | 'all') => {
        if (!pendingRecurringDrag) return;
        const { eventId, calendarId, recurringEventId, startTime, endTime, originalStartTime, originalEndTime } = pendingRecurringDrag;
        try {
            const res = await fetch("/api/calendar/events", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    calendarId,
                    eventId,
                    start: { dateTime: startTime },
                    end: { dateTime: endTime },
                    editMode,
                    recurringEventId,
                }),
            });
            if (!res.ok) {
                // Revert
                setRawCalendarEvents(prev => prev.map(ev =>
                    ev.id === eventId ? { ...ev, startTime: originalStartTime, endTime: originalEndTime } : ev
                ));
            }
        } catch {
            setRawCalendarEvents(prev => prev.map(ev =>
                ev.id === eventId ? { ...ev, startTime: originalStartTime, endTime: originalEndTime } : ev
            ));
        }
        setPendingRecurringDrag(null);
    };

    const handleRecurringDragCancel = () => {
        if (!pendingRecurringDrag) return;
        // Revert to original times
        const { eventId, originalStartTime, originalEndTime } = pendingRecurringDrag;
        setRawCalendarEvents(prev => prev.map(ev =>
            ev.id === eventId ? { ...ev, startTime: originalStartTime, endTime: originalEndTime } : ev
        ));
        setPendingRecurringDrag(null);
    };

    // Get all-day events for a specific date
    const getAllDayEventsForDate = useCallback(
        (date: Date): CalendarEvent[] => {
            return calendarEvents.filter((event) => {
                if (!isAllDayEvent(event)) return false;

                // Parse date safely using our local-time helper
                const start = parseCalendarDate(event.startTime);
                const end = event.endTime
                    ? parseCalendarDate(event.endTime)
                    : new Date(start);

                // Normalize dates to start of day for comparison
                const targetDate = new Date(date);
                targetDate.setHours(0, 0, 0, 0);

                start.setHours(0, 0, 0, 0);
                end.setHours(0, 0, 0, 0);

                // Handle single day case where start == end
                if (start.getTime() === end.getTime()) {
                    return start.getTime() === targetDate.getTime();
                }

                // Standard range comparison (inclusive start, exclusive end)
                return (
                    targetDate.getTime() >= start.getTime() &&
                    targetDate.getTime() < end.getTime()
                );
            });
        },
        [calendarEvents],
    );

    // Get all all-day events for the visible week
    const getAllDayEventsForWeek = useCallback((): Map<
        string,
        CalendarEvent[]
    > => {
        const eventsByDay = new Map<string, CalendarEvent[]>();
        const visibleDays = getVisibleDays();

        visibleDays.forEach((date) => {
            const dateKey = formatDateToISO(date);
            eventsByDay.set(dateKey, getAllDayEventsForDate(date));
        });

        return eventsByDay;
    }, [calendarEvents, currentWeekStart, viewDays]);

    const rollOverdueTasks = useCallback(
        async (currentTasks: Task[]) => {
            const autoRolling = profile.autoRolling ?? false;

            const now = new Date();
            const todayStr = formatDateToISO(now);
            const today = new Date(todayStr);

            // Roll tasks that are explicitly marked as rolling (per-task flag),
            // OR all incomplete overdue tasks if global autoRolling is enabled
            const overdue = currentTasks.filter(
                (t) =>
                    !t.completed &&
                    (t.isRolling || autoRolling) &&
                    t.scheduledDate &&
                    formatDateToISO(new Date(t.scheduledDate)) < todayStr,
            );

            if (overdue.length === 0) return;

            console.log(
                `[ROLLING] Found ${overdue.length} overdue tasks to roll to today. autoRolling=${autoRolling}`,
            );

            const updatedTasks = [...currentTasks];
            let hasChanges = false;

            const dailyEvents = getEventsForDate(today);

            for (const task of overdue) {
                const targetSlot = task.startTime || "09:00"; // Default to 9am if no time
                const taskDuration = task.duration || effectiveCellDuration;

                // Collision detection — checks task duration overlap, not just exact slot match
                const isBlocked = (date: Date, slot: string, tasksToCheck: Task[]) => {
                    const dateStr = formatDateToISO(date);
                    const [h, m] = slot.split(":").map(Number);
                    const slotStart = h * 60 + m;
                    const slotEnd = slotStart + taskDuration;

                    // Check other tasks (duration-aware overlap)
                    const taskConflict = tasksToCheck.some((t) => {
                        if (t.id === task.id || !t.startTime || t.completed) return false;
                        if (t.parentTaskId) return false;
                        const tDateStr = t.scheduledDate
                            ? (typeof t.scheduledDate === "string" ? t.scheduledDate.substring(0, 10) : formatDateToISO(new Date(t.scheduledDate)))
                            : null;
                        if (tDateStr !== dateStr) return false;
                        const [th, tm] = t.startTime.split(":").map(Number);
                        const tStart = th * 60 + tm;
                        const tEnd = tStart + (t.duration || effectiveCellDuration);
                        return slotStart < tEnd && slotEnd > tStart;
                    });
                    if (taskConflict) return true;

                    // Check calendar events
                    const slotStartDate = new Date(date);
                    slotStartDate.setHours(h, m, 0, 0);
                    const slotEndDate = new Date(slotStartDate);
                    slotEndDate.setMinutes(slotEndDate.getMinutes() + taskDuration);

                    return dailyEvents.some((event) => {
                        const eventStart = new Date(event.startTime);
                        const eventEnd = new Date(event.endTime);
                        return slotStartDate < eventEnd && slotEndDate > eventStart;
                    });
                };

                const findFreeSlot = (
                    date: Date,
                    preferred: string,
                    tasksToCheck: Task[],
                ) => {
                    let current = preferred;
                    let [h, m] = current.split(":").map(Number);

                    while (isBlocked(date, current, tasksToCheck)) {
                        m += effectiveCellDuration;
                        if (m >= 60) {
                            h += 1;
                            m = 0;
                        }
                        if (h >= effectiveEndHour) break;
                        current = `${h.toString().padStart(2, "0")}:${m.toString().padStart(2, "0")}`;
                    }
                    return current;
                };

                const nextSlot = findFreeSlot(today, targetSlot, updatedTasks);

                // Update in DB
                try {
                    const res = await fetch("/api/tasks", {
                        method: "PATCH",
                        headers: { "Content-Type": "application/json" },
                        body: JSON.stringify({
                            id: task.id,
                            scheduledDate: todayStr,
                            startTime: nextSlot,
                        }),
                    });

                    if (res.ok) {
                        const data = await res.json();
                        const taskIndex = updatedTasks.findIndex((t) => t.id === task.id);
                        if (taskIndex !== -1) {
                            updatedTasks[taskIndex] = {
                                ...data.task,
                                createdAt: new Date(data.task.createdAt),
                                updatedAt: new Date(data.task.updatedAt),
                            };
                            hasChanges = true;
                        }
                    }
                } catch (err) {
                    console.error(`Failed to roll task ${task.id}:`, err);
                }
            }

            if (hasChanges) {
                setTasks(updatedTasks.filter((t) => !t.somedayListId));
            }
        },
        [profile.autoRolling, effectiveCellDuration, effectiveEndHour, getEventsForDate],
    );

    // Run rolling after profile is loaded and tasks are available
    const rollingRanRef = useRef(false);
    useEffect(() => {
        if (rollingRanRef.current) return;
        if (tasks.length === 0) return;
        // Run if global autoRolling is on, OR if any task has per-task isRolling enabled
        const hasRollingTasks = tasks.some((t) => t.isRolling && !t.completed);
        if (!profile.autoRolling && !hasRollingTasks) return;
        rollingRanRef.current = true;
        rollOverdueTasks(tasks);
    }, [profile.autoRolling, tasks, rollOverdueTasks]);

    // Check if a slot is protected by calendar events (only if slot starts within event time range)
    const isSlotProtected = useCallback(
        (date: Date, slot: string): boolean => {
            if (!protectEventTimes) return false;

            const [slotHour, slotMinute] = slot.split(":").map(Number);
            const slotStart = slotHour * 60 + slotMinute;

            return calendarEvents.some((event) => {
                if (isAllDayEvent(event)) return false;
                // Skip events that have been unlocked by the user
                if (unlockedEvents.has(event.id)) return false;

                const eventDate = new Date(event.startTime);
                if (!isSameDay(eventDate, date)) return false;

                const eventStart = eventDate.getHours() * 60 + eventDate.getMinutes();
                const eventEndDate = new Date(event.endTime);
                const eventEndMinutes =
                    eventEndDate.getHours() * 60 + eventEndDate.getMinutes();

                // Only protect if the slot start time falls within the event's actual duration
                // This ensures protection matches exactly what the event covers
                return slotStart >= eventStart && slotStart < eventEndMinutes;
            });
        },
        [protectEventTimes, calendarEvents, unlockedEvents],
    );

    // Check if a slot is occupied by any task (to prevent stacking)
    const isSlotOccupiedByTask = useCallback(
        (date: Date, slot: string, excludeTaskId?: string): boolean => {
            const dateStr = formatDateToISO(date);
            const [slotHour, slotMinute] = slot.split(":").map(Number);
            const slotStart = slotHour * 60 + slotMinute;
            const slotEnd = slotStart + effectiveCellDuration;

            return tasks.some(task => {
                if (!task.scheduledDate || !task.startTime) return false;
                if (excludeTaskId && task.id === excludeTaskId) return false;
                // Exclude sub-tasks
                if (task.parentTaskId) return false;

                const taskDateStr =
                    typeof task.scheduledDate === "string"
                        ? task.scheduledDate.substring(0, 10)
                        : formatDateToISO(new Date(task.scheduledDate));
                if (taskDateStr !== dateStr) return false;

                const [taskHour, taskMinute] = task.startTime.split(":").map(Number);
                const taskStart = taskHour * 60 + taskMinute;
                const taskDuration = task.duration || 15;
                const taskEnd = taskStart + taskDuration;

                // Skip completed tasks (they don't render in the grid)
                if (task.completed) return false;

                // Overlap condition: task starts before slot ends AND task ends after slot starts
                return taskStart < slotEnd && taskEnd > slotStart;
            });
        },
        [tasks, effectiveCellDuration],
    );

    // Navigation handlers with CSS class-based slide animation (works in all browsers)
    const gridRef = useRef<HTMLElement>(null);
    const allSlideClasses = ["slide-animate-next", "slide-animate-prev", "slide-animate-week-next", "slide-animate-week-prev"];
    const navigate = (
        newDate: Date,
        direction: "left" | "right",
        type: "day" | "week",
    ) => {
        const grid = gridRef.current;
        if (grid) {
            // Remove any existing animation class
            grid.classList.remove(...allSlideClasses);
            // Trigger reflow to restart animation if same direction
            void grid.offsetWidth;
            // Pick class: week uses longer animation
            const prefix = type === "week" ? "slide-animate-week-" : "slide-animate-";
            grid.classList.add(prefix + (direction === "left" ? "next" : "prev"));
            // Clean up after animation
            const cleanup = () => {
                grid.classList.remove(...allSlideClasses);
                grid.removeEventListener("animationend", cleanup);
            };
            grid.addEventListener("animationend", cleanup, { once: true });
        }
        setCurrentWeekStart(newDate);
        setSlideDirection(direction === "left" ? "next" : "prev");
        setSelectedDay(null); // reset so header shows the new week's today/first day
    };

    const goToPrevWeek = () =>
        navigate(
            new Date(currentWeekStart.getTime() - 7 * 24 * 60 * 60 * 1000),
            "right",
            "week",
        );
    const goToNextWeek = () =>
        navigate(
            new Date(currentWeekStart.getTime() + 7 * 24 * 60 * 60 * 1000),
            "left",
            "week",
        );
    const goToPrevDay = () =>
        navigate(
            new Date(currentWeekStart.getTime() - 24 * 60 * 60 * 1000),
            "right",
            "day",
        );
    const goToNextDay = () =>
        navigate(
            new Date(currentWeekStart.getTime() + 24 * 60 * 60 * 1000),
            "left",
            "day",
        );
    const goToToday = () => {
        const d = new Date();
        d.setHours(0, 0, 0, 0);
        // Only apply startDayOffset for multi-day views; on single-day view, go directly to today
        if (viewDays > 1) {
            d.setDate(d.getDate() + (profile?.startDayOffset || 0));
        }
        setCurrentWeekStart(d);
    };

    // Touch swipe navigation for mobile
    useEffect(() => {
        let touchStartX = 0;
        let touchStartY = 0;
        let touchEndX = 0;
        let touchEndY = 0;

        let touchStartedInSomeday = false;

        const handleTouchStart = (e: TouchEvent) => {
            touchStartX = e.changedTouches[0].screenX;
            touchStartY = e.changedTouches[0].screenY;
            // Check if touch started inside the someday area (which has its own horizontal scroll)
            touchStartedInSomeday = !!(e.target as HTMLElement)?.closest?.('.weekly-someday');
        };

        const handleTouchEnd = (e: TouchEvent) => {
            if (touchStartedInSomeday) return; // Don't hijack someday horizontal scrolling
            touchEndX = e.changedTouches[0].screenX;
            touchEndY = e.changedTouches[0].screenY;
            const diffX = touchEndX - touchStartX;
            const diffY = touchEndY - touchStartY;
            // Only trigger if horizontal swipe is dominant and > 80px
            if (Math.abs(diffX) > 80 && Math.abs(diffX) > Math.abs(diffY) * 1.5) {
                if (diffX > 0) {
                    // Swipe right → go to previous day
                    goToPrevDay();
                } else {
                    // Swipe left → go to next day
                    goToNextDay();
                }
            }
        };

        const container = document.querySelector('.weekly-container') as HTMLElement | null;
        if (container) {
            container.addEventListener('touchstart', handleTouchStart as EventListener, { passive: true });
            container.addEventListener('touchend', handleTouchEnd as EventListener, { passive: true });
        }
        return () => {
            if (container) {
                container.removeEventListener('touchstart', handleTouchStart as EventListener);
                container.removeEventListener('touchend', handleTouchEnd as EventListener);
            }
        };
    }, [currentWeekStart]); // Re-attach when week changes so closures are fresh

    const executeImport = async (provider: "google" | "apple" | "outlook" | "synology") => {
        setImportProvider(provider);
        setIsImportModalOpen(true);
        setIsFetchingLists(true);
        setImportLists([]);
        setImportStatusMsg(null);

        try {
            const res = await fetch(`/api/tasks/lists?provider=${provider}`);
            if (res.ok) {
                const data = await res.json();
                setImportLists(data.lists || []);
            } else {
                const errData = await res.json();
                console.error("Failed to fetch lists", errData);
                setIsImportModalOpen(false);
                setImportStatusMsg({
                    type: "error",
                    text: errData.error || "Failed to fetch task lists.",
                });
            }
        } catch (e) {
            console.error("Error fetching lists:", e);
            setIsImportModalOpen(false);
            setImportStatusMsg({ type: "error", text: "Error fetching task lists." });
        } finally {
            setIsFetchingLists(false);
        }
    };

    const fetchAvailableTaskLists = useCallback(
        async (provider: "google" | "apple" | "outlook" | "synology") => {
            setIsFetchingProviderLists((prev) => ({
                ...prev,
                [provider]: true,
            }));
            try {
                const res = await fetch(`/api/tasks/lists?provider=${provider}`);
                if (res.ok) {
                    const data = await res.json();
                    setAvailableTaskLists((prev) => ({
                        ...prev,
                        [provider]: data.lists || [],
                    }));
                }
            } catch (error) {
                console.error(`Failed to fetch lists for ${provider}`, error);
            } finally {
                setIsFetchingProviderLists((prev) => ({
                    ...prev,
                    [provider]: false,
                }));
            }
        },
        [],
    );


    const handleToggleTaskList = async (
        provider: "google" | "apple" | "outlook" | "synology",
        list: { id: string; title: string },
    ) => {
        const existing = somedayLists.find(
            (l) => l.externalId === list.id && l.externalProvider === provider,
        );

        if (existing) {
            // Show inline confirmation instead of browser confirm()
            setUnsyncConfirm({ provider, list });
            return;
        } else {
            // Sync/Import
            await doImport(provider, [list]);
        }
    };

    const confirmUnsync = async () => {
        if (!unsyncConfirm) return;
        const { provider, list } = unsyncConfirm;
        const existing = somedayLists.find(
            (l) => l.externalId === list.id && l.externalProvider === provider,
        );
        if (!existing) { setUnsyncConfirm(null); return; }
        try {
            // tasksOnly=true: soft-disconnect — removes tasks but keeps list record with its tab assignment
            // so when the user reconnects, the tab is restored automatically without re-dragging
            const res = await fetch(`/api/someday-lists?id=${existing.id}&tasksOnly=true`, {
                method: "DELETE",
            });
            if (res.ok) {
                // Remove from local state (clean UI); DB record is kept for tab restoration on reconnect
                setSomedayLists((prev) => prev.filter((l) => l.id !== existing.id));
                setImportStatusMsg({
                    type: "success",
                    text: `Stopped syncing "${list.title}".`,
                });
            }
        } catch (error) {
            console.error("Failed to unsync list", error);
            setImportStatusMsg({
                type: "error",
                text: "Failed to stop syncing list.",
            });
        }
        setUnsyncConfirm(null);
    };

    const handleSyncAll = async (
        provider: "google" | "outlook" | "synology",
        lists: { id: string; title: string }[],
        syncOn: boolean,
    ) => {
        if (syncOn) {
            const unsynced = lists.filter(
                (list) => !somedayLists.some(
                    (sl) => sl.externalId === list.id && sl.externalProvider === provider,
                ),
            );
            if (unsynced.length > 0) await doImport(provider, unsynced);
        } else {
            // Unsync all synced lists
            const synced = lists.filter(
                (list) => somedayLists.some(
                    (sl) => sl.externalId === list.id && sl.externalProvider === provider,
                ),
            );
            for (const list of synced) {
                const existing = somedayLists.find(
                    (l) => l.externalId === list.id && l.externalProvider === provider,
                );
                if (!existing) continue;
                try {
                    // tasksOnly=true: soft-disconnect — keeps list record with tab for reconnect restoration
                    const res = await fetch(`/api/someday-lists?id=${existing.id}&tasksOnly=true`, {
                        method: "DELETE",
                    });
                    if (res.ok) {
                        setSomedayLists((prev) => prev.filter((l) => l.id !== existing.id));
                    }
                } catch (error) {
                    console.error("Failed to unsync list", error);
                }
            }
            setImportStatusMsg({
                type: "success",
                text: `Stopped syncing ${synced.length} list(s).`,
            });
        }
    };

    // Core import logic — accepts provider directly so it works both from modal and sidebar
    const doImport = async (
        provider: "google" | "apple" | "outlook" | "synology",
        selectedLists: { id: string; title: string }[],
    ) => {
        setImportingTasksState(true);
        setImportStatusMsg(null);

        try {
            const response = await fetch("/api/tasks/import", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ provider, sourceLists: selectedLists }),
            });

            const data = await response.json();

            if (response.ok) {
                setImportStatusMsg({
                    type: "success",
                    text: `Synced ${data.count} new tasks across ${data.listsCreated || 1} list(s).`,
                });
                // Trigger immediate pull-sync to get latest state
                try {
                    await fetch("/api/tasks/sync");
                } catch (e) {
                    // Non-critical, auto-sync will catch up
                }
                await fetchTasks();
            } else {
                setImportStatusMsg({
                    type: "error",
                    text: data.error || "Sync failed.",
                });
            }
        } catch (error) {
            console.error("Import error:", error);
            setImportStatusMsg({
                type: "error",
                text: "An error occurred during sync.",
            });
        } finally {
            setImportingTasksState(false);
        }
    };

    // Called from the Google Tasks modal
    const handleConfirmImport = async (
        selectedLists: { id: string; title: string }[],
    ) => {
        if (!importProvider) return;
        setIsImportModalOpen(false);
        await doImport(importProvider, selectedLists);
        setImportProvider(null);
    };

    // Undo/Redo helpers
    const saveSnapshot = useCallback(() => {
        if (skipSnapshotRef.current) return;
        undoStackRef.current = [
            ...undoStackRef.current.slice(-29), // keep last 30 snapshots
            {
                tasks: JSON.parse(JSON.stringify(tasks)),
                somedayLists: JSON.parse(JSON.stringify(somedayLists)),
            },
        ];
        redoStackRef.current = [];
        setUndoCount(undoStackRef.current.length);
        setRedoCount(0);
    }, [tasks, somedayLists]);

    const handleUndo = useCallback(() => {
        if (undoStackRef.current.length === 0) return;
        const snapshot = undoStackRef.current.pop()!;
        redoStackRef.current.push({
            tasks: JSON.parse(JSON.stringify(tasks)),
            somedayLists: JSON.parse(JSON.stringify(somedayLists)),
        });
        skipSnapshotRef.current = true;
        setTasks(snapshot.tasks);
        setSomedayLists(snapshot.somedayLists);
        skipSnapshotRef.current = false;
        setUndoCount(undoStackRef.current.length);
        setRedoCount(redoStackRef.current.length);
    }, [tasks, somedayLists]);

    const handleRedo = useCallback(() => {
        if (redoStackRef.current.length === 0) return;
        const snapshot = redoStackRef.current.pop()!;
        undoStackRef.current.push({
            tasks: JSON.parse(JSON.stringify(tasks)),
            somedayLists: JSON.parse(JSON.stringify(somedayLists)),
        });
        skipSnapshotRef.current = true;
        setTasks(snapshot.tasks);
        setSomedayLists(snapshot.somedayLists);
        skipSnapshotRef.current = false;
        setUndoCount(undoStackRef.current.length);
        setRedoCount(redoStackRef.current.length);
    }, [tasks, somedayLists]);

    // Keyboard shortcuts for undo/redo
    useEffect(() => {
        const handleKeyDown = (e: KeyboardEvent) => {
            if ((e.ctrlKey || e.metaKey) && e.key === "z" && !e.shiftKey) {
                e.preventDefault();
                handleUndo();
            }
            if ((e.ctrlKey || e.metaKey) && (e.key === "y" || (e.key === "z" && e.shiftKey))) {
                e.preventDefault();
                handleRedo();
            }
        };
        window.addEventListener("keydown", handleKeyDown);
        return () => window.removeEventListener("keydown", handleKeyDown);
    }, [handleUndo, handleRedo]);

    // Task CRUD operations
    const addTask = async (date: Date, title: string, startTime?: string) => {
        if (!title.trim()) return;
        saveSnapshot();
        announce(`Task "${title.trim()}" added`);

        const scheduledDate = formatDateToISO(date); // Use local date formatting

        if (!session?.user) {
            // Local-only demo mode when not authenticated
            const tempId = `temp-${Date.now()}`;
            setTasks((prevTasks) => [
                ...prevTasks,
                {
                    id: tempId,
                    title: title.trim(),
                    dayOfWeek: date.getDay(),
                    scheduledDate,
                    order: prevTasks.filter((t) => t.scheduledDate === scheduledDate)
                        .length,
                    completed: false,
                    userId: "temp",
                    startTime,
                    createdAt: new Date(),
                    updatedAt: new Date(),
                },
            ]);
            return;
        }

        try {
            const response = await fetch("/api/tasks", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    title: title.trim(),
                    dayOfWeek: date.getDay(),
                    scheduledDate,
                    order: 0,
                    startTime,
                }),
            });

            if (response.ok) {
                const data = await response.json();
                setTasks((prevTasks) => [
                    ...prevTasks,
                    {
                        ...data.task,
                        createdAt: new Date(data.task.createdAt),
                        updatedAt: new Date(data.task.updatedAt),
                    },
                ]);
            } else {
                console.error("Failed to add task:", await response.text());
            }
        } catch (error) {
            console.error("Error adding task:", error);
        }
    };

    // Create a task in kanban view — auto-creates a someday list if needed
    const addKanbanTask = async (title: string, stageId: string | null) => {
        if (!title.trim() || !session?.user) return;
        saveSnapshot();

        try {
            // Determine the target someday list name
            const activeProject = kanbanFilterProject
                ? projects.find(p => p.id === kanbanFilterProject)
                : null;
            const listName = activeProject ? activeProject.name : "Kanban";

            // Find existing someday list with that name
            let targetList = somedayLists.find(sl => sl.title === listName);

            // Create the list if it doesn't exist
            if (!targetList) {
                const listRes = await fetch("/api/someday-lists", {
                    method: "POST",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ title: listName }),
                });
                if (listRes.ok) {
                    const listData = await listRes.json();
                    targetList = { ...listData.list, tasks: [] };
                    setSomedayLists(prev => [...prev, targetList!]);
                } else {
                    console.error("Failed to create someday list:", await listRes.text());
                    return;
                }
            }

            // Create the task
            const response = await fetch("/api/tasks", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    title: title.trim(),
                    somedayListId: targetList!.id,
                    kanbanStage: stageId,
                    projectId: activeProject?.id || undefined,
                    order: 0,
                }),
            });

            if (response.ok) {
                const data = await response.json();
                const newTask = {
                    ...data.task,
                    createdAt: new Date(data.task.createdAt),
                    updatedAt: new Date(data.task.updatedAt),
                };
                setSomedayLists(prev =>
                    prev.map(sl =>
                        sl.id === targetList!.id
                            ? { ...sl, tasks: [...sl.tasks, newTask] }
                            : sl
                    )
                );
            } else {
                console.error("Failed to add kanban task:", await response.text());
            }
        } catch (error) {
            console.error("Error adding kanban task:", error);
        }

        setKanbanAddingStageId(null);
        setKanbanNewTaskTitle("");
    };

    // Helper to find a task in both calendar tasks and someday lists
    const findTaskAnywhere = (taskId: string): Task | undefined => {
        const calTask = tasks.find((t) => t.id === taskId);
        if (calTask) return calTask;
        for (const list of somedayLists) {
            const found = list.tasks.find((t) => t.id === taskId);
            if (found) return found;
        }
        return undefined;
    };

    const toggleTask = async (taskId: string) => {
        saveSnapshot();
        const task = findTaskAnywhere(taskId);
        if (!task) return;

        const updatedCompleted = !task.completed;
        announce(updatedCompleted ? `"${task.title}" marked complete` : `"${task.title}" marked incomplete`);
        const isSomeday = !!task.somedayListId;

        if (isSomeday) {
            setSomedayLists((prev) =>
                prev.map((l) => ({
                    ...l,
                    tasks: l.tasks.map((t) =>
                        t.id === taskId
                            ? { ...t, completed: updatedCompleted, updatedAt: new Date() }
                            : t,
                    ),
                })),
            );
        } else {
            setTasks(
                tasks.map((t) =>
                    t.id === taskId
                        ? { ...t, completed: updatedCompleted, updatedAt: new Date() }
                        : t,
                ),
            );
        }

        try {
            await fetch("/api/tasks", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ id: taskId, completed: updatedCompleted }),
            });

            if (task.externalId && task.externalProvider) {
                fetch("/api/tasks/sync", {
                    method: "PATCH",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ taskId: taskId, completed: updatedCompleted }),
                }).catch((e) => console.error("Sync error:", e));
            }
        } catch (error) {
            console.error("Error toggling task:", error);
        }
    };

    const updateTask = async (taskId: string, newTitle: string) => {
        saveSnapshot();
        if (!newTitle.trim()) {
            await deleteTask(taskId);
            return;
        }

        const task = findTaskAnywhere(taskId);
        const isSomeday = !!task?.somedayListId;

        if (isSomeday) {
            setSomedayLists((prev) =>
                prev.map((l) => ({
                    ...l,
                    tasks: l.tasks.map((t) =>
                        t.id === taskId
                            ? { ...t, title: newTitle.trim(), updatedAt: new Date() }
                            : t,
                    ),
                })),
            );
        } else {
            setTasks(
                tasks.map((t) =>
                    t.id === taskId
                        ? { ...t, title: newTitle.trim(), updatedAt: new Date() }
                        : t,
                ),
            );
        }
        setEditingTaskId(null);

        try {
            await fetch("/api/tasks", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ id: taskId, title: newTitle.trim() }),
            });

            if (task?.externalId && task?.externalProvider) {
                fetch("/api/tasks/sync", {
                    method: "PATCH",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ taskId, title: newTitle.trim() }),
                }).catch((e) => console.error("Sync error:", e));
            }
        } catch (error) {
            console.error("Error updating task:", error);
        }
    };

    const updateTaskFields = async (taskId: string, fields: Partial<Task>) => {
        setTasks((prev) =>
            prev.map((t) =>
                t.id === taskId ? { ...t, ...fields, updatedAt: new Date() } : t,
            ),
        );

        // Also update someday lists if the task is there
        setSomedayLists((lists) =>
            lists.map((list) => ({
                ...list,
                tasks: list.tasks.map((t) =>
                    t.id === taskId ? { ...t, ...fields, updatedAt: new Date() } : t,
                ),
            })),
        );

        try {
            const res = await fetch("/api/tasks", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ id: taskId, ...fields }),
            });
            if (!res.ok) {
                const errData = await res.json().catch(() => ({}));
                console.error("Failed to update task fields:", res.status, errData);
            }
        } catch (error) {
            console.error("Error updating task fields:", error);
        }
    };

    // Sub-task CRUD operations
    const addSubTask = async (parentId: string, title: string) => {
        if (!title.trim() || !session?.user) return;

        // Find parent task to inherit scheduling
        const parentTask = findTaskAnywhere(parentId);

        try {
            const response = await fetch("/api/tasks", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    title: title.trim(),
                    parentTaskId: parentId,
                    scheduledDate: parentTask?.scheduledDate || null,
                    dayOfWeek: parentTask?.dayOfWeek ?? null,
                    order: (parentTask?.subTasks?.length || 0),
                }),
            });

            if (response.ok) {
                const data = await response.json();
                const newSubTask = {
                    ...data.task,
                    createdAt: new Date(data.task.createdAt),
                    updatedAt: new Date(data.task.updatedAt),
                };

                // Update local state: add sub-task to parent
                setTasks((prev) =>
                    prev.map((t) =>
                        t.id === parentId
                            ? { ...t, subTasks: [...(t.subTasks || []), newSubTask] }
                            : t,
                    ),
                );
                setSomedayLists((prev) =>
                    prev.map((l) => ({
                        ...l,
                        tasks: l.tasks.map((t) =>
                            t.id === parentId
                                ? { ...t, subTasks: [...(t.subTasks || []), newSubTask] }
                                : t,
                        ),
                    })),
                );
            }
        } catch (error) {
            console.error("Error adding sub-task:", error);
        }
    };

    const toggleSubTask = async (subTaskId: string) => {
        // Find the sub-task in any parent
        let foundSubTask: Task | undefined;
        for (const task of tasks) {
            foundSubTask = task.subTasks?.find((st) => st.id === subTaskId);
            if (foundSubTask) break;
        }
        if (!foundSubTask) {
            for (const list of somedayLists) {
                for (const task of list.tasks) {
                    foundSubTask = task.subTasks?.find((st) => st.id === subTaskId);
                    if (foundSubTask) break;
                }
                if (foundSubTask) break;
            }
        }
        if (!foundSubTask) return;

        const newCompleted = !foundSubTask.completed;

        // Optimistic update
        const updateSubTasks = (taskList: Task[]) =>
            taskList.map((t) => ({
                ...t,
                subTasks: t.subTasks?.map((st) =>
                    st.id === subTaskId ? { ...st, completed: newCompleted } : st,
                ),
            }));

        setTasks((prev) => updateSubTasks(prev));
        setSomedayLists((prev) =>
            prev.map((l) => ({ ...l, tasks: updateSubTasks(l.tasks) })),
        );

        try {
            await fetch("/api/tasks", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ id: subTaskId, completed: newCompleted }),
            });
        } catch (error) {
            console.error("Error toggling sub-task:", error);
        }
    };

    const deleteSubTask = async (subTaskId: string) => {
        // Optimistic update: remove from parent's subTasks
        const removeSubTask = (taskList: Task[]) =>
            taskList.map((t) => ({
                ...t,
                subTasks: t.subTasks?.filter((st) => st.id !== subTaskId),
            }));

        setTasks((prev) => removeSubTask(prev));
        setSomedayLists((prev) =>
            prev.map((l) => ({ ...l, tasks: removeSubTask(l.tasks) })),
        );

        try {
            await fetch(`/api/tasks?id=${subTaskId}`, { method: "DELETE" });
        } catch (error) {
            console.error("Error deleting sub-task:", error);
        }
    };

    const updateSubTask = async (subTaskId: string, newTitle: string) => {
        if (!newTitle.trim()) {
            await deleteSubTask(subTaskId);
            return;
        }

        const updateSubTasks = (taskList: Task[]) =>
            taskList.map((t) => ({
                ...t,
                subTasks: t.subTasks?.map((st) =>
                    st.id === subTaskId ? { ...st, title: newTitle.trim() } : st,
                ),
            }));

        setTasks((prev) => updateSubTasks(prev));
        setSomedayLists((prev) =>
            prev.map((l) => ({ ...l, tasks: updateSubTasks(l.tasks) })),
        );

        try {
            await fetch("/api/tasks", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ id: subTaskId, title: newTitle.trim() }),
            });
        } catch (error) {
            console.error("Error updating sub-task:", error);
        }
    };

    const updateTaskDuration = async (
        taskId: string,
        durationMinutes: number,
    ) => {
        const task = tasks.find((t) => t.id === taskId);
        if (!task || !task.startTime) return;

        try {
            // Parse start time (HH:mm)
            const [startHour, startMinute] = task.startTime.split(":").map(Number);

            // Calculate end time
            const totalStartMinutes = startHour * 60 + startMinute;
            const totalEndMinutes = totalStartMinutes + durationMinutes;

            const endHour = Math.floor(totalEndMinutes / 60) % 24; // Wrap around 24h
            const endMinute = totalEndMinutes % 60;

            const endTimeStr = `${endHour.toString().padStart(2, "0")}:${endMinute.toString().padStart(2, "0")}`;

            // Optimistic update
            setTasks(
                tasks.map((t) =>
                    t.id === taskId
                        ? { ...t, endTime: endTimeStr, updatedAt: new Date() }
                        : t,
                ),
            );

            await fetch("/api/tasks", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ id: taskId, endTime: endTimeStr }),
            });
        } catch (error) {
            console.error("Error updating task duration:", error);
        }
    };

    const updateTaskNotes = async (taskId: string, notes: string) => {
        const task = findTaskAnywhere(taskId);
        const isSomeday = !!task?.somedayListId;

        if (isSomeday) {
            setSomedayLists((prev) =>
                prev.map((l) => ({
                    ...l,
                    tasks: l.tasks.map((t) =>
                        t.id === taskId
                            ? { ...t, markdownContent: notes, updatedAt: new Date() }
                            : t,
                    ),
                })),
            );
        } else {
            setTasks(
                tasks.map((t) =>
                    t.id === taskId
                        ? { ...t, markdownContent: notes, updatedAt: new Date() }
                        : t,
                ),
            );
        }

        try {
            await fetch("/api/tasks", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ id: taskId, markdownContent: notes }),
            });

            if (task?.externalId && task?.externalProvider) {
                fetch("/api/tasks/sync", {
                    method: "PATCH",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ taskId, notes }),
                }).catch((e) => console.error("Sync error:", e));
            }
        } catch (error) {
            console.error("Error updating task notes:", error);
        }
    };

    const updateTaskUrl = async (taskId: string, url: string) => {
        const task = findTaskAnywhere(taskId);
        const isSomeday = !!task?.somedayListId;
        const normalised = url.trim() ? (url.trim().startsWith("http") ? url.trim() : `https://${url.trim()}`) : "";

        if (isSomeday) {
            setSomedayLists(prev => prev.map(l => ({
                ...l,
                tasks: l.tasks.map(t => t.id === taskId ? { ...t, url: normalised || null, updatedAt: new Date() } : t),
            })));
        } else {
            setTasks(prev => prev.map(t => t.id === taskId ? { ...t, url: normalised || null, updatedAt: new Date() } : t));
        }
        try {
            await fetch("/api/tasks", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ id: taskId, url: normalised || null }),
            });
        } catch (error) {
            console.error("Error updating task url:", error);
        }
    };

    const toggleTaskRolling = async (taskId: string) => {
        saveSnapshot();
        const task = findTaskAnywhere(taskId);
        if (!task) return;

        const newRollingState = !task.isRolling;
        const isSomeday = !!task.somedayListId;

        if (isSomeday) {
            setSomedayLists((prev) =>
                prev.map((l) => ({
                    ...l,
                    tasks: l.tasks.map((t) =>
                        t.id === taskId
                            ? { ...t, isRolling: newRollingState, updatedAt: new Date() }
                            : t,
                    ),
                })),
            );
        } else {
            setTasks(
                tasks.map((t) =>
                    t.id === taskId
                        ? { ...t, isRolling: newRollingState, updatedAt: new Date() }
                        : t,
                ),
            );
        }

        try {
            await fetch("/api/tasks", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ id: taskId, isRolling: newRollingState }),
            });
        } catch (error) {
            console.error("Error updating task rolling state:", error);
            if (isSomeday) {
                setSomedayLists((prev) =>
                    prev.map((l) => ({
                        ...l,
                        tasks: l.tasks.map((t) =>
                            t.id === taskId ? { ...t, isRolling: !newRollingState } : t,
                        ),
                    })),
                );
            } else {
                setTasks(
                    tasks.map((t) =>
                        t.id === taskId ? { ...t, isRolling: !newRollingState } : t,
                    ),
                );
            }
        }
    };

    const moveTaskToSlot = async (
        taskId: string,
        dayOfWeek: number,
        startTime: string,
        scheduledDate?: Date,
    ) => {
        const newScheduledDate = scheduledDate
            ? formatDateToISO(scheduledDate)
            : undefined;
        const task = tasks.find((t) => t.id === taskId);
        setTasks(
            tasks.map((t) =>
                t.id === taskId
                    ? {
                        ...t,
                        dayOfWeek,
                        startTime,
                        scheduledDate: newScheduledDate || t.scheduledDate,
                        somedayListId: null,
                        somedaySlotIndex: null,
                        updatedAt: new Date(),
                    }
                    : t,
            ),
        );

        try {
            await fetch("/api/tasks", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    id: taskId,
                    dayOfWeek,
                    startTime,
                    scheduledDate: newScheduledDate,
                    somedayListId: null,
                    somedaySlotIndex: null,
                }),
            });

            // Sync due date change to external provider
            if (task?.externalId && task?.externalProvider && newScheduledDate) {
                fetch("/api/tasks/sync", {
                    method: "PATCH",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ taskId, scheduledDate: newScheduledDate }),
                }).catch((e) => console.error("Sync error:", e));
            }
        } catch (error) {
            console.error("Error moving task:", error);
        }
    };

    const assignProject = async (taskId: string, projectId: string | null) => {
        const proj = projectId ? projects.find((p) => p.id === projectId) || null : null;
        // Optimistic update
        const updateTask = (t: Task) =>
            t.id === taskId ? { ...t, projectId: projectId, project: proj } : t;
        setTasks((prev) => prev.map(updateTask));
        setSomedayLists((prev) =>
            prev.map((l) => ({ ...l, tasks: l.tasks.map(updateTask) }))
        );
        try {
            await fetch("/api/tasks", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ id: taskId, projectId }),
            });
        } catch (e) {
            console.error("Failed to assign project:", e);
        }
    };

    const deleteTask = async (taskId: string) => {
        saveSnapshot();
        const taskToDelete = findTaskAnywhere(taskId);
        if (taskToDelete) announce(`"${taskToDelete.title}" deleted`);
        const isSomeday = !!taskToDelete?.somedayListId;
        const isVirtual = taskId.startsWith("virtual-");

        let originalId = taskId;
        if (isVirtual) {
            const match = taskId.match(/^virtual-(.+)-(\d{4}-\d{2}-\d{2})$/);
            if (match) {
                originalId = match[1];
            }
        }

        // Check if it's a series (virtual or real recurring)
        const isSeries = isVirtual || (taskToDelete && taskToDelete.isRecurring);

        if (isSeries) {
            setRecurringDeleteModal({ isOpen: true, taskId });
            return;
        }

        // NORMAL DELETE (Single instance)
        if (isSomeday) {
            setSomedayLists((prev) =>
                prev.map((l) => ({
                    ...l,
                    tasks: l.tasks.filter((t) => t.id !== taskId),
                })),
            );
        } else {
            setTasks((prev) => prev.filter((t) => t.id !== taskId));
        }
        setEditingTaskId(null);

        try {
            if (taskToDelete?.externalId && taskToDelete?.externalProvider) {
                fetch("/api/tasks/sync", {
                    method: "PATCH",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ taskId, action: "delete" }),
                }).catch((e) => console.error("Sync delete error:", e));
            }

            await fetch(`/api/tasks?id=${taskId}`, { method: "DELETE" });
        } catch (error) {
            console.error("Error deleting task:", error);
        }
    };

    const handleConfirmDeleteSeries = async (taskId: string) => {
        let originalId = taskId;
        if (taskId.startsWith("virtual-")) {
            const match = taskId.match(/^virtual-(.+)-(\d{4}-\d{2}-\d{2})$/);
            if (match) originalId = match[1];
        }

        const taskToDelete = findTaskAnywhere(originalId);

        setTasks((prev) =>
            prev.filter((t) => {
                if (taskToDelete && t.title === taskToDelete.title &&
                    t.recurrenceInterval === taskToDelete.recurrenceInterval &&
                    t.recurrenceUnit === taskToDelete.recurrenceUnit) {
                    return false;
                }
                if (t.id === originalId) return false;
                if (t.id.startsWith(`virtual-${originalId}-`)) return false;
                if (t.id === taskId) return false;
                return true;
            }),
        );
        setEditingTaskId(null);
        setRecurringDeleteModal({ isOpen: false, taskId: null });

        try {
            const origTask = findTaskAnywhere(originalId);
            if (origTask?.externalId && origTask?.externalProvider) {
                fetch("/api/tasks/sync", {
                    method: "PATCH",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ taskId: originalId, action: "delete" }),
                }).catch((e) => console.error("Sync delete error:", e));
            }
            await fetch(`/api/tasks?id=${originalId}`, { method: "DELETE" });
        } catch (error) {
            console.error("Error deleting series:", error);
        }
    };

    const handleConfirmDeleteOccurrence = async (taskId: string) => {
        setTasks((prev) => prev.filter((t) => t.id !== taskId));
        setEditingTaskId(null);
        setRecurringDeleteModal({ isOpen: false, taskId: null });

        try {
            const taskToDelete = findTaskAnywhere(taskId);
            if (taskToDelete?.externalId && taskToDelete?.externalProvider) {
                fetch("/api/tasks/sync", {
                    method: "PATCH",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ taskId, action: "delete" }),
                }).catch((e) => console.error("Sync delete error:", e));
            }
            await fetch(`/api/tasks?id=${taskId}`, { method: "DELETE" });
        } catch (error) {
            console.error("Error deleting instance:", error);
        }
    };

    // Toggle rolling status
    const toggleRolling = async (taskId: string) => {
        const task = tasks.find((t) => t.id === taskId);
        if (!task) return;

        const updatedIsRolling = !task.isRolling;

        setTasks(
            tasks.map((t) =>
                t.id === taskId
                    ? { ...t, isRolling: updatedIsRolling, updatedAt: new Date() }
                    : t,
            ),
        );

        try {
            await fetch("/api/tasks", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ id: taskId, isRolling: updatedIsRolling }),
            });
        } catch (error) {
            console.error("Error toggling rolling status:", error);
        }
    };

    // Roll task to tomorrow or next week
    const rollTask = async (
        taskId: string,
        rollType: "tomorrow" | "nextWeek",
    ) => {
        const task = tasks.find((t) => t.id === taskId);
        if (!task || task.completed) return;

        // Get current task date
        const currentDate = task.scheduledDate
            ? new Date(task.scheduledDate)
            : new Date();

        // Calculate new date
        const newDate = new Date(currentDate);
        if (rollType === "tomorrow") {
            newDate.setDate(newDate.getDate() + 1);
        } else {
            newDate.setDate(newDate.getDate() + 7);
        }

        const newScheduledDate = formatDateToISO(newDate);

        // Preserve startTime — if the preferred slot is taken, find next free one
        let resolvedStartTime = task.startTime || undefined;
        if (resolvedStartTime) {
            const targetSlotTasks = tasks.filter((t) => {
                if (t.id === taskId || !t.scheduledDate) return false;
                const tDate = formatDateToISO(new Date(t.scheduledDate));
                return tDate === newScheduledDate && t.startTime === resolvedStartTime;
            });
            if (targetSlotTasks.length > 0) {
                // Slot is taken — find next free slot
                const allSlots = getTimeSlots(
                    effectiveCellDuration,
                    0,
                    24,
                );
                const startIndex = allSlots.indexOf(resolvedStartTime);
                if (startIndex !== -1) {
                    for (let i = startIndex + 1; i < allSlots.length; i++) {
                        const candidate = allSlots[i];
                        const candidateTasks = tasks.filter((t) => {
                            if (t.id === taskId || !t.scheduledDate) return false;
                            const tDate = formatDateToISO(new Date(t.scheduledDate));
                            return tDate === newScheduledDate && t.startTime === candidate;
                        });
                        if (candidateTasks.length === 0) {
                            resolvedStartTime = candidate;
                            break;
                        }
                    }
                }
            }
        }

        setTasks(
            tasks.map((t) =>
                t.id === taskId
                    ? {
                        ...t,
                        scheduledDate: newScheduledDate,
                        dayOfWeek: newDate.getDay(),
                        startTime: resolvedStartTime || t.startTime,
                        updatedAt: new Date(),
                    }
                    : t,
            ),
        );

        try {
            await fetch("/api/tasks", {
                method: "PATCH",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    id: taskId,
                    scheduledDate: newScheduledDate,
                    dayOfWeek: newDate.getDay(),
                    startTime: resolvedStartTime,
                }),
            });

            // Sync due date change to external provider
            if (task.externalId && task.externalProvider) {
                fetch("/api/tasks/sync", {
                    method: "PATCH",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({ taskId, scheduledDate: newScheduledDate }),
                }).catch((e) => console.error("Sync error:", e));
            }
        } catch (error) {
            console.error("Error rolling task:", error);
        }
    };

    // Drag and drop handlers
    const handleDragStart = (e: DragEvent, task: Task) => {
        setDraggedTask(task);
        if (e.dataTransfer) {
            e.dataTransfer.effectAllowed = "move";
            e.dataTransfer.setData("text/plain", task.id);
        }
        // Add drag-source class for styling
        if (e.currentTarget instanceof HTMLElement) {
            e.currentTarget.classList.add("drag-source");
        }
    };

    const handleDragOver = (
        e: DragEvent | React.DragEvent,
        dayOfWeek?: number,
        slot?: string,
    ) => {
        // Reject someday list drags on day slots
        if (draggingListId) {
            e.preventDefault();
            if (e.dataTransfer) {
                e.dataTransfer.dropEffect = "none";
            }
            return;
        }
        e.preventDefault();
        if (e.dataTransfer) {
            e.dataTransfer.dropEffect = "move";
        }
        // Update drop preview if we have day and slot info
        if (dayOfWeek !== undefined && slot) {
            setDropPreview({ day: dayOfWeek, slot });
        }
    };

    const handleDrop = async (e: DragEvent, dayOfWeek: number, slot?: string) => {
        e.preventDefault();
        if (draggedTask) {
            const visibleDays = getVisibleDays();
            const targetDateObj =
                visibleDays.find((d) => d.getDay() === dayOfWeek) || new Date();

            let targetSlot = slot;

            // If no slot provided (dropped on header/background), try to keep original time
            if (!targetSlot && draggedTask.startTime) {
                targetSlot = draggedTask.startTime;
            }

            // Collision detection / Find next free slot
            if (targetSlot) {
                if (isSlotOccupiedByTask(targetDateObj, targetSlot, draggedTask.id)) {
                    const allSlots = getTimeSlots(
                        effectiveCellDuration,
                        0,
                        24,
                    );
                    const startIndex = allSlots.indexOf(targetSlot);
                    if (startIndex !== -1) {
                        for (let i = startIndex + 1; i < allSlots.length; i++) {
                            const nextSlot = allSlots[i];
                            if (!isSlotOccupiedByTask(targetDateObj, nextSlot, draggedTask.id) && !isSlotProtected(targetDateObj, nextSlot)) {
                                targetSlot = nextSlot;
                                break;
                            }
                        }
                    }
                }
            }

            // If the task is a subtask, promote it to a standalone task
            if (draggedTask.parentTaskId) {
                const newScheduledDate = formatDateToISO(targetDateObj);
                // Remove subtask from parent in UI
                setTasks((prev) =>
                    prev.map((t) =>
                        t.id === draggedTask.parentTaskId
                            ? { ...t, subTasks: (t.subTasks || []).filter((s) => s.id !== draggedTask.id) }
                            : t
                    )
                );
                // Add as standalone task in UI
                setTasks((prev) => [
                    ...prev,
                    {
                        ...draggedTask,
                        parentTaskId: null,
                        scheduledDate: newScheduledDate,
                        dayOfWeek,
                        startTime: targetSlot || "",
                    } as Task,
                ]);
                // Persist
                try {
                    await fetch("/api/tasks", {
                        method: "PATCH",
                        headers: { "Content-Type": "application/json" },
                        body: JSON.stringify({
                            id: draggedTask.id,
                            parentTaskId: null,
                            scheduledDate: newScheduledDate,
                            dayOfWeek,
                            startTime: targetSlot || "",
                        }),
                    });
                } catch (error) {
                    console.error("Error promoting subtask:", error);
                }
                setDraggedTask(null);
                setDropPreview(null);
                return;
            }

            // If the task was from a someday list, move it to the calendar
            if (draggedTask.somedayListId) {
                const newScheduledDate = formatDateToISO(targetDateObj);
                // Inherit provider from someday list if task doesn't have one
                const sourceList = somedayLists.find(l => l.id === draggedTask.somedayListId);
                const taskProvider = draggedTask.externalProvider || sourceList?.externalProvider || null;
                // Remove from someday list UI
                setSomedayLists((prev) =>
                    prev.map((l) => ({
                        ...l,
                        tasks: l.tasks.filter((t) => t.id !== draggedTask.id),
                    })),
                );
                // Add to calendar tasks
                setTasks((prev) => [
                    ...prev,
                    {
                        ...draggedTask,
                        somedayListId: null,
                        somedaySlotIndex: null,
                        scheduledDate: newScheduledDate,
                        dayOfWeek,
                        startTime: targetSlot || "",
                        externalProvider: taskProvider,
                    },
                ]);
                // Persist
                try {
                    await fetch("/api/tasks", {
                        method: "PATCH",
                        headers: { "Content-Type": "application/json" },
                        body: JSON.stringify({
                            id: draggedTask.id,
                            somedayListId: null,
                            somedaySlotIndex: null,
                            scheduledDate: newScheduledDate,
                            dayOfWeek,
                            startTime: targetSlot || "",
                            ...(taskProvider && { externalProvider: taskProvider }),
                        }),
                    });

                    // Sync due date to external provider when moving from someday to calendar
                    if (draggedTask.externalId && draggedTask.externalProvider) {
                        fetch("/api/tasks/sync", {
                            method: "PATCH",
                            headers: { "Content-Type": "application/json" },
                            body: JSON.stringify({
                                taskId: draggedTask.id,
                                scheduledDate: newScheduledDate,
                            }),
                        }).catch((e) => console.error("Sync error:", e));
                    }
                } catch (error) {
                    console.error("Error moving task from someday to calendar:", error);
                }
            } else {
                moveTaskToSlot(
                    draggedTask.id,
                    dayOfWeek,
                    targetSlot || "",
                    targetDateObj,
                );
            }
            setDraggedTask(null);
        }
        setDropPreview(null);
    };

    const handleDragEnd = () => {
        setDraggedTask(null);
        setDropPreview(null);
        // Remove drag-source class from all elements
        document
            .querySelectorAll(".drag-source")
            .forEach((el) => el.classList.remove("drag-source"));
    };

    const handleDragLeave = () => {
        setDropPreview(null);
    };


    const handleSomedayDragOver = (e: React.DragEvent, listId: string, slotIdx: number) => {
        e.preventDefault();
        setDropPreview({ listId, slotIdx });
    };

    const handleSomedayDrop = async (e: React.DragEvent, listId: string, slotIndex: number) => {
        e.preventDefault();
        if (draggedTask) {
            // If subtask, remove from parent first
            if (draggedTask.parentTaskId) {
                setTasks((prev) =>
                    prev.map((t) =>
                        t.id === draggedTask.parentTaskId
                            ? { ...t, subTasks: (t.subTasks || []).filter((s) => s.id !== draggedTask.id) }
                            : t
                    )
                );
            }

            // Update local state for someday lists
            setSomedayLists((prev) =>
                prev.map((l) => {
                    // Remove the task from its current position in all lists
                    const filteredTasks = l.tasks.filter((t) => t.id !== draggedTask.id);
                    if (l.id === listId) {
                        const movedTask = {
                            ...draggedTask,
                            parentTaskId: null,
                            somedayListId: listId,
                            somedaySlotIndex: slotIndex,
                            scheduledDate: null as any,
                            dayOfWeek: null as any,
                            startTime: null as any,
                        };
                        return {
                            ...l,
                            tasks: [...filteredTasks, movedTask],
                        };
                    }
                    return { ...l, tasks: filteredTasks };
                }),
            );

            // If it was a calendar task (not someday, not subtask), remove from calendar tasks
            if (!draggedTask.somedayListId && !draggedTask.parentTaskId) {
                setTasks((prev) => prev.filter((t) => t.id !== draggedTask.id));
            }

            // Persist the change
            try {
                await fetch("/api/tasks", {
                    method: "PATCH",
                    headers: { "Content-Type": "application/json" },
                    body: JSON.stringify({
                        id: draggedTask.id,
                        parentTaskId: null,
                        somedayListId: listId,
                        somedaySlotIndex: slotIndex,
                        scheduledDate: null,
                        dayOfWeek: null,
                        startTime: null,
                    }),
                });

                // If the target list is synced to an external provider and
                // the task doesn't already exist at that provider/list, create it there
                const targetList = somedayLists.find((l) => l.id === listId);
                const needsSync = targetList?.externalId && targetList?.externalProvider && (
                    !draggedTask.externalId ||
                    draggedTask.externalProvider !== targetList.externalProvider ||
                    draggedTask.externalListId !== targetList.externalId
                );
                if (needsSync) {
                    try {
                        const syncRes = await fetch("/api/tasks/sync", {
                            method: "POST",
                            headers: { "Content-Type": "application/json" },
                            body: JSON.stringify({ taskId: draggedTask.id }),
                        });
                        if (syncRes.ok) {
                            const syncData = await syncRes.json();
                            // Update local state with external IDs
                            if (syncData.task) {
                                setSomedayLists((prev) =>
                                    prev.map((l) => ({
                                        ...l,
                                        tasks: l.tasks.map((t) =>
                                            t.id === draggedTask.id
                                                ? {
                                                    ...t,
                                                    externalId: syncData.task.externalId,
                                                    externalProvider: syncData.task.externalProvider,
                                                    externalListId: syncData.task.externalListId,
                                                }
                                                : t
                                        ),
                                    }))
                                );
                            }
                        }
                    } catch (syncError) {
                        console.error("Failed to sync task to external provider:", syncError);
                    }
                }
            } catch (error) {
                console.error("Error moving task to someday slot:", error);
            }
            setDraggedTask(null);
            setDropPreview(null);
        }
    };

    // Sync calendar
    const handleSync = async () => {
        setSyncStatus("syncing");
        try {
            // Pull changes from Google Tasks, then force-refresh calendar cache
            await fetch("/api/tasks/sync").catch((e) =>
                console.error("Task pull sync error:", e),
            );
            // Force live refresh from providers (bypass staleness check)
            const syncRes = await fetch("/api/calendar/sync", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    timeMin: new Date(
                        currentWeekStart.getTime() - 7 * 24 * 60 * 60 * 1000,
                    ).toISOString(),
                    timeMax: new Date(
                        currentWeekStart.getTime() + 14 * 24 * 60 * 60 * 1000,
                    ).toISOString(),
                    forceRefresh: true,
                }),
            });
            if (syncRes.ok) {
                const data = await syncRes.json();
                if (data.events) setRawCalendarEvents(data.events);
            }
            await fetchTasks();
            // Re-fetch after background refresh completes
            if (true) {
                setTimeout(() => fetchCalendarEvents(), 8000);
            }
            setSyncStatus("synced");
            announce("Sync complete");
            setTimeout(() => setSyncStatus("idle"), 3000);
        } catch (error) {
            console.error("Error syncing:", error);
            setSyncStatus("idle");
            announce("Sync failed");
            setSyncError("Sync failed");
            setTimeout(() => setSyncError(null), 10000);
        }
    };

    // Start adding someday list UI
    const handleStartAddSomedayList = () => {
        setIsAddingSomedayList(true);
        // Focus will happen in render logic if possible or via ref, but let's render conditional input first
    };

    const saveSomedayList = async () => {
        if (!newSomedayListName.trim()) {
            setIsAddingSomedayList(false);
            setNewSomedayListName("");
            setSelectedSomedayProvider(null);
            return;
        }

        try {
            const url = selectedSomedayProvider
                ? "/api/someday-lists/external"
                : "/api/someday-lists";

            const response = await fetch(url, {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    title: newSomedayListName.trim(),
                    provider: selectedSomedayProvider,
                }),
            });

            if (response.ok) {
                const data = await response.json();
                setSomedayLists((prev) => [
                    ...prev,
                    {
                        ...(data.somedayList || data.list),
                        tasks: [], // Initially empty
                    },
                ]);
                setNewSomedayListName("");
                setSelectedSomedayProvider(null);
                setIsAddingSomedayList(false);
            } else {
                const error = await response.json();
                alert(error.error || "Failed to create list");
            }
        } catch (error) {
            console.error("Error adding someday list:", error);
            alert("An error occurred while creating the list");
        }
    };

    // Get time slots to display
    const visibleSlots = getTimeSlots(
        effectiveCellDuration,
        0,
        24,
    );

    const fontSizeScale = profile.fontSize === "S" ? 0.85 : profile.fontSize === "L" ? 1.15 : 1;
    const mobileScale = isMobile ? (profile.mobileFontScale || 1.0) : 1.0;
    const fontVal = (v: string | undefined) => v && v !== "__custom__" ? v : "";
    const scaleRem = (base: string) => {
        const num = parseFloat(base);
        return `${(num * fontSizeScale * mobileScale).toFixed(3)}rem`;
    };
    const activeTheme = (darkMode ? profile.darkTheme : profile.lightTheme) as Record<string, string> | null;
    const useLeftRail = !isMobile && profile.menuPosition !== "top";

    const containerStyle = {
        ...(activeTheme ? {
            "--weekly-bg": activeTheme.background,
            "--weekly-text": activeTheme.foreground,
            "--weekly-text-light": activeTheme.color8 || activeTheme.color7,
            "--weekly-border": activeTheme.color0,
            "--weekly-teal": activeTheme.color4 || activeTheme.color6,
            "--weekly-settings-item-bg": activeTheme.color0,
            "--weekly-item-hover": activeTheme.color0,
        } : {}),
        "--weekly-font-headline":
            fontVal(profile.headlineFont)
                ? `"${fontVal(profile.headlineFont)}", sans-serif`
                : "var(--font-headline)",
        "--weekly-headline-size": scaleRem(profile.headlineFontSize || "1.25rem"),
        "--weekly-headline-weight": profile.headlineFontWeight || "900",
        "--weekly-date-font": fontVal(profile.dateFontFamily)
            ? `"${fontVal(profile.dateFontFamily)}", sans-serif`
            : "var(--weekly-font-headline)",
        "--weekly-date-size": scaleRem(profile.dateFontSize || "0.65rem"),
        "--weekly-date-weight": profile.dateFontWeight || "400",
        "--weekly-time-task-font": (() => {
            // If time task font is explicitly customized (not default "Inter"), use it
            // Otherwise inherit from task font
            const ttf = fontVal(profile.timeTaskFontFamily);
            const tf = fontVal(profile.taskFontFamily);
            const isDefault = !ttf || ttf === "Inter";
            if (!isDefault) return `"${ttf}", sans-serif`;
            if (tf) return `"${tf}", sans-serif`;
            return "var(--weekly-font)";
        })(),
        "--weekly-time-task-size": scaleRem(
            // If time task size is the old default 0.75rem, use task size instead
            profile.timeTaskFontSize && profile.timeTaskFontSize !== "0.75rem"
                ? profile.timeTaskFontSize
                : profile.taskFontSize || "0.9rem"
        ),
        "--weekly-time-task-weight":
            // If time task weight is the old default 500, use task weight instead
            profile.timeTaskFontWeight && profile.timeTaskFontWeight !== "500"
                ? profile.timeTaskFontWeight
                : profile.taskFontWeight || "400",
        "--weekly-font":
            "var(--font-body)" /* Force default body font as requested */,
        "--weekly-task-font": fontVal(profile.taskFontFamily)
            ? `"${fontVal(profile.taskFontFamily)}", sans-serif`
            : "var(--weekly-font)",
        "--weekly-task-size": scaleRem(profile.taskFontSize || "0.9rem"),
        "--weekly-task-weight": profile.taskFontWeight || "400",
        "--weekly-event-font":
            fontVal(profile.eventFontFamily)
                ? `"${fontVal(profile.eventFontFamily)}", sans-serif`
                : "var(--weekly-font)",
        "--weekly-event-size": scaleRem(profile.eventFontSize || "0.85rem"),
        "--weekly-event-weight": profile.eventFontWeight || "400",
        "--font-weight-body": profile.fontWeight || "400",
        "--weekly-weekend-sat": activeTheme?.color3 || (darkMode
            ? invertColor(profile.weekendColorSat || "#666666")
            : profile.weekendColorSat || "#666666"),
        "--weekly-weekend-sun": activeTheme?.color1 || (darkMode
            ? invertColor(profile.weekendColorSun || "#dc2626")
            : profile.weekendColorSun || "#dc2626"),
        "--weekly-weekday-color": activeTheme?.foreground || (darkMode
            ? invertColor(profile.weekdayColor || "#888888")
            : profile.weekdayColor || "#888888"),
        "--weekly-date-color": activeTheme?.color8 || (darkMode
            ? invertColor(profile.dateColor || "#888888")
            : profile.dateColor || "#888888"),
        "--weekly-task-color": activeTheme?.color7 || (darkMode
            ? invertColor(profile.taskColor || "#333333")
            : profile.taskColor || "#333333"),
        "--weekly-today-highlight": activeTheme?.color0 || (darkMode
            ? invertColor(profile.todayHighlightColor || "#f0fafa")
            : profile.todayHighlightColor || "#f0fafa"),
        "--weekly-past-color": activeTheme?.color8 || (darkMode
            ? invertColor(profile.pastDayColor || "#a6a6a7")
            : profile.pastDayColor || "#a6a6a7"),
        ...(useLeftRail ? { paddingLeft: leftRailExpanded ? "240px" : "44px", transition: "padding-left 0.2s ease" } : {}),
    } as React.CSSProperties;

    if (isLoading) {
        return (
            <div
                className="weekly-container"
                style={{ alignItems: "center", justifyContent: "center" }}
            >
                <div style={{ color: "var(--weekly-text-light)" }}>
                    {translations[profile.language]?.loading || translations["en"].loading}
                </div>
            </div>
        );
    }

    const activeDateLayout = isMobile ? (profile.mobileDateLayout || "below") : (profile.dateLayout || "right");

    // Quick settings sidebar button styles
    const qsBtnStyle = (dm: boolean): React.CSSProperties => ({
        padding: "6px", borderRadius: "6px", border: "none", cursor: "pointer",
        display: "flex", alignItems: "center", justifyContent: "center",
        background: dm ? "#1f2937" : "#e5e7eb", color: dm ? "#9ca3af" : "#6b7280",
    });
    const qsActionStyle = (dm: boolean): React.CSSProperties => ({
        display: "flex", alignItems: "center", gap: "8px", padding: "7px 8px",
        fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer",
        background: "none", color: dm ? "#d1d5db" : "#333", textAlign: "left" as const,
    });

    const railIconBtnStyle: React.CSSProperties = {
        width: "36px", height: "36px", display: "flex", alignItems: "center", justifyContent: "center",
        background: "none", border: "none", cursor: "pointer", borderRadius: "8px",
        color: darkMode ? "#9ca3af" : "#6b7280", flexShrink: 0,
    };
    const flyoutPanelStyle: React.CSSProperties = {
        position: "fixed", left: "48px",
        top: `${Math.min(flyoutY, (typeof window !== "undefined" ? window.innerHeight : 800) - 260)}px`,
        background: darkMode ? "#1a1a2e" : "var(--paper)",
        border: "1px solid var(--line)", borderRadius: "10px", padding: "12px 14px",
        zIndex: 200, boxShadow: "2px 4px 16px rgba(0,0,0,0.10)", minWidth: "200px",
        display: "flex", flexDirection: "column", gap: "10px",
    };
    const flyoutLabelStyle: React.CSSProperties = {
        fontSize: "0.68rem", fontWeight: 700, letterSpacing: "0.06em", textTransform: "uppercase" as const,
        color: darkMode ? "#6b7280" : "var(--ink-3)", marginBottom: "2px",
    };
    const openFlyout = (section: string, e: React.MouseEvent) => {
        if (flyoutTimerRef.current) clearTimeout(flyoutTimerRef.current);
        const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
        setFlyoutY(rect.top);
        setFlyoutSection(section);
    };
    const closeFlyoutDelayed = () => {
        flyoutTimerRef.current = setTimeout(() => setFlyoutSection(null), 180);
    };
    const keepFlyoutOpen = () => {
        if (flyoutTimerRef.current) clearTimeout(flyoutTimerRef.current);
    };
    const railSep = (
        <div style={{ height: "1px", background: "var(--line)", width: "28px", margin: "3px 0", flexShrink: 0, alignSelf: "center" }} />
    );

    // All-Day Events Section (reusable for above/below positioning)
    const allDaySection = (() => {
        if (!effectiveShowAllDay) return null;
        const allDayEvents = calendarEvents.filter((event) =>
            isAllDayEvent(event),
        );
        if (allDayEvents.length === 0) return null;

        const handleOnTop = effectiveAllDayPosition === "below";
        const resizeHandle = isAllDayExpanded ? (
            <div
                className="resize-handle"
                onMouseDown={(e) => startResize(e, 'allday', handleOnTop)}
                onTouchStart={(e) => startResize(e, 'allday', handleOnTop)}
            >
                <div className="resize-handle-bar" />
            </div>
        ) : null;

        return (
            <>
            {effectiveAllDayPosition === "below" && resizeHandle}
            <section
                className={`all-day-events-section ${isAllDayExpanded ? "expanded" : "collapsed"}`}
                style={isAllDayExpanded && allDayHeight ? { height: `${allDayHeight}px`, overflowY: 'auto' } : undefined}
            >
                <div style={{ display: "flex", flexDirection: "row" }}>
                    {profile.showTimeGrid && (
                        <div
                            className="all-day-label-column"
                            onClick={() => setIsAllDayExpanded(!isAllDayExpanded)}
                            style={{
                                width: "55px",
                                flexShrink: 0,
                                display: "flex",
                                flexDirection: "column",
                                alignItems: "center",
                                justifyContent: "flex-start",
                                cursor: "pointer",
                                borderRight: "1px solid var(--weekly-border)",
                                padding: "4px 4px 2px",
                                gap: "0px",
                                marginLeft: "-1px",
                                position: "relative",
                            }}
                            title={isAllDayExpanded ? "Collapse" : "Expand"}
                        >
                            <span
                                style={{
                                    fontSize: "0.6rem",
                                    fontWeight: 600,
                                    color: "var(--weekly-text-light)",
                                    textTransform: "uppercase",
                                    letterSpacing: "0.05em",
                                    lineHeight: 1.1,
                                    textAlign: "center",
                                }}
                            >
                                all day
                            </span>
                            <span
                                className="all-day-events-count"
                                style={{
                                    fontSize: "0.55rem",
                                    padding: "0px 3px",
                                    marginTop: "1px",
                                }}
                            >
                                {(() => {
                                    const visibleDays = getVisibleDays();
                                    const seen = new Set<string>();
                                    visibleDays.forEach(d => getAllDayEventsForDate(d).forEach(e => seen.add(e.id)));
                                    return seen.size;
                                })()}
                            </span>
                        </div>
                    )}
                    {/* In list mode (no time grid), skip the label column so events align with day columns */}
                    {isAllDayExpanded && (
                        <div
                            className={`all-day-events-grid cols-${viewDays}`}
                            style={{ flex: 1 }}
                        >
                            {getVisibleDays().map((date) => {
                                const dayEvents = getAllDayEventsForDate(date);
                                return (
                                    <div
                                        key={date.toISOString()}
                                        className="all-day-events-column"
                                    >
                                        {dayEvents.length > 0 ? (
                                            dayEvents.map((event) => (
                                                <div
                                                    key={event.id}
                                                    className="all-day-event"
                                                    title={`${event.calendarTitle}: ${event.title}`}
                                                    onClick={(e) => {
                                                        e.stopPropagation();
                                                        if (event.editable) {
                                                            setCalendarEventModal({
                                                                isOpen: true,
                                                                event: event,
                                                            });
                                                        }
                                                    }}
                                                    style={{
                                                        backgroundColor:
                                                            event.calendarColor || "#3b82f6",
                                                        color: "white",
                                                        borderLeft: "none",
                                                        padding: "2px 4px",
                                                        borderRadius: "3px",
                                                        fontSize: "0.75rem",
                                                        marginBottom: "2px",
                                                        whiteSpace: "nowrap",
                                                        overflow: "hidden",
                                                        textOverflow: "ellipsis",
                                                        display: "flex",
                                                        alignItems: "center",
                                                        gap: "4px",
                                                        cursor: event.editable ? "pointer" : "default",
                                                        transition: "filter 0.1s ease",
                                                    }}
                                                    onMouseEnter={(e) => {
                                                        if (event.editable) e.currentTarget.style.filter = "brightness(0.9)";
                                                    }}
                                                    onMouseLeave={(e) => {
                                                        if (event.editable) e.currentTarget.style.filter = "none";
                                                    }}
                                                >
                                                    <span className="event-indicator">📅</span>
                                                    <span className="all-day-event-title">
                                                        {event.title}
                                                    </span>
                                                </div>
                                            ))
                                        ) : (
                                            <div className="all-day-empty"></div>
                                        )}
                                    </div>
                                );
                            })}
                        </div>
                    )}
                </div>
            </section>
            {effectiveAllDayPosition === "above" && resizeHandle}
            </>
        );
    })();

    return (
        <div
            className={`weekly-container ${darkMode ? "dark-mode" : ""} font-size-${(profile.fontSize ?? "M").toLowerCase()} ${profile.viewStyle}-view ${profile.showTimeGrid ? "time-grid-on" : "time-grid-off"}${(() => { const hd = isMobile ? (isPortrait ? (profile.mobilePortraitHeaderDisplay || "current_day") : (profile.mobileLandscapeHeaderDisplay || profile.headerDisplay || "kw")) : (profile.headerDisplay || "kw"); return (viewDays === 1 && hd === "current_day") ? " header-current-day-single" : ""; })()}`}
            style={containerStyle}
        >
            {/* Visually hidden live region for screen reader announcements */}
            <div
                role="status"
                aria-live="polite"
                aria-atomic="true"
                style={{ position: 'absolute', width: '1px', height: '1px', padding: 0, margin: '-1px', overflow: 'hidden', clip: 'rect(0,0,0,0)', whiteSpace: 'nowrap', border: 0 }}
            >
                {announceMsg}
            </div>
            {/* Mobile sticky day indicator */}
            {isMobile && mobileStickyDay && mobileStickyDayVisible && (
                <div
                    className="mobile-sticky-day-bar"
                    style={{
                        position: 'fixed',
                        top: 0,
                        left: 0,
                        right: 0,
                        zIndex: 90,
                        background: darkMode ? 'rgba(26,26,46,0.95)' : 'rgba(255,255,255,0.95)',
                        backdropFilter: 'blur(8px)',
                        WebkitBackdropFilter: 'blur(8px)',
                        borderBottom: `1px solid ${darkMode ? '#333' : '#e5e7eb'}`,
                        padding: '6px 16px',
                        fontSize: '0.82rem',
                        fontWeight: 700,
                        color: darkMode ? '#e5e7eb' : '#333',
                        fontFamily: 'var(--weekly-font-headline, var(--weekly-font))',
                        textTransform: 'uppercase',
                        letterSpacing: '0.02em',
                    }}
                >
                    {mobileStickyDay}
                </div>
            )}

            {/* Mobile Quick Settings — full overlay triggered from mobile header */}
            {isMobile && showQuickSettings && (
                <>
                <div onClick={() => setShowQuickSettings(false)} style={{ position: "fixed", inset: 0, zIndex: 999 }} />
                <div style={{ position: "fixed", left: 0, top: 0, bottom: 0, width: "240px", background: darkMode ? "#1a1a2e" : "var(--paper)", borderRight: "1px solid var(--line)", zIndex: 1000, display: "flex", flexDirection: "column", padding: "16px 14px", gap: "10px", overflowY: "auto", boxShadow: "2px 0 8px rgba(0,0,0,0.04)" }}>
                    <div style={{ fontSize: "0.85rem", fontWeight: 700, color: darkMode ? "#e5e7eb" : "#333", marginBottom: "2px" }}>{profile.language === "de" ? "Einstellungen" : "Preferences"}</div>
                    <div style={{ display: "flex", justifyContent: "center", gap: "4px", padding: "4px 0", borderBottom: "1px solid var(--line)", paddingBottom: "10px" }}>
                        <button onClick={() => { goToPrevWeek(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Previous Week"><ChevronsLeft size={16} /></button>
                        <button onClick={() => { goToPrevDay(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Previous Day"><ChevronLeft size={16} /></button>
                        <button onClick={() => { goToToday(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "56px", fontWeight: 700, fontSize: "0.7rem" }} title="Today">{profile.language === "de" ? "Heute" : "Today"}</button>
                        <button onClick={() => { goToNextDay(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Next Day"><ChevronRight size={16} /></button>
                        <button onClick={() => { goToNextWeek(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Next Week"><ChevronsRight size={16} /></button>
                    </div>
                    <div style={{ display: "flex", flexDirection: "column", gap: "1px" }}>
                        <button onClick={() => { setIsSearchOpen(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Search size={16} /> <span>{profile.language === "de" ? "Suche" : "Search"}</span></button>
                        <button onClick={() => { setShowDatePicker(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Calendar size={16} /> <span>{profile.language === "de" ? "Datum wählen" : "Jump to date"}</span></button>
                        <button onClick={() => { const now = new Date(); setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` }); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Plus size={16} /> <span>{profile.language === "de" ? "Kalendereintrag" : "Calendar Event"}</span></button>
                        <button onClick={() => { setShowProjectsSidebar(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><FolderPlus size={16} /> <span>{profile.language === "de" ? "Projekte" : "Projects"}</span></button>
                        <button onClick={() => { setIsRecurringTasksOpen(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Repeat size={16} /> <span>{profile.language === "de" ? "Wiederkehrend" : "Recurring Tasks"}</span></button>
                        <button onClick={() => { const nv = !profile.showNextTask; setShowNextTask(nv); saveSetting("showNextTask", nv); }} style={qsActionStyle(darkMode)}>{profile.showNextTask ? <Play size={16} /> : <Target size={16} />}<span>{profile.showNextTask ? (profile.language === "de" ? "Nächste Aufgabe" : "Next Task") : (profile.language === "de" ? "Ziel" : "Goal")}</span></button>
                        <button onClick={() => { setShowFocusMode(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Zap size={16} /> <span>{profile.language === "de" ? "Fokus" : "Focus"}</span></button>
                    </div>
                    <div style={{ borderTop: "1px solid var(--line)", paddingTop: "8px" }} />
                    <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
                        <span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "var(--ink-3)" }}>{profile.language === "de" ? "Ansicht" : "View"}</span>
                        <div style={{ display: "flex", gap: "4px" }}>{[{ key: "simple", icon: <Calendar size={13} /> }, { key: "calendar", icon: <CalendarDays size={13} /> }, { key: "list", icon: <ListTodo size={13} /> }, { key: "kanban", icon: <Kanban size={13} /> }, { key: "priority", icon: <Target size={13} /> }].map((v) => (<button key={v.key} onClick={() => { setViewStyle(v.key as any); saveSetting("viewStyle", v.key); if (v.key === "list") { setShowTimeGrid(false); saveSetting("showTimeGrid", false); } if (v.key === "simple" || v.key === "calendar") { setShowTimeGrid(true); saveSetting("showTimeGrid", true); } if (v.key === "priority" || v.key === "kanban") { setShowTimeGrid(false); saveSetting("showTimeGrid", false); } }} style={{ flex: 1, padding: "5px 0", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", fontWeight: profile.viewStyle === v.key ? 700 : 400, background: profile.viewStyle === v.key ? "var(--accent)" : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.viewStyle === v.key ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{v.icon}</button>))}</div>
                    </div>
                    <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
                        <span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "var(--ink-3)" }}>{profile.language === "de" ? "Spalten" : "Days"}</span>
                        <div style={{ display: "flex", gap: "4px" }}>{[1, 2, 3, 5, 7].map((num) => (<button key={num} onClick={() => { setViewDays(num); savedViewDaysRef.current = num; saveSetting("viewDays", num); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: viewDays === num ? 700 : 400, background: viewDays === num ? (darkMode ? "#374151" : "var(--ink)") : (darkMode ? "#1f2937" : "#e5e7eb"), color: viewDays === num ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{num}</button>))}</div>
                    </div>
                    {profile.showTimeGrid && (<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "var(--ink-3)" }}>{profile.language === "de" ? "Zeitfenster" : "Slot"}</span><div style={{ display: "flex", gap: "4px" }}>{(([15, 20, 30, 60] as CellDuration[])).map((d) => (<button key={d} onClick={() => { setCellDuration(d); saveSetting("cellDuration", d); saveViewSetting("cellDuration", d, true); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: effectiveCellDuration === d ? 700 : 400, background: effectiveCellDuration === d ? (darkMode ? "#374151" : "var(--ink)") : (darkMode ? "#1f2937" : "#e5e7eb"), color: effectiveCellDuration === d ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{d}m</button>))}</div></div>)}
                    {profile.showTimeGrid && (<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}><span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>:15/:30/:45</span><button onClick={() => { const v = !effectiveShowSubHourSlots; setShowSubHourSlots(v); saveSetting("showSubHourSlots", v); }} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>{effectiveShowSubHourSlots ? <Eye size={16} /> : <EyeOff size={16} />}</button></div>)}
                    <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Textgröße" : "Text size"}</span><div style={{ display: "flex", gap: "4px" }}>{(["S", "M", "L"] as const).map((size) => (<button key={size} onClick={() => { setFontSize(size); saveSetting("fontSize", size); }} style={{ padding: "4px 10px", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: profile.fontSize === size ? 700 : 400, background: profile.fontSize === size ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.fontSize === size ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{size}</button>))}</div></div>
                    <div style={{ borderTop: `1px solid ${darkMode ? "#333" : "#e5e7eb"}`, paddingTop: "4px" }} />
                    {[{ label: profile.language === "de" ? "Irgendwann" : "Someday", value: effectiveShowSomeday, toggle: () => saveViewSetting("showSomeday", !effectiveShowSomeday, true) }, { label: profile.language === "de" ? "Ganztägig" : "All-day", value: effectiveShowAllDay, toggle: () => saveViewSetting("showAllDayEvents", !effectiveShowAllDay, true) }, { label: profile.language === "de" ? "Checkboxen" : "Checkboxes", value: effectiveShowTaskCheckboxes, toggle: () => saveViewSetting("showTaskCheckboxes", !effectiveShowTaskCheckboxes, true) }, { label: profile.language === "de" ? "Projekt-Icons" : "Project Icons", value: effectiveShowProjectIcons, toggle: () => saveViewSetting("showProjectIcons", !effectiveShowProjectIcons, true) }, { label: profile.language === "de" ? "Prioritäts-Icons" : "Priority Icons", value: effectiveShowPriorityIcons, toggle: () => saveViewSetting("showPriorityIcons", !effectiveShowPriorityIcons, true) }, ...((profile.weatherEnabled || profile.weatherLat || profile.weatherLon) ? [{ label: profile.language === "de" ? "Wetter" : "Weather", value: effectiveWeatherEnabled, toggle: () => { const v = !effectiveWeatherEnabled; setProfile((p: any) => ({ ...p, weatherEnabled: v })); saveViewSetting("weatherEnabled", v, true); } }] : []) ].map(({ label, value, toggle }) => (<div key={label} style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}><span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{label}</span><button onClick={toggle} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>{value ? <Eye size={16} /> : <EyeOff size={16} />}</button></div>))}
                    <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Starten mit" : "Start on"}</span><div style={{ display: "flex", gap: "4px" }}><button onClick={() => { setProfile({ ...profile, startDayOffset: 0 }); saveSetting("startDayOffset", 0); const d = new Date(); d.setHours(0, 0, 0, 0); setCurrentWeekStart(d); }} style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: (profile.startDayOffset || 0) === 0 ? 700 : 400, background: (profile.startDayOffset || 0) === 0 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: (profile.startDayOffset || 0) === 0 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{profile.language === "de" ? "Heute" : "Today"}</button><button onClick={() => { setProfile({ ...profile, startDayOffset: -1 }); saveSetting("startDayOffset", -1); const d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() - 1); setCurrentWeekStart(d); }} style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: profile.startDayOffset === -1 ? 700 : 400, background: profile.startDayOffset === -1 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.startDayOffset === -1 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{profile.language === "de" ? "Gestern" : "Yesterday"}</button></div></div>
                    <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Anzeige" : "Display"}</span><div style={{ display: "flex", gap: "4px" }}><button onClick={() => setDarkMode(false)} style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", gap: "4px", fontWeight: !darkMode ? 700 : 400, background: !darkMode ? "#333" : (darkMode ? "#1f2937" : "#e5e7eb"), color: !darkMode ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}><Sun size={12} /> {profile.language === "de" ? "Hell" : "Light"}</button><button onClick={() => setDarkMode(true)} style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", gap: "4px", fontWeight: darkMode ? 700 : 400, background: darkMode ? "#374151" : "#e5e7eb", color: darkMode ? "#fff" : "#6b7280" }}><Moon size={12} /> {profile.language === "de" ? "Dunkel" : "Dark"}</button></div></div>
                    <div style={{ borderTop: `1px solid ${darkMode ? "#333" : "#e5e7eb"}`, paddingTop: "4px" }} />
                    <div style={{ display: "flex", justifyContent: "center", gap: "8px", padding: "2px 0" }}>
                        <button onClick={handleUndo} disabled={undoCount === 0} style={{ ...qsBtnStyle(darkMode), opacity: undoCount === 0 ? 0.3 : 1 }} title="Undo"><Undo2 size={15} /></button>
                        <button onClick={handleRedo} disabled={redoCount === 0} style={{ ...qsBtnStyle(darkMode), opacity: redoCount === 0 ? 0.3 : 1 }} title="Redo"><Redo2 size={15} /></button>
                        <button onClick={() => { fetchCalendarEvents(true); fetchTasks(); setShowQuickSettings(false); }} style={qsBtnStyle(darkMode)} title="Refresh"><RefreshCcw size={15} /></button>
                    </div>
                    <div style={{ flex: 1 }} />
                    <button onClick={() => { setShowMobileRail(true); setShowQuickSettings(false); }} style={{ display: "flex", alignItems: "center", gap: "6px", background: "none", border: "none", cursor: "pointer", fontSize: "0.75rem", color: darkMode ? "#9ca3af" : "#6b7280", padding: "4px 0" }}>
                        <LayoutPanelLeft size={16} />{profile.language === "de" ? "Icon-Leiste" : "Icon Rail"}
                    </button>
                    <button onClick={() => setShowQuickSettings(false)} style={{ display: "flex", alignItems: "center", gap: "6px", background: "none", border: "none", cursor: "pointer", fontSize: "0.75rem", color: darkMode ? "#6b7280" : "#9ca3af", padding: "4px 0" }}>
                        <PanelLeftClose size={16} />{profile.language === "de" ? "Ausblenden" : "Hide"}
                    </button>
                </div>
                </>
            )}

            {/* Desktop Top-mode overlay — opens like the mobile overlay, triggered by header button */}
            {!isMobile && !useLeftRail && showQuickSettings && (
                <>
                <div onClick={() => setShowQuickSettings(false)} style={{ position: "fixed", inset: 0, zIndex: 999 }} />
                <div style={{ position: "fixed", left: 0, top: 0, bottom: 0, width: "240px", background: darkMode ? "#1a1a2e" : "var(--paper)", borderRight: "1px solid var(--line)", zIndex: 1000, display: "flex", flexDirection: "column", padding: "16px 14px", gap: "10px", overflowY: "auto", boxShadow: "2px 0 8px rgba(0,0,0,0.04)" }}>
                    <div style={{ fontSize: "0.85rem", fontWeight: 700, color: darkMode ? "#e5e7eb" : "#333" }}>{profile.language === "de" ? "Einstellungen" : "Preferences"}</div>
                    {/* Menu position toggle */}
                    <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
                        <span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "var(--ink-3)" }}>{profile.language === "de" ? "Menüposition" : "Menu position"}</span>
                        <div style={{ display: "flex", gap: "4px" }}>
                            <button onClick={() => { setProfile((p: any) => ({ ...p, menuPosition: "left" })); saveSetting("menuPosition", "left"); setShowQuickSettings(false); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: "5px", fontWeight: (profile.menuPosition || "left") === "left" ? 700 : 400, background: (profile.menuPosition || "left") === "left" ? "var(--accent)" : (darkMode ? "#1f2937" : "#e5e7eb"), color: (profile.menuPosition || "left") === "left" ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}><LayoutPanelLeft size={13} />{profile.language === "de" ? "Links" : "Left"}</button>
                            <button onClick={() => { setProfile((p: any) => ({ ...p, menuPosition: "top" })); saveSetting("menuPosition", "top"); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: "5px", fontWeight: (profile.menuPosition || "left") === "top" ? 700 : 400, background: (profile.menuPosition || "left") === "top" ? "var(--accent)" : (darkMode ? "#1f2937" : "#e5e7eb"), color: (profile.menuPosition || "left") === "top" ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}><LayoutPanelTop size={13} />{profile.language === "de" ? "Oben" : "Top"}</button>
                        </div>
                    </div>
                    <div style={{ borderTop: "1px solid var(--line)", paddingTop: "8px" }} />
                    <div style={{ display: "flex", justifyContent: "center", gap: "4px", borderBottom: "1px solid var(--line)", paddingBottom: "10px" }}>
                        <button onClick={() => { goToPrevWeek(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Previous Week"><ChevronsLeft size={16} /></button>
                        <button onClick={() => { goToPrevDay(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Previous Day"><ChevronLeft size={16} /></button>
                        <button onClick={() => { goToToday(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "56px", fontWeight: 700, fontSize: "0.7rem" }}>{profile.language === "de" ? "Heute" : "Today"}</button>
                        <button onClick={() => { goToNextDay(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Next Day"><ChevronRight size={16} /></button>
                        <button onClick={() => { goToNextWeek(); setShowQuickSettings(false); }} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Next Week"><ChevronsRight size={16} /></button>
                    </div>
                    <div style={{ display: "flex", flexDirection: "column", gap: "1px" }}>
                        <button onClick={() => { setIsSearchOpen(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Search size={16} /> <span>{profile.language === "de" ? "Suche" : "Search"}</span></button>
                        <button onClick={() => { setShowDatePicker(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Calendar size={16} /> <span>{profile.language === "de" ? "Datum wählen" : "Jump to date"}</span></button>
                        <button onClick={() => { const now = new Date(); setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` }); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Plus size={16} /> <span>{profile.language === "de" ? "Kalendereintrag" : "Calendar Event"}</span></button>
                        <button onClick={() => { setShowProjectsSidebar(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><FolderPlus size={16} /> <span>{profile.language === "de" ? "Projekte" : "Projects"}</span></button>
                        <button onClick={() => { setIsRecurringTasksOpen(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Repeat size={16} /> <span>{profile.language === "de" ? "Wiederkehrend" : "Recurring Tasks"}</span></button>
                        <button onClick={() => { const nv = !profile.showNextTask; setShowNextTask(nv); saveSetting("showNextTask", nv); }} style={qsActionStyle(darkMode)}>{profile.showNextTask ? <Play size={16} /> : <Target size={16} />}<span>{profile.showNextTask ? (profile.language === "de" ? "Nächste Aufgabe" : "Next Task") : (profile.language === "de" ? "Ziel" : "Goal")}</span></button>
                        <button onClick={() => { setShowFocusMode(true); setShowQuickSettings(false); }} style={qsActionStyle(darkMode)}><Zap size={16} /> <span>{profile.language === "de" ? "Fokus" : "Focus"}</span></button>
                    </div>
                    <div style={{ borderTop: "1px solid var(--line)", paddingTop: "8px" }} />
                    <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "var(--ink-3)" }}>{profile.language === "de" ? "Ansicht" : "View"}</span><div style={{ display: "flex", gap: "4px" }}>{[{ key: "simple", icon: <Calendar size={13} /> }, { key: "calendar", icon: <CalendarDays size={13} /> }, { key: "list", icon: <ListTodo size={13} /> }, { key: "kanban", icon: <Kanban size={13} /> }, { key: "priority", icon: <Target size={13} /> }].map((v) => (<button key={v.key} onClick={() => { setViewStyle(v.key as any); saveSetting("viewStyle", v.key); if (v.key === "list") { setShowTimeGrid(false); saveSetting("showTimeGrid", false); } if (v.key === "simple" || v.key === "calendar") { setShowTimeGrid(true); saveSetting("showTimeGrid", true); } if (v.key === "priority" || v.key === "kanban") { setShowTimeGrid(false); saveSetting("showTimeGrid", false); } }} style={{ flex: 1, padding: "5px 0", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", fontWeight: profile.viewStyle === v.key ? 700 : 400, background: profile.viewStyle === v.key ? "var(--accent)" : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.viewStyle === v.key ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{v.icon}</button>))}</div></div>
                    <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "var(--ink-3)" }}>{profile.language === "de" ? "Spalten" : "Days"}</span><div style={{ display: "flex", gap: "4px" }}>{[1, 2, 3, 5, 7].map((num) => (<button key={num} onClick={() => { setViewDays(num); savedViewDaysRef.current = num; saveSetting("viewDays", num); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: viewDays === num ? 700 : 400, background: viewDays === num ? (darkMode ? "#374151" : "var(--ink)") : (darkMode ? "#1f2937" : "#e5e7eb"), color: viewDays === num ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{num}</button>))}</div></div>
                    {profile.showTimeGrid && (<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "var(--ink-3)" }}>{profile.language === "de" ? "Zeitfenster" : "Slot"}</span><div style={{ display: "flex", gap: "4px" }}>{(([15, 20, 30, 60] as CellDuration[])).map((d) => (<button key={d} onClick={() => { setCellDuration(d); saveSetting("cellDuration", d); saveViewSetting("cellDuration", d, true); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: effectiveCellDuration === d ? 700 : 400, background: effectiveCellDuration === d ? (darkMode ? "#374151" : "var(--ink)") : (darkMode ? "#1f2937" : "#e5e7eb"), color: effectiveCellDuration === d ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{d}m</button>))}</div></div>)}
                    {profile.showTimeGrid && (<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}><span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>:15/:30/:45</span><button onClick={() => { const v = !effectiveShowSubHourSlots; setShowSubHourSlots(v); saveSetting("showSubHourSlots", v); }} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>{effectiveShowSubHourSlots ? <Eye size={16} /> : <EyeOff size={16} />}</button></div>)}
                    <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Textgröße" : "Text size"}</span><div style={{ display: "flex", gap: "4px" }}>{(["S", "M", "L"] as const).map((size) => (<button key={size} onClick={() => { setFontSize(size); saveSetting("fontSize", size); }} style={{ padding: "4px 10px", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: profile.fontSize === size ? 700 : 400, background: profile.fontSize === size ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.fontSize === size ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{size}</button>))}</div></div>
                    <div style={{ borderTop: `1px solid ${darkMode ? "#333" : "#e5e7eb"}`, paddingTop: "4px" }} />
                    {[{ label: profile.language === "de" ? "Irgendwann" : "Someday", value: effectiveShowSomeday, toggle: () => saveViewSetting("showSomeday", !effectiveShowSomeday, true) }, { label: profile.language === "de" ? "Ganztägig" : "All-day", value: effectiveShowAllDay, toggle: () => saveViewSetting("showAllDayEvents", !effectiveShowAllDay, true) }, { label: profile.language === "de" ? "Checkboxen" : "Checkboxes", value: effectiveShowTaskCheckboxes, toggle: () => saveViewSetting("showTaskCheckboxes", !effectiveShowTaskCheckboxes, true) }, { label: profile.language === "de" ? "Projekt-Icons" : "Project Icons", value: effectiveShowProjectIcons, toggle: () => saveViewSetting("showProjectIcons", !effectiveShowProjectIcons, true) }, { label: profile.language === "de" ? "Prioritäts-Icons" : "Priority Icons", value: effectiveShowPriorityIcons, toggle: () => saveViewSetting("showPriorityIcons", !effectiveShowPriorityIcons, true) }, ...((profile.weatherEnabled || profile.weatherLat || profile.weatherLon) ? [{ label: profile.language === "de" ? "Wetter" : "Weather", value: effectiveWeatherEnabled, toggle: () => { const v = !effectiveWeatherEnabled; setProfile((p: any) => ({ ...p, weatherEnabled: v })); saveViewSetting("weatherEnabled", v, true); } }] : []) ].map(({ label, value, toggle }) => (<div key={label} style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}><span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{label}</span><button onClick={toggle} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>{value ? <Eye size={16} /> : <EyeOff size={16} />}</button></div>))}
                    <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Starten mit" : "Start on"}</span><div style={{ display: "flex", gap: "4px" }}><button onClick={() => { setProfile({ ...profile, startDayOffset: 0 }); saveSetting("startDayOffset", 0); const d = new Date(); d.setHours(0, 0, 0, 0); setCurrentWeekStart(d); }} style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: (profile.startDayOffset || 0) === 0 ? 700 : 400, background: (profile.startDayOffset || 0) === 0 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: (profile.startDayOffset || 0) === 0 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{profile.language === "de" ? "Heute" : "Today"}</button><button onClick={() => { setProfile({ ...profile, startDayOffset: -1 }); saveSetting("startDayOffset", -1); const d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() - 1); setCurrentWeekStart(d); }} style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: profile.startDayOffset === -1 ? 700 : 400, background: profile.startDayOffset === -1 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.startDayOffset === -1 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{profile.language === "de" ? "Gestern" : "Yesterday"}</button></div></div>
                    <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Anzeige" : "Display"}</span><div style={{ display: "flex", gap: "4px" }}><button onClick={() => setDarkMode(false)} style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", gap: "4px", fontWeight: !darkMode ? 700 : 400, background: !darkMode ? "#333" : (darkMode ? "#1f2937" : "#e5e7eb"), color: !darkMode ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}><Sun size={12} /> {profile.language === "de" ? "Hell" : "Light"}</button><button onClick={() => setDarkMode(true)} style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", gap: "4px", fontWeight: darkMode ? 700 : 400, background: darkMode ? "#374151" : "#e5e7eb", color: darkMode ? "#fff" : "#6b7280" }}><Moon size={12} /> {profile.language === "de" ? "Dunkel" : "Dark"}</button></div></div>
                    <div style={{ borderTop: `1px solid ${darkMode ? "#333" : "#e5e7eb"}`, paddingTop: "4px" }} />
                    <div style={{ display: "flex", justifyContent: "center", gap: "8px", padding: "2px 0" }}>
                        <button onClick={handleUndo} disabled={undoCount === 0} style={{ ...qsBtnStyle(darkMode), opacity: undoCount === 0 ? 0.3 : 1 }} title="Undo"><Undo2 size={15} /></button>
                        <button onClick={handleRedo} disabled={redoCount === 0} style={{ ...qsBtnStyle(darkMode), opacity: redoCount === 0 ? 0.3 : 1 }} title="Redo"><Redo2 size={15} /></button>
                        <button onClick={() => { fetchCalendarEvents(true); fetchTasks(); setShowQuickSettings(false); }} style={qsBtnStyle(darkMode)} title="Refresh"><RefreshCcw size={15} /></button>
                    </div>
                    <div style={{ flex: 1 }} />
                    <button onClick={() => setShowQuickSettings(false)} style={{ display: "flex", alignItems: "center", gap: "6px", background: "none", border: "none", cursor: "pointer", fontSize: "0.75rem", color: darkMode ? "#6b7280" : "#9ca3af", padding: "4px 0" }}>
                        <PanelLeftClose size={16} />{profile.language === "de" ? "Ausblenden" : "Hide"}
                    </button>
                </div>
                </>
            )}

            {/* Desktop Left Rail — persistent, collapses to icon strip */}
            {useLeftRail && (
                <>
                {/* The rail panel */}
                <div style={{ position: "fixed", left: 0, top: 0, bottom: 0, width: leftRailExpanded ? "240px" : "44px", transition: "width 0.2s ease", background: darkMode ? "#1a1a2e" : "var(--paper)", borderRight: "1px solid var(--line)", zIndex: 100, display: "flex", flexDirection: "column", overflow: "hidden" }}>
                    {leftRailExpanded ? (
                        // ── EXPANDED MODE ──
                        <div style={{ padding: "16px 14px", display: "flex", flexDirection: "column", gap: "10px", overflowY: "auto", flex: 1 }}>
                            <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                                <span style={{ fontSize: "0.85rem", fontWeight: 700, color: darkMode ? "#e5e7eb" : "#333" }}>{profile.language === "de" ? "Einstellungen" : "Preferences"}</span>
                                <button onClick={() => setLeftRailExpanded(false)} style={{ background: "none", border: "none", cursor: "pointer", color: darkMode ? "#6b7280" : "#9ca3af", padding: "2px", display: "flex" }} title="Collapse">
                                    <PanelLeftClose size={16} />
                                </button>
                            </div>
                            {/* Menu position toggle */}
                            <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
                                <span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "var(--ink-3)" }}>{profile.language === "de" ? "Menüposition" : "Menu position"}</span>
                                <div style={{ display: "flex", gap: "4px" }}>
                                    <button onClick={() => { setProfile((p: any) => ({ ...p, menuPosition: "left" })); saveSetting("menuPosition", "left"); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: "5px", fontWeight: (profile.menuPosition || "left") === "left" ? 700 : 400, background: (profile.menuPosition || "left") === "left" ? "var(--accent)" : (darkMode ? "#1f2937" : "#e5e7eb"), color: (profile.menuPosition || "left") === "left" ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}><LayoutPanelLeft size={13} />{profile.language === "de" ? "Links" : "Left"}</button>
                                    <button onClick={() => { setProfile((p: any) => ({ ...p, menuPosition: "top" })); saveSetting("menuPosition", "top"); setLeftRailExpanded(false); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: "5px", fontWeight: (profile.menuPosition || "left") === "top" ? 700 : 400, background: (profile.menuPosition || "left") === "top" ? "var(--accent)" : (darkMode ? "#1f2937" : "#e5e7eb"), color: (profile.menuPosition || "left") === "top" ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}><LayoutPanelTop size={13} />{profile.language === "de" ? "Oben" : "Top"}</button>
                                </div>
                            </div>
                            <div style={{ borderTop: "1px solid var(--line)" }} />
                            {/* Navigation */}
                            <div style={{ display: "flex", justifyContent: "center", gap: "4px", padding: "4px 0", borderBottom: "1px solid var(--line)", paddingBottom: "10px" }}>
                                <button onClick={goToPrevWeek} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Previous Week"><ChevronsLeft size={16} /></button>
                                <button onClick={goToPrevDay} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Previous Day"><ChevronLeft size={16} /></button>
                                <button onClick={goToToday} style={{ ...qsBtnStyle(darkMode), minWidth: "56px", fontWeight: 700, fontSize: "0.7rem" }}>{profile.language === "de" ? "Heute" : "Today"}</button>
                                <button onClick={goToNextDay} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Next Day"><ChevronRight size={16} /></button>
                                <button onClick={goToNextWeek} style={{ ...qsBtnStyle(darkMode), minWidth: "36px" }} title="Next Week"><ChevronsRight size={16} /></button>
                            </div>
                            {/* Quick Actions */}
                            <div style={{ display: "flex", flexDirection: "column", gap: "1px" }}>
                                <button onClick={() => setIsSearchOpen(true)} style={qsActionStyle(darkMode)}><Search size={16} /> <span>{profile.language === "de" ? "Suche" : "Search"}</span></button>
                                <button onClick={() => setShowDatePicker(true)} style={qsActionStyle(darkMode)}><Calendar size={16} /> <span>{profile.language === "de" ? "Datum wählen" : "Jump to date"}</span></button>
                                <button onClick={() => { const now = new Date(); setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` }); }} style={qsActionStyle(darkMode)}><Plus size={16} /> <span>{profile.language === "de" ? "Kalendereintrag" : "Calendar Event"}</span></button>
                                <button onClick={() => setShowProjectsSidebar(true)} style={qsActionStyle(darkMode)}><FolderPlus size={16} /> <span>{profile.language === "de" ? "Projekte" : "Projects"}</span></button>
                                <button onClick={() => setIsRecurringTasksOpen(true)} style={qsActionStyle(darkMode)}><Repeat size={16} /> <span>{profile.language === "de" ? "Wiederkehrend" : "Recurring Tasks"}</span></button>
                                <button onClick={() => { const nv = !profile.showNextTask; setShowNextTask(nv); saveSetting("showNextTask", nv); }} style={qsActionStyle(darkMode)}>{profile.showNextTask ? <Play size={16} /> : <Target size={16} />}<span>{profile.showNextTask ? (profile.language === "de" ? "Nächste Aufgabe" : "Next Task") : (profile.language === "de" ? "Ziel" : "Goal")}</span></button>
                                <button onClick={() => setShowFocusMode(true)} style={qsActionStyle(darkMode)}><Zap size={16} /> <span>{profile.language === "de" ? "Fokus" : "Focus"}</span></button>
                            </div>
                            <div style={{ borderTop: "1px solid var(--line)", paddingTop: "8px" }} />
                            {/* View Style */}
                            <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
                                <span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "var(--ink-3)" }}>{profile.language === "de" ? "Ansicht" : "View"}</span>
                                <div style={{ display: "flex", gap: "4px" }}>{[{ key: "simple", icon: <Calendar size={13} /> }, { key: "calendar", icon: <CalendarDays size={13} /> }, { key: "list", icon: <ListTodo size={13} /> }, { key: "kanban", icon: <Kanban size={13} /> }, { key: "priority", icon: <Target size={13} /> }].map((v) => (<button key={v.key} onClick={() => { setViewStyle(v.key as any); saveSetting("viewStyle", v.key); if (v.key === "list") { setShowTimeGrid(false); saveSetting("showTimeGrid", false); } if (v.key === "simple" || v.key === "calendar") { setShowTimeGrid(true); saveSetting("showTimeGrid", true); } if (v.key === "priority" || v.key === "kanban") { setShowTimeGrid(false); saveSetting("showTimeGrid", false); } }} style={{ flex: 1, padding: "5px 0", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", fontWeight: profile.viewStyle === v.key ? 700 : 400, background: profile.viewStyle === v.key ? "var(--accent)" : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.viewStyle === v.key ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{v.icon}</button>))}</div>
                            </div>
                            {/* Columns / Days */}
                            <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}>
                                <span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "var(--ink-3)" }}>{profile.language === "de" ? "Spalten" : "Days"}</span>
                                <div style={{ display: "flex", gap: "4px" }}>{[1, 2, 3, 5, 7].map((num) => (<button key={num} onClick={() => { setViewDays(num); savedViewDaysRef.current = num; saveSetting("viewDays", num); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: viewDays === num ? 700 : 400, background: viewDays === num ? (darkMode ? "#374151" : "var(--ink)") : (darkMode ? "#1f2937" : "#e5e7eb"), color: viewDays === num ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{num}</button>))}</div>
                            </div>
                            {/* Slot Duration */}
                            {profile.showTimeGrid && (<div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "var(--ink-3)" }}>{profile.language === "de" ? "Zeitfenster" : "Slot"}</span><div style={{ display: "flex", gap: "4px" }}>{(([15, 20, 30, 60] as CellDuration[])).map((d) => (<button key={d} onClick={() => { setCellDuration(d); saveSetting("cellDuration", d); saveViewSetting("cellDuration", d, true); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: effectiveCellDuration === d ? 700 : 400, background: effectiveCellDuration === d ? (darkMode ? "#374151" : "var(--ink)") : (darkMode ? "#1f2937" : "#e5e7eb"), color: effectiveCellDuration === d ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{d}m</button>))}</div></div>)}
                            {profile.showTimeGrid && (<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}><span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>:15/:30/:45</span><button onClick={() => { const v = !effectiveShowSubHourSlots; setShowSubHourSlots(v); saveSetting("showSubHourSlots", v); }} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>{effectiveShowSubHourSlots ? <Eye size={16} /> : <EyeOff size={16} />}</button></div>)}
                            {/* Text size */}
                            <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Textgröße" : "Text size"}</span><div style={{ display: "flex", gap: "4px" }}>{(["S", "M", "L"] as const).map((size) => (<button key={size} onClick={() => { setFontSize(size); saveSetting("fontSize", size); }} style={{ padding: "4px 10px", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: profile.fontSize === size ? 700 : 400, background: profile.fontSize === size ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.fontSize === size ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{size}</button>))}</div></div>
                            <div style={{ borderTop: `1px solid ${darkMode ? "#333" : "#e5e7eb"}`, paddingTop: "4px" }} />
                            {/* Visibility toggles */}
                            {[{ label: profile.language === "de" ? "Irgendwann" : "Someday", value: effectiveShowSomeday, toggle: () => saveViewSetting("showSomeday", !effectiveShowSomeday, true) }, { label: profile.language === "de" ? "Ganztägig" : "All-day", value: effectiveShowAllDay, toggle: () => saveViewSetting("showAllDayEvents", !effectiveShowAllDay, true) }, { label: profile.language === "de" ? "Checkboxen" : "Checkboxes", value: effectiveShowTaskCheckboxes, toggle: () => saveViewSetting("showTaskCheckboxes", !effectiveShowTaskCheckboxes, true) }, { label: profile.language === "de" ? "Projekt-Icons" : "Project Icons", value: effectiveShowProjectIcons, toggle: () => saveViewSetting("showProjectIcons", !effectiveShowProjectIcons, true) }, { label: profile.language === "de" ? "Prioritäts-Icons" : "Priority Icons", value: effectiveShowPriorityIcons, toggle: () => saveViewSetting("showPriorityIcons", !effectiveShowPriorityIcons, true) }, ...((profile.weatherEnabled || profile.weatherLat || profile.weatherLon) ? [{ label: profile.language === "de" ? "Wetter" : "Weather", value: effectiveWeatherEnabled, toggle: () => { const v = !effectiveWeatherEnabled; setProfile((p: any) => ({ ...p, weatherEnabled: v })); saveViewSetting("weatherEnabled", v, true); } }] : []) ].map(({ label, value, toggle }) => (<div key={label} style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}><span style={{ fontSize: "0.75rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{label}</span><button onClick={toggle} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280" }}>{value ? <Eye size={16} /> : <EyeOff size={16} />}</button></div>))}
                            {/* Start on */}
                            <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Starten mit" : "Start on"}</span><div style={{ display: "flex", gap: "4px" }}><button onClick={() => { setProfile({ ...profile, startDayOffset: 0 }); saveSetting("startDayOffset", 0); const d = new Date(); d.setHours(0, 0, 0, 0); setCurrentWeekStart(d); }} style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: (profile.startDayOffset || 0) === 0 ? 700 : 400, background: (profile.startDayOffset || 0) === 0 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: (profile.startDayOffset || 0) === 0 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{profile.language === "de" ? "Heute" : "Today"}</button><button onClick={() => { setProfile({ ...profile, startDayOffset: -1 }); saveSetting("startDayOffset", -1); const d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() - 1); setCurrentWeekStart(d); }} style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: profile.startDayOffset === -1 ? 700 : 400, background: profile.startDayOffset === -1 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.startDayOffset === -1 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{profile.language === "de" ? "Gestern" : "Yesterday"}</button></div></div>
                            {/* Display */}
                            <div style={{ display: "flex", flexDirection: "column", gap: "6px" }}><span style={{ fontSize: "0.7rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#6b7280" }}>{profile.language === "de" ? "Anzeige" : "Display"}</span><div style={{ display: "flex", gap: "4px" }}><button onClick={() => setDarkMode(false)} style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", gap: "4px", fontWeight: !darkMode ? 700 : 400, background: !darkMode ? "#333" : (darkMode ? "#1f2937" : "#e5e7eb"), color: !darkMode ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}><Sun size={12} /> {profile.language === "de" ? "Hell" : "Light"}</button><button onClick={() => setDarkMode(true)} style={{ padding: "4px 10px", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", gap: "4px", fontWeight: darkMode ? 700 : 400, background: darkMode ? "#374151" : "#e5e7eb", color: darkMode ? "#fff" : "#6b7280" }}><Moon size={12} /> {profile.language === "de" ? "Dunkel" : "Dark"}</button></div></div>
                            <div style={{ borderTop: `1px solid ${darkMode ? "#333" : "#e5e7eb"}`, paddingTop: "4px" }} />
                            {/* Undo / Redo / Refresh */}
                            <div style={{ display: "flex", justifyContent: "center", gap: "8px", padding: "2px 0" }}>
                                <button onClick={handleUndo} disabled={undoCount === 0} style={{ ...qsBtnStyle(darkMode), opacity: undoCount === 0 ? 0.3 : 1 }} title="Undo"><Undo2 size={15} /></button>
                                <button onClick={handleRedo} disabled={redoCount === 0} style={{ ...qsBtnStyle(darkMode), opacity: redoCount === 0 ? 0.3 : 1 }} title="Redo"><Redo2 size={15} /></button>
                                <button onClick={() => { fetchCalendarEvents(true); fetchTasks(); }} style={qsBtnStyle(darkMode)} title="Refresh"><RefreshCcw size={15} /></button>
                                <button onClick={() => setShowWeekPrintModal(true)} style={qsBtnStyle(darkMode)} title={profile.language === "de" ? "Drucken" : "Print"}><Printer size={15} /></button>
                            </div>
                            <div style={{ flex: 1 }} />
                        </div>
                    ) : (
                        // ── COLLAPSED MODE — icon strip ──
                        <div style={{ display: "flex", flexDirection: "column", alignItems: "center", paddingTop: "6px", paddingBottom: "8px", height: "100%", overflowY: "auto", overflowX: "visible" }}>
                            {/* Expand toggle */}
                            <button onClick={() => setLeftRailExpanded(true)} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Erweitern" : "Expand"}><PanelLeftOpen size={16} /></button>
                            {railSep}
                            {/* Navigation */}
                            <button onClick={goToPrevWeek} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Vorherige Woche" : "Previous Week"}><ChevronsLeft size={15} /></button>
                            <button onClick={goToPrevDay} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Vorheriger Tag" : "Previous Day"}><ChevronLeft size={15} /></button>
                            <button onClick={goToToday} style={{ ...railIconBtnStyle, fontSize: "0.55rem", fontWeight: 800, letterSpacing: "0.05em" }} title="Today">{profile.language === "de" ? "HEUTE" : "TODAY"}</button>
                            <button onClick={goToNextDay} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Nächster Tag" : "Next Day"}><ChevronRight size={15} /></button>
                            <button onClick={goToNextWeek} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Nächste Woche" : "Next Week"}><ChevronsRight size={15} /></button>
                            {railSep}
                            {/* View flyout */}
                            <button style={{ ...railIconBtnStyle, color: "var(--accent)" }} title={profile.language === "de" ? "Ansicht" : "View"} onMouseEnter={(e) => openFlyout("view", e)} onMouseLeave={closeFlyoutDelayed}>
                                {profile.viewStyle === "simple" ? <Calendar size={15} /> : profile.viewStyle === "calendar" ? <CalendarDays size={15} /> : profile.viewStyle === "list" ? <ListTodo size={15} /> : profile.viewStyle === "kanban" ? <Kanban size={15} /> : <Target size={15} />}
                            </button>
                            {/* Columns flyout */}
                            <button style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Spalten" : "Columns"} onMouseEnter={(e) => openFlyout("columns", e)} onMouseLeave={closeFlyoutDelayed}><LayoutGrid size={15} /></button>
                            {/* Slot flyout */}
                            {profile.showTimeGrid && (<button style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Zeitfenster" : "Slot"} onMouseEnter={(e) => openFlyout("slot", e)} onMouseLeave={closeFlyoutDelayed}><Clock size={15} /></button>)}
                            {railSep}
                            {/* Quick Actions */}
                            <button onClick={() => setIsSearchOpen(true)} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Suche" : "Search"}><Search size={15} /></button>
                            <button onClick={() => setShowDatePicker(true)} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Datum wählen" : "Jump to date"}><CalendarDays size={15} /></button>
                            <button onClick={() => { const now = new Date(); setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` }); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Kalendereintrag" : "Calendar Event"}><Plus size={15} /></button>
                            <button onClick={() => setShowProjectsSidebar(true)} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Projekte" : "Projects"}><FolderOpen size={15} /></button>
                            <button onClick={() => setIsRecurringTasksOpen(true)} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Wiederkehrend" : "Recurring"}><Repeat size={15} /></button>
                            <button onClick={() => { const nv = !profile.showNextTask; setShowNextTask(nv); saveSetting("showNextTask", nv); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Ziel" : "Goal"}>{profile.showNextTask ? <Play size={15} /> : <Target size={15} />}</button>
                            <button onClick={() => setShowFocusMode(true)} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Fokus" : "Focus"}><Zap size={15} /></button>
                            {railSep}
                            {/* Visibility flyout */}
                            <button style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Sichtbarkeit" : "Visibility"} onMouseEnter={(e) => openFlyout("visibility", e)} onMouseLeave={closeFlyoutDelayed}><Eye size={15} /></button>
                            {/* Appearance flyout */}
                            <button style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Darstellung" : "Appearance"} onMouseEnter={(e) => openFlyout("display", e)} onMouseLeave={closeFlyoutDelayed}>{darkMode ? <Moon size={15} /> : <Sun size={15} />}</button>
                            {railSep}
                            {/* History & Utilities */}
                            <button onClick={handleUndo} disabled={undoCount === 0} style={{ ...railIconBtnStyle, opacity: undoCount === 0 ? 0.3 : 1 }} title="Undo"><Undo2 size={15} /></button>
                            <button onClick={handleRedo} disabled={redoCount === 0} style={{ ...railIconBtnStyle, opacity: redoCount === 0 ? 0.3 : 1 }} title="Redo"><Redo2 size={15} /></button>
                            <button onClick={() => { fetchCalendarEvents(true); fetchTasks(); }} style={{ ...railIconBtnStyle }} title="Refresh"><RefreshCcw size={15} /></button>
                            <button onClick={() => setShowWeekPrintModal(true)} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Drucken" : "Print"}><Printer size={15} /></button>
                            <button onClick={() => setDarkMode(!darkMode)} style={{ ...railIconBtnStyle }} title={darkMode ? "Light Mode" : "Dark Mode"}>{darkMode ? <Sun size={15} /> : <Moon size={15} />}</button>
                            <div style={{ flex: 1 }} />
                            {railSep}
                            {/* Settings (cogwheel) + User menu at bottom */}
                            <button onClick={() => setShowSettings(true)} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Einstellungen" : "Settings"}><Settings size={15} /></button>
                            <div style={{ position: "relative" }}>
                                <button onClick={() => setShowRailUserMenu(!showRailUserMenu)} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Benutzerprofil" : "User profile"}><User size={15} /></button>
                                {showRailUserMenu && (
                                    <>
                                        <div style={{ position: "fixed", inset: 0, zIndex: 998 }} onClick={() => setShowRailUserMenu(false)} />
                                        <div style={{ position: "fixed", left: "52px", bottom: "60px", width: "200px", background: darkMode ? "#1f2937" : "#ffffff", border: "1px solid var(--line)", borderRadius: "10px", boxShadow: "2px 4px 16px rgba(0,0,0,0.15)", zIndex: 999, overflow: "hidden" }}>
                                            <div style={{ padding: "10px 14px", borderBottom: "1px solid var(--line)" }}>
                                                <p style={{ fontSize: "0.8rem", fontWeight: 600, color: darkMode ? "#e5e7eb" : "#374151", margin: 0 }}>{profile.language === "de" ? "Angemeldet als" : "Signed in as"}</p>
                                                <p style={{ fontSize: "0.75rem", color: darkMode ? "#9ca3af" : "#6b7280", margin: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{session?.user?.email || "User"}</p>
                                            </div>
                                            <button onClick={() => { setActiveTab("account"); setShowSettings(true); setShowRailUserMenu(false); }} style={{ width: "100%", textAlign: "left", padding: "8px 14px", fontSize: "0.85rem", color: darkMode ? "#e5e7eb" : "#374151", background: "none", border: "none", cursor: "pointer", display: "flex", alignItems: "center", gap: "8px" }}
                                                onMouseEnter={(e) => (e.currentTarget.style.background = darkMode ? "#374151" : "#f3f4f6")}
                                                onMouseLeave={(e) => (e.currentTarget.style.background = "none")}>
                                                <Settings size={15} style={{ opacity: 0.5 }} />
                                                {profile.language === "de" ? "Einstellungen" : "Settings"}
                                            </button>
                                            <div style={{ borderTop: "1px solid var(--line)", margin: "2px 0" }} />
                                            <button onClick={() => signOut()} style={{ width: "100%", textAlign: "left", padding: "8px 14px", fontSize: "0.85rem", color: "#ef4444", background: "none", border: "none", cursor: "pointer", display: "flex", alignItems: "center", gap: "8px" }}
                                                onMouseEnter={(e) => (e.currentTarget.style.background = "rgba(239,68,68,0.08)")}
                                                onMouseLeave={(e) => (e.currentTarget.style.background = "none")}>
                                                <LogOut size={15} style={{ opacity: 0.7 }} />
                                                {profile.language === "de" ? "Abmelden" : "Sign Out"}
                                            </button>
                                        </div>
                                    </>
                                )}
                            </div>
                        </div>
                    )}
                </div>

                {/* Flyout panels — rendered outside the rail so they can overflow */}
                {!leftRailExpanded && flyoutSection && (
                    <div style={{ ...flyoutPanelStyle }} onMouseEnter={keepFlyoutOpen} onMouseLeave={closeFlyoutDelayed}>
                        {flyoutSection === "view" && (
                            <>
                                <div style={flyoutLabelStyle}>{profile.language === "de" ? "Ansicht" : "View"}</div>
                                <div style={{ display: "flex", gap: "4px" }}>{[{ key: "simple", icon: <Calendar size={13} />, label: profile.language === "de" ? "Einfach" : "Simple" }, { key: "calendar", icon: <CalendarDays size={13} />, label: profile.language === "de" ? "Kalender" : "Calendar" }, { key: "list", icon: <ListTodo size={13} />, label: profile.language === "de" ? "Liste" : "List" }, { key: "kanban", icon: <Kanban size={13} />, label: "Kanban" }, { key: "priority", icon: <Target size={13} />, label: profile.language === "de" ? "Priorität" : "Priority" }].map((v) => (<button key={v.key} onClick={() => { setViewStyle(v.key as any); saveSetting("viewStyle", v.key); if (v.key === "list") { setShowTimeGrid(false); saveSetting("showTimeGrid", false); } if (v.key === "simple" || v.key === "calendar") { setShowTimeGrid(true); saveSetting("showTimeGrid", true); } if (v.key === "priority" || v.key === "kanban") { setShowTimeGrid(false); saveSetting("showTimeGrid", false); } setFlyoutSection(null); }} title={v.label} style={{ flex: 1, padding: "6px 0", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", background: profile.viewStyle === v.key ? "var(--accent)" : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.viewStyle === v.key ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{v.icon}</button>))}</div>
                            </>
                        )}
                        {flyoutSection === "columns" && (
                            <>
                                <div style={flyoutLabelStyle}>{profile.language === "de" ? "Spalten" : "Days"}</div>
                                <div style={{ display: "flex", gap: "4px" }}>{[1, 2, 3, 5, 7].map((num) => (<button key={num} onClick={() => { setViewDays(num); savedViewDaysRef.current = num; saveSetting("viewDays", num); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: viewDays === num ? 700 : 400, background: viewDays === num ? (darkMode ? "#374151" : "var(--ink)") : (darkMode ? "#1f2937" : "#e5e7eb"), color: viewDays === num ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{num}</button>))}</div>
                            </>
                        )}
                        {flyoutSection === "slot" && (
                            <>
                                <div style={flyoutLabelStyle}>{profile.language === "de" ? "Zeitfenster" : "Slot Duration"}</div>
                                <div style={{ display: "flex", gap: "4px" }}>{(([15, 20, 30, 60] as CellDuration[])).map((d) => (<button key={d} onClick={() => { setCellDuration(d); saveSetting("cellDuration", d); saveViewSetting("cellDuration", d, true); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: effectiveCellDuration === d ? 700 : 400, background: effectiveCellDuration === d ? (darkMode ? "#374151" : "var(--ink)") : (darkMode ? "#1f2937" : "#e5e7eb"), color: effectiveCellDuration === d ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{d}m</button>))}</div>
                                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}><span style={{ fontSize: "0.75rem", color: darkMode ? "#9ca3af" : "#6b7280" }}>:15/:30/:45</span><button onClick={() => { const v = !effectiveShowSubHourSlots; setShowSubHourSlots(v); saveSetting("showSubHourSlots", v); }} style={{ background: "none", border: "none", cursor: "pointer", color: darkMode ? "#9ca3af" : "#6b7280" }}>{effectiveShowSubHourSlots ? <Eye size={15} /> : <EyeOff size={15} />}</button></div>
                            </>
                        )}
                        {flyoutSection === "visibility" && (
                            <>
                                <div style={flyoutLabelStyle}>{profile.language === "de" ? "Sichtbarkeit" : "Visibility"}</div>
                                {[{ label: profile.language === "de" ? "Irgendwann" : "Someday", value: effectiveShowSomeday, toggle: () => saveViewSetting("showSomeday", !effectiveShowSomeday, true) }, { label: profile.language === "de" ? "Ganztägig" : "All-day", value: effectiveShowAllDay, toggle: () => saveViewSetting("showAllDayEvents", !effectiveShowAllDay, true) }, { label: profile.language === "de" ? "Checkboxen" : "Checkboxes", value: effectiveShowTaskCheckboxes, toggle: () => saveViewSetting("showTaskCheckboxes", !effectiveShowTaskCheckboxes, true) }, { label: profile.language === "de" ? "Projekt-Icons" : "Project Icons", value: effectiveShowProjectIcons, toggle: () => saveViewSetting("showProjectIcons", !effectiveShowProjectIcons, true) }, { label: profile.language === "de" ? "Prioritäts-Icons" : "Priority Icons", value: effectiveShowPriorityIcons, toggle: () => saveViewSetting("showPriorityIcons", !effectiveShowPriorityIcons, true) }, ...((profile.weatherEnabled || profile.weatherLat || profile.weatherLon) ? [{ label: profile.language === "de" ? "Wetter" : "Weather", value: effectiveWeatherEnabled, toggle: () => { const v = !effectiveWeatherEnabled; setProfile((p: any) => ({ ...p, weatherEnabled: v })); saveViewSetting("weatherEnabled", v, true); } }] : []) ].map(({ label, value, toggle }) => (<div key={label} style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: "16px" }}><span style={{ fontSize: "0.8rem", color: darkMode ? "#d1d5db" : "#333", whiteSpace: "nowrap" }}>{label}</span><button onClick={toggle} style={{ background: "none", border: "none", cursor: "pointer", color: darkMode ? "#9ca3af" : "#6b7280", flexShrink: 0 }}>{value ? <Eye size={15} /> : <EyeOff size={15} />}</button></div>))}
                            </>
                        )}
                        {flyoutSection === "display" && (
                            <>
                                <div style={flyoutLabelStyle}>{profile.language === "de" ? "Darstellung" : "Appearance"}</div>
                                <div><div style={{ fontSize: "0.7rem", color: darkMode ? "#9ca3af" : "#6b7280", marginBottom: "4px" }}>{profile.language === "de" ? "Textgröße" : "Text size"}</div><div style={{ display: "flex", gap: "4px" }}>{(["S", "M", "L"] as const).map((size) => (<button key={size} onClick={() => { setFontSize(size); saveSetting("fontSize", size); }} style={{ flex: 1, padding: "4px 0", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: profile.fontSize === size ? 700 : 400, background: profile.fontSize === size ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.fontSize === size ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{size}</button>))}</div></div>
                                <div><div style={{ fontSize: "0.7rem", color: darkMode ? "#9ca3af" : "#6b7280", marginBottom: "4px" }}>{profile.language === "de" ? "Starten mit" : "Start on"}</div><div style={{ display: "flex", gap: "4px" }}><button onClick={() => { setProfile({ ...profile, startDayOffset: 0 }); saveSetting("startDayOffset", 0); const d = new Date(); d.setHours(0, 0, 0, 0); setCurrentWeekStart(d); }} style={{ flex: 1, padding: "4px 0", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: (profile.startDayOffset || 0) === 0 ? 700 : 400, background: (profile.startDayOffset || 0) === 0 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: (profile.startDayOffset || 0) === 0 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{profile.language === "de" ? "Heute" : "Today"}</button><button onClick={() => { setProfile({ ...profile, startDayOffset: -1 }); saveSetting("startDayOffset", -1); const d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() - 1); setCurrentWeekStart(d); }} style={{ flex: 1, padding: "4px 0", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: profile.startDayOffset === -1 ? 700 : 400, background: profile.startDayOffset === -1 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.startDayOffset === -1 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{profile.language === "de" ? "Gestern" : "Yesterday"}</button></div></div>
                                <div><div style={{ fontSize: "0.7rem", color: darkMode ? "#9ca3af" : "#6b7280", marginBottom: "4px" }}>{profile.language === "de" ? "Anzeige" : "Display"}</div><div style={{ display: "flex", gap: "4px" }}><button onClick={() => setDarkMode(false)} style={{ flex: 1, padding: "4px 0", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: "4px", fontWeight: !darkMode ? 700 : 400, background: !darkMode ? "#333" : (darkMode ? "#1f2937" : "#e5e7eb"), color: !darkMode ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}><Sun size={12} /> {profile.language === "de" ? "Hell" : "Light"}</button><button onClick={() => setDarkMode(true)} style={{ flex: 1, padding: "4px 0", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: "4px", fontWeight: darkMode ? 700 : 400, background: darkMode ? "#374151" : "#e5e7eb", color: darkMode ? "#fff" : "#6b7280" }}><Moon size={12} /> {profile.language === "de" ? "Dunkel" : "Dark"}</button></div></div>
                            </>
                        )}
                    </div>
                )}
                </>
            )}

            {/* Projects Sidebar */}
            {showProjectsSidebar && (
                <ProjectsSidebar
                    darkMode={darkMode}
                    language={profile.language}
                    projects={projects}
                    onProjectsChanged={fetchProjects}
                    onClose={() => setShowProjectsSidebar(false)}
                    tasks={[...tasks, ...somedayLists.flatMap(l => l.tasks)]}
                    activeProjectFilter={activeProjectFilter}
                    onSetProjectFilter={setActiveProjectFilter}
                />
            )}

            {/* View Transitions Style Block */}
            <style
                dangerouslySetInnerHTML={{
                    __html: (() => {
                        // Generate View Transition styles for a wide range of days around current view
                        // to ensure both entering and exiting days have the 500ms duration.
                        const center = currentWeekStart;
                        const validNames = [];
                        // Cover +/- 2 weeks just to be safe (exiting days need styles too)
                        for (let i = -14; i <= 21; i++) {
                            const d = new Date(center);
                            d.setDate(d.getDate() + i);
                            validNames.push(
                                `day-${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`,
                            );
                        }

                        return validNames
                            .map(
                                (name) => `
                        ::view-transition-group(${name}) {
                            animation-duration: 0.5s;
                            animation-timing-function: ease-in-out;
                        }
                    `,
                            )
                            .join("");
                    })(),
                }}
            />

            {/* Mobile Header */}
            {isMobile && (
                <header className="mobile-header" style={{ background: darkMode ? "#111827" : "#ffffff", borderBottom: `1px solid ${darkMode ? "#374151" : "#e5e7eb"}` }}>
                    {/* Left: Quick Settings */}
                    <button className="mobile-header-btn" onClick={() => setShowQuickSettings(true)} title="Quick Settings" style={{ color: darkMode ? "#e5e7eb" : "#6b7280" }}>
                        <PanelLeftOpen size={22} />
                    </button>

                    {/* Center: Date display (tap to jump to date) + fixed-width sync slot */}
                    <button className="mobile-header-date" onClick={() => setShowDatePicker(true)} style={{
                        fontFamily: profile.cwFontFamily || "Inter",
                        fontSize: scaleRem(profile.cwFontSize || "0.9rem"),
                        fontWeight: Number(profile.cwFontWeight || "700"),
                        color: adjustColorForDarkMode(profile.cwColor || (darkMode ? "#e5e7eb" : "#333333"), darkMode),
                    }}>
                        <span>
                            {(() => {
                                const visibleDays = getVisibleDays();
                                const mobileDisplay = isPortrait
                                    ? (profile.mobilePortraitHeaderDisplay || "current_day")
                                    : (profile.mobileLandscapeHeaderDisplay || profile.headerDisplay || "kw");
                                if (mobileDisplay === "none") return "";
                                if (mobileDisplay === "current_day") {
                                    const fmt = profile.headerCurrentDayFormat || "DDD, DD. MMMM YYYY";
                                    return formatCustomHeader(fmt, visibleDays, profile.language, t, getSelectedDay(visibleDays, selectedDay));
                                }
                                if (mobileDisplay === "date") return new Date().toLocaleDateString(profile.language, { day: '2-digit', month: '2-digit', year: 'numeric' });
                                if (mobileDisplay === "month_year") return getCWReferenceDate(visibleDays).toLocaleDateString(profile.language, { month: 'long', year: 'numeric' });
                                if (mobileDisplay === "month") return getCWReferenceDate(visibleDays).toLocaleDateString(profile.language, { month: "long" });
                                if (mobileDisplay === "custom") return formatCustomHeader(profile.headerCustomFormat || "KW WW | YYYY", visibleDays, profile.language, t);
                                return `KW ${getWeekNumber(getCWReferenceDate(visibleDays)).toString().padStart(2, "0")} | ${getCWReferenceDate(visibleDays).getFullYear()}`;
                            })()}
                        </span>
                        <ChevronDown size={12} style={{ opacity: 0.5 }} />
                    </button>

                    {/* Sync status indicator — fixed width so date never shifts */}
                    <div style={{ width: 24, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
                        {syncError
                            ? <span role="img" aria-label={syncError ?? 'Sync error'} style={{ display: 'inline-flex' }}><AlertCircle size={14} className="text-red-500" aria-hidden="true" /></span>
                            : (isLoading || isSyncing || syncStatus === "syncing")
                                ? <div className="weekly-spinner" role="status" aria-label="Syncing..." style={{ width: 14, height: 14 }}></div>
                                : null}
                    </div>

                    {/* Right: Settings menu */}
                    <button className="mobile-header-btn" onClick={() => setShowSettings(true)} title="Settings" style={{ color: darkMode ? "#e5e7eb" : "#6b7280" }}>
                        <Menu size={22} />
                    </button>
                </header>
            )}

            {/* Mobile left sidebar (icon rail — mirrors desktop collapsed rail) */}
            {isMobile && showMobileRail && (
                <>
                    <div
                        className="mobile-rail-backdrop"
                        onClick={() => { setShowMobileRail(false); setFlyoutSection(null); }}
                        style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.35)", zIndex: 200 }}
                    />
                    <div className="mobile-left-sidebar" style={{
                        position: "fixed", left: 0, top: 0, bottom: 0, width: "60px",
                        background: darkMode ? "#1a1a2e" : "var(--paper)",
                        borderRight: `1px solid var(--line)`,
                        zIndex: 201, display: "flex", flexDirection: "column",
                        alignItems: "center", paddingTop: "6px", paddingBottom: "8px", gap: "2px",
                        overflowY: "auto",
                    }}>
                        {/* Collapse */}
                        <button className="mobile-rail-btn" onClick={() => { setShowMobileRail(false); setFlyoutSection(null); }} style={{ ...railIconBtnStyle }} title="Close"><PanelLeftClose size={16} /></button>
                        {railSep}
                        {/* Navigation */}
                        <button className="mobile-rail-btn" onClick={() => { goToPrevWeek(); setShowMobileRail(false); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Vorherige Woche" : "Previous Week"}><ChevronsLeft size={15} /></button>
                        <button className="mobile-rail-btn" onClick={() => { goToPrevDay(); setShowMobileRail(false); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Vorheriger Tag" : "Previous Day"}><ChevronLeft size={15} /></button>
                        <button className="mobile-rail-btn" onClick={() => { goToToday(); setShowMobileRail(false); }} style={{ ...railIconBtnStyle, fontSize: "0.5rem", fontWeight: 800, letterSpacing: "0.05em" }} title="Today">{profile.language === "de" ? "HEUTE" : "TODAY"}</button>
                        <button className="mobile-rail-btn" onClick={() => { goToNextDay(); setShowMobileRail(false); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Nächster Tag" : "Next Day"}><ChevronRight size={15} /></button>
                        <button className="mobile-rail-btn" onClick={() => { goToNextWeek(); setShowMobileRail(false); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Nächste Woche" : "Next Week"}><ChevronsRight size={15} /></button>
                        {railSep}
                        {/* View flyout */}
                        <button className="mobile-rail-btn" style={{ ...railIconBtnStyle, color: "var(--accent)" }} title={profile.language === "de" ? "Ansicht" : "View"} onClick={(e) => { const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); setFlyoutY(rect.top); setFlyoutSection(flyoutSection === "view" ? null : "view"); }}>
                            {profile.viewStyle === "simple" ? <Calendar size={15} /> : profile.viewStyle === "calendar" ? <CalendarDays size={15} /> : profile.viewStyle === "list" ? <ListTodo size={15} /> : profile.viewStyle === "kanban" ? <Kanban size={15} /> : <Target size={15} />}
                        </button>
                        {/* Columns flyout */}
                        <button className="mobile-rail-btn" style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Spalten" : "Columns"} onClick={(e) => { const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); setFlyoutY(rect.top); setFlyoutSection(flyoutSection === "columns" ? null : "columns"); }}><LayoutGrid size={15} /></button>
                        {/* Slot flyout */}
                        {profile.showTimeGrid && (<button className="mobile-rail-btn" style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Zeitfenster" : "Slot"} onClick={(e) => { const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); setFlyoutY(rect.top); setFlyoutSection(flyoutSection === "slot" ? null : "slot"); }}><Clock size={15} /></button>)}
                        {railSep}
                        {/* Quick Actions */}
                        <button className="mobile-rail-btn" onClick={() => { setIsSearchOpen(true); setShowMobileRail(false); setFlyoutSection(null); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Suche" : "Search"}><Search size={15} /></button>
                        <button className="mobile-rail-btn" onClick={() => { setShowDatePicker(true); setShowMobileRail(false); setFlyoutSection(null); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Datum wählen" : "Jump to date"}><CalendarDays size={15} /></button>
                        <button className="mobile-rail-btn" onClick={() => { const now = new Date(); setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` }); setShowMobileRail(false); setFlyoutSection(null); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Kalendereintrag" : "Calendar Event"}><Plus size={15} /></button>
                        <button className="mobile-rail-btn" onClick={() => { setShowProjectsSidebar(true); setShowMobileRail(false); setFlyoutSection(null); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Projekte" : "Projects"}><FolderOpen size={15} /></button>
                        <button className="mobile-rail-btn" onClick={() => { setIsRecurringTasksOpen(true); setShowMobileRail(false); setFlyoutSection(null); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Wiederkehrend" : "Recurring"}><Repeat size={15} /></button>
                        <button className="mobile-rail-btn" onClick={() => { const nv = !profile.showNextTask; setShowNextTask(nv); saveSetting("showNextTask", nv); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Ziel" : "Goal"}>{profile.showNextTask ? <Play size={15} /> : <Target size={15} />}</button>
                        <button className="mobile-rail-btn" onClick={() => { setShowFocusMode(true); setShowMobileRail(false); setFlyoutSection(null); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Fokus" : "Focus"}><Zap size={15} /></button>
                        {railSep}
                        {/* Visibility flyout */}
                        <button className="mobile-rail-btn" style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Sichtbarkeit" : "Visibility"} onClick={(e) => { const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); setFlyoutY(rect.top); setFlyoutSection(flyoutSection === "visibility" ? null : "visibility"); }}><Eye size={15} /></button>
                        {/* Appearance flyout */}
                        <button className="mobile-rail-btn" style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Darstellung" : "Appearance"} onClick={(e) => { const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); setFlyoutY(rect.top); setFlyoutSection(flyoutSection === "display" ? null : "display"); }}>{darkMode ? <Moon size={15} /> : <Sun size={15} />}</button>
                        {railSep}
                        {/* History & Utilities */}
                        <button className="mobile-rail-btn" onClick={handleUndo} disabled={undoCount === 0} style={{ ...railIconBtnStyle, opacity: undoCount === 0 ? 0.3 : 1 }} title="Undo"><Undo2 size={15} /></button>
                        <button className="mobile-rail-btn" onClick={handleRedo} disabled={redoCount === 0} style={{ ...railIconBtnStyle, opacity: redoCount === 0 ? 0.3 : 1 }} title="Redo"><Redo2 size={15} /></button>
                        <button className="mobile-rail-btn" onClick={() => { fetchCalendarEvents(true); fetchTasks(); setShowMobileRail(false); setFlyoutSection(null); }} style={{ ...railIconBtnStyle }} title="Refresh"><RefreshCcw size={15} /></button>
                        <button className="mobile-rail-btn" onClick={() => { setShowWeekPrintModal(true); setShowMobileRail(false); setFlyoutSection(null); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Drucken" : "Print"}><Printer size={15} /></button>
                        <button className="mobile-rail-btn" onClick={() => setDarkMode(!darkMode)} style={{ ...railIconBtnStyle }} title={darkMode ? "Light Mode" : "Dark Mode"}>{darkMode ? <Sun size={15} /> : <Moon size={15} />}</button>
                        <div style={{ flex: 1 }} />
                        {railSep}
                        {/* Settings + User/logout */}
                        <button className="mobile-rail-btn" onClick={() => { setShowSettings(true); setShowMobileRail(false); setFlyoutSection(null); }} style={{ ...railIconBtnStyle }} title={profile.language === "de" ? "Einstellungen" : "Settings"}><Settings size={15} /></button>
                        <button className="mobile-rail-btn" onClick={() => signOut()} style={{ ...railIconBtnStyle, color: "#ef4444" }} title={profile.language === "de" ? "Abmelden" : "Sign out"}><LogOut size={15} /></button>
                    </div>
                    {/* Mobile flyout panel — positioned right of the 60px rail */}
                    {flyoutSection && (
                        <>
                            <div onClick={() => setFlyoutSection(null)} style={{ position: "fixed", inset: 0, zIndex: 202 }} />
                            <div style={{ ...flyoutPanelStyle, left: "68px", zIndex: 203 }} onClick={(e) => e.stopPropagation()}>
                                {flyoutSection === "view" && (
                                    <>
                                        <div style={flyoutLabelStyle}>{profile.language === "de" ? "Ansicht" : "View"}</div>
                                        <div style={{ display: "flex", gap: "4px" }}>{[{ key: "simple", icon: <Calendar size={13} />, label: profile.language === "de" ? "Einfach" : "Simple" }, { key: "calendar", icon: <CalendarDays size={13} />, label: profile.language === "de" ? "Kalender" : "Calendar" }, { key: "list", icon: <ListTodo size={13} />, label: profile.language === "de" ? "Liste" : "List" }, { key: "kanban", icon: <Kanban size={13} />, label: "Kanban" }, { key: "priority", icon: <Target size={13} />, label: profile.language === "de" ? "Priorität" : "Priority" }].map((v) => (<button key={v.key} onClick={() => { setViewStyle(v.key as any); saveSetting("viewStyle", v.key); if (v.key === "list") { setShowTimeGrid(false); saveSetting("showTimeGrid", false); } if (v.key === "simple" || v.key === "calendar") { setShowTimeGrid(true); saveSetting("showTimeGrid", true); } if (v.key === "priority" || v.key === "kanban") { setShowTimeGrid(false); saveSetting("showTimeGrid", false); } setFlyoutSection(null); }} title={v.label} style={{ flex: 1, padding: "6px 0", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", background: profile.viewStyle === v.key ? "var(--accent)" : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.viewStyle === v.key ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{v.icon}</button>))}</div>
                                    </>
                                )}
                                {flyoutSection === "columns" && (
                                    <>
                                        <div style={flyoutLabelStyle}>{profile.language === "de" ? "Spalten" : "Days"}</div>
                                        <div style={{ display: "flex", gap: "4px" }}>{[1, 2, 3, 5, 7].map((num) => (<button key={num} onClick={() => { setViewDays(num); savedViewDaysRef.current = num; saveSetting("viewDays", num); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: viewDays === num ? 700 : 400, background: viewDays === num ? (darkMode ? "#374151" : "var(--ink)") : (darkMode ? "#1f2937" : "#e5e7eb"), color: viewDays === num ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{num}</button>))}</div>
                                    </>
                                )}
                                {flyoutSection === "slot" && (
                                    <>
                                        <div style={flyoutLabelStyle}>{profile.language === "de" ? "Zeitfenster" : "Slot Duration"}</div>
                                        <div style={{ display: "flex", gap: "4px" }}>{(([15, 20, 30, 60] as CellDuration[])).map((d) => (<button key={d} onClick={() => { setCellDuration(d); saveSetting("cellDuration", d); saveViewSetting("cellDuration", d, true); }} style={{ flex: 1, padding: "5px 0", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: effectiveCellDuration === d ? 700 : 400, background: effectiveCellDuration === d ? (darkMode ? "#374151" : "var(--ink)") : (darkMode ? "#1f2937" : "#e5e7eb"), color: effectiveCellDuration === d ? "#fff" : (darkMode ? "#9ca3af" : "var(--ink-3)") }}>{d}m</button>))}</div>
                                        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}><span style={{ fontSize: "0.75rem", color: darkMode ? "#9ca3af" : "#6b7280" }}>:15/:30/:45</span><button onClick={() => { const v = !effectiveShowSubHourSlots; setShowSubHourSlots(v); saveSetting("showSubHourSlots", v); }} style={{ background: "none", border: "none", cursor: "pointer", color: darkMode ? "#9ca3af" : "#6b7280" }}>{effectiveShowSubHourSlots ? <Eye size={15} /> : <EyeOff size={15} />}</button></div>
                                    </>
                                )}
                                {flyoutSection === "visibility" && (
                                    <>
                                        <div style={flyoutLabelStyle}>{profile.language === "de" ? "Sichtbarkeit" : "Visibility"}</div>
                                        {[{ label: profile.language === "de" ? "Irgendwann" : "Someday", value: effectiveShowSomeday, toggle: () => saveViewSetting("showSomeday", !effectiveShowSomeday, true) }, { label: profile.language === "de" ? "Ganztägig" : "All-day", value: effectiveShowAllDay, toggle: () => saveViewSetting("showAllDayEvents", !effectiveShowAllDay, true) }, { label: profile.language === "de" ? "Checkboxen" : "Checkboxes", value: effectiveShowTaskCheckboxes, toggle: () => saveViewSetting("showTaskCheckboxes", !effectiveShowTaskCheckboxes, true) }, { label: profile.language === "de" ? "Projekt-Icons" : "Project Icons", value: effectiveShowProjectIcons, toggle: () => saveViewSetting("showProjectIcons", !effectiveShowProjectIcons, true) }, { label: profile.language === "de" ? "Prioritäts-Icons" : "Priority Icons", value: effectiveShowPriorityIcons, toggle: () => saveViewSetting("showPriorityIcons", !effectiveShowPriorityIcons, true) }, ...((profile.weatherEnabled || profile.weatherLat || profile.weatherLon) ? [{ label: profile.language === "de" ? "Wetter" : "Weather", value: effectiveWeatherEnabled, toggle: () => { const v = !effectiveWeatherEnabled; setProfile((p: any) => ({ ...p, weatherEnabled: v })); saveViewSetting("weatherEnabled", v, true); } }] : []) ].map(({ label, value, toggle }) => (<div key={label} style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: "16px" }}><span style={{ fontSize: "0.8rem", color: darkMode ? "#d1d5db" : "#333", whiteSpace: "nowrap" }}>{label}</span><button onClick={toggle} style={{ background: "none", border: "none", cursor: "pointer", color: darkMode ? "#9ca3af" : "#6b7280", flexShrink: 0 }}>{value ? <Eye size={15} /> : <EyeOff size={15} />}</button></div>))}
                                    </>
                                )}
                                {flyoutSection === "display" && (
                                    <>
                                        <div style={flyoutLabelStyle}>{profile.language === "de" ? "Darstellung" : "Appearance"}</div>
                                        <div><div style={{ fontSize: "0.7rem", color: darkMode ? "#9ca3af" : "#6b7280", marginBottom: "4px" }}>{profile.language === "de" ? "Textgröße" : "Text size"}</div><div style={{ display: "flex", gap: "4px" }}>{(["S", "M", "L"] as const).map((size) => (<button key={size} onClick={() => { setFontSize(size); saveSetting("fontSize", size); }} style={{ flex: 1, padding: "4px 0", fontSize: "0.8rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: profile.fontSize === size ? 700 : 400, background: profile.fontSize === size ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.fontSize === size ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{size}</button>))}</div></div>
                                        <div><div style={{ fontSize: "0.7rem", color: darkMode ? "#9ca3af" : "#6b7280", marginBottom: "4px" }}>{profile.language === "de" ? "Starten mit" : "Start on"}</div><div style={{ display: "flex", gap: "4px" }}><button onClick={() => { setProfile({ ...profile, startDayOffset: 0 }); saveSetting("startDayOffset", 0); const d = new Date(); d.setHours(0, 0, 0, 0); setCurrentWeekStart(d); }} style={{ flex: 1, padding: "4px 0", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: (profile.startDayOffset || 0) === 0 ? 700 : 400, background: (profile.startDayOffset || 0) === 0 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: (profile.startDayOffset || 0) === 0 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{profile.language === "de" ? "Heute" : "Today"}</button><button onClick={() => { setProfile({ ...profile, startDayOffset: -1 }); saveSetting("startDayOffset", -1); const d = new Date(); d.setHours(0, 0, 0, 0); d.setDate(d.getDate() - 1); setCurrentWeekStart(d); }} style={{ flex: 1, padding: "4px 0", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", fontWeight: profile.startDayOffset === -1 ? 700 : 400, background: profile.startDayOffset === -1 ? (darkMode ? "#374151" : "#333") : (darkMode ? "#1f2937" : "#e5e7eb"), color: profile.startDayOffset === -1 ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}>{profile.language === "de" ? "Gestern" : "Yesterday"}</button></div></div>
                                        <div><div style={{ fontSize: "0.7rem", color: darkMode ? "#9ca3af" : "#6b7280", marginBottom: "4px" }}>{profile.language === "de" ? "Anzeige" : "Display"}</div><div style={{ display: "flex", gap: "4px" }}><button onClick={() => setDarkMode(false)} style={{ flex: 1, padding: "4px 0", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: "4px", fontWeight: !darkMode ? 700 : 400, background: !darkMode ? "#333" : (darkMode ? "#1f2937" : "#e5e7eb"), color: !darkMode ? "#fff" : (darkMode ? "#9ca3af" : "#6b7280") }}><Sun size={12} /> {profile.language === "de" ? "Hell" : "Light"}</button><button onClick={() => setDarkMode(true)} style={{ flex: 1, padding: "4px 0", fontSize: "0.75rem", borderRadius: "6px", border: "none", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", gap: "4px", fontWeight: darkMode ? 700 : 400, background: darkMode ? "#374151" : "#e5e7eb", color: darkMode ? "#fff" : "#6b7280" }}><Moon size={12} /> {profile.language === "de" ? "Dunkel" : "Dark"}</button></div></div>
                                    </>
                                )}
                            </div>
                        </>
                    )}
                </>
            )}

            {/* Desktop Header: Left, Center, Right */}
            <header className="group relative flex items-center justify-between w-full px-4 py-1.5 border-b bg-white dark:bg-gray-900 dark:text-white transition-colors duration-200" style={isMobile ? { display: "none" } : { borderBottomColor: 'var(--line)', minHeight: useLeftRail ? "44px" : undefined }}>
                {/* LEFT SECTION: View Switcher, Days, Hours, Slot Duration — only shown in top-toolbar mode */}
                <div className={`weekly-header-controls flex items-center gap-4 transition-opacity duration-700 ${!useLeftRail ? "opacity-0 group-hover:opacity-100" : ""}`} style={{ zIndex: 1, display: useLeftRail ? "none" : undefined, ...(showIntroHints ? { opacity: 1 } : {}) }}>
                    {/* Quick-settings button (top mode only) */}
                    {!useLeftRail && (
                        <button
                            onClick={() => setShowQuickSettings(true)}
                            className="p-1.5 rounded text-gray-400 hover:text-gray-700 hover:bg-gray-100 dark:hover:text-white dark:hover:bg-gray-700 transition-colors"
                            title={profile.language === "de" ? "Einstellungen" : "Settings"}
                        >
                            <PanelLeftOpen size={16} />
                        </button>
                    )}
                    {/* View Switcher */}
                    <div className="flex items-center gap-0.5 bg-gray-100 dark:bg-gray-800 rounded p-0.5" title={t.viewStyle}>
                        <button
                            onClick={() => { setViewStyle("simple"); setShowTimeGrid(true); saveSetting("viewStyle", "simple"); saveSetting("showTimeGrid", true); }}
                            className={`p-1.5 rounded transition-colors ${profile.viewStyle ==="simple" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
                            title={t.simpleView}
                        >
                            <Calendar size={16} />
                        </button>
                        <button
                            onClick={() => { setViewStyle("calendar"); setShowTimeGrid(true); saveSetting("viewStyle", "calendar"); saveSetting("showTimeGrid", true); }}
                            className={`p-1.5 rounded transition-colors ${profile.viewStyle ==="calendar" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
                            title={t.calendarView}
                        >
                            <CalendarDays size={16} />
                        </button>
                        <button
                            onClick={() => { setViewStyle("list"); setShowTimeGrid(false); saveSetting("viewStyle", "list"); saveSetting("showTimeGrid", false); }}
                            className={`p-1.5 rounded transition-colors ${profile.viewStyle ==="list" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
                            title={t.listView}
                        >
                            <ListTodo size={16} />
                        </button>
                        <button
                            onClick={() => { setViewStyle("kanban"); saveSetting("viewStyle", "kanban"); setShowTimeGrid(false); saveSetting("showTimeGrid", false); }}
                            className={`p-1.5 rounded transition-colors ${profile.viewStyle ==="kanban" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
                            title={t.kanbanView}
                        >
                            <Kanban size={16} />
                        </button>
                        <button
                            onClick={() => { setViewStyle("priority"); saveSetting("viewStyle", "priority"); setShowTimeGrid(false); saveSetting("showTimeGrid", false); }}
                            className={`p-1.5 rounded transition-colors ${profile.viewStyle ==="priority" ? "bg-white shadow-sm text-black dark:bg-gray-700 dark:text-white" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
                            title={profile.language === "de" ? "Prioritäten" : "Priority View"}
                        >
                            <Target size={16} />
                        </button>
                    </div>

                    {/* Days to Show — desktop only (available in sidebar on tablet) */}
                    <div
                        className="header-desktop-only items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded p-1"
                        title="Days to show"
                    >
                        <LayoutGrid size={16} className="text-gray-500 mr-1" />
                        {[1, 2, 3, 5, 7].map((num) => (
                            <button
                                key={num}
                                onClick={() => {
                                    setViewDays(num);
                                    savedViewDaysRef.current = num;
                                    saveSetting("viewDays", num);
                                }}
                                className={`px-2 py-0.5 text-xs rounded transition-colors ${viewDays === num ? "bg-white shadow-sm font-bold text-black" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
                            >
                                {num}
                            </button>
                        ))}
                    </div>

                    {/* Slot Duration — desktop only (available in sidebar on tablet) */}
                    {profile.showTimeGrid && (
                        <div
                            className="header-desktop-only items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded p-1"
                            title="Slot Duration"
                        >
                            <Clock size={16} className="text-gray-500 mr-1" />
                            {(([15, 20, 30, 60] as CellDuration[])).map((duration) => (
                                <button
                                    key={duration}
                                    onClick={() => {
                                        setCellDuration(duration);
                                        saveSetting("cellDuration", duration);
                                        saveViewSetting("cellDuration", duration, true);
                                    }}
                                    className={`px-2 py-0.5 text-xs rounded transition-colors ${effectiveCellDuration === duration ? "bg-white shadow-sm font-bold text-black" : "text-gray-500 hover:text-gray-900 hover:bg-gray-200 dark:hover:bg-gray-700"}`}
                                >
                                    {duration}m
                                </button>
                            ))}
                        </div>
                    )}

                </div>

                {/* CENTER SECTION: Week/Year, Goal, Focus Mode - Reveal on Hover */}
                <div className={`flex items-center justify-center gap-6 absolute left-1/2 transform -translate-x-1/2 z-0 transition-all duration-300 ${useLeftRail ? "" : "group-hover:opacity-20 group-hover:blur-[2px]"}`}>
                    {/* Week & Year */}
                    <div className="whitespace-nowrap flex items-center gap-2">
                        {/* Clickable Week & Year */}
                        <div
                            ref={datePickerBtnRef}
                            className="relative flex items-center gap-2 cursor-pointer hover:opacity-80"
                            onClick={() => setShowDatePicker(!showDatePicker)}
                            title="Jump to date"
                        >
                            {showDatePicker && !isMobile && (
                                <SimpleDatePicker
                                    selected={currentWeekStart}
                                    onSelect={(date) => {
                                        setCurrentWeekStart(getStartOfWeek(date));
                                        setShowDatePicker(false);
                                    }}
                                    onClose={() => setShowDatePicker(false)}
                                    language={profile.language}
                                    anchorRef={datePickerBtnRef}
                                />
                            )}
                            <span style={{
                                fontFamily: profile.cwFontFamily || "Inter",
                                fontSize: profile.cwFontSize || "1.125rem",
                                fontWeight: Number(profile.cwFontWeight || "700"),
                                color: adjustColorForDarkMode(profile.cwColor || "#333333", darkMode),
                                filter: "brightness(var(--weekly-header-brightness, 1))"
                            }}>
                                {(() => {
                                    const effectiveDisplay = (profile.viewStyle === "kanban" && !profile.headerDisplay) ? "current_day" : (profile.headerDisplay || "kw");
                                    const visibleDays = getVisibleDays();
                                    if (effectiveDisplay === "none") return "";
                                    if (effectiveDisplay === "current_day") {
                                        const fmt = profile.headerCurrentDayFormat || "DDD, DD. MMMM YYYY";
                                        return formatCustomHeader(fmt, visibleDays, profile.language, t, getSelectedDay(visibleDays, selectedDay));
                                    }
                                    if (effectiveDisplay === "month") return getCWReferenceDate(visibleDays).toLocaleDateString(profile.language, { month: "long" });
                                    if (effectiveDisplay === "month_year") return getCWReferenceDate(visibleDays).toLocaleDateString(profile.language, { month: "long", year: "numeric" });
                                    if (effectiveDisplay === "date") return new Date().toLocaleDateString(profile.language, { day: '2-digit', month: '2-digit', year: 'numeric' });
                                    if (effectiveDisplay === "custom") return formatCustomHeader(profile.headerCustomFormat || "KW WW | YYYY", visibleDays, profile.language, t);
                                    return `KW ${getWeekNumber(getCWReferenceDate(visibleDays)).toString().padStart(2, "0")}`;
                                })()}
                            </span>
                            {profile.headerDisplay !== "none" && profile.headerDisplay !== "current_day" && profile.headerDisplay !== "date" && profile.headerDisplay !== "month_year" && (profile.headerDisplay === "kw" || profile.headerDisplay === "month" || !profile.headerDisplay) && (
                                <>
                                    <span className="text-gray-400">|</span>
                                    <span
                                        style={{
                                            fontFamily: profile.yearFontFamily || "Inter",
                                            fontSize: profile.yearFontSize || "1.125rem",
                                            fontWeight: Number(profile.yearFontWeight || "700"),
                                            color: adjustColorForDarkMode(profile.yearColor || "#333333", darkMode),
                                            filter: "brightness(var(--weekly-header-brightness, 1))"
                                        }}
                                    >
                                        {getCWReferenceDate(getVisibleDays()).getFullYear()}
                                    </span>
                                </>
                            )}
                        </div>
                        {/* Refresh / sync status — fixed-width slot so the date never shifts */}
                        <div style={{ width: 28, display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
                            {syncError ? (
                                <div title={syncError} className="flex items-center text-red-500">
                                    <AlertCircle size={14} />
                                </div>
                            ) : (isLoading || isSyncing || syncStatus === "syncing") ? (
                                <div className="weekly-spinner" title="Syncing..." style={{ width: 14, height: 14 }}></div>
                            ) : (
                                <button
                                    onClick={() => { fetchCalendarEvents(true); fetchTasks(); }}
                                    className="p-1 rounded-full hover:bg-gray-100 dark:hover:bg-gray-800 transition-all text-gray-400 hover:text-gray-600 opacity-0 group-hover:opacity-100"
                                    title="Refresh Calendar & Tasks"
                                >
                                    <RefreshCcw size={14} />
                                </button>
                            )}
                        </div>
                    </div>

                    {/* Goal — hidden on tablet to save space */}
                    <div className="header-desktop-only items-center text-sm">
                        {isEditingGoal ? (
                            <input
                                type="text"
                                value={goal}
                                onChange={(e) => setGoal(e.target.value)}
                                onBlur={() => {
                                    saveGoal(goal);
                                    setIsEditingGoal(false);
                                }}
                                onKeyDown={(e) => e.key === "Enter" && e.currentTarget.blur()}
                                autoFocus
                                className="border-b border-gray-300 focus:outline-none focus:border-black px-1 text-center font-medium italic"
                                style={{
                                    width: `${Math.max(10, goal.length)}ch`,
                                    fontFamily: profile.goalFontFamily
                                        ? `"${profile.goalFontFamily}", sans-serif`
                                        : undefined,
                                    fontSize: profile.goalFontSize || undefined,
                                    fontWeight: profile.goalFontWeight || undefined,
                                }}
                            />
                        ) : (
                            <span
                                onClick={() => !profile.showNextTask && setIsEditingGoal(true)}
                                className={`cursor-pointer font-medium italic transition-colors ${profile.showNextTask ? "cursor-default text-gray-600 dark:text-white hover:text-black dark:hover:text-gray-100" : "text-gray-600 dark:text-yellow-400 hover:text-black dark:hover:text-yellow-300"}`}
                                title={profile.showNextTask ? "Next task" : "Edit goal"}
                                style={{
                                    fontFamily: profile.goalFontFamily
                                        ? `"${profile.goalFontFamily}", sans-serif`
                                        : undefined,
                                    fontSize: profile.goalFontSize || undefined,
                                    fontWeight: profile.goalFontWeight || undefined,
                                    color: adjustColorForDarkMode((profile.goalFallbackType === "quote" ? profile.taskColor : undefined) || "#333333", darkMode),
                                    filter: "brightness(var(--weekly-goal-brightness, 1))",
                                    maxWidth: "800px",
                                    textAlign: "center" as const,
                                    overflow: "hidden",
                                    display: "-webkit-box",
                                    WebkitLineClamp: 2,
                                    WebkitBoxOrient: "vertical" as const,
                                }}
                            >
                                {profile.showNextTask
                                    ? (() => {
                                        const today = new Date();
                                        today.setHours(0, 0, 0, 0);
                                        const todayStr = formatDateToISO(today);
                                        const todayDay = today.getDay();
                                        const todaysTasks = tasks
                                            .filter((t) => {
                                                if (t.completed || t.somedayListId) return false;
                                                if (t.scheduledDate)
                                                    return (
                                                        formatDateToISO(new Date(t.scheduledDate)) ===
                                                        todayStr
                                                    );
                                                if (t.dayOfWeek === todayDay && !t.scheduledDate)
                                                    return true;
                                                return false;
                                            })
                                            .sort((a, b) => {
                                                if (a.startTime && b.startTime)
                                                    return a.startTime.localeCompare(b.startTime);
                                                if (a.startTime) return -1;
                                                if (b.startTime) return 1;
                                                return a.order - b.order;
                                            });
                                        const nextTask = todaysTasks[0];
                                        const nextTaskText = nextTask ? `Do this now: ${nextTask.title}` : (goal || (profile.goalFallbackType === "quote" ? motivationalQuote : goal));
                                        return nextTaskText;
                                    })()
                                    : (goal || (profile.goalFallbackType === "quote" ? motivationalQuote : goal))}
                            </span>
                        )}
                    </div>
                </div>

                {/* RIGHT SECTION: Navigation & Tools */}
                <div className="weekly-header-controls flex-shrink-0 flex items-center gap-1.5 sm:gap-2 transition-opacity duration-700 opacity-0 group-hover:opacity-100" style={{ zIndex: 10, display: useLeftRail ? "none" : undefined, ...(showIntroHints ? { opacity: 1 } : {}) }}>
                    {/* Secondary actions — hidden on tablet, visible on desktop */}
                    <div className="header-desktop-only flex items-center gap-1.5">
                        <button onClick={handleUndo} disabled={undoCount === 0} className="weekly-btn-icon disabled:opacity-30 disabled:cursor-default" title="Undo (Ctrl+Z)">
                            <Undo2 size={17} className="text-gray-600 hover:text-black transition-colors" />
                        </button>
                        <button onClick={handleRedo} disabled={redoCount === 0} className="weekly-btn-icon disabled:opacity-30 disabled:cursor-default" title="Redo (Ctrl+Y)">
                            <Redo2 size={17} className="text-gray-600 hover:text-black transition-colors" />
                        </button>
                        <button onClick={() => { const now = new Date(); setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` }); }} className="weekly-btn-icon" title="Add Calendar Event">
                            <Plus size={17} className="text-gray-600 hover:text-black transition-colors" />
                        </button>
                        <button onClick={() => { const newVal = !profile.showNextTask; setShowNextTask(newVal); saveSetting("showNextTask", newVal); }} className={`weekly-btn-icon ${profile.showNextTask ? "active" : ""}`} title={profile.showNextTask ? "Showing Next Task" : "Showing Goal"}>
                            {profile.showNextTask ? <Play size={17} className="text-teal-600" /> : <Target size={17} className="text-gray-400" />}
                        </button>
                        <button onClick={() => setShowFocusMode(true)} className="weekly-btn-icon" title="Enter Focus Mode">
                            <Zap size={17} className="text-gray-600 hover:text-yellow-500 transition-colors" />
                        </button>
                        <button onClick={() => setDarkMode(!darkMode)} className="weekly-btn-icon" title={darkMode ? "Light Mode" : "Dark Mode"}>
                            {darkMode ? <Sun size={17} className="text-yellow-500" /> : <Moon size={17} className="text-gray-500" />}
                        </button>
                    </div>

                    {/* Navigation Controls — always visible */}
                    <div className="flex items-center bg-gray-100 dark:bg-gray-800 rounded-lg p-0.5">
                        <button className="p-1 hover:bg-white dark:hover:bg-gray-700 hover:shadow-sm rounded text-gray-500 hover:text-black dark:hover:text-white transition-all" onClick={goToPrevWeek} title="Previous Week"><ChevronsLeft size={15} /></button>
                        <button className="p-1 hover:bg-white dark:hover:bg-gray-700 hover:shadow-sm rounded text-gray-500 hover:text-black dark:hover:text-white transition-all" onClick={goToPrevDay} title="Previous Day"><ChevronLeft size={15} /></button>
                        <button className="px-2 py-1 text-xs font-bold text-gray-600 dark:text-gray-400 hover:text-black dark:hover:text-white hover:bg-white dark:hover:bg-gray-700 hover:shadow-sm rounded transition-all" onClick={goToToday} title="Go to Today">Today</button>
                        <button className="p-1 hover:bg-white dark:hover:bg-gray-700 hover:shadow-sm rounded text-gray-500 hover:text-black dark:hover:text-white transition-all" onClick={goToNextDay} title="Next Day"><ChevronLeft size={15} className="rotate-180" /></button>
                        <button className="p-1 hover:bg-white dark:hover:bg-gray-700 hover:shadow-sm rounded text-gray-500 hover:text-black dark:hover:text-white transition-all" onClick={goToNextWeek} title="Next Week"><ChevronsLeft size={15} className="rotate-180" /></button>
                    </div>

                    {/* Always visible: Search, Settings, User */}
                    <button className="weekly-btn-icon" onClick={() => setIsSearchOpen(true)} title="Search"><Search size={17} /></button>
                    <button className="weekly-btn-icon" onClick={() => setShowSettings(true)} title="Settings"><Settings size={17} /></button>

                    {/* Overflow menu — visible on tablet, hidden on desktop */}
                    <div className="header-tablet-only" style={{ position: "relative" }}>
                        <button className="weekly-btn-icon" onClick={() => setShowHeaderMore(!showHeaderMore)} title="More">
                            <MoreVertical size={17} />
                        </button>
                        {showHeaderMore && (
                            <>
                                <div style={{ position: "fixed", inset: 0, zIndex: 99 }} onClick={() => setShowHeaderMore(false)} />
                                <div className="header-overflow-menu">
                                    <button onClick={() => { handleUndo(); setShowHeaderMore(false); }} disabled={undoCount === 0}><Undo2 size={16} /> <span>Undo</span></button>
                                    <button onClick={() => { handleRedo(); setShowHeaderMore(false); }} disabled={redoCount === 0}><Redo2 size={16} /> <span>Redo</span></button>
                                    <button onClick={() => { const now = new Date(); setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` }); setShowHeaderMore(false); }}><Plus size={16} /> <span>{profile.language === "de" ? "Termin erstellen" : "Add Event"}</span></button>
                                    <button onClick={() => { setIsRecurringTasksOpen(true); setShowHeaderMore(false); }}><Repeat size={16} /> <span>{profile.language === "de" ? "Wiederkehrend" : "Recurring"}</span></button>
                                    <button onClick={() => { const nv = !showNextTask; setShowNextTask(nv); saveSetting("showNextTask", nv); setShowHeaderMore(false); }}>{showNextTask ? <Play size={16} /> : <Target size={16} />} <span>{showNextTask ? "Next Task" : "Goal"}</span></button>
                                    <button onClick={() => { setShowFocusMode(true); setShowHeaderMore(false); }}><Zap size={16} /> <span>{profile.language === "de" ? "Fokus" : "Focus"}</span></button>
                                    <button onClick={() => { setDarkMode(!darkMode); setShowHeaderMore(false); }}>{darkMode ? <Sun size={16} /> : <Moon size={16} />} <span>{darkMode ? "Light" : "Dark"}</span></button>
                                    <button onClick={() => { setShowProjectsSidebar(true); setShowHeaderMore(false); }}><FolderPlus size={16} /> <span>{profile.language === "de" ? "Neues Projekt" : "New Project"}</span></button>
                                    <div style={{ borderTop: "1px solid var(--border-color, #e5e7eb)", margin: "2px 0" }} />
                                    <div style={{ padding: "6px 12px", display: "flex", alignItems: "center", gap: "6px", flexWrap: "wrap" }}>
                                        <span style={{ fontSize: "12px", color: "#888", marginRight: "4px" }}>{profile.language === "de" ? "Tage" : "Days"}:</span>
                                        {[1, 2, 3, 5, 7].map((num) => (
                                            <button
                                                key={num}
                                                onClick={() => { setViewDays(num); savedViewDaysRef.current = num; saveSetting("viewDays", num); }}
                                                style={{ padding: "2px 8px", fontSize: "12px", borderRadius: "4px", border: "none", cursor: "pointer", fontWeight: viewDays === num ? 700 : 400, background: viewDays === num ? "var(--bg-secondary, #e5e7eb)" : "transparent", color: "inherit" }}
                                            >
                                                {num}
                                            </button>
                                        ))}
                                    </div>
                                    {profile.showTimeGrid && (
                                        <div style={{ padding: "6px 12px", display: "flex", alignItems: "center", gap: "6px" }}>
                                            <span style={{ fontSize: "12px", color: "#888", marginRight: "4px" }}>{profile.language === "de" ? "Slot" : "Slot"}:</span>
                                            {(([15, 20, 30, 60] as CellDuration[])).map((duration) => (
                                                <button
                                                    key={duration}
                                                    onClick={() => { setCellDuration(duration); saveSetting("cellDuration", duration); saveViewSetting("cellDuration", duration, true); }}
                                                    style={{ padding: "2px 8px", fontSize: "12px", borderRadius: "4px", border: "none", cursor: "pointer", fontWeight: effectiveCellDuration === duration ? 700 : 400, background: effectiveCellDuration === duration ? "var(--bg-secondary, #e5e7eb)" : "transparent", color: "inherit" }}
                                                >
                                                    {duration}m
                                                </button>
                                            ))}
                                        </div>
                                    )}
                                </div>
                            </>
                        )}
                    </div>

                    {/* Desktop only: Recurring Tasks + New Project */}
                    <button className="weekly-btn-icon header-desktop-only" onClick={() => setIsRecurringTasksOpen(true)} title="Recurring Tasks"><Repeat size={17} /></button>
                    <button className="weekly-btn-icon header-desktop-only" onClick={() => setShowProjectsSidebar(true)} title="New Project"><FolderPlus size={17} /></button>
                    <button className="weekly-btn-icon header-desktop-only" onClick={() => setShowWeekPrintModal(true)} title={profile.language === "de" ? "Woche drucken / exportieren" : "Print / export week"}><Printer size={17} /></button>

                    {/* User Menu */}
                    <UserMenu
                        userEmail={session?.user?.email}
                        onOpenSettings={() => setShowSettings(true)}
                        language={profile.language}
                        trigger={<button className="weekly-btn-icon" title="User Menu"><User size={17} /></button>}
                    />
                </div>
            </header>

            {/* All-Day Events Section (above position) — hidden in kanban/priority */}
            {profile.viewStyle !== "kanban" && profile.viewStyle !== "priority" && effectiveAllDayPosition === "above" && allDaySection}

            {/* Priority View */}
            {profile.viewStyle === "priority" && (
                <>
                    <div
                        ref={priorityViewRef}
                        style={{ height: `${priorityViewHeight}px`, overflowY: "auto", flexShrink: 0 }}
                    >
                        <PriorityView
                            tasks={[...tasks, ...somedayLists.flatMap(l => l.tasks)].filter(t => !activeProjectFilter || t.projectId === activeProjectFilter)}
                            somedayLists={somedayLists.map(l => ({ id: l.id, title: l.title }))}
                            projects={projects}
                            darkMode={darkMode}
                            language={profile.language}
                            onUpdateTask={async (id, fields) => { await updateTaskFields(id, fields as any); }}
                            initialMethod={(profile.priorityStyle || "eisenhower") as any}
                            onMethodChange={(m) => {
                                setProfile((p: any) => ({ ...p, priorityStyle: m }));
                                saveSetting("priorityStyle", m);
                            }}
                        />
                    </div>
                    <div
                        className="resize-handle"
                        onMouseDown={(e) => startResize(e, 'priority')}
                        onTouchStart={(e) => startResize(e, 'priority')}
                    >
                        <div className="resize-handle-bar" />
                    </div>
                </>
            )}

            {/* Kanban Board View */}
            {profile.viewStyle ==="kanban" && (() => {
                // Combine all tasks (weekly + someday) for kanban
                const allSomedayTasks = somedayLists.flatMap(l => l.tasks);
                const allKanbanTasks = [...tasks, ...allSomedayTasks];

                // Build week options for filter
                const weekOptions = (() => {
                    const weeks = new Map<string, string>();
                    allKanbanTasks.forEach(t => {
                        if (t.scheduledDate) {
                            const d = new Date(t.scheduledDate);
                            const weekStart = getStartOfWeek(d);
                            const key = weekStart.toISOString().split("T")[0];
                            if (!weeks.has(key)) {
                                const weekEnd = new Date(weekStart);
                                weekEnd.setDate(weekEnd.getDate() + 6);
                                weeks.set(key, `${weekStart.toLocaleDateString(profile.language, { month: "short", day: "numeric" })} - ${weekEnd.toLocaleDateString(profile.language, { month: "short", day: "numeric" })}`);
                            }
                        }
                    });
                    return Array.from(weeks.entries()).sort((a, b) => a[0].localeCompare(b[0]));
                })();

                // Apply filters
                const filteredKanbanTasks = allKanbanTasks.filter(t => {
                    if (!effectiveShowCompletedTasks && t.completed) return false;
                    if (kanbanSearch && !t.title.toLowerCase().includes(kanbanSearch.toLowerCase())) return false;
                    if (kanbanFilterProject && t.projectId !== kanbanFilterProject) return false;
                    if (activeProjectFilter && t.projectId !== activeProjectFilter) return false;
                    if (kanbanFilterList) {
                        if (kanbanFilterList === "__none__") {
                            if (t.somedayListId) return false;
                        } else {
                            if (t.somedayListId !== kanbanFilterList) return false;
                        }
                    }
                    if (kanbanFilterWeek && t.scheduledDate) {
                        const d = new Date(t.scheduledDate);
                        const weekStart = getStartOfWeek(d);
                        if (weekStart.toISOString().split("T")[0] !== kanbanFilterWeek) return false;
                    }
                    return true;
                });

                const renderKanbanCard = (task: Task) => {
                    const subTasks = task.subTasks || [];
                    const subCompleted = subTasks.filter(s => s.completed).length;
                    const subTotal = subTasks.length;
                    const subPct = subTotal > 0 ? (subCompleted / subTotal) * 100 : 0;
                    const allSubDone = subTotal > 0 && subCompleted === subTotal;
                    const isExpanded = kanbanExpandedCards.has(task.id);

                    return (
                    <div
                        key={task.id}
                        className={`kanban-card ${task.completed ? "kanban-card-done" : ""}`}
                        draggable
                        onDragStart={(e) => {
                            e.dataTransfer.setData("text/kanban-task", task.id);
                            e.dataTransfer.setData("text/plain", task.id);
                            e.dataTransfer.effectAllowed = "move";
                            setDraggedTask(task);
                        }}
                        onDragEnd={() => setDraggedTask(null)}
                        onClick={(e) => {
                            const target = e.target as HTMLElement;
                            if (target.tagName === "INPUT" || target.contentEditable === "true" || target.closest("button") || target.closest(".kanban-card-subtask-list")) return;
                            setKanbanDetailTask(task);
                        }}
                        style={{ cursor: "pointer" }}
                    >
                        <div className="kanban-card-header">
                            {effectiveShowTaskCheckboxes && (
                                <input
                                    type="checkbox"
                                    checked={task.completed}
                                    onChange={() => toggleTask(task.id)}
                                    className="kanban-card-checkbox"
                                />
                            )}
                            {effectiveShowPriorityIcons && (() => {
                                const pb = getPriorityBadge(task, profile.priorityStyle || "eisenhower", 12);
                                return pb ? (
                                    <span title={pb.label} style={{ flexShrink: 0, display: "flex", alignItems: "center", marginRight: "4px" }}>
                                        {pb.node}
                                    </span>
                                ) : null;
                            })()}
                            {task.delegatedTo && (
                                <span
                                    title={task.delegatedTo === "AI" ? `AI: ${task.delegationNote || ""}` : task.delegatedTo}
                                    style={{ flexShrink: 0, display: "flex", alignItems: "center", marginRight: "4px" }}
                                >
                                    {task.delegatedTo === "AI"
                                        ? <Bot size={12} color="#8b5cf6" />
                                        : <User size={12} color="#8b5cf6" />}
                                </span>
                            )}
                            <span
                                className="kanban-card-title"
                                contentEditable
                                suppressContentEditableWarning
                                onBlur={(e) => {
                                    const text = (e.target as HTMLElement).textContent || "";
                                    if (text !== task.title) updateTask(task.id, text);
                                }}
                                onKeyDown={(e) => {
                                    if (e.key === "Enter") { e.preventDefault(); (e.target as HTMLElement).blur(); }
                                }}
                            >
                                {task.title}
                            </span>
                        </div>
                        {subTotal > 0 && (
                            <div className="kanban-card-subtask-toggle" onClick={(e) => e.stopPropagation()}>
                                <button
                                    className="kanban-card-subtask-btn"
                                    onClick={() => {
                                        setKanbanExpandedCards(prev => {
                                            const next = new Set(prev);
                                            if (next.has(task.id)) next.delete(task.id);
                                            else next.add(task.id);
                                            return next;
                                        });
                                    }}
                                >
                                    <ChevronDown size={12} style={{ transform: isExpanded ? "rotate(0deg)" : "rotate(-90deg)", transition: "transform 0.2s" }} />
                                    <span className="kanban-card-subtask-bar">
                                        <span className="kanban-card-subtask-bar-fill" style={{ width: `${subPct}%`, background: allSubDone ? "#0d9488" : "var(--weekly-accent, #6366f1)" }} />
                                    </span>
                                    <span className="kanban-card-subtask-count" style={{ color: allSubDone ? "#0d9488" : undefined }}>
                                        {subCompleted}/{subTotal}
                                    </span>
                                </button>
                                {isExpanded && (
                                    <div className="kanban-card-subtask-list">
                                        {subTasks.map(sub => (
                                            <div key={sub.id} className={`kanban-card-subtask-item ${sub.completed ? "completed" : ""}`}>
                                                <input
                                                    type="checkbox"
                                                    checked={sub.completed}
                                                    onChange={() => toggleSubTask(sub.id)}
                                                    style={{ accentColor: "var(--weekly-accent, #6366f1)" }}
                                                />
                                                <span className={sub.completed ? "kanban-card-subtask-done" : ""}>{sub.title}</span>
                                            </div>
                                        ))}
                                    </div>
                                )}
                            </div>
                        )}
                        {task.markdownContent && (
                            <div className="kanban-card-has-notes" style={{ fontSize: "0.65rem", color: "#9ca3af", marginTop: "2px", display: "flex", alignItems: "center", gap: "3px" }}>
                                <FileText size={10} /> {profile.language === "de" ? "Notizen" : "Notes"}
                            </div>
                        )}
                        {(task.scheduledDate || task.startTime) && (
                            <div className="kanban-card-date">
                                {task.scheduledDate && new Date(task.scheduledDate).toLocaleDateString(profile.language, { weekday: "short", month: "short", day: "numeric" })}
                                {task.startTime && <span className="kanban-card-time"> {task.startTime}</span>}
                            </div>
                        )}
                        {task.project && (
                            <div className="kanban-card-project" style={{ color: task.project.color || "#888" }}>
                                <ProjectIcon icon={task.project.icon} size={12} color={task.project.color || "#888"} /> {task.project.name}
                            </div>
                        )}
                        {task.somedayListId && (() => {
                            const list = somedayLists.find(l => l.id === task.somedayListId);
                            return list ? <div className="kanban-card-list">{list.title}</div> : null;
                        })()}
                    </div>
                    );
                };

                const kanbanColumnDrop = (stageId: string | null) => ({
                    onDragOver: (e: React.DragEvent) => {
                        e.preventDefault();
                        e.dataTransfer.dropEffect = "move";
                        e.currentTarget.classList.add("kanban-column-drag-over");
                    },
                    onDragLeave: (e: React.DragEvent) => {
                        if (!e.currentTarget.contains(e.relatedTarget as Node)) {
                            e.currentTarget.classList.remove("kanban-column-drag-over");
                        }
                    },
                    onDrop: async (e: React.DragEvent) => {
                        e.preventDefault();
                        e.currentTarget.classList.remove("kanban-column-drag-over");
                        const taskId = e.dataTransfer.getData("text/kanban-task");
                        if (taskId) {
                            await updateTaskFields(taskId, { kanbanStage: stageId });
                        }
                    },
                });

                const kanbanProjectDrop = (projectId: string | null) => ({
                    onDragOver: (e: React.DragEvent) => {
                        e.preventDefault();
                        e.dataTransfer.dropEffect = "move";
                        e.currentTarget.classList.add("kanban-project-chip-drag-over");
                    },
                    onDragLeave: (e: React.DragEvent) => {
                        if (!e.currentTarget.contains(e.relatedTarget as Node)) {
                            e.currentTarget.classList.remove("kanban-project-chip-drag-over");
                        }
                    },
                    onDrop: async (e: React.DragEvent) => {
                        e.preventDefault();
                        e.currentTarget.classList.remove("kanban-project-chip-drag-over");
                        const taskId = e.dataTransfer.getData("text/kanban-task");
                        if (taskId) {
                            await updateTaskFields(taskId, { projectId });
                        }
                    },
                });

                const hasActiveFilters = kanbanSearch || kanbanFilterProject || kanbanFilterList || kanbanFilterWeek;

                return (
                    <div className="kanban-wrapper">
                        {/* Unified toolbar: projects on left, filters on right */}
                        <div className="kanban-filter-bar">
                            {/* Left side: + button, project chips */}
                            <button
                                onClick={() => setShowProjectsSidebar(true)}
                                className="kanban-project-chip"
                                style={{ background: darkMode ? "#374151" : "#e5e7eb", color: darkMode ? "#9ca3af" : "#6b7280", cursor: "pointer", border: "2px dashed " + (darkMode ? "#4b5563" : "#d1d5db") }}
                                title={t.projects || "Projects"}
                            >
                                <Plus size={12} />
                            </button>
                            {projects.map(p => (
                                <div key={p.id} className="kanban-project-chip" style={{ background: (p.color || "#6366f1") + "18", color: p.color || "#6366f1" }} {...kanbanProjectDrop(p.id)}>
                                    <ProjectIcon icon={p.icon} size={12} color={p.color || "#6366f1"} />
                                    <span>{p.name}</span>
                                </div>
                            ))}
                            {projects.length > 0 && (
                                <div className="kanban-project-chip" style={{ background: darkMode ? "#1f2937" : "#f3f4f6", color: "#9ca3af" }} {...kanbanProjectDrop(null)}>
                                    <X size={12} />
                                    <span>{profile.language === "de" ? "Kein Projekt" : "No project"}</span>
                                </div>
                            )}
                            {/* Spacer pushes filters to right */}
                            <div style={{ flex: 1 }} />
                            {/* Right side: search + filters */}
                            <div className="kanban-filter-search">
                                <Search size={14} className="kanban-filter-icon" />
                                <input
                                    type="text"
                                    value={kanbanSearch}
                                    onChange={(e) => setKanbanSearch(e.target.value)}
                                    placeholder="Search..."
                                    className="kanban-filter-input"
                                />
                                {kanbanSearch && (
                                    <button onClick={() => setKanbanSearch("")} className="kanban-filter-clear"><X size={12} /></button>
                                )}
                            </div>
                            <select
                                value={kanbanFilterProject}
                                onChange={(e) => setKanbanFilterProject(e.target.value)}
                                className="kanban-filter-select"
                            >
                                <option value="">{t.filterByProject}</option>
                                {projects.map(p => (
                                    <option key={p.id} value={p.id}>● {p.name}</option>
                                ))}
                            </select>
                            <select
                                value={kanbanFilterList}
                                onChange={(e) => setKanbanFilterList(e.target.value)}
                                className="kanban-filter-select"
                            >
                                <option value="">{t.filterByList}</option>
                                <option value="__none__">{t.weekView}</option>
                                {somedayLists.map(l => (
                                    <option key={l.id} value={l.id}>{l.title}</option>
                                ))}
                            </select>
                            <select
                                value={kanbanFilterWeek}
                                onChange={(e) => setKanbanFilterWeek(e.target.value)}
                                className="kanban-filter-select"
                            >
                                <option value="">{t.filterByWeek}</option>
                                {weekOptions.map(([key, label]) => (
                                    <option key={key} value={key}>{label}</option>
                                ))}
                            </select>
                            {hasActiveFilters && (
                                <button
                                    onClick={() => { setKanbanSearch(""); setKanbanFilterProject(""); setKanbanFilterList(""); setKanbanFilterWeek(""); }}
                                    className="kanban-filter-reset"
                                    title="Clear filters"
                                >
                                    <X size={14} />
                                </button>
                            )}
                        </div>
                        <div className="kanban-board">
                            {kanbanStages.map((stage, idx) => {
                                const stageTasks = filteredKanbanTasks.filter(t => (t.kanbanStage || null) === stage.id);
                                return (
                                    <div key={stage.id} className="kanban-column" {...kanbanColumnDrop(stage.id)}>
                                        <div className="kanban-column-header" style={{ borderBottomColor: stage.color }}>
                                            <input
                                                type="color"
                                                value={stage.color}
                                                onChange={(e) => {
                                                    const updated = kanbanStages.map((s, i) => i === idx ? { ...s, color: e.target.value } : s);
                                                    saveKanbanStages(updated);
                                                }}
                                                title={profile.language === "de" ? "Farbe ändern" : "Change color"}
                                                style={{ width: "14px", height: "14px", border: "none", cursor: "pointer", padding: 0, borderRadius: "50%", flexShrink: 0 }}
                                            />
                                            <span
                                                className="kanban-column-title"
                                                contentEditable
                                                suppressContentEditableWarning
                                                onBlur={(e) => {
                                                    const name = (e.target as HTMLElement).textContent || stage.name;
                                                    if (name !== stage.name) {
                                                        const updated = kanbanStages.map((s, i) => i === idx ? { ...s, name } : s);
                                                        saveKanbanStages(updated);
                                                    }
                                                }}
                                                onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); (e.target as HTMLElement).blur(); } }}
                                            >
                                                {stage.name}
                                            </span>
                                            <span className="kanban-column-count">{stageTasks.length}</span>
                                            {kanbanDeleteStageId === stage.id ? (
                                                <div style={{ display: "flex", alignItems: "center", gap: "3px", flexShrink: 0 }}>
                                                    <button
                                                        onClick={async () => {
                                                            // Move all tasks in this stage back to "no phase"
                                                            const tasksInStage = filteredKanbanTasks.filter(tk => tk.kanbanStage === stage.id);
                                                            for (const tk of tasksInStage) {
                                                                await updateTaskFields(tk.id, { kanbanStage: null });
                                                            }
                                                            saveKanbanStages(kanbanStages.filter((_, i) => i !== idx));
                                                            setKanbanDeleteStageId(null);
                                                        }}
                                                        style={{ padding: "2px 6px", fontSize: "0.65rem", borderRadius: "4px", border: "none", cursor: "pointer", background: "#ef4444", color: "#fff", fontWeight: 600, whiteSpace: "nowrap" }}
                                                    >
                                                        {profile.language === "de" ? "Ja, löschen" : "Confirm"}
                                                    </button>
                                                    <button
                                                        onClick={() => setKanbanDeleteStageId(null)}
                                                        style={{ padding: "2px", background: "none", border: "none", cursor: "pointer", color: "#9ca3af", display: "flex" }}
                                                        title={profile.language === "de" ? "Abbrechen" : "Cancel"}
                                                    >
                                                        <X size={12} />
                                                    </button>
                                                </div>
                                            ) : (
                                                <button
                                                    onClick={() => setKanbanDeleteStageId(stage.id)}
                                                    className="kanban-column-delete"
                                                    title={profile.language === "de" ? "Phase löschen" : "Delete stage"}
                                                >
                                                    <Trash2 size={12} />
                                                </button>
                                            )}
                                        </div>
                                        <div className="kanban-column-body">
                                            {stageTasks.map(renderKanbanCard)}
                                            {kanbanAddingStageId === stage.id ? (
                                                <div className="kanban-add-task-input">
                                                    <input
                                                        type="text"
                                                        autoFocus
                                                        placeholder={profile.language === "de" ? "Aufgabe eingeben..." : "Enter task..."}
                                                        value={kanbanNewTaskTitle}
                                                        onChange={(e) => setKanbanNewTaskTitle(e.target.value)}
                                                        onKeyDown={(e) => {
                                                            if (e.key === "Enter" && kanbanNewTaskTitle.trim()) {
                                                                addKanbanTask(kanbanNewTaskTitle, stage.id);
                                                            } else if (e.key === "Escape") {
                                                                setKanbanAddingStageId(null);
                                                                setKanbanNewTaskTitle("");
                                                            }
                                                        }}
                                                        onBlur={() => {
                                                            if (kanbanNewTaskTitle.trim()) {
                                                                addKanbanTask(kanbanNewTaskTitle, stage.id);
                                                            } else {
                                                                setKanbanAddingStageId(null);
                                                                setKanbanNewTaskTitle("");
                                                            }
                                                        }}
                                                        style={{
                                                            width: "100%",
                                                            padding: "6px 8px",
                                                            fontSize: "0.8rem",
                                                            border: "1px solid var(--border-color, #d1d5db)",
                                                            borderRadius: "6px",
                                                            background: "var(--card-bg, #fff)",
                                                            color: "var(--text-color, #111)",
                                                            outline: "none",
                                                        }}
                                                    />
                                                </div>
                                            ) : (
                                                <button
                                                    className="kanban-add-task-btn"
                                                    onClick={() => {
                                                        setKanbanAddingStageId(stage.id);
                                                        setKanbanNewTaskTitle("");
                                                    }}
                                                    style={{
                                                        width: "100%",
                                                        padding: "6px 8px",
                                                        fontSize: "0.75rem",
                                                        color: "#9ca3af",
                                                        background: "none",
                                                        border: "1px dashed #d1d5db",
                                                        borderRadius: "6px",
                                                        cursor: "pointer",
                                                        display: "flex",
                                                        alignItems: "center",
                                                        gap: "4px",
                                                        justifyContent: "center",
                                                        marginTop: "4px",
                                                    }}
                                                >
                                                    <Plus size={12} />
                                                    {profile.language === "de" ? "Aufgabe" : "Add task"}
                                                </button>
                                            )}
                                        </div>
                                    </div>
                                );
                            })}
                            {/* Add stage column */}
                            <div
                                className="kanban-column kanban-column-add"
                                onClick={() => {
                                    const id = `stage-${Date.now()}`;
                                    saveKanbanStages([...kanbanStages, { id, name: t.stageName, color: "#6b7280" }]);
                                }}
                            >
                                <div className="kanban-column-header" style={{ borderBottomColor: "transparent", cursor: "pointer", justifyContent: "center", color: "#9ca3af" }}>
                                    <Plus size={16} />
                                </div>
                            </div>
                            {/* Unassigned column */}
                            {(() => {
                                const unassigned = filteredKanbanTasks.filter(t => !t.kanbanStage && !t.completed);
                                if (unassigned.length === 0 && !hasActiveFilters) return null;
                                return (
                                    <div className="kanban-column kanban-column-unassigned" {...kanbanColumnDrop(null)}>
                                        <div className="kanban-column-header" style={{ borderBottomColor: "#d1d5db" }}>
                                            <span className="kanban-column-dot" style={{ background: "#d1d5db" }} />
                                            <span className="kanban-column-title">{t.noStage}</span>
                                            <span className="kanban-column-count">{unassigned.length}</span>
                                        </div>
                                        <div className="kanban-column-body">
                                            {unassigned.map(renderKanbanCard)}
                                            {kanbanAddingStageId === "__unassigned__" ? (
                                                <div className="kanban-add-task-input">
                                                    <input
                                                        type="text"
                                                        autoFocus
                                                        placeholder={profile.language === "de" ? "Aufgabe eingeben..." : "Enter task..."}
                                                        value={kanbanNewTaskTitle}
                                                        onChange={(e) => setKanbanNewTaskTitle(e.target.value)}
                                                        onKeyDown={(e) => {
                                                            if (e.key === "Enter" && kanbanNewTaskTitle.trim()) {
                                                                addKanbanTask(kanbanNewTaskTitle, null);
                                                            } else if (e.key === "Escape") {
                                                                setKanbanAddingStageId(null);
                                                                setKanbanNewTaskTitle("");
                                                            }
                                                        }}
                                                        onBlur={() => {
                                                            if (kanbanNewTaskTitle.trim()) {
                                                                addKanbanTask(kanbanNewTaskTitle, null);
                                                            } else {
                                                                setKanbanAddingStageId(null);
                                                                setKanbanNewTaskTitle("");
                                                            }
                                                        }}
                                                        style={{
                                                            width: "100%",
                                                            padding: "6px 8px",
                                                            fontSize: "0.8rem",
                                                            border: "1px solid var(--border-color, #d1d5db)",
                                                            borderRadius: "6px",
                                                            background: "var(--card-bg, #fff)",
                                                            color: "var(--text-color, #111)",
                                                            outline: "none",
                                                        }}
                                                    />
                                                </div>
                                            ) : (
                                                <button
                                                    className="kanban-add-task-btn"
                                                    onClick={() => {
                                                        setKanbanAddingStageId("__unassigned__");
                                                        setKanbanNewTaskTitle("");
                                                    }}
                                                    style={{
                                                        width: "100%",
                                                        padding: "6px 8px",
                                                        fontSize: "0.75rem",
                                                        color: "#9ca3af",
                                                        background: "none",
                                                        border: "1px dashed #d1d5db",
                                                        borderRadius: "6px",
                                                        cursor: "pointer",
                                                        display: "flex",
                                                        alignItems: "center",
                                                        gap: "4px",
                                                        justifyContent: "center",
                                                        marginTop: "4px",
                                                    }}
                                                >
                                                    <Plus size={12} />
                                                    {profile.language === "de" ? "Aufgabe" : "Add task"}
                                                </button>
                                            )}
                                        </div>
                                    </div>
                                );
                            })()}
                        </div>
                    </div>
                );
            })()}

            {/* Main Grid with Time Column */}
            {profile.viewStyle !== "kanban" && <div style={{ position: "relative", flex: 1, minHeight: 0, overflow: 'hidden' }}>
            <div className="time-grid-wrapper" ref={gridRef as React.Ref<HTMLDivElement>} onScroll={handleGridScroll} style={profile.showTimeGrid ? {
                height: '100%',
                overflowY: 'auto',
                overflowX: 'hidden',
                WebkitOverflowScrolling: 'touch' as any,
            } : undefined}>
                {/* Time Column */}
                {profile.showTimeGrid && (
                    <div
                      className="time-column"
                      style={{
                        height: `${24 * (60 / effectiveCellDuration) * getSlotHeight(effectiveCellDuration) + measuredHeaderHeight}px`,
                        flex: 'none',
                        alignSelf: "flex-start",
                        position: 'relative'
                      }}
                    >
                        <div className="time-column-header" style={{
                            border: 'none',
                            background: 'var(--weekly-bg)',
                            position: 'sticky',
                            top: 0,
                            zIndex: 30,
                            minHeight: `${measuredHeaderHeight}px`,
                            display: 'flex',
                            alignItems: 'center',
                            justifyContent: 'center'
                        }}>
                            {/* Side Navigation Arrows (hover overlays) - now inside header */}
                            <div className="side-nav side-nav-left">
                                <button onClick={goToPrevDay} title="Previous Day" className="side-nav-btn">
                                    <ChevronLeft size={16} />
                                </button>
                                <button onClick={goToPrevWeek} title="Previous Week" className="side-nav-btn">
                                    <ChevronsLeft size={16} />
                                </button>
                            </div>
                            {/* Invisible structural match of day header to guarantee perfect height alignment */}
                            <div
                                style={{
                                    visibility: "hidden", pointerEvents: "none",
                                    display: "flex",
                                    width: "100%",
                                    alignItems:
                                        activeDateLayout === "above" ||
                                            activeDateLayout === "below"
                                            ? (profile.dateAlignment === "left" ? "flex-start" : profile.dateAlignment === "right" ? "flex-end" : "center")
                                            : "center",
                                    justifyContent:
                                        profile.dateAlignment === "left"
                                            ? "flex-start"
                                            : profile.dateAlignment === "right"
                                                ? "flex-end"
                                                : "center",
                                    flexDirection:
                                        activeDateLayout === "above"
                                            ? "column-reverse"
                                            : activeDateLayout === "below"
                                                ? "column"
                                                : "row",
                                    gap: profile.dateAlignment === "tight" ? "2px" : (profile.dayHeaderGap || "0.35em"),
                                }}
                            >
                                {activeDateLayout === "left" && (
                                    <span className="weekly-day-date">W</span>
                                )}
                                <h3 className="weekly-day-name" style={{ marginBottom: 0 }}>
                                    X
                                </h3>
                                {(activeDateLayout === "right" ||
                                    activeDateLayout === "above" ||
                                    activeDateLayout === "below" ||
                                    activeDateLayout === undefined) && (
                                        <span className="weekly-day-date">W</span>
                                    )}
                            </div>
                        </div>
                        <div
                            className="time-column-slots"
                            style={{ 
                                flex: "none",
                                position: 'relative'
                            }}
                        >
                            {visibleSlots.map((slot, index) => {
                                const hour = getHourFromSlot(slot);
                                const minutes = slot.split(":")[1];
                                const isHourStart = minutes === "00";
                                if (!isHourStart && !effectiveShowSubHourSlots) return (
                                    <div
                                        key={slot}
                                        className="time-slot-label"
                                        style={{ height: `${getSlotHeight(effectiveCellDuration)}px` }}
                                    />
                                );
                                // Punkt 6: render extra timezone hours alongside the local label.
                                const extras: string[] = (profile.viewSettings?.extraTimezones as string[]) || [];
                                const localLabel = formatHour(hour, parseInt(minutes), (isHourStart ? effectiveHourLabelFormat : 'full') as "short" | "full", profile.timeFormat);
                                let extraLabels: string[] = [];
                                if (isHourStart && extras.length > 0) {
                                    const userZone = profile.timezone || Intl.DateTimeFormat().resolvedOptions().timeZone;
                                    const today = new Date();
                                    today.setHours(hour, parseInt(minutes), 0, 0);
                                    extraLabels = extras.map((zone) => {
                                        try {
                                            const opt = TIMEZONE_OPTIONS_LOCAL.find((o) => o.zone === zone);
                                            const code = opt?.code || zone.split("/").pop() || zone;
                                            const time = new Intl.DateTimeFormat("en-GB", {
                                                timeZone: zone,
                                                hour: "2-digit",
                                                minute: "2-digit",
                                                hour12: profile.timeFormat === "12h",
                                            }).format(today);
                                            return `${code} ${time}`;
                                        } catch {
                                            return "";
                                        }
                                    }).filter(Boolean);
                                }
                                return (
                                    <div
                                        key={slot}
                                        className={`time-slot-label ${isHourStart ? "hour-start" : "sub-hour"}`}
                                        style={{ height: `${getSlotHeight(effectiveCellDuration)}px`, cursor: isHourStart ? 'pointer' : 'default' }}
                                        onClick={isHourStart ? () => jumpToHour(hour) : undefined}
                                        title={isHourStart ? `Jump to ${hour}:00` : undefined}
                                    >
                                        {(isHourStart || effectiveShowSubHourSlots) && (
                                            <span style={{ display: "inline-flex", flexDirection: "column", alignItems: "flex-end", lineHeight: 1.05 }}>
                                                <span>{localLabel}</span>
                                                {extraLabels.map((lbl, i) => (
                                                    <span key={i} style={{ fontSize: "0.55em", opacity: 0.65 }}>{lbl}</span>
                                                ))}
                                            </span>
                                        )}
                                    </div>
                                );
                            })}
                            {/* End-of-day 24:00 label */}
                            <div className="time-slot-label hour-start" style={{ height: '0px', lineHeight: 0 }}>
                                <span>{profile.timeFormat === '24h' ? '24' : '12 AM'}</span>
                            </div>
                        </div>
                    </div>
                )}

                {/* Day Columns */}
                <main
                    className={`weekly-days-grid cols-${viewDays}`}
                    data-slide-direction={slideDirection}
                    data-nav-type={viewDays > 1 ? "week" : "day"}
                    style={profile.showTimeGrid ? {
                        height: `${24 * (60 / effectiveCellDuration) * getSlotHeight(effectiveCellDuration) + getHeaderHeight(effectiveCellDuration)}px`,
                        flex: 1,
                        alignSelf: "flex-start",
                    } : {
                        flex: 1,
                    }}
                >
                    {getVisibleDays().map((date, colIndex) => {
                        const todayMidnight = new Date();
                        todayMidnight.setHours(0, 0, 0, 0);
                        const isToday = isSameDay(date, todayMidnight);
                        const isPast = date < todayMidnight && !isToday;

                        return (
                            <div
                                key={date.toISOString()}
                                className={`weekly-day-column ${date.getDay() === 6 ? "is-sat" : ""} ${date.getDay() === 0 ? "is-sun" : ""} ${isToday ? "is-today" : ""} ${isPast ? "is-past" : ""}`}
                                data-date={`${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`}
                                onClick={() => setSelectedDay(date)}
                            >
                                {/* Day Header */}
                                <header className="weekly-day-header" ref={colIndex === 0 ? dayHeaderRef : undefined}>
                                    <div
                                        style={{
                                            display: "flex",
                                            width: "100%",
                                            alignItems:
                                                activeDateLayout === "above" ||
                                                    activeDateLayout === "below"
                                                    ? (profile.dateAlignment === "left" ? "flex-start" : profile.dateAlignment === "right" ? "flex-end" : "center")
                                                    : "baseline",
                                            justifyContent:
                                                profile.dateAlignment === "left"
                                                    ? "flex-start"
                                                    : profile.dateAlignment === "right"
                                                        ? "flex-end"
                                                        : "center",
                                            flexDirection:
                                                activeDateLayout === "above"
                                                    ? "column-reverse"
                                                    : activeDateLayout === "below"
                                                        ? "column"
                                                        : "row",
                                            gap: profile.dateAlignment === "tight" ? "2px"
                                                : (activeDateLayout === "above" || activeDateLayout === "below") ? "0px"
                                                : (profile.dayHeaderGap || "0.35em"),
                                        }}
                                    >
                                        {(() => {
                                            // Compute date vertical offset relative to weekday font size
                                            const isHorizontal = activeDateLayout === "left" || activeDateLayout === "right" || activeDateLayout === undefined;
                                            const headlineSizePx = parseFloat(profile.headlineFontSize || "1.25rem") * (String(profile.headlineFontSize || "").includes("px") ? 1 : 16);
                                            const dateOffset = !isHorizontal ? undefined
                                                : profile.dateVerticalAlign === "top" ? `${-headlineSizePx * 0.55}px`
                                                : profile.dateVerticalAlign === "bottom" ? "0px"
                                                : `${-headlineSizePx * 0.25}px`; // center
                                            const dateStyle = isHorizontal ? {
                                                flexShrink: 0 as const, marginBottom: 0,
                                                position: "relative" as const, top: dateOffset,
                                            } : { flexShrink: 0 as const };
                                            return (
                                                <>
                                                    {activeDateLayout === "left" && (
                                                        <span className="weekly-day-date" style={dateStyle}>
                                                            {formatDateHeader(date, profile.language)}
                                                        </span>
                                                    )}
                                                    <h3
                                                        className={`weekly-day-name ${isSameDay(date, new Date()) ? "is-today" : ""}`}
                                                        style={{ marginBottom: 0, flexShrink: 0 }}
                                                    >
                                                        {getDayName(date, profile.language, profile.weekdayFormat, profile.customWeekdayNames, profile.weekStartDay, profile.weekdayCase)}
                                                    </h3>
                                                    {(activeDateLayout === "right" ||
                                                        activeDateLayout === "above" ||
                                                        activeDateLayout === "below" ||
                                                        activeDateLayout === undefined) && (
                                                            <span className="weekly-day-date" style={dateStyle}>
                                                                {formatDateHeader(date, profile.language)}
                                                            </span>
                                                        )}
                                                </>
                                            );
                                        })()}
                                    </div>
                                </header>

                                {/* Time Grid or Simple List */}
                                {profile.showTimeGrid ? (
                                    <div
                                        className="time-slots-container"
                                        onDragLeave={handleDragLeave}
                                        style={{ position: "relative" }}
                                    >
                                        {/* Calendar Fetching Indicator */}
                                        {profile.showTimeGrid && colIndex === 0 && isFetchingCalendar && (
                                            <div className="absolute top-2 left-2 z-[60] flex items-center gap-2 bg-white/90 dark:bg-zinc-800/90 px-3 py-1.5 rounded-full shadow-sm border border-zinc-200 dark:border-zinc-700 text-xs text-zinc-600 dark:text-zinc-300 pointer-events-none">
                                                <div className="w-3 h-3 border-2 border-zinc-400 border-t-transparent rounded-full animate-spin"></div>
                                                Syncing Calendar...
                                            </div>
                                        )}

                                        {/* Now Line - only show on today's column */}
                                        {isSameDay(date, new Date()) &&
                                            (() => {
                                                const now = currentTime;
                                                const nowHour = now.getHours();
                                                const nowMinute = now.getMinutes();
                                                // Show if within 24h range
                                                if (
                                                    nowHour >= 0 &&
                                                    nowHour < 24
                                                ) {
                                                    const minutesSinceStart =
                                                        nowHour * 60 + nowMinute;
                                                    const pixelsPerMinute =
                                                        getSlotHeight(effectiveCellDuration) / effectiveCellDuration;
                                                    const topPosition =
                                                        minutesSinceStart * pixelsPerMinute;
                                                    const timeString = formatHour(nowHour, nowMinute, "full", timeFormat);
                                                    return (
                                                        <div
                                                            className="now-line"
                                                            data-time={timeString}
                                                            style={{ top: `${topPosition}px` }}
                                                        />
                                                    );
                                                }
                                                return null;
                                            })()}
                                        {/* Protection overlays - render at exact event positions */}
                                        {protectEventTimes &&
                                            getEventsForDate(date)
                                                .filter((e) => !isAllDayEvent(e))
                                                .map((event) => {
                                                    const eventStart = new Date(event.startTime);
                                                    const eventEnd = new Date(event.endTime);
                                                    const eventStartHour = eventStart.getHours();
                                                    const eventStartMinute = eventStart.getMinutes();

                                                    // Show if within 24h range
                                                    if (
                                                        eventStartHour < 0 ||
                                                        eventStartHour >= 24
                                                    )
                                                        return null;

                                                    const minutesSinceStart =
                                                        eventStartHour * 60 +
                                                        eventStartMinute;
                                                    const pixelsPerMinute =
                                                        getSlotHeight(effectiveCellDuration) / effectiveCellDuration;
                                                    const topPosition =
                                                        minutesSinceStart * pixelsPerMinute;

                                                    // Calculate height based on event duration
                                                    const durationMinutes =
                                                        (eventEnd.getTime() - eventStart.getTime()) /
                                                        (1000 * 60);
                                                    const calculatedHeight =
                                                        durationMinutes * pixelsPerMinute;
                                                    // Ensure minimum height of 15px for visibility
                                                    const height = Math.max(calculatedHeight, 15);

                                                    const isUnlocked = unlockedEvents.has(event.id);

                                                    return (
                                                        <div
                                                            key={`protection-${event.id}`}
                                                            className="event-protection-overlay"
                                                            style={{
                                                                position: "absolute",
                                                                top: `${topPosition}px`,
                                                                left: 0,
                                                                right: 0,
                                                                height: `${height}px`,
                                                                zIndex: 1,
                                                                pointerEvents: "none",
                                                            }}
                                                        >
                                                            <button
                                                                className="event-unlock-btn"
                                                                onClick={(e) => {
                                                                    e.stopPropagation();
                                                                    setUnlockedEvents((prev) => {
                                                                        const next = new Set(prev);
                                                                        if (next.has(event.id)) {
                                                                            next.delete(event.id);
                                                                        } else {
                                                                            next.add(event.id);
                                                                        }
                                                                        return next;
                                                                    });
                                                                }}
                                                                title={
                                                                    isUnlocked
                                                                        ? "Lock this time slot"
                                                                        : "Unlock this time slot"
                                                                }
                                                                style={{ pointerEvents: "auto" }}
                                                            >
                                                                {isUnlocked ? "🔓" : "🔒"}
                                                            </button>
                                                        </div>
                                                    );
                                                })}
                                        {/* GridTaskBlocks for timed tasks */}
                                        {getTasksForDate(date)
                                            .filter(t => !!t.startTime)
                                            .map(task => (
                                                <GridTaskBlock
                                                    key={task.id}
                                                    task={task}
                                                    date={date}
                                                    activeDate={currentWeekStart}
                                                    cellDuration={effectiveCellDuration}
                                                    darkMode={darkMode}
                                                    isProtected={false}
                                                    editingTaskId={editingTaskId}
                                                    setEditingTaskId={setEditingTaskId}
                                                    updateTask={updateTask}
                                                    updateTaskNotes={updateTaskNotes}
                                                    updateTaskUrl={updateTaskUrl}
                                                    updateTaskDuration={updateTaskDuration}
                                                    toggleTask={toggleTask}
                                                    deleteTask={deleteTask}
                                                    toggleTaskRolling={toggleTaskRolling}
                                                    setSelectedTaskForNotes={setSelectedTaskForNotes}
                                                    setSelectedTaskForRecurrence={setSelectedTaskForRecurrence}
                                                    handleDragStart={handleDragStart}
                                                    handleDragEnd={handleDragEnd}
                                                    getSlotHeight={getSlotHeight}
                                                    draggedTask={draggedTask as any}
                                                    addSubTask={addSubTask}
                                                    toggleSubTask={toggleSubTask}
                                                    updateSubTask={updateSubTask}
                                                    deleteSubTask={deleteSubTask}
                                                    onSetEditingTaskId={setEditingTaskId}
                                                    workingHoursStart={workingHoursStart}
                                                    showTaskCheckboxes={effectiveShowTaskCheckboxes}
                                                    showProjectIcons={effectiveShowProjectIcons}
                                                    showPriorityIcons={effectiveShowPriorityIcons}
                                                    priorityStyle={effectivePriorityStyle}
                                                    projects={projects}
                                                    onProjectAssign={assignProject}
                                                    kanbanStages={kanbanStages}
                                                    weatherEnabled={effectiveWeatherEnabled}
                                                    onMoveTask={(taskId, targetDate, targetTime) => {
                                                        moveTaskToSlot(taskId, targetDate.getDay(), targetTime, targetDate);
                                                    }}
                                                />
                                            ))}
                                        {visibleSlots.map((slot) => {
                                            const hour = getHourFromSlot(slot);
                                            const minutes = slot.split(":")[1];
                                            const isHourStart = minutes === "00";
                                            const slotEvents = getEventsForSlot(date, slot);
                                            const isActive =
                                                activeSlot?.day === date.getDay() &&
                                                activeSlot?.slot === slot;
                                            const isProtected = isSlotProtected(date, slot);
                                            const isOccupiedByTask = isSlotOccupiedByTask(date, slot, draggedTask?.id);
                                            const isOccupiedByAnyTask = isSlotOccupiedByTask(date, slot);

                                            const handleSlotClick = (e: React.MouseEvent) => {
                                                if (slotDragJustEndedRef.current) return; // Suppress click after drag-to-create
                                                if (isProtected || isOccupiedByAnyTask) return; // Don't allow adding tasks to protected or occupied slots

                                                // Alt+Click to Create Calendar Event
                                                if (e.altKey) {
                                                    e.stopPropagation();
                                                    setCalendarEventModal({
                                                        isOpen: true,
                                                        initialDate: date,
                                                        initialStartTime: slot,
                                                    });
                                                    return;
                                                }

                                                if (!isActive) {
                                                    setActiveSlot({ day: date.getDay(), slot });
                                                    setNewSlotTask("");
                                                }
                                            };

                                            const handleSlotSubmit = async (e: React.FormEvent) => {
                                                e.preventDefault();
                                                e.stopPropagation();
                                                const taskTitle = newSlotTask.trim();
                                                // Clear state immediately to prevent double submit
                                                setActiveSlot(null);
                                                setNewSlotTask("");
                                                if (taskTitle) {
                                                    await addTask(date, taskTitle, slot);
                                                }
                                            };

                                            const handleSlotDrop = (e: React.DragEvent) => {
                                                e.preventDefault();
                                                if (isProtected || isOccupiedByTask) return; // Don't allow dropping on protected or occupied slots
                                                handleDrop(e, date.getDay(), slot);
                                            };

                                            const isDropTarget =
                                                dropPreview?.day === date.getDay() &&
                                                dropPreview?.slot === slot;

                                            const dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
                                            const isInDragSelection = slotDragSelection &&
                                                slotDragSelection.dateStr === dateStr &&
                                                slot >= slotDragSelection.startSlot &&
                                                slot <= slotDragSelection.endSlot;

                                            return (
                                                <div
                                                    key={slot}
                                                    data-slot={slot}
                                                    data-slot-blocked={isProtected || isOccupiedByAnyTask ? "1" : undefined}
                                                    className={`time-slot ${isHourStart ? "hour-start" : ""} ${draggedTask && !isProtected && !isOccupiedByTask ? "drop-target" : ""} ${isActive ? "active" : ""} ${isInDragSelection ? "slot-drag-selected" : ""}`}
                                                    style={{
                                                        height: `${getSlotHeight(effectiveCellDuration)}px`,
                                                        position: "relative",
                                                        cursor: isProtected || isOccupiedByAnyTask ? "not-allowed" : "text",
                                                    }}
                                                    onClick={handleSlotClick}
                                                    onMouseDown={(e) => {
                                                        // Only start slot drag on empty slots, left button, no modifiers
                                                        if (e.button !== 0 || e.altKey || e.ctrlKey || e.metaKey) return;
                                                        if (isProtected || isOccupiedByAnyTask) return;
                                                        // Don't start drag if clicking on an event or task
                                                        const target = e.target as HTMLElement;
                                                        if (target.closest('.calendar-event-block, .grid-task-block, .task-input-slot')) return;
                                                        slotDragRef.current = {
                                                            active: false,
                                                            date: new Date(date),
                                                            startSlot: slot,
                                                            currentSlot: slot,
                                                            startY: e.clientY,
                                                        };
                                                    }}
                                                    onDragOver={(e) =>
                                                        !isProtected && !isOccupiedByTask &&
                                                        handleDragOver(e, date.getDay(), slot)
                                                    }
                                                    onDrop={handleSlotDrop}
                                                >
                                                    {/* Weather indicator for hour-start slots */}
                                                    {isHourStart && effectiveWeatherEnabled && (() => {
                                                        const h = parseInt(slot.split(":")[0]);
                                                        const dateStr = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, "0")}-${String(date.getDate()).padStart(2, "0")}T${String(h).padStart(2, "0")}:00`;
                                                        const w = weatherData[dateStr];
                                                        if (!w) return null;
                                                        const d = effectiveWeatherDisplay;
                                                        const parts: string[] = [];
                                                        if (d.includes("temp")) parts.push(`${w.temp}°`);
                                                        if (d.includes("feelsLike") && w.feelsLike != null) parts.push(`(${w.feelsLike}°)`);
                                                        if (d.includes("wind") && w.wind != null) parts.push(`${w.wind}km/h`);
                                                        if (d.includes("gusts") && w.gusts != null) parts.push(`💨${w.gusts}`);
                                                        if (d.includes("precipProb") && w.precipProb != null) parts.push(`${w.precipProb}%`);
                                                        if (d.includes("precip") && w.precip != null && w.precip > 0) parts.push(`${w.precip}mm`);
                                                        if (d.includes("humidity") && w.humidity != null) parts.push(`💧${w.humidity}%`);
                                                        if (d.includes("uv") && w.uv != null && w.uv > 0) parts.push(`UV${w.uv}`);
                                                        return (
                                                            <div className="weather-chip" style={{ position: "absolute", top: "2px", right: "3px", display: "flex", alignItems: "center", gap: "2px", fontSize: "10px", pointerEvents: "none", zIndex: 20, lineHeight: 1, color: darkMode ? "#bbb" : "#555", background: darkMode ? "rgba(17,17,17,0.9)" : "rgba(255,255,255,0.92)", padding: "1px 5px", borderRadius: "6px", backdropFilter: "blur(4px)", boxShadow: "0 0 0 1px " + (darkMode ? "rgba(255,255,255,0.06)" : "rgba(0,0,0,0.06)") }}>
                                                                {d.includes("icon") && <span>{getWeatherIcon(w.code)}</span>}
                                                                {parts.length > 0 && <span style={{ fontWeight: 600 }}>{parts.join(" ")}</span>}
                                                            </div>
                                                        );
                                                    })()}
                                                    {/* Drop preview indicator */}
                                                    {isDropTarget && !isProtected && !isOccupiedByTask && (
                                                        <div className="drop-preview" />
                                                    )}
                                                    {/* Calendar Events in time slot */}
                                                    {slotEvents.map((event) => {
                                                        // During drag, use the drag state's current times for position/height
                                                        const isDragging = eventDragState?.eventId === event.id && eventDragState?.hasMoved;
                                                        const displayStartTime = isDragging ? new Date(eventDragState!.currentStartTime) : new Date(event.startTime);
                                                        const displayEndTime = isDragging ? new Date(eventDragState!.currentEndTime) : new Date(event.endTime);
                                                        const durationMs = displayEndTime.getTime() - displayStartTime.getTime();
                                                        const durationMinutes = durationMs / (1000 * 60);
                                                        const pxPerMin = getSlotHeight(effectiveCellDuration) / effectiveCellDuration;
                                                        const eventHeight = Math.max(durationMinutes * pxPerMin, 15);
                                                        const timeStr = `${displayStartTime.getHours().toString().padStart(2, "0")}:${displayStartTime.getMinutes().toString().padStart(2, "0")} - ${displayEndTime.getHours().toString().padStart(2, "0")}:${displayEndTime.getMinutes().toString().padStart(2, "0")}`;

                                                        // Calculate offset within the slot based on event start time
                                                        const [slotHour, slotMinute] = slot
                                                            .split(":")
                                                            .map(Number);
                                                        const slotStartMinutes = slotHour * 60 + slotMinute;
                                                        const eventStartMinutes =
                                                            displayStartTime.getHours() * 60 +
                                                            displayStartTime.getMinutes();
                                                        const offsetMinutes =
                                                            eventStartMinutes - slotStartMinutes;
                                                        const topOffset = offsetMinutes * pxPerMin;

                                                        // Convert hex to rgba for background, or use default
                                                        const eventColor = event.calendarColor || "#009a9a";
                                                        const bgColor = eventColor.startsWith("#")
                                                            ? `${eventColor}20` // Add alpha for transparency
                                                            : eventColor;
                                                        const borderColor = eventColor.startsWith("#")
                                                            ? eventColor
                                                            : "var(--weekly-teal)";

                                                        const overlap = eventOverlapLayout[event.id] || { column: 0, totalColumns: 1 };
                                                        const colWidth = 100 / overlap.totalColumns;
                                                        const colLeft = overlap.column * colWidth;

                                                        return (
                                                            <div
                                                                key={event.id}
                                                                className={`time-slot-event${isDragging ? ' event-dragging' : ''}`}
                                                                title={`${event.calendarTitle}: ${event.title}\n${timeStr}`}
                                                                style={{
                                                                    height: `${eventHeight}px`,
                                                                    minHeight: `15px`,
                                                                    position: "absolute",
                                                                    top: `${topOffset}px`,
                                                                    left: `calc(${colLeft}% + 1px)`,
                                                                    width: `calc(${colWidth}% - 3px)`,
                                                                    zIndex: isDragging ? 50 : 1,
                                                                    flexDirection: "column",
                                                                    alignItems: "flex-start",
                                                                    justifyContent: "flex-start",
                                                                    backgroundColor: bgColor,
                                                                    borderLeftColor: borderColor,
                                                                    color: borderColor,
                                                                    cursor: event.editable
                                                                        ? (isDragging ? "grabbing" : "grab")
                                                                        : "default",
                                                                    opacity: isDragging && eventDragState?.mode === 'move' ? 0.7 : 1,
                                                                    transition: isDragging ? 'none' : undefined,
                                                                    userSelect: 'none',
                                                                }}
                                                                onClick={(e) => {
                                                                    e.stopPropagation();
                                                                    if (dragJustEndedRef.current) return; // Don't open modal after drag
                                                                    if (event.editable) {
                                                                        setCalendarEventModal({
                                                                            isOpen: true,
                                                                            event: event,
                                                                        });
                                                                    }
                                                                }}
                                                                onMouseDown={(e) => {
                                                                    if (event.editable && e.button === 0) {
                                                                        handleEventDragStart(e, event, 'move');
                                                                    }
                                                                }}
                                                            >
                                                                {/* Top resize handle */}
                                                                {event.editable && (
                                                                    <div
                                                                        className="event-resize-handle event-resize-handle-top"
                                                                        onMouseDown={(e) => {
                                                                            e.stopPropagation();
                                                                            handleEventDragStart(e, event, 'resize-top');
                                                                        }}
                                                                    />
                                                                )}
                                                                <div className="event-title-row">
                                                                    <span className="event-indicator">📅</span>
                                                                    <span className="event-title">
                                                                        {event.title}
                                                                    </span>
                                                                </div>
                                                                <div className="event-time-row">{timeStr}</div>
                                                                {event.location && (
                                                                    <div className="event-location-row">{event.location}</div>
                                                                )}
                                                                <div className="event-icons-row">
                                                                    {event.description && (
                                                                        <span className="event-note-icon" data-note={stripHtml(event.description || '')}>
                                                                            <FileText size={11} />
                                                                        </span>
                                                                    )}
                                                                    {event.isRecurring && <Repeat size={11} />}
                                                                    <FontAwesomeIcon
                                                                        icon={event.source === "google" ? faGoogle : event.source === "apple" ? faApple : event.source === "outlook" ? faMicrosoft : faServer}
                                                                        style={{ fontSize: '0.6rem' }}
                                                                    />
                                                                </div>
                                                                {/* Bottom resize handle */}
                                                                {event.editable && (
                                                                    <div
                                                                        className="event-resize-handle event-resize-handle-bottom"
                                                                        onMouseDown={(e) => {
                                                                            e.stopPropagation();
                                                                            handleEventDragStart(e, event, 'resize-bottom');
                                                                        }}
                                                                    />
                                                                )}
                                                            </div>
                                                        );
                                                    })}
                                                    {isActive && (
                                                        <form
                                                            onSubmit={handleSlotSubmit}
                                                            className="slot-input-form"
                                                        >
                                                            <input
                                                                type="text"
                                                                value={newSlotTask}
                                                                onChange={(e) => setNewSlotTask(e.target.value)}
                                                                onBlur={async (e) => {
                                                                    // Prevent double submission if form was submitted
                                                                    if (activeSlot && newSlotTask.trim()) {
                                                                        // Delay slightly to let onSubmit fire if that was the cause
                                                                        setTimeout(async () => {
                                                                            if (activeSlot && newSlotTask.trim()) {
                                                                                const taskTitle = newSlotTask.trim();
                                                                                setActiveSlot(null);
                                                                                setNewSlotTask("");
                                                                                await addTask(date, taskTitle, slot);
                                                                            }
                                                                        }, 100);
                                                                    } else {
                                                                        setActiveSlot(null);
                                                                        setNewSlotTask("");
                                                                    }
                                                                }}
                                                                onKeyDown={(e) => {
                                                                    if (e.key === "Escape") {
                                                                        setActiveSlot(null);
                                                                        setNewSlotTask("");
                                                                    }
                                                                }}
                                                                autoFocus
                                                                className="weekly-task-input"
                                                                style={{
                                                                    width: "100%",
                                                                    background: "transparent",
                                                                    outline: "none",
                                                                    minHeight: "24px",
                                                                    paddingLeft: "0",
                                                                }}
                                                            />

                                                        </form>
                                                    )}
                                                </div>
                                            );
                                        })}
                                        {/* End-of-day 24:00 line */}
                                        <div className="time-slot hour-start" style={{ height: 0, position: 'relative' }} />
                                        {/* All Day Events Section */}


                                    </div>
                                ) : (
                                    <div
                                        onDragOver={(e) => handleDragOver(e, date.getDay())}
                                        onDrop={(e) => handleDrop(e, date.getDay())}
                                        onDragLeave={handleDragLeave}
                                        style={{ flex: 1 }}
                                    >
                                        {/* Calendar Events */}
                                        {getEventsForDate(date).map((event) => {
                                            const eventColor = event.calendarColor || "#009a9a";
                                            const bgColor = eventColor.startsWith("#")
                                                ? `${eventColor}20`
                                                : eventColor;
                                            const borderColor = eventColor.startsWith("#")
                                                ? eventColor
                                                : "var(--weekly-teal)";

                                            return (
                                                <div
                                                    key={event.id}
                                                    className="weekly-calendar-event"
                                                    onClick={(e) => {
                                                        e.stopPropagation();
                                                        if (event.editable) {
                                                            setCalendarEventModal({
                                                                isOpen: true,
                                                                event: event,
                                                            });
                                                        }
                                                    }}
                                                    style={{
                                                        backgroundColor: bgColor,
                                                        borderLeftColor: borderColor,
                                                        color: borderColor,
                                                        cursor: event.editable ? "pointer" : "default",
                                                    }}
                                                >
                                                    <div
                                                        className="weekly-calendar-event-time"
                                                        style={{ color: "inherit", opacity: 0.8 }}
                                                    >
                                                        {new Date(event.startTime).toLocaleTimeString(
                                                            "en-US",
                                                            { hour: "numeric", minute: "2-digit" },
                                                        )}
                                                    </div>
                                                    <div
                                                        className="weekly-calendar-event-title"
                                                        style={{ color: "inherit" }}
                                                    >
                                                        {event.title}
                                                    </div>
                                                    {event.location && (
                                                        <div className="event-location-row" style={{ color: "inherit", opacity: 0.7 }}>{event.location}</div>
                                                    )}
                                                    {(event.isRecurring || event.description || profile.showCalendarProviderIcon) && (
                                                        <div className="event-icons-row">
                                                            {event.description && (
                                                                <span className="event-note-icon" data-note={stripHtml(event.description || '')}>
                                                                    <FileText size={11} />
                                                                </span>
                                                            )}
                                                            {event.isRecurring && <Repeat size={11} />}
                                                            {profile.showCalendarProviderIcon && (
                                                                <img
                                                                    src={
                                                                        event.source === "google" ? "/icons/google-calendar.svg"
                                                                        : event.source === "apple" ? "/icons/apple-calendar.svg"
                                                                        : event.source === "outlook" ? "/icons/outlook-calendar.svg"
                                                                        : event.source === "synology" ? "/icons/synology-calendar.svg"
                                                                        : undefined
                                                                    }
                                                                    alt={event.source}
                                                                    style={{ width: 13, height: 13 }}
                                                                    onError={(e) => { (e.target as HTMLImageElement).style.display = 'none'; }}
                                                                />
                                                            )}
                                                        </div>
                                                    )}
                                                </div>
                                            );
                                        })}

                                        {/* Tasks */}
                                        <ol className="weekly-task-list">
                                            {getTasksForDate(date).map((task) => (
                                                <TaskItem
                                                    key={task.id}
                                                    task={task}
                                                    isEditing={editingTaskId === task.id}
                                                    onToggle={() => toggleTask(task.id)}
                                                    onEdit={() => setEditingTaskId(task.id)}
                                                    onUpdate={(newTitle) => updateTask(task.id, newTitle)}
                                                    onDelete={() => deleteTask(task.id)}
                                                    onNotes={(notes) => updateTaskNotes(task.id, notes)}
                                                    onUrl={(url) => updateTaskUrl(task.id, url)}
                                                    onRollToggle={() => toggleTaskRolling(task.id)}
                                                    onRecurrence={() =>
                                                        setSelectedTaskForRecurrence(task)
                                                    }
                                                    onDragStart={(e, t) => handleDragStart(e, t)}
                                                    onDragEnd={handleDragEnd}
                                                    onAddSubTask={addSubTask}
                                                    onToggleSubTask={toggleSubTask}
                                                    onDeleteSubTask={deleteSubTask}
                                                    onUpdateSubTask={updateSubTask}
                                                    editingTaskId={editingTaskId}
                                                    onSetEditingTaskId={setEditingTaskId}
                                                    showTaskCheckboxes={effectiveShowTaskCheckboxes}
                                                    showProjectIcons={effectiveShowProjectIcons}
                                                    showPriorityIcons={effectiveShowPriorityIcons}
                                                    priorityStyle={effectivePriorityStyle}
                                                    projects={projects}
                                                    onProjectAssign={assignProject}
                                                    kanbanStages={kanbanStages}
                                                />
                                            ))}
                                        </ol>
                                    </div>
                                )}
                            </div>
                        );
                    })}
                </main>

            </div>
            {/* Right Navigation Arrows (outside scroll wrapper, fixed to right edge) */}
            <div
              className="side-nav side-nav-right"
              style={{
                height: `${measuredHeaderHeight}px`,
                position: 'absolute',
                top: 0,
                right: 16,
                width: '30px',
                zIndex: 50
              }}
            >
                <button onClick={goToNextDay} title="Next Day" className="side-nav-btn">
                    <ChevronRight size={16} />
                </button>
                <button onClick={goToNextWeek} title="Next Week" className="side-nav-btn">
                    <ChevronsRight size={16} />
                </button>
            </div>
            </div>}

            {/* All-Day Events Section (below position) — hidden in kanban */}
            {profile.viewStyle !== "kanban" && profile.viewStyle !== "priority" && effectiveAllDayPosition === "below" && allDaySection}

            {/* Someday Section */}
            {effectiveShowSomeday && (<>
                {/* Resize handle - on top border of someday section */}
                {somedayExpanded && (
                    <div
                        className="resize-handle"
                        onMouseDown={(e) => startResize(e, 'someday', true)}
                        onTouchStart={(e) => startResize(e, 'someday', true)}
                    >
                        <div className="resize-handle-bar" />
                    </div>
                )}
                <section
                    ref={somedaySectionRefCb}
                    className={`weekly-someday ${somedayExpanded ? "expanded" : "collapsed"} transition-colors duration-200`}
                    style={somedayExpanded && somedayHeight ? { height: `${somedayHeight}px`, overflowY: 'auto' } : undefined}
                >
                    {/* Someday tabs bar */}
                    <div className="someday-tabs-bar">
                        <div
                            onClick={() => setSomedayExpanded(!somedayExpanded)}
                            style={{
                                cursor: "pointer",
                                display: "flex",
                                alignItems: "center",
                                gap: "4px",
                                marginRight: "4px",
                                marginBottom: "6px",
                            }}
                            title={somedayExpanded ? "Collapse" : "Expand"}
                        >
                            <ChevronRight
                                size={14}
                                style={{
                                    transform: somedayExpanded ? "rotate(90deg)" : "rotate(0deg)",
                                    transition: "transform 0.15s",
                                    color: "var(--weekly-text-light)",
                                    flexShrink: 0,
                                }}
                            />
                            <span style={{
                                fontSize: "0.7rem",
                                fontWeight: 600,
                                color: "var(--weekly-text-light)",
                                textTransform: "uppercase",
                                letterSpacing: "0.05em",
                                whiteSpace: "nowrap",
                            }}>
                                any day
                            </span>
                        </div>
                        <button
                            className="someday-bar-icon-btn"
                            onClick={() => handleStartAddSomedayList()}
                            title={t.newList}
                        >
                            <ListPlus size={14} />
                        </button>
                        <button
                            className="someday-bar-icon-btn"
                            onClick={() => { setCreatingNewTab(true); setCreatingNewTabName(""); }}
                            title={t.newTab}
                        >
                            <FolderPlus size={14} />
                        </button>
                        {creatingNewTab && (
                            <input
                                className="someday-tab-rename-input"
                                value={creatingNewTabName}
                                onChange={(e) => setCreatingNewTabName(e.target.value)}
                                onBlur={() => {
                                    const name = creatingNewTabName.trim();
                                    if (name && !somedayTabs.includes(name)) {
                                        saveCustomTabs([...customTabs, name]);
                                        setSomedayTab(name);
                                    } else if (name) {
                                        setSomedayTab(name);
                                    }
                                    setCreatingNewTab(false);
                                }}
                                onKeyDown={(e) => {
                                    if (e.key === "Enter") e.currentTarget.blur();
                                    if (e.key === "Escape") setCreatingNewTab(false);
                                }}
                                placeholder={t.newTab}
                                autoFocus
                                style={{
                                    fontSize: "0.75rem",
                                    border: "1px solid var(--weekly-border)",
                                    borderRadius: "3px",
                                    padding: "2px 6px",
                                    background: "var(--weekly-bg)",
                                    color: "var(--weekly-text)",
                                    width: "80px",
                                }}
                            />
                        )}
                        <div className="someday-tabs-bar-divider" />
                        <button
                            className={`someday-tab-btn-h ${activeSomedayTab === null ? "active" : ""} ${dragOverTab === "__all__" ? "drag-over" : ""}`}
                            onClick={() => setSomedayTab(null)}
                            onDragOver={(e) => {
                                if (e.dataTransfer.types.includes("text/list-id")) {
                                    e.preventDefault();
                                    e.dataTransfer.dropEffect = "move";
                                    setDragOverTab("__all__");
                                }
                            }}
                            onDragLeave={() => setDragOverTab(null)}
                            onDrop={(e) => {
                                const listId = e.dataTransfer.getData("text/list-id");
                                if (listId) {
                                    e.preventDefault();
                                    e.stopPropagation();
                                    assignListToTab(listId, null);
                                    setDraggingListId(null);
                                    setDropTargetListIndex(null);
                                }
                                setDragOverTab(null);
                            }}
                        >{t.allTabs} <span className="someday-tab-count">{somedayLists.length}</span></button>
                        {somedayTabs.map(tab => (
                            editingTabName === tab ? (
                                <input
                                    key={tab}
                                    className="someday-tab-rename-input"
                                    value={renamingTabValue}
                                    onChange={(e) => setRenamingTabValue(e.target.value)}
                                    onBlur={() => {
                                        renameTab(tab, renamingTabValue);
                                        setEditingTabName(null);
                                    }}
                                    onKeyDown={(e) => {
                                        if (e.key === "Enter") e.currentTarget.blur();
                                        if (e.key === "Escape") setEditingTabName(null);
                                    }}
                                    autoFocus
                                    style={{
                                        fontSize: "0.75rem",
                                        border: "1px solid var(--weekly-border)",
                                        borderRadius: "3px",
                                        padding: "2px 6px",
                                        background: "var(--weekly-bg)",
                                        color: "var(--weekly-text)",
                                        width: "80px",
                                    }}
                                />
                            ) : (
                                <div
                                    key={tab}
                                    className="someday-tab-wrapper-h"
                                    style={{ position: "relative" }}
                                    onDragOver={(e) => {
                                        if (e.dataTransfer.types.includes("text/list-id")) {
                                            e.preventDefault();
                                            e.dataTransfer.dropEffect = "move";
                                            setDragOverTab(tab);
                                        }
                                    }}
                                    onDragLeave={() => setDragOverTab(null)}
                                    onDrop={(e) => {
                                        const listId = e.dataTransfer.getData("text/list-id");
                                        if (listId) {
                                            e.preventDefault();
                                            e.stopPropagation();
                                            assignListToTab(listId, tab);
                                            setDraggingListId(null);
                                            setDropTargetListIndex(null);
                                        }
                                        setDragOverTab(null);
                                    }}
                                >
                                    {(() => {
                                        const tv = getTabVisuals(tab);
                                        return (
                                            <button
                                                className={`someday-tab-btn-h ${activeSomedayTab === tab ? "active" : ""} ${dragOverTab === tab ? "drag-over" : ""}`}
                                                onClick={() => setSomedayTab(tab)}
                                                onDoubleClick={(e) => { e.stopPropagation(); const newTab = editingTabVisualsName === tab ? null : tab; if (newTab) setEditingTabVisualsRect((e.currentTarget as HTMLElement).getBoundingClientRect()); setEditingTabVisualsName(newTab); }}
                                                style={tv.color ? {
                                                    background: activeSomedayTab === tab ? tv.color : `${tv.color}22`,
                                                    color: activeSomedayTab === tab ? "#fff" : tv.color,
                                                    borderColor: tv.color,
                                                    borderBottomColor: activeSomedayTab === tab ? "transparent" : tv.color,
                                                } : undefined}
                                                title={profile.language === "de" ? "Doppelklick zum Bearbeiten" : "Double-click to edit"}
                                            >
                                                {tv.icon && (
                                                    <span style={{ display: "inline-flex", alignItems: "center", marginRight: "4px" }}>
                                                        <ProjectIcon icon={tv.icon} size={12} color={activeSomedayTab === tab && tv.color ? "#fff" : (tv.color || "currentColor")} />
                                                    </span>
                                                )}
                                                {tab} <span className="someday-tab-count">{somedayLists.filter(l => l.tab === tab).length}</span>
                                            </button>
                                        );
                                    })()}
                                    {editingTabVisualsName === tab && (
                                        <TabVisualsPopover
                                            tabName={tab}
                                            visuals={getTabVisuals(tab)}
                                            darkMode={darkMode}
                                            language={profile.language}
                                            onChange={(updates) => updateTabVisuals(tab, updates)}
                                            onRename={(newName) => { renameTab(tab, newName); setEditingTabVisualsName(null); }}
                                            onDissolve={() => dissolveTab(tab)}
                                            onClose={() => setEditingTabVisualsName(null)}
                                            anchorRect={editingTabVisualsRect}
                                        />
                                    )}
                                </div>
                            )
                        ))}
                    </div>
                    <div style={{ display: "flex", flexDirection: "row", maxWidth: "100%", width: "100%" }}>
                        <div ref={somedayGridRef} style={{ flex: 1, minWidth: 0, overflowX: "auto" }}>
                            {somedayExpanded && (
                                <div
                                    className={`weekly-someday-lists-grid cols-${Math.min(7, Math.max(1, viewDays))}`}
                                    style={{ display: "flex", flexDirection: "row", flexWrap: "nowrap" }}
                                    onDragLeave={(e) => {
                                        // Clear indicator when leaving the someday grid entirely
                                        if (draggingListId && !e.currentTarget.contains(e.relatedTarget as Node)) {
                                            setDropTargetListIndex(null);
                                        }
                                    }}
                                >
                                    {(() => {
                                        const baseLists = filteredSomedayLists.length > 0
                                            ? filteredSomedayLists
                                            : [{ id: "default", title: "LISTE", tasks: [] as Task[] }];
                                        return baseLists.slice(0, Math.max(filteredSomedayLists.length, viewDays));
                                    })()
                                        .flatMap((list, listIdx, arr) => {
                                            const indicator = draggingListId && dropTargetListIndex === listIdx && draggingListId !== list.id ? (
                                                <div key={`drop-indicator-${listIdx}`} style={{
                                                    width: "3px",
                                                    flexShrink: 0,
                                                    background: "#6366f1",
                                                    borderRadius: "2px",
                                                    alignSelf: "stretch",
                                                    transition: "opacity 0.15s",
                                                }} />
                                            ) : null;
                                            // After last item, check for drop at end
                                            const endIndicator = listIdx === arr.length - 1 && draggingListId && dropTargetListIndex === arr.length && draggingListId !== list.id ? (
                                                <div key="drop-indicator-end" style={{
                                                    width: "3px",
                                                    flexShrink: 0,
                                                    background: "#6366f1",
                                                    borderRadius: "2px",
                                                    alignSelf: "stretch",
                                                    transition: "opacity 0.15s",
                                                }} />
                                            ) : null;
                                            const listEl = (
                                            <div
                                                key={list.id}
                                                className={`weekly-someday-list ${draggingListId === list.id ? "is-dragging" : ""} transition-colors duration-200`}
                                                style={{
                                                    minHeight: "200px",
                                                    cursor: "text",
                                                    display: "flex",
                                                    flexDirection: "column",
                                                    position: "relative",
                                                    ...(list.color ? {
                                                        background: `${list.color}1f`,
                                                        borderLeft: `4px solid ${list.color}`,
                                                        borderRadius: "6px",
                                                    } : {}),
                                                }}
                                                onMouseDown={(e) => {
                                                    const target = e.target as HTMLElement;
                                                    if (
                                                        target.closest(".task-list-slot") ||
                                                        target.closest(".someday-list-header") ||
                                                        target.closest("button") ||
                                                        target.tagName === "INPUT"
                                                    ) {
                                                        return;
                                                    }

                                                    const input = e.currentTarget.querySelector(
                                                        `[data-someday-add-input="${list.id}"]`,
                                                    ) as HTMLInputElement;
                                                    if (input) {
                                                        input.focus();
                                                    }
                                                }}
                                                draggable
                                                onDragStart={(e) => {
                                                    const target = e.target as HTMLElement;
                                                    if (target.closest(".weekly-task-item")) {
                                                        return;
                                                    }
                                                    if (!isDragFromHandle.current) {
                                                        e.preventDefault();
                                                        return;
                                                    }
                                                    isDragFromHandle.current = false;
                                                    setDraggingListId(list.id);
                                                    e.dataTransfer.setData("text/list-id", list.id);
                                                    e.dataTransfer.effectAllowed = "move";
                                                }}
                                                onDragEnd={() => { setDraggingListId(null); setDropTargetListIndex(null); setDragOverTab(null); }}
                                                onDragOver={(e) => {
                                                    e.preventDefault();
                                                    e.dataTransfer.dropEffect = "move";
                                                    if (!draggingListId || draggingListId === list.id) return;
                                                    const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
                                                    const midX = rect.left + rect.width / 2;
                                                    // Drop before or after this list
                                                    if (e.clientX < midX) {
                                                        setDropTargetListIndex(listIdx);
                                                    } else {
                                                        setDropTargetListIndex(listIdx + 1);
                                                    }
                                                }}
                                                onDrop={async (e) => {
                                                    e.preventDefault();
                                                    const droppedListId =
                                                        e.dataTransfer.getData("text/list-id");
                                                    const draggedTaskId =
                                                        e.dataTransfer.getData("text/plain");

                                                    if (droppedListId === list.id && !draggedTaskId) {
                                                        setDraggingListId(null);
                                                        setDropTargetListIndex(null);
                                                        return;
                                                    }

                                                    // If a task is dropped on the list generally (not on a specific slot), 
                                                    // find the first free slot and place it there.
                                                    if (draggedTaskId && draggedTask && draggedTask.id === draggedTaskId) {
                                                        const occupiedSlots = list.tasks.map(t => t.somedaySlotIndex).filter(s => s !== null && s !== undefined) as number[];
                                                        let nextFreeSlot = 0;
                                                        while (occupiedSlots.includes(nextFreeSlot)) {
                                                            nextFreeSlot++;
                                                        }
                                                        handleSomedayDrop(e, list.id, nextFreeSlot);
                                                        return;
                                                    }

                                                    // Reorder logic (list drag) - apply the visual order
                                                    if (!droppedListId || dropTargetListIndex === null) {
                                                        setDraggingListId(null);
                                                        setDropTargetListIndex(null);
                                                        return;
                                                    }
                                                    const dragIdx = somedayLists.findIndex(
                                                        (l) => l.id === droppedListId,
                                                    );
                                                    if (dragIdx === -1) {
                                                        setDraggingListId(null);
                                                        setDropTargetListIndex(null);
                                                        return;
                                                    }

                                                    const newLists = [...somedayLists];
                                                    const [moved] = newLists.splice(dragIdx, 1);
                                                    // Adjust target index since we removed an item before it
                                                    const insertIdx = dragIdx < dropTargetListIndex
                                                        ? dropTargetListIndex - 1
                                                        : dropTargetListIndex;
                                                    newLists.splice(insertIdx, 0, moved);

                                                    setSomedayLists(newLists);
                                                    setDraggingListId(null);
                                                    setDropTargetListIndex(null);

                                                    // Persist order
                                                    const orderUpdates = newLists.map((l, index) => ({
                                                        id: l.id,
                                                        order: index,
                                                    }));
                                                    try {
                                                        await fetch("/api/someday-lists", {
                                                            method: "PATCH",
                                                            headers: { "Content-Type": "application/json" },
                                                            body: JSON.stringify(orderUpdates),
                                                        });
                                                    } catch (err) {
                                                        console.error("Failed to update list order", err);
                                                    }
                                                }}
                                            >
                                                <div
                                                    className="weekly-someday-list-title-header"
                                                    style={{
                                                        display: "flex",
                                                        justifyContent: "flex-start",
                                                        alignItems: "center",
                                                        ...(listToDelete === list.id ? { position: "relative", zIndex: 10 } : {}),
                                                    }}
                                                >
                                                    {listToDelete === list.id ? (
                                                        <div style={{ display: "flex", flexDirection: "column", width: "100%", gap: "6px", padding: "4px" }}>
                                                            <span style={{ fontSize: "0.9rem", fontWeight: "bold" }}>
                                                                {profile.language === 'de' ? 'Diese Liste löschen?' : 'Delete this list?'}
                                                            </span>
                                                            {list.externalProvider ? (
                                                                <>
                                                                    <span style={{ fontSize: "0.75rem", color: "#888" }}>
                                                                        {profile.language === 'de'
                                                                            ? `Diese Liste ist mit ${list.externalProvider} verknüpft. Wie soll fortgefahren werden?`
                                                                            : `This list is linked to ${list.externalProvider}. How would you like to proceed?`}
                                                                    </span>
                                                                    <div style={{ display: "flex", flexDirection: "column", gap: "6px", marginTop: "4px" }}>
                                                                        <button onClick={(e) => {
                                                                            e.stopPropagation();
                                                                            setListToDelete(null);
                                                                        }} style={{ padding: "6px 8px", borderRadius: "4px", backgroundColor: "#eee", color: "#333", border: "none", cursor: "pointer", fontSize: "0.8rem", textAlign: "left" }}>
                                                                            {profile.language === 'de' ? 'Abbrechen' : 'Cancel'}
                                                                        </button>
                                                                        <button onClick={async (e) => {
                                                                            e.stopPropagation();
                                                                            try {
                                                                                await fetch(`/api/someday-lists?id=${list.id}&tasksOnly=true`, { method: "DELETE" });
                                                                                setSomedayLists((prev) => prev.filter((l) => l.id !== list.id));
                                                                                setListToDelete(null);
                                                                            } catch (err) { console.error(err); }
                                                                        }} style={{ padding: "6px 8px", borderRadius: "4px", backgroundColor: "#3b82f6", color: "#fff", border: "none", cursor: "pointer", fontSize: "0.8rem", textAlign: "left" }}>
                                                                            {profile.language === 'de'
                                                                                ? `Nur hier ausblenden (in ${list.externalProvider} bleibt sie)`
                                                                                : `Hide here only (keep in ${list.externalProvider})`}
                                                                        </button>
                                                                        <button onClick={async (e) => {
                                                                            e.stopPropagation();
                                                                            try {
                                                                                const res = await fetch(`/api/someday-lists?id=${list.id}&deleteExternal=true`, { method: "DELETE" });
                                                                                const data = await res.json().catch(() => ({}));
                                                                                if (data.externalDeleteFailed) {
                                                                                    alert(profile.language === 'de'
                                                                                        ? `Hinweis: Die Liste wurde lokal gelöscht, aber nicht aus ${list.externalProvider} (Fehler beim Provider).`
                                                                                        : `Note: The list was deleted locally, but not from ${list.externalProvider} (provider error).`);
                                                                                }
                                                                                setSomedayLists((prev) => prev.filter((l) => l.id !== list.id));
                                                                                setListToDelete(null);
                                                                            } catch (err) { console.error(err); }
                                                                        }} style={{ padding: "6px 8px", borderRadius: "4px", backgroundColor: "#dc2626", color: "#fff", border: "none", cursor: "pointer", fontSize: "0.8rem", textAlign: "left" }}>
                                                                            {profile.language === 'de'
                                                                                ? `Hier UND in ${list.externalProvider} löschen`
                                                                                : `Delete here AND in ${list.externalProvider}`}
                                                                        </button>
                                                                    </div>
                                                                </>
                                                            ) : (
                                                                <div style={{ display: "flex", gap: "8px", marginTop: "4px" }}>
                                                                    <button onClick={(e) => {
                                                                        e.stopPropagation();
                                                                        setListToDelete(null);
                                                                    }} style={{ padding: "4px 8px", borderRadius: "4px", backgroundColor: "#eee", color: "#333", border: "none", cursor: "pointer", fontSize: "0.8rem" }}>
                                                                        {profile.language === 'de' ? 'Abbrechen' : 'Cancel'}
                                                                    </button>
                                                                    <button onClick={async (e) => {
                                                                        e.stopPropagation();
                                                                        try {
                                                                            await fetch(`/api/someday-lists?id=${list.id}`, { method: "DELETE" });
                                                                            setSomedayLists((prev) => prev.filter((l) => l.id !== list.id));
                                                                            setListToDelete(null);
                                                                        } catch (err) { console.error(err); }
                                                                    }} style={{ padding: "4px 8px", borderRadius: "4px", backgroundColor: "#dc2626", color: "#fff", border: "none", cursor: "pointer", fontSize: "0.8rem" }}>
                                                                        {profile.language === 'de' ? 'Löschen' : 'Delete'}
                                                                    </button>
                                                                </div>
                                                            )}
                                                        </div>
                                                    ) : (
                                                        <>
                                                            <div
                                                                className="someday-drag-handle"
                                                                title="Drag to reorder"
                                                                onMouseDown={() => { isDragFromHandle.current = true; }}
                                                                onMouseUp={() => { isDragFromHandle.current = false; }}
                                                            >
                                                                <GripVertical size={14} />
                                                            </div>
                                                            {list.icon && (
                                                                <span
                                                                    onClick={(e) => { e.stopPropagation(); setEditingListVisualsId(list.id); }}
                                                                    title={profile.language === "de" ? "Listen-Stil bearbeiten" : "Edit list style"}
                                                                    style={{ display: "inline-flex", alignItems: "center", marginRight: "6px", cursor: "pointer", flexShrink: 0 }}
                                                                >
                                                                    <ProjectIcon icon={list.icon} size={14} color={list.color || "var(--weekly-text, #555)"} />
                                                                </span>
                                                            )}
                                                            <input
                                                                type="text"
                                                                defaultValue={list.title}
                                                                className="weekly-someday-list-title-input dark:bg-transparent dark:text-white"
                                                                onBlur={async (e) => {
                                                                    const newTitle = e.target.value.trim();
                                                                    if (newTitle && newTitle !== list.title) {
                                                                        try {
                                                                            await fetch("/api/someday-lists", {
                                                                                method: "PATCH",
                                                                                headers: {
                                                                                    "Content-Type": "application/json",
                                                                                },
                                                                                body: JSON.stringify({
                                                                                    id: list.id,
                                                                                    title: newTitle,
                                                                                }),
                                                                            });
                                                                            setSomedayLists((prev) =>
                                                                                prev.map((l) =>
                                                                                    l.id === list.id
                                                                                        ? { ...l, title: newTitle }
                                                                                        : l,
                                                                                ),
                                                                            );
                                                                        } catch (err) {
                                                                            console.error(err);
                                                                            e.target.value = list.title;
                                                                        }
                                                                    }
                                                                }}
                                                                onKeyDown={(e) => {
                                                                    if (e.key === "Enter") e.currentTarget.blur();
                                                                }}
                                                            />
                                                            {/* Flyout menu: provider icon (or pencil) triggers all list actions */}
                                                            <div style={{ marginLeft: "auto", position: "relative", flexShrink: 0 }}>
                                                                <button
                                                                    onClick={(e) => { e.stopPropagation(); setMenuOpenListId(menuOpenListId === list.id ? null : list.id); }}
                                                                    style={{ border: "none", background: "none", cursor: "pointer", padding: "4px", display: "flex", alignItems: "center", color: darkMode ? "#6b7280" : "#aaa", borderRadius: "4px" }}
                                                                    title={profile.language === "de" ? "Listenoptionen" : "List options"}
                                                                >
                                                                    {list.externalProvider === "google" ? <FontAwesomeIcon icon={faGoogle} style={{ fontSize: 13 }} /> :
                                                                     list.externalProvider === "outlook" ? <FontAwesomeIcon icon={faMicrosoft} style={{ fontSize: 13 }} /> :
                                                                     list.externalProvider === "apple" ? <FontAwesomeIcon icon={faApple} style={{ fontSize: 13 }} /> :
                                                                     list.externalProvider === "synology" ? <FontAwesomeIcon icon={faServer} style={{ fontSize: 13 }} /> :
                                                                     list.externalProvider === "notion" ? <FontAwesomeIcon icon={faNotion} style={{ fontSize: 13 }} /> :
                                                                     <Pencil size={13} />}
                                                                </button>
                                                                {menuOpenListId === list.id && (
                                                                    <>
                                                                        <div style={{ position: "fixed", inset: 0, zIndex: 199 }} onClick={(e) => { e.stopPropagation(); setMenuOpenListId(null); }} />
                                                                        <div style={{ position: "absolute", top: "calc(100% + 4px)", right: 0, zIndex: 200, background: darkMode ? "#1f2937" : "#fff", border: "1px solid var(--weekly-border)", borderRadius: "8px", boxShadow: "0 4px 16px rgba(0,0,0,0.12)", minWidth: "170px", overflow: "hidden" }}>
                                                                            {/* Provider link */}
                                                                            {list.externalProvider && (() => {
                                                                                const providerUrl = list.externalProvider === "google" ? "https://tasks.google.com/tasks/" : list.externalProvider === "outlook" ? "https://to-do.live.com/tasks/" : list.externalProvider === "apple" ? "https://www.icloud.com/reminders/" : null;
                                                                                const providerName = list.externalProvider === "outlook" ? "Microsoft" : list.externalProvider === "google" ? "Google" : list.externalProvider === "apple" ? "Apple" : list.externalProvider === "notion" ? "Notion" : list.externalProvider;
                                                                                return providerUrl ? (
                                                                                    <a href={providerUrl} target="_blank" rel="noopener noreferrer" onClick={(e) => { e.stopPropagation(); setMenuOpenListId(null); }} style={{ display: "flex", alignItems: "center", gap: "8px", padding: "8px 12px", fontSize: "0.8rem", color: darkMode ? "#e5e7eb" : "#374151", textDecoration: "none" }}>
                                                                                        {list.externalProvider === "google" ? <FontAwesomeIcon icon={faGoogle} style={{ fontSize: 13, opacity: 0.6 }} /> : list.externalProvider === "outlook" ? <FontAwesomeIcon icon={faMicrosoft} style={{ fontSize: 13, opacity: 0.6 }} /> : list.externalProvider === "apple" ? <FontAwesomeIcon icon={faApple} style={{ fontSize: 13, opacity: 0.6 }} /> : <RefreshCcw size={13} style={{ opacity: 0.6 }} />}
                                                                                        {profile.language === "de" ? `In ${providerName} öffnen` : `Open in ${providerName}`}
                                                                                    </a>
                                                                                ) : null;
                                                                            })()}
                                                                            {/* Assign to tab */}
                                                                            <div style={{ position: "relative", display: "flex", alignItems: "center", gap: "8px", padding: "8px 12px", fontSize: "0.8rem", color: darkMode ? "#e5e7eb" : "#374151", cursor: "pointer" }}>
                                                                                <FolderPlus size={13} style={{ opacity: 0.6, flexShrink: 0 }} />
                                                                                <span>{profile.language === "de" ? "Tab zuweisen" : "Assign to tab"}{list.tab ? ` (${list.tab})` : ""}</span>
                                                                                <select
                                                                                    value={list.tab || ""}
                                                                                    onClick={(e) => e.stopPropagation()}
                                                                                    onChange={(e) => {
                                                                                        const val = e.target.value;
                                                                                        if (val === "__new__") {
                                                                                            e.target.value = list.tab || "";
                                                                                            setNewTabForListId(list.id);
                                                                                            setNewTabNameValue("");
                                                                                            setMenuOpenListId(null);
                                                                                        } else {
                                                                                            assignListToTab(list.id, val || null);
                                                                                            setMenuOpenListId(null);
                                                                                        }
                                                                                    }}
                                                                                    style={{ position: "absolute", inset: 0, opacity: 0, cursor: "pointer", width: "100%" }}
                                                                                >
                                                                                    <option value="">{t.noTab}</option>
                                                                                    {somedayTabs.map(tab => <option key={tab} value={tab}>{tab}</option>)}
                                                                                    <option value="__new__">+ {t.newTab || "New tab"}</option>
                                                                                </select>
                                                                            </div>
                                                                            {/* Edit style */}
                                                                            <button onClick={(e) => { e.stopPropagation(); setEditingListVisualsRect((e.currentTarget as HTMLElement).closest(".weekly-someday-list")?.getBoundingClientRect() ?? (e.currentTarget as HTMLElement).getBoundingClientRect()); setEditingListVisualsId(list.id); setMenuOpenListId(null); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: "8px", padding: "8px 12px", fontSize: "0.8rem", color: darkMode ? "#e5e7eb" : "#374151", background: "none", border: "none", cursor: "pointer", textAlign: "left" }}>
                                                                                <Pencil size={13} style={{ opacity: 0.6, flexShrink: 0 }} />
                                                                                {profile.language === "de" ? "Stil bearbeiten" : "Edit style"}
                                                                            </button>
                                                                            <div style={{ height: "1px", background: "var(--weekly-border)", margin: "2px 0" }} />
                                                                            {/* Delete */}
                                                                            <button onClick={(e) => { e.stopPropagation(); setListToDelete(list.id); setMenuOpenListId(null); }} style={{ width: "100%", display: "flex", alignItems: "center", gap: "8px", padding: "8px 12px", fontSize: "0.8rem", color: "#ef4444", background: "none", border: "none", cursor: "pointer", textAlign: "left" }}>
                                                                                <Trash2 size={13} style={{ flexShrink: 0 }} />
                                                                                {profile.language === "de" ? "Löschen" : "Delete"}
                                                                            </button>
                                                                        </div>
                                                                    </>
                                                                )}
                                                                {newTabForListId === list.id && (
                                                                    <input
                                                                        className="someday-tab-new-input"
                                                                        value={newTabNameValue}
                                                                        onChange={(e) => setNewTabNameValue(e.target.value)}
                                                                        onBlur={() => {
                                                                            if (newTabNameValue.trim()) assignListToTab(list.id, newTabNameValue.trim());
                                                                            setNewTabForListId(null);
                                                                            setNewTabNameValue("");
                                                                        }}
                                                                        onKeyDown={(e) => {
                                                                            if (e.key === "Enter") e.currentTarget.blur();
                                                                            if (e.key === "Escape") { setNewTabForListId(null); setNewTabNameValue(""); }
                                                                        }}
                                                                        placeholder={t.newTabName || "Tab name..."}
                                                                        autoFocus
                                                                        onClick={(e) => e.stopPropagation()}
                                                                        style={{ fontSize: "0.7rem", border: "1px solid var(--weekly-border)", borderRadius: "4px", padding: "2px 6px", background: "var(--weekly-bg)", color: "var(--weekly-text)", width: "80px", outline: "none" }}
                                                                    />
                                                                )}
                                                            </div>
                                                        </>
                                                    )}
                                                </div>
                                                {/* List visuals popover (Punkt 7+8) */}
                                                {editingListVisualsId === list.id && (
                                                    <ListVisualsPopover
                                                        list={list}
                                                        darkMode={darkMode}
                                                        language={profile.language}
                                                        onChange={(updates) => updateListVisuals(list.id, updates)}
                                                        onClose={() => setEditingListVisualsId(null)}
                                                        anchorRect={editingListVisualsRect}
                                                    />
                                                )}

                                                <div
                                                    className="weekly-task-list"
                                                    style={{
                                                        flex: 1,
                                                        flexDirection: "column",
                                                        justifyContent: "flex-start",
                                                        position: "relative",
                                                        display: "flex",
                                                    }}
                                                >
                                                    {(() => {
                                                        // Separate complete from active so done tasks always render at bottom
                                                        const activeTasks = list.tasks.filter(t => !t.completed);
                                                        const doneTasks = list.tasks.filter(t => t.completed);

                                                        const slotCount = getSomedaySlotCount(activeTasks);
                                                        const indexedTasks = activeTasks.filter(t => t.somedaySlotIndex !== null && t.somedaySlotIndex !== undefined && t.somedaySlotIndex < slotCount);
                                                        const unindexedTasks = activeTasks.filter(t => t.somedaySlotIndex === null || t.somedaySlotIndex === undefined || t.somedaySlotIndex >= slotCount);

                                                        // Fill indexed slots and put unindexed tasks in empty slots starting from top
                                                        const slots = Array.from({ length: slotCount }, (_, i) => ({ index: i, task: indexedTasks.find(t => t.somedaySlotIndex === i) || null }));

                                                        let unindexedIdx = 0;
                                                        const finalSlots = slots.map(slot => {
                                                            if (!slot.task && unindexedIdx < unindexedTasks.length) {
                                                                return { ...slot, task: unindexedTasks[unindexedIdx++] };
                                                            }
                                                            return slot;
                                                        });

                                                        // Any remaining unindexed active tasks that didn't fit in slots
                                                        const remainingTasks = unindexedTasks.slice(unindexedIdx);

                                                        return (
                                                            <>
                                                                {listToDelete !== list.id && <SomedayAddTask
                                                                    listId={list.id}
                                                                    darkMode={darkMode}
                                                                    showProjectIcons={effectiveShowProjectIcons}
                                                                    showTaskCheckboxes={effectiveShowTaskCheckboxes}
                                                                    onAdd={async (title) => {
                                                                        const occupiedSlots = list.tasks.map(t => t.somedaySlotIndex).filter(s => s !== null && s !== undefined) as number[];
                                                                        let nextFreeSlot = 0;
                                                                        while (occupiedSlots.includes(nextFreeSlot)) {
                                                                            nextFreeSlot++;
                                                                        }

                                                                        try {
                                                                            const res = await fetch("/api/tasks", {
                                                                                method: "POST",
                                                                                headers: {
                                                                                    "Content-Type": "application/json",
                                                                                },
                                                                                body: JSON.stringify({
                                                                                    title,
                                                                                    somedayListId: list.id,
                                                                                    somedaySlotIndex: nextFreeSlot
                                                                                }),
                                                                            });
                                                                            if (res.ok) {
                                                                                const data = await res.json();
                                                                                const newTask = {
                                                                                    ...data.task,
                                                                                    createdAt: new Date(data.task.createdAt),
                                                                                    updatedAt: new Date(data.task.updatedAt),
                                                                                };
                                                                                setSomedayLists((prev) =>
                                                                                    prev.map((l) =>
                                                                                        l.id === list.id
                                                                                            ? { ...l, tasks: [...l.tasks, newTask] }
                                                                                            : l,
                                                                                    ),
                                                                                );
                                                                            }
                                                                        } catch (e) {
                                                                            console.error(e);
                                                                        }
                                                                    }}
                                                                />}
                                                                {finalSlots.map((slot) => {
                                                                    const isTarget = dropPreview?.listId === list.id && dropPreview?.slotIdx === slot.index;
                                                                    const task = slot.task;
                                                                    return (
                                                                        <div
                                                                            key={slot.index}
                                                                            className={`task-list-slot ${isTarget ? 'drop-target' : ''}`}
                                                                            onDragOver={(e) => handleSomedayDragOver(e, list.id, slot.index)}
                                                                            onDrop={(e) => handleSomedayDrop(e, list.id, slot.index)}
                                                                            onDragLeave={() => setDropPreview(null)}
                                                                            onMouseDown={(e) => {
                                                                                e.stopPropagation();
                                                                                if (!task) {
                                                                                    setActiveAddSlot({ listId: list.id, slotIdx: slot.index });
                                                                                }
                                                                            }}
                                                                            style={{ minHeight: "24px", cursor: task ? "default" : "text" }}
                                                                        >
                                                                            {task ? (
                                                                                <TaskItem
                                                                                    key={task.id}
                                                                                    task={task}
                                                                                    isEditing={editingTaskId === task.id}
                                                                                    onToggle={() => toggleTask(task.id)}
                                                                                    onEdit={() => setEditingTaskId(task.id)}
                                                                                    onUpdate={(title) => updateTask(task.id, title)}
                                                                                    onDelete={() => deleteTask(task.id)}
                                                                                    onNotes={(notes) => updateTaskNotes(task.id, notes)}
                                                                                    onUrl={(url) => updateTaskUrl(task.id, url)}
                                                                                    onRollToggle={() => toggleTaskRolling(task.id)}
                                                                                    onRecurrence={() => setSelectedTaskForRecurrence(task)}
                                                                                    onDragStart={(e, t) => handleDragStart(e, t)}
                                                                                    onDragEnd={handleDragEnd}
                                                                                    variant="minimal"
                                                                                    isSomeday={true}
                                                                                    onAddSubTask={addSubTask}
                                                                                    onToggleSubTask={toggleSubTask}
                                                                                    onDeleteSubTask={deleteSubTask}
                                                                                    onUpdateSubTask={updateSubTask}
                                                                                    editingTaskId={editingTaskId}
                                                                                    onSetEditingTaskId={setEditingTaskId}
                                                                                    showTaskCheckboxes={effectiveShowTaskCheckboxes}
                                                    showProjectIcons={effectiveShowProjectIcons}
                                                    showPriorityIcons={effectiveShowPriorityIcons}
                                                    priorityStyle={effectivePriorityStyle}
                                                                                    projects={projects}
                                                                                    onProjectAssign={assignProject}
                                                                                    kanbanStages={kanbanStages}
                                                                                />
                                                                            ) : (
                                                                                activeAddSlot?.listId === list.id && activeAddSlot?.slotIdx === slot.index && (
                                                                                    <SomedayAddTask
                                                                                        listId={list.id}
                                                                                        slotIdx={slot.index}
                                                                                        onAdd={async (title) => {
                                                                                            try {
                                                                                                const res = await fetch("/api/tasks", {
                                                                                                    method: "POST",
                                                                                                    headers: { "Content-Type": "application/json" },
                                                                                                    body: JSON.stringify({
                                                                                                        title,
                                                                                                        somedayListId: list.id,
                                                                                                        somedaySlotIndex: slot.index
                                                                                                    }),
                                                                                                });
                                                                                                if (res.ok) {
                                                                                                    const data = await res.json();
                                                                                                    const newTask = {
                                                                                                        ...data.task,
                                                                                                        createdAt: new Date(data.task.createdAt),
                                                                                                        updatedAt: new Date(data.task.updatedAt),
                                                                                                    };
                                                                                                    setSomedayLists((prev) =>
                                                                                                        prev.map((l) =>
                                                                                                            l.id === list.id
                                                                                                                ? { ...l, tasks: [...l.tasks, newTask] }
                                                                                                                : l,
                                                                                                        ),
                                                                                                    );
                                                                                                }
                                                                                            } catch (e) {
                                                                                                console.error(e);
                                                                                            }
                                                                                            setActiveAddSlot(null);
                                                                                        }}
                                                                                        onCancel={() => setActiveAddSlot(null)}
                                                                                    />
                                                                                )
                                                                            )}
                                                                        </div>
                                                                    );
                                                                })}
                                                                {remainingTasks.map((task) => (
                                                                    <div key={task.id} className="task-list-slot">
                                                                        <TaskItem
                                                                            key={task.id}
                                                                            task={task}
                                                                            isEditing={editingTaskId === task.id}
                                                                            onToggle={() => toggleTask(task.id)}
                                                                            onEdit={() => setEditingTaskId(task.id)}
                                                                            onUpdate={(title) => updateTask(task.id, title)}
                                                                            onDelete={() => deleteTask(task.id)}
                                                                            onNotes={(notes) => updateTaskNotes(task.id, notes)}
                                                                            onUrl={(url) => updateTaskUrl(task.id, url)}
                                                                            onRollToggle={() => toggleTaskRolling(task.id)}
                                                                            onRecurrence={() => setSelectedTaskForRecurrence(task)}
                                                                            onDragStart={(e, t) => handleDragStart(e, t)}
                                                                            onDragEnd={handleDragEnd}
                                                                            variant="minimal"
                                                                            isSomeday={true}
                                                                            onAddSubTask={addSubTask}
                                                                            onToggleSubTask={toggleSubTask}
                                                                            onDeleteSubTask={deleteSubTask}
                                                                            onUpdateSubTask={updateSubTask}
                                                                            editingTaskId={editingTaskId}
                                                                            onSetEditingTaskId={setEditingTaskId}
                                                                            showTaskCheckboxes={effectiveShowTaskCheckboxes}
                                                    showProjectIcons={effectiveShowProjectIcons}
                                                    showPriorityIcons={effectiveShowPriorityIcons}
                                                    priorityStyle={effectivePriorityStyle}
                                                                            projects={projects}
                                                                            onProjectAssign={assignProject}
                                                                            kanbanStages={kanbanStages}
                                                                        />
                                                                    </div>
                                                                ))}
                                                                {/* Completed tasks always rendered at bottom */}
                                                                {doneTasks.map((task) => (
                                                                    <div key={task.id} className="task-list-slot">
                                                                        <TaskItem
                                                                            key={task.id}
                                                                            task={task}
                                                                            isEditing={editingTaskId === task.id}
                                                                            onToggle={() => toggleTask(task.id)}
                                                                            onEdit={() => setEditingTaskId(task.id)}
                                                                            onUpdate={(title) => updateTask(task.id, title)}
                                                                            onDelete={() => deleteTask(task.id)}
                                                                            onNotes={(notes) => updateTaskNotes(task.id, notes)}
                                                                            onUrl={(url) => updateTaskUrl(task.id, url)}
                                                                            onRollToggle={() => toggleTaskRolling(task.id)}
                                                                            onRecurrence={() => setSelectedTaskForRecurrence(task)}
                                                                            onDragStart={(e, t) => handleDragStart(e, t)}
                                                                            onDragEnd={handleDragEnd}
                                                                            variant="minimal"
                                                                            isSomeday={true}
                                                                            onAddSubTask={addSubTask}
                                                                            onToggleSubTask={toggleSubTask}
                                                                            onDeleteSubTask={deleteSubTask}
                                                                            onUpdateSubTask={updateSubTask}
                                                                            editingTaskId={editingTaskId}
                                                                            onSetEditingTaskId={setEditingTaskId}
                                                                            showTaskCheckboxes={effectiveShowTaskCheckboxes}
                                                                            showProjectIcons={effectiveShowProjectIcons}
                                                                            showPriorityIcons={effectiveShowPriorityIcons}
                                                                            priorityStyle={effectivePriorityStyle}
                                                                            projects={projects}
                                                                            onProjectAssign={assignProject}
                                                                            kanbanStages={kanbanStages}
                                                                        />
                                                                    </div>
                                                                ))}
                                                            </>
                                                        );
                                                    })()}
                                                </div>
                                            </div>
                                            );
                                            return [indicator, listEl, endIndicator].filter(Boolean);
                                        })}

                                    {/* Modal for adding lists if needed, or just rely on placeholders */}
                                    {isAddingSomedayList && (
                                        <div
                                            className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 px-4"
                                            onClick={(e) => {
                                                e.stopPropagation();
                                                setIsAddingSomedayList(false);
                                                setSelectedSomedayProvider(null);
                                            }}
                                        >
                                            <div
                                                className="bg-white dark:bg-zinc-900 p-6 rounded-xl shadow-2xl w-full max-w-md"
                                                onClick={(e) => e.stopPropagation()}
                                            >
                                                <h2 className="text-xl font-black mb-1 flex items-center gap-2">
                                                    <Plus className="w-6 h-6" />
                                                    NEW LIST
                                                </h2>
                                                <p className="text-xs text-zinc-500 dark:text-zinc-400 mb-6 uppercase tracking-widest font-bold">
                                                    Create a new section for your tasks
                                                </p>

                                                <div className="mb-6">
                                                    <label className="block text-xs font-black text-zinc-400 dark:text-zinc-500 mb-2 uppercase tracking-tighter">
                                                        List Title
                                                    </label>
                                                    <input
                                                        autoFocus
                                                        type="text"
                                                        placeholder="NAME YOUR LIST..."
                                                        value={newSomedayListName}
                                                        onChange={(e) =>
                                                            setNewSomedayListName(e.target.value)
                                                        }
                                                        onKeyDown={(e) => {
                                                            if (e.key === "Enter") saveSomedayList();
                                                            if (e.key === "Escape") {
                                                                setIsAddingSomedayList(false);
                                                                setNewSomedayListName("");
                                                                setSelectedSomedayProvider(null);
                                                            }
                                                        }}
                                                        className="w-full p-4 bg-zinc-50 dark:bg-zinc-800/50 border-2 border-zinc-100 dark:border-zinc-800 rounded-xl focus:border-zinc-900 dark:focus:border-zinc-100 outline-none transition-all font-bold text-lg"
                                                        style={{
                                                            fontFamily: profile.taskFontFamily
                                                                ? `"${profile.taskFontFamily}"`
                                                                : "inherit",
                                                        }}
                                                    />
                                                </div>

                                                <div className="mb-8">
                                                    <label className="block text-xs font-black text-zinc-400 dark:text-zinc-500 mb-3 uppercase tracking-tighter">
                                                        Sync with External Provider (Optional)
                                                    </label>
                                                    <div
                                                        className="grid gap-2"
                                                        style={{ gridTemplateColumns: `repeat(${1 + (connections?.some(c => c.provider === "google") ? 1 : 0) + (connections?.some(c => c.provider === "outlook") ? 1 : 0) + (connections?.some(c => c.provider === "synology") ? 1 : 0)}, minmax(0, 1fr))` }}
                                                    >
                                                        <button
                                                            onClick={() => setSelectedSomedayProvider(null)}
                                                            className={`flex flex-col items-center justify-center p-3 rounded-xl border-2 transition-all ${!selectedSomedayProvider ? "border-zinc-900 bg-zinc-900 text-white" : "border-zinc-100 dark:border-zinc-800 hover:border-zinc-300 dark:hover:border-zinc-600"}`}
                                                        >
                                                            <div className="w-6 h-6 flex items-center justify-center mb-1">
                                                                <Layout size={18} />
                                                            </div>
                                                            <span className="text-[10px] font-black uppercase">
                                                                Local
                                                            </span>
                                                        </button>
                                                        {connections?.some(c => c.provider === "google") && (
                                                            <button
                                                                onClick={() =>
                                                                    setSelectedSomedayProvider("google")
                                                                }
                                                                className={`flex flex-col items-center justify-center p-3 rounded-xl border-2 transition-all ${selectedSomedayProvider === "google" ? "border-blue-500 bg-blue-50 dark:bg-blue-900/20" : "border-zinc-100 dark:border-zinc-800 hover:border-blue-200 dark:hover:border-blue-800/40"}`}
                                                            >
                                                                <div className="w-6 h-6 flex items-center justify-center mb-1">
                                                                    <FontAwesomeIcon icon={faGoogle} className="w-4 h-4 text-[#4285F4]" />
                                                                </div>
                                                                <span className="text-[10px] font-black uppercase">
                                                                    Google
                                                                </span>
                                                            </button>
                                                        )}
                                                        {connections?.some(c => c.provider === "outlook") && (
                                                            <button
                                                                onClick={() =>
                                                                    setSelectedSomedayProvider("outlook")
                                                                }
                                                                className={`flex flex-col items-center justify-center p-3 rounded-xl border-2 transition-all ${selectedSomedayProvider === "outlook" ? "border-blue-600 bg-blue-100 dark:bg-blue-900/30" : "border-zinc-100 dark:border-zinc-800 hover:border-blue-300 dark:hover:border-blue-800/50"}`}
                                                            >
                                                                <div className="w-6 h-6 flex items-center justify-center mb-1">
                                                                    <FontAwesomeIcon icon={faMicrosoft} className="w-4 h-4 text-[#00A4EF]" />
                                                                </div>
                                                                <span className="text-[10px] font-black uppercase">
                                                                    Outlook
                                                                </span>
                                                            </button>
                                                        )}
                                                        {connections?.some(c => c.provider === "synology") && (
                                                            <button
                                                                onClick={() =>
                                                                    setSelectedSomedayProvider("synology")
                                                                }
                                                                className={`flex flex-col items-center justify-center p-3 rounded-xl border-2 transition-all ${selectedSomedayProvider === "synology" ? "border-zinc-900 bg-zinc-50 dark:bg-zinc-800" : "border-zinc-100 dark:border-zinc-800 hover:border-zinc-300 dark:hover:border-zinc-600"}`}
                                                            >
                                                                <div className="w-6 h-6 flex items-center justify-center mb-1">
                                                                    <FontAwesomeIcon icon={faServer} className="w-4 h-4 text-zinc-500" />
                                                                </div>
                                                                <span className="text-[10px] font-black uppercase">
                                                                    Synology
                                                                </span>
                                                            </button>
                                                        )}
                                                    </div>
                                                </div>

                                                <div className="flex gap-3">
                                                    <button
                                                        onClick={() => {
                                                            setIsAddingSomedayList(false);
                                                            setNewSomedayListName("");
                                                            setSelectedSomedayProvider(null);
                                                        }}
                                                        className="flex-1 px-4 py-4 text-sm font-black text-zinc-500 hover:bg-zinc-100 dark:hover:bg-zinc-800 rounded-xl transition-all uppercase tracking-widest"
                                                    >
                                                        Cancel
                                                    </button>
                                                    <button
                                                        onClick={saveSomedayList}
                                                        disabled={!newSomedayListName.trim()}
                                                        className="flex-[2] px-4 py-4 bg-zinc-900 dark:bg-zinc-100 text-white dark:text-zinc-900 font-black rounded-xl hover:opacity-90 transition-all uppercase tracking-widest shadow-xl disabled:opacity-50 disabled:cursor-not-allowed"
                                                    >
                                                        Create List
                                                    </button>
                                                </div>
                                            </div>
                                        </div>
                                    )}
                                </div>
                            )}
                        </div>
                    </div>
                    {/* close flex row */}
                </section>
            </>
            )
            }

            {/* Search Modal */}
            <SearchModal
                isOpen={isSearchOpen}
                onClose={() => setIsSearchOpen(false)}
                tasks={tasks}
                events={calendarEvents}
                somedayLists={somedayLists}
                onSelectTask={(date) => {
                    setCurrentWeekStart(getStartOfWeek(date));
                }}
            />

            {/* Recurring Tasks Manager */}
            <RecurringTasksManager
                isOpen={isRecurringTasksOpen}
                onClose={() => setIsRecurringTasksOpen(false)}
                tasks={tasks}
                onStopRecurring={async (task) => {
                    const idToUpdate = task.id.startsWith("virtual-")
                        ? task.id.split("-")[1]
                        : task.id;
                    const dateStr = new Date().toISOString();

                    // Update locally
                    setTasks((prev) => {
                        const newTasks = [];
                        for (const t of prev) {
                            const isMatch =
                                t.title === task.title &&
                                t.userId === task.userId &&
                                t.recurrenceInterval === task.recurrenceInterval &&
                                t.recurrenceUnit === task.recurrenceUnit;

                            if (isMatch) {
                                // Remove future occurrences from the UI
                                if (t.scheduledDate && new Date(t.scheduledDate) > new Date(dateStr)) {
                                    continue;
                                }
                                newTasks.push({ ...t, recurrenceEndDate: new Date(dateStr) });
                            } else {
                                newTasks.push(t);
                            }
                        }
                        return newTasks;
                    });

                    // Update DB
                    try {
                        await fetch("/api/tasks", {
                            method: "PATCH",
                            headers: { "Content-Type": "application/json" },
                            body: JSON.stringify({
                                id: idToUpdate,
                                recurrenceEndDate: dateStr,
                            }),
                        });
                        fetchTasks();
                    } catch (error) {
                        console.error("Failed to stop recurring series:", error);
                    }
                }}
                onSeriesUpdated={() => fetchTasks()}
            />

            {/* Recurring Task Delete Confirmation Modal */}
            {
                recurringDeleteModal.isOpen && (
                    <div
                        className="fixed inset-0 bg-black/50 flex items-center justify-center z-[100] px-4"
                        onClick={() =>
                            setRecurringDeleteModal({ isOpen: false, taskId: null })
                        }
                    >
                        <div
                            className="bg-white dark:bg-zinc-900 p-8 rounded-2xl shadow-2xl w-full max-w-md border border-zinc-100 dark:border-zinc-800"
                            onClick={(e) => e.stopPropagation()}
                        >
                            <div className="flex items-center gap-3 mb-6">
                                <div className="w-12 h-12 bg-red-100 dark:bg-red-900/30 rounded-full flex items-center justify-center text-red-600 dark:text-red-400">
                                    <Repeat size={24} />
                                </div>
                                <div>
                                    <h2 className="text-xl font-black uppercase tracking-tight">
                                        Recurring Task
                                    </h2>
                                    <p className="text-xs text-zinc-500 dark:text-zinc-400 font-bold uppercase tracking-widest">
                                        Deletion Options
                                    </p>
                                </div>
                            </div>

                            <div className="space-y-4 mb-8">
                                <div className="p-4 bg-zinc-50 dark:bg-zinc-800/50 rounded-xl border border-zinc-100 dark:border-zinc-800">
                                    <p className="text-sm font-medium text-zinc-600 dark:text-zinc-300 leading-relaxed">
                                        How would you like to delete this task?
                                    </p>
                                </div>
                            </div>

                            <div className="grid gap-3">
                                <button
                                    onClick={() =>
                                        recurringDeleteModal.taskId &&
                                        handleConfirmDeleteSeries(recurringDeleteModal.taskId)
                                    }
                                    className="group flex items-center gap-4 p-4 bg-red-600 hover:bg-red-700 text-white rounded-xl transition-all shadow-lg hover:shadow-red-500/20 text-left"
                                >
                                    <div className="w-10 h-10 bg-white/20 rounded-lg flex items-center justify-center group-hover:scale-110 transition-transform">
                                        <Repeat size={20} />
                                    </div>
                                    <div>
                                        <span className="block font-black uppercase text-xs tracking-widest">
                                            Entire Series
                                        </span>
                                        <span className="text-[10px] opacity-80 font-bold">
                                            Stop recurrence & remove all future
                                        </span>
                                    </div>
                                </button>

                                <button
                                    onClick={() =>
                                        recurringDeleteModal.taskId &&
                                        handleConfirmDeleteOccurrence(recurringDeleteModal.taskId)
                                    }
                                    className="group flex items-center gap-4 p-4 bg-zinc-100 dark:bg-zinc-800 hover:bg-zinc-200 dark:hover:bg-zinc-700 text-zinc-900 dark:text-zinc-100 rounded-xl transition-all text-left"
                                >
                                    <div className="w-10 h-10 bg-zinc-200 dark:bg-zinc-700 rounded-lg flex items-center justify-center group-hover:scale-110 transition-transform">
                                        <Calendar size={20} />
                                    </div>
                                    <div>
                                        <span className="block font-black uppercase text-xs tracking-widest">
                                            Only This One
                                        </span>
                                        <span className="text-[10px] text-zinc-500 dark:text-zinc-400 font-bold">
                                            Only remove the selected instance
                                        </span>
                                    </div>
                                </button>

                                <button
                                    onClick={() =>
                                        setRecurringDeleteModal({ isOpen: false, taskId: null })
                                    }
                                    className="w-full mt-2 p-3 text-xs font-black text-zinc-400 dark:text-zinc-500 hover:text-zinc-900 dark:hover:text-zinc-100 uppercase tracking-widest transition-colors"
                                >
                                    Cancel
                                </button>
                            </div>
                        </div>
                    </div>
                )
            }

            {/* Calendar Event Modal */}
            {
                calendarEventModal.isOpen && (
                    <CalendarEventModal
                        event={calendarEventModal.event}
                        initialDate={calendarEventModal.initialDate}
                        initialStartTime={calendarEventModal.initialStartTime}
                        initialEndTime={calendarEventModal.initialEndTime}
                        connections={connections}
                        weekStartDay={profile.weekStartDay ?? 1}
                        language={profile.language}
                        onClose={() =>
                            setCalendarEventModal({ ...calendarEventModal, isOpen: false })
                        }
                        onSave={handleEventSave}
                        onDelete={handleEventDelete}
                    />
                )
            }
            {/* Recurring event drag/resize confirmation */}
            {pendingRecurringDrag && (
                <div style={{
                    position: 'fixed', inset: 0, zIndex: 2000,
                    display: 'flex', justifyContent: 'center', alignItems: 'center',
                    background: 'rgba(0,0,0,0.35)', backdropFilter: 'blur(2px)',
                }} onClick={handleRecurringDragCancel}>
                    <div style={{
                        background: darkMode ? '#1e1e1e' : 'white',
                        color: darkMode ? '#eee' : '#333',
                        borderRadius: 12, width: '90%', maxWidth: 420,
                        boxShadow: '0 12px 40px rgba(0,0,0,0.25)',
                        overflow: 'hidden',
                    }} onClick={e => e.stopPropagation()}>
                        <div style={{
                            padding: '16px 20px 12px', fontWeight: 700, fontSize: '0.95rem',
                            borderBottom: '2px solid #3b82f6',
                        }}>
                            {profile.language === 'de' ? 'Wiederkehrendes Ereignis bearbeiten' : 'Edit recurring event'}
                        </div>
                        <div style={{ padding: '12px 20px' }}>
                            {([
                                { value: 'this' as const, title: profile.language === 'de' ? 'Nur dieses Ereignis' : 'This event', desc: profile.language === 'de' ? 'Alle anderen Ereignisse der Serie bleiben unverändert.' : 'All other events in the series stay the same.' },
                                { value: 'future' as const, title: profile.language === 'de' ? 'Dieses und folgende Ereignisse' : 'This and following events', desc: profile.language === 'de' ? 'Dieses und alle zukünftigen Ereignisse der Serie werden geändert.' : 'This and all future events in the series will be changed.' },
                                { value: 'all' as const, title: profile.language === 'de' ? 'Alle Ereignisse' : 'All events', desc: profile.language === 'de' ? 'Alle Ereignisse der Serie werden geändert.' : 'All events in the series will be changed.' },
                            ]).map(opt => (
                                <label key={opt.value} style={{
                                    display: 'flex', gap: 12, padding: '10px 4px', cursor: 'pointer',
                                    borderBottom: `1px solid ${darkMode ? '#333' : '#eee'}`,
                                    alignItems: 'flex-start',
                                }} onClick={() => setRecurringDragEditMode(opt.value)}>
                                    <input
                                        type="radio" name="recurringDragEditMode"
                                        checked={recurringDragEditMode === opt.value}
                                        onChange={() => setRecurringDragEditMode(opt.value)}
                                        style={{ marginTop: 3, accentColor: '#3b82f6' }}
                                    />
                                    <div>
                                        <div style={{ fontWeight: 600, fontSize: '0.88rem' }}>{opt.title}</div>
                                        <div style={{ fontSize: '0.78rem', opacity: 0.6, marginTop: 2 }}>{opt.desc}</div>
                                    </div>
                                </label>
                            ))}
                        </div>
                        <div style={{
                            padding: '12px 20px', display: 'flex', justifyContent: 'flex-end', gap: 8,
                        }}>
                            <button onClick={handleRecurringDragCancel} style={{
                                padding: '8px 16px', fontSize: '0.85rem', fontWeight: 600,
                                background: 'none', border: 'none', cursor: 'pointer',
                                color: darkMode ? '#aaa' : '#666',
                            }}>{profile.language === 'de' ? 'Abbrechen' : 'Cancel'}</button>
                            <button onClick={() => handleRecurringDragConfirm(recurringDragEditMode)} style={{
                                padding: '8px 20px', fontSize: '0.85rem', fontWeight: 600,
                                background: '#3b82f6', color: 'white', border: 'none',
                                borderRadius: 8, cursor: 'pointer',
                            }}>{profile.language === 'de' ? 'Speichern' : 'Save'}</button>
                        </div>
                    </div>
                </div>
            )}
            {/* Focus Mode Overlay */}
            {
                showFocusMode && (
                    <FocusModeOverlay
                        task={(() => {
                            // Logic to find the "Next Task"
                            // 1. Tasks for today with start time, sorted by time
                            // 2. Tasks for today without start time, sorted by order
                            // 3. Tasks rolling over from previous days

                            const now = new Date();
                            const todayStr = now.toISOString().split("T")[0];

                            // Get all tasks relevant for "Now"
                            const activeTasks = tasks.filter(
                                (t) =>
                                    !t.completed &&
                                    !t.somedayListId &&
                                    // Scheduled for today
                                    ((t.scheduledDate &&
                                        new Date(t.scheduledDate).toISOString().split("T")[0] ===
                                        todayStr) ||
                                        // Or rolling and overdue (simplified, assuming rolling means show on today if not done)
                                        (t.isRolling &&
                                            (!t.scheduledDate || new Date(t.scheduledDate) <= now)) ||
                                        // Or implicitly today if within current view logic (e.g. dayOfWeek match in current week)
                                        // But let's stick to explicit date or rolling for Focus Mode to be precise.
                                        (!t.scheduledDate &&
                                            t.dayOfWeek === now.getDay() &&
                                            isSameDay(
                                                currentWeekStart,
                                                getStartOfWeek(now, profile.weekStartDay ?? 1),
                                            ))),
                            );

                            // Sort: Time-based first, then Order
                            activeTasks.sort((a, b) => {
                                if (a.startTime && b.startTime)
                                    return a.startTime.localeCompare(b.startTime);
                                if (a.startTime) return -1;
                                if (b.startTime) return 1;
                                return a.order - b.order;
                            });

                            return activeTasks.length > 0 ? activeTasks[0] : null;
                        })()}
                        duration={focusTimerDuration}
                        onClose={() => setShowFocusMode(false)}
                        onComplete={(taskId) => toggleTask(taskId)}
                    />
                )
            }

            {/* Settings Sidebar */}
            {
                showSettings && (
                    <SettingsSidebar
                        initialTab={activeTab}
                        onRemoveConnection={handleRemoveConnection}
                        onClose={() => {
                            setShowSettings(false);
                            if (profile.hasCompletedOnboarding === false && localStorage.getItem("onboarding_step")) {
                                setShowOnboarding(true);
                            }
                        }}
                        onSettingsChanged={handleSettingsChanged}
                        showTimeGrid={profile.showTimeGrid ?? true}
                        setShowTimeGrid={setShowTimeGrid}
                        cellDuration={profile.cellDuration ?? 30}
                        setCellDuration={setCellDuration}
                        weekStartDay={profile.weekStartDay ?? 1}
                        setWeekStartDay={setWeekStartDay}
                        viewStyle={profile.viewStyle ?? "simple"}
                        setViewStyle={setViewStyle}
                        showSomeday={profile.showSomeday ?? true}
                        setShowSomeday={setShowSomeday}
                        showAllDay={profile.showAllDayEvents ?? true}
                        setShowAllDay={setShowAllDay}
                        showSchedule={profile.showSchedule ?? true}
                        setShowSchedule={setShowSchedule}
                        goal={goal}
                        setGoal={setGoal}
                        saveGoal={saveGoal}
                        connections={connections}
                        onUpdateConnections={setConnections}
                        focusTimerDuration={focusTimerDuration}
                        setFocusTimerDuration={setFocusTimerDuration}
                        focusBreakDuration={focusBreakDuration}
                        setFocusBreakDuration={setFocusBreakDuration}
                        fontSize={profile.fontSize ?? "M"}
                        setFontSize={setFontSize}
                        showNextTask={profile.showNextTask ?? false}
                        setShowNextTask={setShowNextTask}
                        headlineFont={profile.headlineFont ?? "Inter"}
                        headlineFontSize={profile.headlineFontSize ?? "1.25rem"}
                        headlineFontWeight={profile.headlineFontWeight ?? "900"}
                        dateFontFamily={profile.dateFontFamily ?? "Inter"}
                        dateFontSize={profile.dateFontSize ?? "0.65rem"}
                        dateFontWeight={profile.dateFontWeight ?? "400"}
                        timeTaskFontFamily={profile.timeTaskFontFamily ?? "Inter"}
                        timeTaskFontSize={profile.timeTaskFontSize ?? "0.75rem"}
                        timeTaskFontWeight={profile.timeTaskFontWeight ?? "500"}
                        bodyFont={profile.bodyFont ?? "Inter"}
                        taskFontFamily={profile.taskFontFamily ?? "Inter"}
                        taskFontSize={profile.taskFontSize ?? "0.9rem"}
                        taskFontWeight={profile.taskFontWeight ?? "400"}
                        fontWeight={profile.fontWeight ?? "400"}
                        weekendColorSat={profile.weekendColorSat ?? "#666666"}
                        weekendColorSun={profile.weekendColorSun ?? "#dc2626"}
                        protectEventTimes={protectEventTimes}
                        setProtectEventTimes={setProtectEventTimes}
                        goalFontWeight={profile.goalFontWeight || "500"}
                        goalFallbackType={profile.goalFallbackType}
                        goalDefaultSentence={profile.goalDefaultSentence}
                        importingTasksState={importingTasksState}
                        executeImport={executeImport}
                        onImportLists={(lists) => doImport("apple", lists)}
                        importStatusMsg={importStatusMsg}
                        hourLabelFormat={profile.hourLabelFormat ?? "short"}
                        setHourLabelFormat={setHourLabelFormat}
                        showSubHourSlots={profile.showSubHourSlots ?? true}
                        setShowSubHourSlots={setShowSubHourSlots}
                        allDayPosition={profile.allDayPosition ?? "above"}
                        setAllDayPosition={setAllDayPosition}
                        saveSetting={saveSetting}
                        availableTaskLists={availableTaskLists}
                        isFetchingProviderLists={isFetchingProviderLists}
                        somedayLists={somedayLists}
                        handleToggleTaskList={handleToggleTaskList}
                        unsyncConfirm={unsyncConfirm}
                        onConfirmUnsync={confirmUnsync}
                        onCancelUnsync={() => setUnsyncConfirm(null)}
                        handleSyncAll={handleSyncAll}
                        fetchAvailableTaskLists={fetchAvailableTaskLists}
                        setCurrentWeekStart={setCurrentWeekStart}
                        projects={projects}
                        onProjectsChanged={fetchProjects}
                        kanbanStages={kanbanStages}
                        saveKanbanStages={saveKanbanStages}
                        profile={profile}
                        setProfile={setProfile}
                        isMobile={isMobile}
                        mobileActions={{
                            goToPrevWeek,
                            goToPrevDay,
                            goToToday,
                            goToNextDay,
                            goToNextWeek,
                            onJumpToDate: () => setShowDatePicker(true),
                            onAddCalendarEvent: () => {
                                const now = new Date();
                                setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` });
                            },
                            onAddProject: () => { setShowProjectsSidebar(true); },
                            onRecurringTasks: () => setIsRecurringTasksOpen(true),
                            onToggleNextTask: () => { const newVal = !profile.showNextTask; setShowNextTask(newVal); saveSetting("showNextTask", newVal); },
                            onFocusMode: () => setShowFocusMode(true),
                            onToggleDarkMode: () => setDarkMode(!darkMode),
                            onSearch: () => setIsSearchOpen(true),
                            onUndo: handleUndo,
                            onRedo: handleRedo,
                            onRefresh: () => { fetchCalendarEvents(true); fetchTasks(); },
                            darkMode,
                            showNextTask: profile.showNextTask ?? false,
                            undoCount,
                            redoCount,
                            viewDays,
                            onViewDaysChange: (num: number) => { setViewDays(num); savedViewDaysRef.current = num; saveSetting("viewDays", num); },
                            showTimeGrid: profile.showTimeGrid ?? true,
                            cellDuration: profile.cellDuration ?? 30,
                            onCellDurationChange: (d: CellDuration) => { setCellDuration(d); saveSetting("cellDuration", d); },
                            viewStyle: profile.viewStyle ?? "simple",
                            onViewStyleChange: (s: string) => { setViewStyle(s as any); saveSetting("viewStyle", s); },
                            startHour: profile.startHour ?? 8,
                            endHour: profile.endHour ?? 18,
                            onStartHourChange: (h: number) => { setStartHour(h); saveSetting("startHour", h); },
                            onEndHourChange: (h: number) => { setEndHour(h); saveSetting("endHour", h); },
                        }}
                        perView={{
                            saveViewSetting: saveViewSetting as any,
                            getEffective: getEffective as any,
                        }}
                        onRunSetupAssistant={() => setShowOnboarding(true)}
                    />
                )
            }

            {
                selectedTaskForRecurrence && (
                    <TaskRecurrenceModal
                        task={selectedTaskForRecurrence}
                        onClose={() => setSelectedTaskForRecurrence(null)}
                        onSave={handleRecurrenceSave}
                        language={profile.language}
                    />
                )
            }

            {/* Onboarding Wizard */}
            {showOnboarding && (
                <OnboardingWizard
                    profile={profile}
                    darkMode={darkMode}
                    language={profile.language}
                    connections={connections}
                    onComplete={async () => { await saveSetting("hasCompletedOnboarding", true); setShowOnboarding(false); await fetchProfile(); }}
                    onSkip={async () => { await saveSetting("hasCompletedOnboarding", true); setShowOnboarding(false); await fetchProfile(); }}
                    saveSetting={saveSetting}
                    onLanguageChange={(lang: string) => { setLanguage(lang); }}
                    onDarkModeToggle={() => setDarkMode(!darkMode)}
                    onConnectProvider={(provider: string) => {
                        setShowOnboarding(false);
                        setActiveTab("calendar");
                        setShowSettings(true);
                    }}
                />
            )}

            {
                selectedTaskForNotes && (
                    <NotesSidebar
                        task={selectedTaskForNotes}
                        onClose={() => setSelectedTaskForNotes(null)}
                        updateTaskNotes={updateTaskNotes}
                        updateTaskUrl={updateTaskUrl}
                    />
                )
            }

            {/* Kanban Detail Modal */}
            {kanbanDetailTask && (() => {
                const task = kanbanDetailTask;
                // Re-resolve the task from state to get latest data
                const liveTask = findTaskAnywhere(task.id) || task;
                return (
                    <div className="kanban-detail-overlay" onClick={() => setKanbanDetailTask(null)}>
                        <div className="kanban-detail-modal" onClick={(e) => e.stopPropagation()}>
                            {/* Header */}
                            <div className="kanban-detail-header">
                                <div style={{ display: "flex", alignItems: "center", gap: "8px", flex: 1 }}>
                                    <input
                                        type="checkbox"
                                        checked={liveTask.completed}
                                        onChange={() => { toggleTask(liveTask.id); setKanbanDetailTask({ ...liveTask, completed: !liveTask.completed }); }}
                                        style={{ width: "18px", height: "18px", cursor: "pointer", accentColor: "var(--weekly-accent, #6366f1)" }}
                                    />
                                    <input
                                        type="text"
                                        defaultValue={liveTask.title}
                                        onBlur={(e) => {
                                            const val = e.target.value.trim();
                                            if (val && val !== liveTask.title) {
                                                updateTask(liveTask.id, val);
                                                setKanbanDetailTask({ ...liveTask, title: val });
                                            }
                                        }}
                                        onKeyDown={(e) => { if (e.key === "Enter") (e.target as HTMLInputElement).blur(); }}
                                        className="kanban-detail-title-input"
                                    />
                                </div>
                                <button onClick={() => setKanbanDetailTask(null)} className="kanban-detail-close">
                                    <X size={18} />
                                </button>
                            </div>

                            <div className="kanban-detail-body">
                                {/* Meta row: project, stage, date */}
                                <div className="kanban-detail-meta">
                                    {/* Project picker */}
                                    <div className="kanban-detail-field">
                                        <label><Tag size={13} /> {t.project || "Project"}</label>
                                        <select
                                            value={liveTask.projectId || ""}
                                            onChange={(e) => {
                                                const pid = e.target.value || null;
                                                assignProject(liveTask.id, pid);
                                                const proj = pid ? projects.find(p => p.id === pid) || null : null;
                                                setKanbanDetailTask({ ...liveTask, projectId: pid, project: proj });
                                            }}
                                            className="kanban-detail-select"
                                        >
                                            <option value="">{t.noProject || "No project"}</option>
                                            {projects.map(p => (
                                                <option key={p.id} value={p.id}>{p.name}</option>
                                            ))}
                                        </select>
                                    </div>

                                    {/* Kanban stage picker */}
                                    <div className="kanban-detail-field">
                                        <label><Kanban size={13} /> {t.stage || "Stage"}</label>
                                        <select
                                            value={liveTask.kanbanStage || ""}
                                            onChange={(e) => {
                                                const stage = e.target.value || null;
                                                updateTaskFields(liveTask.id, { kanbanStage: stage });
                                                setKanbanDetailTask({ ...liveTask, kanbanStage: stage });
                                            }}
                                            className="kanban-detail-select"
                                        >
                                            <option value="">{t.noStage || "No stage"}</option>
                                            {kanbanStages.map(s => (
                                                <option key={s.id} value={s.id}>{s.name}</option>
                                            ))}
                                        </select>
                                    </div>

                                    {/* Due date */}
                                    <div className="kanban-detail-field">
                                        <label><CalendarDays size={13} /> {t.dueDate || "Due date"}</label>
                                        <input
                                            type="date"
                                            value={liveTask.scheduledDate ? new Date(liveTask.scheduledDate).toISOString().split("T")[0] : ""}
                                            onChange={(e) => {
                                                const val = e.target.value || null;
                                                updateTaskFields(liveTask.id, { scheduledDate: val });
                                                setKanbanDetailTask({ ...liveTask, scheduledDate: val });
                                            }}
                                            className="kanban-detail-date"
                                        />
                                    </div>

                                    {/* Someday list */}
                                    <div className="kanban-detail-field">
                                        <label><ListTodo size={13} /> {t.list || "List"}</label>
                                        <select
                                            value={liveTask.somedayListId || ""}
                                            onChange={(e) => {
                                                const lid = e.target.value || null;
                                                updateTaskFields(liveTask.id, { somedayListId: lid });
                                                setKanbanDetailTask({ ...liveTask, somedayListId: lid });
                                                fetchTasks();
                                            }}
                                            className="kanban-detail-select"
                                        >
                                            <option value="">—</option>
                                            {somedayLists.map(sl => (
                                                <option key={sl.id} value={sl.id}>{sl.title}</option>
                                            ))}
                                        </select>
                                    </div>
                                </div>

                                {/* URL */}
                                <div className="kanban-detail-section">
                                    <label><svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ display: "inline" }}><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg> {t.link || "Link"}</label>
                                    <div style={{ display: "flex", alignItems: "center", gap: "6px" }}>
                                        <input
                                            type="url"
                                            defaultValue={liveTask.url || ""}
                                            onBlur={(e) => {
                                                const raw = e.target.value.trim();
                                                const normalised = raw ? (raw.startsWith("http") ? raw : `https://${raw}`) : "";
                                                if (normalised !== (liveTask.url || "")) {
                                                    updateTaskUrl(liveTask.id, normalised);
                                                    setKanbanDetailTask({ ...liveTask, url: normalised || null });
                                                }
                                            }}
                                            onKeyDown={(e) => { if (e.key === "Enter") (e.target as HTMLInputElement).blur(); }}
                                            placeholder="https://..."
                                            className="kanban-detail-url"
                                            style={{ flex: 1 }}
                                        />
                                        {liveTask.url && (
                                            <a href={liveTask.url} target="_blank" rel="noopener noreferrer" title="Open link" style={{ color: "#2563eb", display: "inline-flex", flexShrink: 0 }}>
                                                <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
                                                    <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
                                                    <polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/>
                                                </svg>
                                            </a>
                                        )}
                                    </div>
                                </div>

                                {/* Notes */}
                                <div className="kanban-detail-section">
                                    <label><FileText size={13} /> {t.notes || "Notes"}</label>
                                    <RichTextEditor
                                        value={liveTask.markdownContent || ""}
                                        onChange={(html) => updateTaskNotes(liveTask.id, html)}
                                        placeholder={profile.language === "de" ? "Notizen hinzufügen..." : "Add notes..."}
                                        minHeight="120px"
                                    />
                                </div>

                                {/* Subtasks */}
                                <div className="kanban-detail-section">
                                    <label><Check size={13} /> {t.subtasks || "Subtasks"}</label>
                                    <div className="kanban-detail-subtasks">
                                        {(liveTask.subTasks || []).map(sub => (
                                            <div key={sub.id} className="kanban-detail-subtask">
                                                <input
                                                    type="checkbox"
                                                    checked={sub.completed}
                                                    onChange={() => toggleSubTask(sub.id)}
                                                    style={{ accentColor: "var(--weekly-accent, #6366f1)" }}
                                                />
                                                <input
                                                    type="text"
                                                    defaultValue={sub.title}
                                                    onBlur={(e) => {
                                                        const val = e.target.value.trim();
                                                        if (!val) deleteSubTask(sub.id);
                                                        else if (val !== sub.title) updateSubTask(sub.id, val);
                                                    }}
                                                    onKeyDown={(e) => { if (e.key === "Enter") (e.target as HTMLInputElement).blur(); }}
                                                    className={`kanban-detail-subtask-title ${sub.completed ? "completed" : ""}`}
                                                />
                                                <button onClick={() => deleteSubTask(sub.id)} className="kanban-detail-subtask-delete">
                                                    <X size={12} />
                                                </button>
                                            </div>
                                        ))}
                                        <form
                                            onSubmit={(e) => {
                                                e.preventDefault();
                                                const input = (e.target as HTMLFormElement).elements.namedItem("newSub") as HTMLInputElement;
                                                const val = input.value.trim();
                                                if (val) {
                                                    addSubTask(liveTask.id, val);
                                                    input.value = "";
                                                    // Refresh modal task after adding
                                                    setTimeout(() => {
                                                        const refreshed = findTaskAnywhere(liveTask.id);
                                                        if (refreshed) setKanbanDetailTask(refreshed);
                                                    }, 300);
                                                }
                                            }}
                                            className="kanban-detail-subtask-add"
                                        >
                                            <Plus size={14} />
                                            <input
                                                name="newSub"
                                                type="text"
                                                placeholder={profile.language === "de" ? "Unteraufgabe hinzufügen..." : "Add subtask..."}
                                                className="kanban-detail-subtask-input"
                                            />
                                        </form>
                                    </div>
                                </div>
                            </div>

                            {/* Footer */}
                            <div className="kanban-detail-footer">
                                <button
                                    onClick={() => { deleteTask(liveTask.id); setKanbanDetailTask(null); }}
                                    className="kanban-detail-delete"
                                    title={profile.language === "de" ? "Löschen" : "Delete"}
                                >
                                    <Trash2 size={16} />
                                </button>
                                <div className="kanban-detail-footer-right">
                                    <button
                                        onClick={() => setKanbanDetailTask(null)}
                                        className="kanban-detail-btn kanban-detail-btn-cancel"
                                    >
                                        {profile.language === "de" ? "Abbrechen" : "Cancel"}
                                    </button>
                                    <button
                                        onClick={() => setKanbanDetailTask(null)}
                                        className="kanban-detail-btn kanban-detail-btn-ok"
                                    >
                                        OK
                                    </button>
                                </div>
                            </div>
                        </div>
                    </div>
                );
            })()}

            <ImportListModal
                isOpen={isImportModalOpen}
                onClose={() => setIsImportModalOpen(false)}
                onImport={handleConfirmImport}
                provider={importProvider}
                lists={importLists}
                isLoading={isFetchingLists}
            />

            {/* Week Print / PDF Export Modal */}
            <WeekPrintModal
                isOpen={showWeekPrintModal}
                onClose={() => setShowWeekPrintModal(false)}
                currentWeekStart={currentWeekStart}
                viewDays={viewDays}
                startHour={startHour}
                endHour={endHour}
                language={profile.language || "de"}
                weatherEnabled={!!(profile.weatherLat && profile.weatherLon)}
            />

            {/* Mobile: Floating Action Button with quick menu */}
            {isMobile && !showMobileFabSheet && !showSettings && !showFocusMode && (
                <>
                    {showMobileFabMenu && (
                        <div className="mobile-fab-backdrop" onClick={() => setShowMobileFabMenu(false)} />
                    )}
                    {showMobileFabMenu && (
                        <div className="mobile-fab-menu">
                            <button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setIsSearchOpen(true); }}>
                                <div className="mobile-fab-menu-icon" style={{ background: "#10b981" }}><Search size={18} /></div>
                                <span>{profile.language === "de" ? "Suchen" : "Search"}</span>
                            </button>
                            <button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setShowFocusMode(true); }}>
                                <div className="mobile-fab-menu-icon" style={{ background: "#f59e0b" }}><Zap size={18} /></div>
                                <span>{profile.language === "de" ? "Fokus" : "Focus"}</span>
                            </button>
                            <button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setShowProjectsSidebar(true); }}>
                                <div className="mobile-fab-menu-icon" style={{ background: "#6366f1" }}><FolderPlus size={18} /></div>
                                <span>{profile.language === "de" ? "Projekt" : "Project"}</span>
                            </button>
                            <button className="mobile-fab-menu-item" onClick={() => {
                                setShowMobileFabMenu(false);
                                const now = new Date();
                                setCalendarEventModal({ isOpen: true, event: undefined, initialDate: now, initialStartTime: `${String(now.getHours()).padStart(2, "0")}:00` });
                            }}>
                                <div className="mobile-fab-menu-icon" style={{ background: "#8b5cf6" }}><Calendar size={18} /></div>
                                <span>{profile.language === "de" ? "Termin" : "Event"}</span>
                            </button>
                            <button className="mobile-fab-menu-item" onClick={() => { setShowMobileFabMenu(false); setShowMobileFabSheet(true); }}>
                                <div className="mobile-fab-menu-icon" style={{ background: "#0ea5e9" }}><Plus size={18} /></div>
                                <span>{profile.language === "de" ? "Aufgabe" : "Task"}</span>
                            </button>
                        </div>
                    )}
                    <button
                        className={`mobile-fab ${showMobileFabMenu ? "active" : ""}`}
                        onClick={() => setShowMobileFabMenu(!showMobileFabMenu)}
                    >
                        <Plus size={28} style={{ transform: showMobileFabMenu ? "rotate(45deg)" : "rotate(0deg)", transition: "transform 0.2s ease" }} />
                    </button>
                </>
            )}

            {/* Mobile: Bottom Sheet for task creation */}
            {isMobile && showMobileFabSheet && (
                <>
                    <div className="bottom-sheet-backdrop" onClick={() => { setShowMobileFabSheet(false); setFabTaskTitle(""); }} />
                    <div className="bottom-sheet">
                        <div className="bottom-sheet-handle" />
                        <textarea
                            ref={fabTextareaRef}
                            value={fabTaskTitle}
                            onChange={(e) => setFabTaskTitle(e.target.value)}
                            onKeyDown={(e) => {
                                if (e.key === "Enter" && !e.shiftKey) {
                                    e.preventDefault();
                                    if (fabTaskTitle.trim()) {
                                        // Find today's date and add task
                                        const today = new Date();
                                        const todayStr = formatDateToISO(today);
                                        addTask(today, fabTaskTitle.trim());
                                        setFabTaskTitle("");
                                        setShowMobileFabSheet(false);
                                    }
                                }
                            }}
                            placeholder="What do you need to do?"
                            rows={2}
                            style={{
                                width: "100%",
                                border: `1px solid ${darkMode ? "#374151" : "#e5e7eb"}`,
                                borderRadius: "12px",
                                padding: "12px 16px",
                                fontSize: "1rem",
                                background: darkMode ? "#111827" : "#f9fafb",
                                color: darkMode ? "#e5e7eb" : "#333",
                                outline: "none",
                                resize: "none",
                                fontFamily: "inherit",
                            }}
                        />
                        <div style={{ display: "flex", justifyContent: "flex-end", marginTop: "12px", gap: "8px" }}>
                            <button
                                onClick={() => { setShowMobileFabSheet(false); setFabTaskTitle(""); }}
                                style={{ padding: "8px 16px", borderRadius: "8px", border: "none", background: darkMode ? "#374151" : "#e5e7eb", color: darkMode ? "#e5e7eb" : "#333", fontSize: "0.85rem", cursor: "pointer" }}
                            >
                                Cancel
                            </button>
                            <button
                                onClick={() => {
                                    if (fabTaskTitle.trim()) {
                                        const today = new Date();
                                        addTask(today, fabTaskTitle.trim());
                                        setFabTaskTitle("");
                                        setShowMobileFabSheet(false);
                                    }
                                }}
                                style={{ padding: "8px 16px", borderRadius: "8px", border: "none", background: "#0ea5e9", color: "white", fontSize: "0.85rem", fontWeight: 600, cursor: "pointer" }}
                            >
                                Add Task
                            </button>
                        </div>
                    </div>
                </>
            )}

            {/* Mobile: Date Picker as centered modal overlay */}
            {isMobile && showDatePicker && (
                <div className="mobile-date-picker-overlay" onClick={() => setShowDatePicker(false)}>
                    <div onClick={(e) => e.stopPropagation()}>
                        <SimpleDatePicker
                            selected={currentWeekStart}
                            onSelect={(date) => {
                                setCurrentWeekStart(getStartOfWeek(date));
                                setShowDatePicker(false);
                            }}
                            onClose={() => setShowDatePicker(false)}
                            language={profile.language}
                        />
                    </div>
                </div>
            )}
        </div >
    );
}

// Task Input Component
interface TaskInputProps {
    onAddTask: (title: string) => void;
    onDragOver: (e: React.DragEvent) => void;
    onDrop: (e: React.DragEvent) => void;
}

function TaskInput({ onAddTask, onDragOver, onDrop }: TaskInputProps) {
    const [newTaskTitle, setNewTaskTitle] = useState("");

    const handleAddTask = () => {
        if (newTaskTitle.trim()) {
            onAddTask(newTaskTitle);
            setNewTaskTitle("");
        }
    };

    return (
        <div
            className="weekly-task-input"
            onDragOver={onDragOver}
            onDrop={onDrop}
        >
            <textarea
                value={newTaskTitle}
                onChange={(e) => setNewTaskTitle(e.target.value)}
                onKeyDown={(e) => {
                    if (e.key === "Enter" && !e.shiftKey) {
                        e.preventDefault();
                        handleAddTask();
                    }
                }}
                placeholder="Type a to-do..."
                rows={newTaskTitle.split("\n").length || 1}
                style={{
                    resize: "none",
                    overflow: "hidden",
                    fontFamily: "inherit",
                    lineHeight: "inherit",
                    width: "100%",
                    border: "none",
                    background: "transparent",
                    outline: "none",
                    padding: "inherit",
                    fontSize: "inherit",
                }}
            />
        </div>
    );
}

function SomedayAddTask({
    listId,
    onAdd,
    onCancel,
    slotIdx,
    darkMode,
    showProjectIcons,
    showTaskCheckboxes,
}: {
    listId: string;
    onAdd: (title: string) => void;
    onCancel?: () => void;
    slotIdx?: number;
    darkMode?: boolean;
    showProjectIcons?: boolean;
    showTaskCheckboxes?: boolean;
}) {
    const [title, setTitle] = useState("");
    const inputRef = useRef<HTMLInputElement>(null);

    const handleSubmit = () => {
        if (title.trim()) {
            onAdd(title.trim());
            setTitle("");
        } else if (onCancel) {
            onCancel();
        }
    };

    useEffect(() => {
        if (slotIdx !== undefined && inputRef.current) {
            inputRef.current.focus();
        }
    }, [slotIdx]);

    const isBottomAddInput = slotIdx === undefined;

    if (isBottomAddInput) {
        // Render as a flex row that mirrors the task item layout so the input
        // aligns exactly with the task text column (icon spacer + checkbox spacer + input).
        return (
            <li
                className="weekly-task-item minimal"
                style={{ margin: "0", listStyle: "none", width: "100%", padding: "4px 24px 4px 8px" }}
            >
                <form
                    onSubmit={(e) => { e.preventDefault(); handleSubmit(); }}
                    style={{ display: "flex", alignItems: "center", gap: "4px", width: "100%" }}
                >
                    {/* Icon column spacer — matches task item icon column */}
                    {showProjectIcons && <span style={{ width: "18px", minWidth: "18px", flexShrink: 0 }} />}
                    {/* Checkbox spacer — matches task item checkbox column */}
                    {showTaskCheckboxes && <span style={{ width: "16px", minWidth: "16px", flexShrink: 0 }} />}
                    <input
                        ref={inputRef}
                        type="text"
                        value={title}
                        onChange={(e) => setTitle(e.target.value)}
                        onBlur={handleSubmit}
                        onKeyDown={(e) => {
                            if (e.key === "Escape") {
                                setTitle("");
                                if (onCancel) onCancel();
                                else e.currentTarget.blur();
                            }
                        }}
                        className="weekly-task-text"
                        style={{
                            flex: 1,
                            border: `1px solid ${darkMode ? "#374151" : "#e5e7eb"}`,
                            background: darkMode ? "#1f2937" : "#ffffff",
                            color: darkMode ? "#f9fafb" : "#111827",
                            padding: "4px 8px",
                            borderRadius: "4px",
                            fontSize: "0.9375rem",
                            outline: "none",
                            height: "26px",
                            boxSizing: "border-box",
                        }}
                        placeholder="Add task..."
                        data-someday-add-input={listId}
                    />
                </form>
            </li>
        );
    }

    // Inline slot editor: transparent, no border
    return (
        <li
            className="weekly-task-item minimal"
            style={{ margin: "0", listStyle: "none", width: "100%" }}
        >
            <form
                onSubmit={(e) => { e.preventDefault(); handleSubmit(); }}
                style={{ width: "100%" }}
            >
                <input
                    ref={inputRef}
                    type="text"
                    value={title}
                    onChange={(e) => setTitle(e.target.value)}
                    onBlur={handleSubmit}
                    onKeyDown={(e) => {
                        if (e.key === "Escape") {
                            setTitle("");
                            if (onCancel) onCancel();
                            else e.currentTarget.blur();
                        }
                    }}
                    className="weekly-task-text"
                    style={{
                        width: "100%",
                        border: "none",
                        background: "transparent",
                        padding: "0",
                        fontSize: "0.9375rem",
                        outline: "none",
                        height: "auto",
                        display: "block",
                    }}
                />
            </form>
        </li>
    );
}

// Task Item Component
interface TaskItemProps {
    task: Task;
    isEditing: boolean;
    onToggle: () => void;
    onEdit: () => void;
    onUpdate: (title: string) => void;
    onDelete: () => void;
    onNotes: (notes: string) => void;
    onUrl?: (url: string) => void;
    onRollToggle: () => void;
    onRecurrence: () => void;
    onDragStart: (e: DragEvent, task: Task) => void;
    onDragEnd: () => void;
    variant?: "default" | "minimal";
    isSomeday?: boolean;
    onAddSubTask?: (parentId: string, title: string) => void;
    onToggleSubTask?: (subTaskId: string) => void;
    onDeleteSubTask?: (subTaskId: string) => void;
    onUpdateSubTask?: (subTaskId: string, title: string) => void;
    editingTaskId?: string | null;
    onSetEditingTaskId?: (id: string | null) => void;
    isSubTask?: boolean;
    showTaskCheckboxes?: boolean;
    showProjectIcons?: boolean;
    showPriorityIcons?: boolean;
    priorityStyle?: string;
    projects?: { id: string; name: string; icon?: string | null; color?: string | null }[];
    onProjectAssign?: (taskId: string, projectId: string | null) => void;
    kanbanStages?: KanbanStage[];
}

// ── Priority indicator helper ─────────────────────────────────────
// Renders a small priority badge for a task. The visual style is selected
// by the user's `priorityStyle` setting:
//   - "eisenhower" → quadrant icons + colors (urgency × importance)
//   - "abcde"      → letter A–E in a colored circle
//   - "ivylee"     → digit 1–6 in a colored circle (rank persisted in priority)
//   - "pareto"     → star for the "vital few" (importance flag)
// Returns null when the task has no priority data for the active style.
type PriorityBadge = { node: React.ReactNode; label: string };

const PRIORITY_NUMBER_COLORS: Record<string, string> = {
    "1": "#ef4444", "2": "#f97316", "3": "#eab308",
    "4": "#22c55e", "5": "#3b82f6", "6": "#8b5cf6",
};
const PRIORITY_LETTER_COLORS: Record<string, string> = {
    A: "#ef4444", B: "#3b82f6", C: "#eab308", D: "#f97316", E: "#9ca3af",
};

function makeBadgeCircle(text: string, color: string, size: number, label: string): PriorityBadge {
    return {
        label,
        node: (
            <span style={{
                display: "inline-flex",
                alignItems: "center",
                justifyContent: "center",
                width: size,
                height: size,
                borderRadius: "50%",
                background: color,
                color: "#fff",
                fontSize: Math.max(8, size - 6),
                fontWeight: 700,
                lineHeight: 1,
                flexShrink: 0,
            }}>{text}</span>
        ),
    };
}

export function getPriorityBadge(task: Task, style: string, size = 12): PriorityBadge | null {
    // Universal "important" star — shown for any task explicitly marked important
    // (e.g. Outlook To-Do tasks with the star flag) regardless of the active priority style.
    const importantStar = (): PriorityBadge => ({
        label: "Important",
        node: <Star size={size + 1} fill="#eab308" color="#eab308" style={{ flexShrink: 0 }} />,
    });

    if (style === "abcde") {
        if (task.priority && PRIORITY_LETTER_COLORS[task.priority]) {
            return makeBadgeCircle(task.priority, PRIORITY_LETTER_COLORS[task.priority], size + 2, task.priority);
        }
        if (task.importance === true) return importantStar();
        return null;
    }
    if (style === "ivylee") {
        if (task.priority && PRIORITY_NUMBER_COLORS[task.priority]) {
            return makeBadgeCircle(task.priority, PRIORITY_NUMBER_COLORS[task.priority], size + 2, `Ivy Lee #${task.priority}`);
        }
        if (task.importance === true) return importantStar();
        return null;
    }
    if (style === "pareto") {
        if (task.importance !== true && task.priority !== "A" && task.priority !== "B") return null;
        return {
            label: "Vital Few (80/20)",
            node: <Star size={size + 1} fill="#eab308" color="#eab308" style={{ flexShrink: 0 }} />,
        };
    }
    // eisenhower (default)
    if (task.urgency != null && task.importance != null) {
        if (task.urgency && task.importance)
            return { label: "Sofort erledigen", node: <Zap size={size} color="#ef4444" style={{ flexShrink: 0 }} /> };
        if (!task.urgency && task.importance)
            return { label: "Planen", node: <CalendarClock size={size} color="#3b82f6" style={{ flexShrink: 0 }} /> };
        if (task.urgency && !task.importance)
            return { label: "Delegieren", node: <CornerUpRight size={size} color="#f97316" style={{ flexShrink: 0 }} /> };
        return { label: "Eliminieren", node: <Archive size={size} color="#9ca3af" style={{ flexShrink: 0 }} /> };
    }
    // Eisenhower with only importance set (e.g. imported from Outlook with no urgency)
    if (task.importance === true) return importantStar();
    return null;
}

function TaskItem({
    task,
    isEditing,
    onToggle,
    onEdit,
    onUpdate,
    onDelete,
    onNotes,
    onUrl,
    onRollToggle,
    onRecurrence,
    onDragStart,
    onDragEnd,
    variant = "default",
    isSomeday = false,
    onAddSubTask,
    onToggleSubTask,
    onDeleteSubTask,
    onUpdateSubTask,
    editingTaskId,
    onSetEditingTaskId,
    isSubTask = false,
    showTaskCheckboxes = false,
    showProjectIcons = false,
    showPriorityIcons = true,
    priorityStyle = "eisenhower",
    projects = [],
    onProjectAssign,
    kanbanStages = [],
}: TaskItemProps) {
    const [editValue, setEditValue] = useState(task.title);
    const [isNotesOpen, setIsNotesOpen] = useState(false);
    const [notesValue, setNotesValue] = useState(task.markdownContent || "");
    const [isUrlOpen, setIsUrlOpen] = useState(false);
    const [urlValue, setUrlValue] = useState(task.url || "");
    const urlInputRef = useRef<HTMLInputElement>(null);
    const [isSubTaskInputOpen, setIsSubTaskInputOpen] = useState(false);
    const [isSubTasksOpen, setIsSubTasksOpen] = useState(false);
    const [newSubTaskTitle, setNewSubTaskTitle] = useState("");
    const [showProjectPicker, setShowProjectPicker] = useState(false);
    const projectPickerRef = useRef<HTMLDivElement>(null);
    const inputRef = useRef<HTMLTextAreaElement>(null);
    const subTaskInputRef = useRef<HTMLInputElement>(null);

    // Touch: tap-to-reveal actions
    const [touchActive, setTouchActive] = useState(false);
    const taskItemRef = useRef<HTMLLIElement>(null);

    // Touch: swipe gesture state
    const [swipeX, setSwipeX] = useState(0);
    const swipeTouchStart = useRef({ x: 0, y: 0, swiping: false });

    // Close touch-active on outside click
    useEffect(() => {
        if (!touchActive) return;
        const handler = (e: Event) => {
            if (taskItemRef.current && !taskItemRef.current.contains(e.target as Node)) {
                setTouchActive(false);
            }
        };
        document.addEventListener("touchstart", handler);
        document.addEventListener("mousedown", handler);
        return () => {
            document.removeEventListener("touchstart", handler);
            document.removeEventListener("mousedown", handler);
        };
    }, [touchActive]);

    // Close project picker on outside click
    useEffect(() => {
        if (!showProjectPicker) return;
        const handler = (e: Event) => {
            if (projectPickerRef.current && !projectPickerRef.current.contains(e.target as Node)) {
                setShowProjectPicker(false);
            }
        };
        document.addEventListener("mousedown", handler);
        return () => document.removeEventListener("mousedown", handler);
    }, [showProjectPicker]);

    const needsSync = task.externalProvider && (
        !task.externalId ||
        !task.lastSyncedAt ||
        new Date(task.updatedAt) > new Date(task.lastSyncedAt)
    );

    useEffect(() => {
        if (isEditing && inputRef.current) {
            inputRef.current.focus();
            inputRef.current.select();
        }
    }, [isEditing]);

    // Focus URL input when opened; sync when task.url changes
    useEffect(() => { if (isUrlOpen) setTimeout(() => urlInputRef.current?.focus(), 50); }, [isUrlOpen]);
    useEffect(() => { setUrlValue(task.url || ""); }, [task.url]);

    const handleUrlSave = (val: string) => {
        setIsUrlOpen(false);
        if (val.trim() !== (task.url || "") && onUrl) {
            onUrl(val.trim());
        }
    };

    const handleSubmit = (e: React.FormEvent) => {
        e.preventDefault();
        onUpdate(editValue);
    };

    const handleKeyDown = (e: React.KeyboardEvent) => {
        if (e.key === "Enter" && !e.shiftKey) {
            e.preventDefault();
            (e.target as HTMLElement).blur();
        }
        if (e.key === "Escape") {
            setEditValue(task.title);
            onUpdate(task.title);
        }
    };

    return (
        <li
            ref={taskItemRef}
            className={`weekly-task-item ${variant} ${task.completed ? "completed" : ""} ${task.completed && showTaskCheckboxes ? "completed-with-checkbox" : ""} ${isSomeday ? "relative mx-2 w-full" : ""} ${touchActive ? "touch-active" : ""} ${showProjectPicker ? "picker-open" : ""} ${swipeX !== 0 ? "task-swipe-container" : ""}`}
            style={(() => {
                const stageColor = task.kanbanStage ? kanbanStages.find(s => s.id === task.kanbanStage)?.color : null;
                if (stageColor) return { borderLeft: `4px solid ${stageColor}`, paddingLeft: "6px" };
                if (task.project?.color) return { borderLeft: `3px solid ${task.project.color}`, paddingLeft: "6px" };
                return undefined;
            })()}
            draggable={!isEditing && !isNotesOpen && swipeX === 0}
            onDragStart={(e) => {
                // If dragging a subtask, don't drag the parent
                const target = e.target as HTMLElement;
                if (target.closest('.subtask-list')) {
                    e.stopPropagation();
                    return;
                }
                onDragStart(e as unknown as DragEvent, task);
            }}
            onDragEnd={onDragEnd}
            onClick={(e) => {
                // Touch: toggle action toolbar on tap
                if (window.matchMedia("(pointer: coarse)").matches && !isEditing) {
                    const target = e.target as HTMLElement;
                    if (target.closest(".task-actions") || target.closest("button")) return;
                    setTouchActive(!touchActive);
                    return;
                }
                if ((variant === "minimal" || isSomeday) && !isEditing) {
                    const target = e.target as HTMLElement;
                    if (
                        target.tagName === "BUTTON" ||
                        target.tagName === "INPUT" ||
                        target.closest("button")
                    )
                        return;
                    onEdit();
                }
            }}
            onTouchStart={() => {
                // No task-level swipe — container handles day navigation
            }}
        >
            {/* Swipe indicators */}
            {swipeX > 20 && (
                <div className="task-swipe-indicator complete" style={{ width: Math.abs(swipeX) }}>
                    <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><polyline points="20 6 9 17 4 12" /></svg>
                </div>
            )}
            {swipeX < -20 && (
                <div className="task-swipe-indicator delete" style={{ width: Math.abs(swipeX) }}>
                    <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18" /><line x1="6" y1="6" x2="18" y2="18" /></svg>
                </div>
            )}
            <div style={{ width: "100%", position: "relative", transform: swipeX !== 0 ? `translateX(${swipeX}px)` : undefined, transition: swipeX === 0 ? "transform 0.2s ease" : "none", background: "inherit" }}>
                {/* Visual Indicator for Rolling Tasks */}
                {task.isRolling && !task.completed && !isSomeday && (
                    <div className="rolling-icon-indicator" title="Auto-rolling task">
                        <svg
                            viewBox="0 0 24 24"
                            width="10"
                            height="10"
                            stroke="currentColor"
                            strokeWidth="3"
                            fill="none"
                            strokeLinecap="round"
                            strokeLinejoin="round"
                        >
                            <polyline points="23 4 23 10 17 10"></polyline>
                            <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
                        </svg>
                    </div>
                )}

                <div
                    style={{
                        display: "flex",
                        alignItems: isSomeday ? "center" : "flex-start",
                        gap: isSomeday ? "4px" : "0.5rem",
                        width: "100%",
                    }}
                >
                    {isEditing ? (
                        <>
                        {/* Someday: match icon + checkbox column widths so textarea aligns with task text */}
                        {isSomeday && showProjectIcons && <span style={{ width: "18px", minWidth: "18px", flexShrink: 0 }} />}
                        {isSomeday && showTaskCheckboxes && <span style={{ width: "16px", minWidth: "16px", flexShrink: 0 }} />}
                        <form onSubmit={handleSubmit} style={{ flex: 1, display: "flex" }}>
                            {variant === "minimal" ? (
                                <textarea
                                    ref={inputRef}
                                    className="weekly-task-text"
                                    value={editValue}
                                    onChange={(e) => setEditValue(e.target.value)}
                                    onKeyDown={handleKeyDown}
                                    onBlur={() => onUpdate(editValue)}
                                    rows={editValue.split("\n").length || 1}
                                    style={{
                                        border: "none",
                                        background: "transparent",
                                        outline: "none",
                                        width: "100%",
                                        padding: "0",
                                        resize: "none",
                                        overflow: "hidden",
                                        fontFamily: "inherit",
                                        fontSize: "inherit",
                                        fontWeight: "inherit",
                                        lineHeight: "inherit",
                                    }}
                                />
                            ) : (
                                <textarea
                                    ref={inputRef}
                                    className="weekly-task-text"
                                    value={editValue}
                                    onChange={(e) => setEditValue(e.target.value)}
                                    onKeyDown={handleKeyDown}
                                    onBlur={() => onUpdate(editValue)}
                                    rows={editValue.split("\n").length || 1}
                                    style={{
                                        resize: "none",
                                        overflow: "hidden",
                                        fontFamily: "inherit",
                                        lineHeight: "inherit",
                                    }}
                                />
                            )}
                        </form>
                        </>
                    ) : (
                        <>
                            {/* Someday: fixed-width icon column — project icon, priority badge, delegation, or empty placeholder */}
                            {isSomeday && (
                                <span style={{ width: "18px", minWidth: "18px", flexShrink: 0, display: "inline-flex", alignItems: "center", justifyContent: "center" }}>
                                    {showProjectIcons && task.project
                                        ? <ProjectIcon icon={task.project.icon} size={13} color={task.project.color || "#888"} />
                                        : (() => {
                                            if (showPriorityIcons) { const pb = getPriorityBadge(task, priorityStyle, 11); if (pb) return pb.node; }
                                            if (task.delegatedTo) return task.delegatedTo === "AI" ? <Bot size={11} color="#8b5cf6" /> : <User size={11} color="#8b5cf6" />;
                                            return null;
                                        })()
                                    }
                                </span>
                            )}
                            {/* Someday: checkbox outside text span so it aligns in its own column */}
                            {isSomeday && showTaskCheckboxes && (
                                <input
                                    type="checkbox"
                                    checked={task.completed}
                                    onChange={(e) => { e.stopPropagation(); onToggle(); }}
                                    onClick={(e) => e.stopPropagation()}
                                    className="task-checkbox flex-shrink-0"
                                    style={{ width: "16px", height: "16px", margin: 0, cursor: "pointer", flexShrink: 0, accentColor: "var(--weekly-teal, #009a9a)", WebkitAppearance: "checkbox" }}
                                />
                            )}
                            <span
                                className={`weekly-task-text flex-1 ${task.completed ? "completed" : ""}`}
                                onClick={(e) => {
                                    if (variant === "default" && !showTaskCheckboxes) onToggle();
                                    // For minimal/someday, parent onClick handles edit
                                }}
                                onDoubleClick={variant === "default" ? onEdit : undefined}
                                style={
                                    variant === "minimal" || isSomeday
                                        ? { display: "flex", alignItems: "center", gap: "4px", ...(task.completed && showTaskCheckboxes ? { opacity: 0.5 } : {}) }
                                        : { display: "flex", alignItems: "center", gap: "6px", ...(task.completed && showTaskCheckboxes ? { opacity: 0.5 } : {}) }
                                }
                            >
                                {/* Non-someday: checkbox stays inside text span */}
                                {!isSomeday && showTaskCheckboxes && (
                                    <input
                                        type="checkbox"
                                        checked={task.completed}
                                        onChange={(e) => { e.stopPropagation(); onToggle(); }}
                                        onClick={(e) => e.stopPropagation()}
                                        className="task-checkbox flex-shrink-0"
                                        style={{
                                            width: "16px",
                                            height: "16px",
                                            margin: 0,
                                            cursor: "pointer",
                                            position: "relative",
                                            top: "3px",
                                            left: "-2px",
                                            accentColor: "var(--weekly-teal, #009a9a)",
                                            WebkitAppearance: "checkbox"
                                        }}
                                    />
                                )}
                                <span
                                    style={{
                                        whiteSpace: "pre-wrap",
                                        wordBreak: "break-word",
                                        overflow: "visible",
                                        flex: 1,
                                    }}
                                >
                                    {/* Non-someday only: priority/delegation icons inline. Someday shows them in the leading column. */}
                                    {!isSomeday && showPriorityIcons && (() => {
                                        const pb = getPriorityBadge(task, priorityStyle, 11);
                                        return pb ? (
                                            <span title={pb.label} style={{ marginRight: "3px", verticalAlign: "middle", display: "inline-flex", alignItems: "center" }}>
                                                {pb.node}
                                            </span>
                                        ) : null;
                                    })()}
                                    {!isSomeday && task.delegatedTo && (
                                        <span
                                            title={task.delegatedTo === "AI" ? `AI: ${task.delegationNote || ""}` : task.delegatedTo}
                                            style={{ marginRight: "3px", verticalAlign: "middle", display: "inline-flex", alignItems: "center" }}
                                        >
                                            {task.delegatedTo === "AI"
                                                ? <Bot size={11} color="#8b5cf6" />
                                                : <User size={11} color="#8b5cf6" />}
                                        </span>
                                    )}
                                    {/* Non-someday: inline project icon; someday uses the column above */}
                                    {showProjectIcons && task.project && !isSomeday && (
                                        <span style={{ marginRight: "4px", verticalAlign: "middle" }}>
                                            <ProjectIcon icon={task.project.icon} size={13} color={task.project.color || "#888"} />
                                        </span>
                                    )}
                                    {task.title}
                                </span>
                                {(() => {
                                    const provider = task.externalProvider
                                        || (task.externalId?.startsWith("synology::") ? "synology" : null);
                                    if (!provider) return null;
                                    const iconMap: Record<string, { icon: any; color: string; label: string }> = {
                                        google: { icon: faGoogle, color: "#4285F4", label: "Google" },
                                        outlook: { icon: faMicrosoft, color: "#0078D4", label: "Microsoft" },
                                        apple: { icon: faApple, color: "#555", label: "Apple" },
                                        synology: { icon: faServer, color: "#007AFF", label: "Synology" },
                                        notion: { icon: faNotion, color: "#000000", label: "Notion" },
                                    };
                                    const info = iconMap[provider];
                                    if (!info) return null;
                                    return (
                                        <span
                                            className="flex-shrink-0"
                                            title={`Synced with ${info.label}`}
                                            style={{ display: "inline-flex", alignItems: "center", opacity: 0.55, paddingLeft: "4px" }}
                                        >
                                            <FontAwesomeIcon icon={info.icon} style={{ width: 12, height: 12, color: info.color }} />
                                        </span>
                                    );
                                })()}
                            </span>

                            {/* Subtask indicator - toggles subtask list */}
                            {task.subTasks && task.subTasks.length > 0 && !isSubTask && (() => {
                                const completed = task.subTasks!.filter(s => s.completed).length;
                                const total = task.subTasks!.length;
                                const allDone = completed === total;
                                const expanded = isSubTasksOpen || isSubTaskInputOpen;
                                const pct = total > 0 ? (completed / total) * 100 : 0;
                                return (
                                    <button
                                        onClick={(e) => {
                                            e.stopPropagation();
                                            setIsSubTasksOpen(!isSubTasksOpen);
                                        }}
                                        className="subtask-indicator-badge"
                                        title={expanded ? "Collapse subtasks" : `${completed}/${total} subtasks done`}
                                        style={{
                                            display: "inline-flex",
                                            alignItems: "center",
                                            gap: "4px",
                                            padding: "2px 8px 2px 4px",
                                            borderRadius: "12px",
                                            background: expanded ? "rgba(99,102,241,0.08)" : "transparent",
                                            color: allDone ? "var(--weekly-teal, #0d9488)" : "var(--weekly-text-light, #9ca3af)",
                                            border: "none",
                                            cursor: "pointer",
                                            fontSize: "0.7rem",
                                            fontWeight: 600,
                                            lineHeight: 1,
                                            flexShrink: 0,
                                            whiteSpace: "nowrap",
                                            transition: "all 0.15s",
                                        }}
                                    >
                                        <ChevronDown size={12} style={{ transform: expanded ? "rotate(0deg)" : "rotate(-90deg)", transition: "transform 0.2s", flexShrink: 0 }} />
                                        <span style={{
                                            display: "inline-block",
                                            width: "36px",
                                            height: "5px",
                                            borderRadius: "3px",
                                            background: "var(--weekly-border, #e5e7eb)",
                                            position: "relative",
                                            overflow: "hidden",
                                            flexShrink: 0,
                                        }}>
                                            <span style={{
                                                position: "absolute",
                                                left: 0,
                                                top: 0,
                                                height: "100%",
                                                width: `${pct}%`,
                                                borderRadius: "3px",
                                                background: allDone ? "var(--weekly-teal, #0d9488)" : "var(--weekly-accent, #6366f1)",
                                                transition: "width 0.3s ease",
                                            }} />
                                        </span>
                                        <span style={{ opacity: 0.8 }}>{completed}/{total}</span>
                                    </button>
                                );
                            })()}

                            {/* URL indicator */}
                            {task.url && (
                                <a
                                    href={task.url}
                                    target="_blank"
                                    rel="noopener noreferrer"
                                    onClick={(e) => e.stopPropagation()}
                                    title={task.url}
                                    style={{
                                        display: "inline-flex", alignItems: "center",
                                        padding: "2px 5px", borderRadius: "4px",
                                        background: "rgba(37,99,235,0.10)", color: "#2563eb",
                                        textDecoration: "none", flexShrink: 0,
                                    }}
                                >
                                    <svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                                        <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/>
                                        <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
                                    </svg>
                                </a>
                            )}
                            {/* Note indicator - toggles inline notes */}
                            {task.markdownContent && task.markdownContent.trim().length > 0 && (
                                <button
                                    onClick={(e) => {
                                        e.stopPropagation();
                                        setIsNotesOpen(!isNotesOpen);
                                    }}
                                    className="focus:outline-none flex-shrink-0"
                                    title={isNotesOpen ? "Collapse note" : "Expand note"}
                                    style={{
                                        display: "inline-flex",
                                        alignItems: "center",
                                        gap: "2px",
                                        padding: "2px 5px",
                                        borderRadius: "4px",
                                        background: isNotesOpen ? "rgba(245, 158, 11, 0.1)" : "transparent",
                                        color: isNotesOpen ? "#f59e0b" : "var(--weekly-text-muted, #999)",
                                        border: "none",
                                        cursor: "pointer",
                                        lineHeight: 1,
                                        transition: "background 0.15s, color 0.15s",
                                    }}
                                >
                                    <svg viewBox="0 0 24 24" width="11" height="11" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                                        <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
                                        <polyline points="14 2 14 8 20 8" />
                                        <line x1="16" y1="13" x2="8" y2="13" />
                                        <line x1="16" y1="17" x2="8" y2="17" />
                                    </svg>
                                    <svg viewBox="0 0 24 24" width="8" height="8" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ transform: isNotesOpen ? "rotate(90deg)" : "rotate(0deg)", transition: "transform 0.2s" }}>
                                        <polyline points="9 18 15 12 9 6" />
                                    </svg>
                                </button>
                            )}

                            <div className="task-actions z-20">
                                {/* Complete */}
                                <button
                                    className={`task-action-btn ${task.completed ? "active text-green-600 dark:text-green-500" : ""}`}
                                    onClick={(e) => {
                                        e.stopPropagation();
                                        onToggle();
                                    }}
                                    title={task.completed ? "Mark incomplete" : "Mark complete"}
                                >
                                    <svg
                                        viewBox="0 0 24 24"
                                        width="12"
                                        height="12"
                                        stroke="currentColor"
                                        strokeWidth="3"
                                        fill="none"
                                        strokeLinecap="round"
                                        strokeLinejoin="round"
                                    >
                                        <line x1="5" y1="12" x2="19" y2="12"></line>
                                    </svg>
                                </button>
                                {/* Edit */}
                                <button
                                    className="task-action-btn"
                                    onClick={(e) => {
                                        e.stopPropagation();
                                        onEdit();
                                    }}
                                    title="Edit"
                                >
                                    <svg
                                        viewBox="0 0 24 24"
                                        width="12"
                                        height="12"
                                        stroke="currentColor"
                                        strokeWidth="2.5"
                                        fill="none"
                                        strokeLinecap="round"
                                        strokeLinejoin="round"
                                    >
                                        <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"></path>
                                        <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"></path>
                                    </svg>
                                </button>

                                {/* Add Sub-task */}
                                {!isSubTask && onAddSubTask && (
                                    <button
                                        className={`task-action-btn ${isSubTaskInputOpen ? "active" : ""}`}
                                        onClick={(e) => {
                                            e.stopPropagation();
                                            setIsSubTaskInputOpen(!isSubTaskInputOpen);
                                            if (!isSubTaskInputOpen) {
                                                setTimeout(() => subTaskInputRef.current?.focus(), 50);
                                            }
                                        }}
                                        title="Add sub-task"
                                    >
                                        <svg
                                            viewBox="0 0 24 24"
                                            width="12"
                                            height="12"
                                            stroke="currentColor"
                                            strokeWidth="2.5"
                                            fill="none"
                                            strokeLinecap="round"
                                            strokeLinejoin="round"
                                        >
                                            <line x1="12" y1="5" x2="12" y2="19"></line>
                                            <line x1="5" y1="12" x2="19" y2="12"></line>
                                        </svg>
                                    </button>
                                )}

                                {/* Recurrence (hidden for someday tasks) */}
                                {!isSomeday && (
                                <button
                                    className={`task-action-btn ${task.isRecurring ? "active" : ""}`}
                                    onClick={(e) => {
                                        e.stopPropagation();
                                        onRecurrence();
                                    }}
                                    title={
                                        task.isRecurring ? "Edit recurrence" : "Make recurring"
                                    }
                                >
                                    <svg
                                        viewBox="0 0 24 24"
                                        width="12"
                                        height="12"
                                        stroke="currentColor"
                                        strokeWidth="2.5"
                                        fill="none"
                                        strokeLinecap="round"
                                        strokeLinejoin="round"
                                    >
                                        <polyline points="23 4 23 10 17 10"></polyline>
                                        <path d="M20.49 15a9 9 0 1 1-2.12-9.36L23 10"></path>
                                    </svg>
                                </button>
                                )}

                                {/* Notes */}
                                <button
                                    className={`task-action-btn ${isNotesOpen || (task.markdownContent && task.markdownContent.trim().length > 0) ? "active" : ""}`}
                                    onClick={(e) => {
                                        e.stopPropagation();
                                        setIsNotesOpen(!isNotesOpen);
                                    }}
                                    title="Notes"
                                >
                                    <svg
                                        viewBox="0 0 24 24"
                                        width="12"
                                        height="12"
                                        stroke="currentColor"
                                        strokeWidth="2.5"
                                        fill="none"
                                        strokeLinecap="round"
                                        strokeLinejoin="round"
                                    >
                                        <line x1="3" y1="12" x2="21" y2="12"></line>
                                        <line x1="3" y1="6" x2="21" y2="6"></line>
                                        <line x1="3" y1="18" x2="21" y2="18"></line>
                                    </svg>
                                </button>

                                {/* Project Assignment */}
                                {!isSubTask && projects.length > 0 && onProjectAssign && (
                                    <div className="relative" ref={projectPickerRef}>
                                        <button
                                            className={`task-action-btn ${task.project ? "active" : ""}`}
                                            onClick={(e) => {
                                                e.stopPropagation();
                                                setShowProjectPicker(!showProjectPicker);
                                            }}
                                            title={task.project ? task.project.name : "Assign project"}
                                        >
                                            {task.project?.icon ? (
                                                <span style={{ fontSize: "12px", lineHeight: 1 }}>{task.project.icon}</span>
                                            ) : (
                                                <Circle
                                                    size={12}
                                                    fill={task.project?.color || "none"}
                                                    stroke={task.project?.color || "currentColor"}
                                                    strokeWidth={2}
                                                />
                                            )}
                                        </button>
                                        {showProjectPicker && (
                                            <div className="absolute z-50 top-full left-0 mt-1 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-600 rounded-lg shadow-lg py-1 min-w-[140px]" style={{ whiteSpace: "nowrap" }}>
                                                {task.projectId && (
                                                    <button
                                                        className="flex items-center gap-2 w-full px-3 py-1.5 text-xs hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-500"
                                                        onClick={(e) => {
                                                            e.stopPropagation();
                                                            onProjectAssign(task.id, null);
                                                            setShowProjectPicker(false);
                                                        }}
                                                    >
                                                        <X size={10} /> Remove
                                                    </button>
                                                )}
                                                {projects.map((p) => (
                                                    <button
                                                        key={p.id}
                                                        className={`flex items-center gap-2 w-full px-3 py-1.5 text-xs hover:bg-gray-100 dark:hover:bg-gray-700 ${task.projectId === p.id ? "font-bold" : ""}`}
                                                        onClick={(e) => {
                                                            e.stopPropagation();
                                                            onProjectAssign(task.id, task.projectId === p.id ? null : p.id);
                                                            setShowProjectPicker(false);
                                                        }}
                                                    >
                                                        <span style={{ fontSize: "12px" }}><ProjectIcon icon={p.icon} size={12} color={p.color || "#999"} /></span>
                                                        <Circle size={8} fill={p.color || "#999"} stroke={p.color || "#999"} strokeWidth={0} />
                                                        {p.name}
                                                    </button>
                                                ))}
                                            </div>
                                        )}
                                    </div>
                                )}

                                {/* Roll Toggle - Active State Colored (hidden for someday tasks) */}
                                {!task.completed && !isSomeday && (
                                    <button
                                        className={`task-action-btn ${task.isRolling ? "active" : ""}`}
                                        onClick={(e) => {
                                            e.stopPropagation();
                                            onRollToggle();
                                        }}
                                        title={
                                            task.isRolling ? "Disable rolling" : "Enable rolling"
                                        }
                                    >
                                        <svg
                                            viewBox="0 0 24 24"
                                            width="12"
                                            height="12"
                                            stroke="currentColor"
                                            strokeWidth="2.5"
                                            fill="none"
                                            strokeLinecap="round"
                                            strokeLinejoin="round"
                                        >
                                            <polyline points="1 4 1 10 7 10"></polyline>
                                            <path d="M3.51 15a9 9 0 1 0 2.13-9.36L1 10"></path>
                                        </svg>
                                    </button>
                                )}

                                {/* Link */}
                                <button
                                    className={`task-action-btn ${task.url || isUrlOpen ? "active" : ""}`}
                                    onClick={(e) => { e.stopPropagation(); setIsUrlOpen(!isUrlOpen); }}
                                    title={task.url || "Add link"}
                                    style={task.url ? { color: "#2563eb" } : {}}
                                >
                                    <svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
                                        <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/>
                                        <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
                                    </svg>
                                </button>

                                {/* Delete */}
                                <button
                                    className="task-action-btn delete text-red-500 hover:text-red-700 hover:bg-red-100/50 dark:hover:bg-red-900/30 rounded"
                                    onClick={(e) => {
                                        e.stopPropagation();
                                        onDelete();
                                    }}
                                    title="Delete"
                                >
                                    <svg
                                        viewBox="0 0 24 24"
                                        width="12"
                                        height="12"
                                        stroke="currentColor"
                                        strokeWidth="2.5"
                                        fill="none"
                                        strokeLinecap="round"
                                        strokeLinejoin="round"
                                    >
                                        <polyline points="3 6 5 6 21 6"></polyline>
                                        <path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
                                    </svg>
                                </button>
                            </div>

                        </>
                    )}
                </div>

                {/* URL editor */}
                {isUrlOpen && (
                    <div className="weekly-notes-inline" onClick={(e) => e.stopPropagation()} style={{ padding: "6px 8px", display: "flex", alignItems: "center", gap: "6px" }}>
                        <svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="#2563eb" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}>
                            <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/>
                            <path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
                        </svg>
                        <input
                            ref={urlInputRef}
                            type="url"
                            value={urlValue}
                            onChange={(e) => setUrlValue(e.target.value)}
                            onKeyDown={(e) => {
                                if (e.key === "Enter") { e.preventDefault(); handleUrlSave(urlValue); }
                                if (e.key === "Escape") { setIsUrlOpen(false); setUrlValue(task.url || ""); }
                            }}
                            onBlur={() => handleUrlSave(urlValue)}
                            placeholder="https://..."
                            style={{ flex: 1, fontSize: "0.78rem", border: "1px solid var(--weekly-border, #ddd)", borderRadius: "4px", padding: "3px 6px", background: "var(--weekly-bg, white)", color: "var(--weekly-text, #333)", outline: "none" }}
                        />
                        {urlValue && (
                            <button onMouseDown={(e) => { e.preventDefault(); setUrlValue(""); if (onUrl) onUrl(""); setIsUrlOpen(false); }} title="Remove link" style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: "#999", flexShrink: 0 }}>
                                <svg viewBox="0 0 24 24" width="12" height="12" stroke="currentColor" strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
                            </button>
                        )}
                        {urlValue && (
                            <a href={urlValue.startsWith("http") ? urlValue : `https://${urlValue}`} target="_blank" rel="noopener noreferrer" onClick={(e) => e.stopPropagation()} title="Open link" style={{ color: "#2563eb", flexShrink: 0, display: "inline-flex" }}>
                                <svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
                                    <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
                                    <polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/>
                                </svg>
                            </a>
                        )}
                    </div>
                )}

                {/* Inline Notes Editor */}
                {isNotesOpen && (
                    <div className="weekly-notes-inline" onClick={(e) => e.stopPropagation()} style={{ padding: "0" }}>
                        <div style={{ display: "flex", justifyContent: "flex-end", padding: "4px 6px 0" }}>
                            <button onMouseDown={(e) => { e.preventDefault(); setIsNotesOpen(false); }} style={{ background: "none", border: "none", cursor: "pointer", fontSize: "1rem", lineHeight: 1, color: "#999", padding: "2px 4px" }} title="Close">×</button>
                        </div>
                        <div style={{ padding: "0 6px 8px" }}>
                            <RichTextEditor
                                value={notesValue}
                                onChange={(html) => { setNotesValue(html); onNotes(html); }}
                                placeholder="Add notes..."
                                minHeight="80px"
                            />
                        </div>
                    </div>
                )}

                {/* Sub-tasks section */}
                {
                    !isSubTask && (isSubTasksOpen || isSubTaskInputOpen) && task.subTasks && task.subTasks.length > 0 && (
                        <ul className="subtask-list" onClick={(e) => e.stopPropagation()} style={task.project?.color ? { borderLeft: `2px solid ${task.project.color}`, marginLeft: "2px" } : undefined}>
                            {task.subTasks.map((subTask) => (
                                <li
                                    key={subTask.id}
                                    className={`subtask-item ${subTask.completed ? "completed" : ""}`}
                                    draggable
                                    onDragStart={(e) => {
                                        e.stopPropagation();
                                        if (onDragStart) {
                                            onDragStart(e as any, { ...subTask, parentTaskId: task.id, scheduledDate: task.scheduledDate } as any);
                                        }
                                    }}
                                    onDragEnd={(e) => { e.stopPropagation(); onDragEnd?.(); }}
                                >
                                    <button
                                        className="subtask-checkbox"
                                        onClick={() => onToggleSubTask?.(subTask.id)}
                                        aria-label={subTask.completed ? "Mark incomplete" : "Mark complete"}
                                    >
                                        {subTask.completed ? (
                                            <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
                                                <polyline points="20 6 9 17 4 12" />
                                            </svg>
                                        ) : (
                                            <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                                                <circle cx="12" cy="12" r="10" />
                                            </svg>
                                        )}
                                    </button>
                                    {editingTaskId === subTask.id ? (
                                        <form
                                            onSubmit={(e) => {
                                                e.preventDefault();
                                                const input = e.currentTarget.querySelector("input");
                                                if (input) {
                                                    onUpdateSubTask?.(subTask.id, input.value);
                                                    onSetEditingTaskId?.(null);
                                                }
                                            }}
                                            style={{ flex: 1 }}
                                        >
                                            <input
                                                type="text"
                                                defaultValue={subTask.title}
                                                autoFocus
                                                className="subtask-edit-input"
                                                onBlur={(e) => {
                                                    onUpdateSubTask?.(subTask.id, e.target.value);
                                                    onSetEditingTaskId?.(null);
                                                }}
                                                onKeyDown={(e) => {
                                                    if (e.key === "Escape") onSetEditingTaskId?.(null);
                                                }}
                                            />
                                        </form>
                                    ) : (
                                        <span
                                            className={`subtask-title ${subTask.completed ? "completed" : ""}`}
                                            onClick={() => onSetEditingTaskId?.(subTask.id)}
                                        >
                                            {subTask.title}
                                        </span>
                                    )}
                                    <button
                                        className="subtask-delete-btn"
                                        onClick={() => onDeleteSubTask?.(subTask.id)}
                                        title="Remove sub-task"
                                    >
                                        <svg viewBox="0 0 24 24" width="10" height="10" stroke="currentColor" strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round">
                                            <line x1="18" y1="6" x2="6" y2="18" />
                                            <line x1="6" y1="6" x2="18" y2="18" />
                                        </svg>
                                    </button>
                                </li>
                            ))}
                        </ul>
                    )
                }

                {/* Add sub-task input */}
                {
                    !isSubTask && isSubTaskInputOpen && (
                        <div className="subtask-add-row" onClick={(e) => e.stopPropagation()}>
                            <form
                                onSubmit={(e) => {
                                    e.preventDefault();
                                    if (newSubTaskTitle.trim()) {
                                        onAddSubTask?.(task.id, newSubTaskTitle.trim());
                                        setNewSubTaskTitle("");
                                    }
                                }}
                                style={{ display: "flex", alignItems: "center", gap: "0.25rem", flex: 1 }}
                            >
                                <svg viewBox="0 0 24 24" width="12" height="12" stroke="var(--weekly-text-muted, #999)" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round" style={{ flexShrink: 0 }}>
                                    <circle cx="12" cy="12" r="10" />
                                </svg>
                                <input
                                    ref={subTaskInputRef}
                                    type="text"
                                    value={newSubTaskTitle}
                                    onChange={(e) => setNewSubTaskTitle(e.target.value)}
                                    onBlur={() => {
                                        if (!newSubTaskTitle.trim()) {
                                            setIsSubTaskInputOpen(false);
                                        }
                                    }}
                                    onKeyDown={(e) => {
                                        if (e.key === "Escape") {
                                            setNewSubTaskTitle("");
                                            setIsSubTaskInputOpen(false);
                                        }
                                    }}
                                    placeholder="Add sub-task..."
                                    className="subtask-add-input"
                                    autoFocus
                                />
                            </form>
                        </div>
                    )
                }
            </div >
        </li >
    );
}

// Punkt 7+8 — popover for editing a someday list's icon and color.
function ListVisualsPopover({
    list,
    darkMode,
    language,
    onChange,
    onClose,
    anchorRect,
}: {
    list: { id: string; title: string; color?: string | null; icon?: string | null };
    darkMode: boolean;
    language: string;
    anchorRect?: DOMRect | null;
    onChange: (updates: { color?: string | null; icon?: string | null }) => void;
    onClose: () => void;
}) {
    const [iconPickerOpen, setIconPickerOpen] = useState(false);
    const containerRef = useRef<HTMLDivElement>(null);
    const onCloseRef = useRef(onClose);
    useEffect(() => { onCloseRef.current = onClose; }, [onClose]);
    useEffect(() => {
        const onDoc = (e: MouseEvent) => {
            if (containerRef.current && !containerRef.current.contains(e.target as Node)) onCloseRef.current();
        };
        document.addEventListener("mousedown", onDoc);
        return () => document.removeEventListener("mousedown", onDoc);
    }, []);
    const de = language === "de";
    const top = anchorRect ? anchorRect.top + 32 : -9999;
    const left = anchorRect ? anchorRect.left + 4 : -9999;
    return (
        <div
            ref={containerRef}
            style={{
                position: "fixed",
                top,
                left,
                zIndex: 10000,
                background: darkMode ? "#1e1e2e" : "#fff",
                border: `1px solid ${darkMode ? "#444" : "#e5e7eb"}`,
                borderRadius: "10px",
                padding: "12px",
                boxShadow: "0 8px 24px rgba(0,0,0,0.18)",
                minWidth: "240px",
                display: "flex",
                flexDirection: "column",
                gap: "10px",
            }}
            onClick={(e) => e.stopPropagation()}
        >
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
                <span style={{ fontSize: "0.78rem", fontWeight: 600, color: darkMode ? "#d1d5db" : "#444" }}>
                    {de ? "Listen-Stil" : "List style"}
                </span>
                <button onClick={onClose} style={{ background: "none", border: "none", cursor: "pointer", color: darkMode ? "#9ca3af" : "#888", padding: "2px" }}>
                    <X size={14} />
                </button>
            </div>
            <div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
                <span style={{ fontSize: "0.75rem", color: darkMode ? "#9ca3af" : "#666", flex: 1 }}>{de ? "Icon" : "Icon"}</span>
                <button
                    onClick={() => setIconPickerOpen((v) => !v)}
                    style={{ width: "32px", height: "32px", borderRadius: "8px", border: `1px solid ${darkMode ? "#444" : "#e5e7eb"}`, background: darkMode ? "#2a2a3a" : "#fff", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}
                >
                    <ProjectIcon icon={list.icon} size={16} color={list.color || (darkMode ? "#d1d5db" : "#555")} />
                </button>
                {list.icon && (
                    <button
                        onClick={() => onChange({ icon: null })}
                        title={de ? "Icon entfernen" : "Remove icon"}
                        style={{ background: "none", border: "none", cursor: "pointer", color: "#ef4444", padding: "2px" }}
                    >
                        <X size={12} />
                    </button>
                )}
            </div>
            {iconPickerOpen && (
                <div style={{ position: "fixed", top: top + 78, left, zIndex: 10001 }}>
                    <IconPicker
                        selectedIcon={list.icon || ""}
                        onSelect={(name) => { onChange({ icon: name }); setIconPickerOpen(false); }}
                        darkMode={darkMode}
                    />
                </div>
            )}
            <div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
                <span style={{ fontSize: "0.75rem", color: darkMode ? "#9ca3af" : "#666", flex: 1 }}>{de ? "Farbe" : "Color"}</span>
                <input
                    type="color"
                    value={list.color || "#6366f1"}
                    onChange={(e) => onChange({ color: e.target.value })}
                    style={{ width: "32px", height: "32px", border: "none", cursor: "pointer", padding: 0, borderRadius: "6px" }}
                />
                {list.color && (
                    <button
                        onClick={() => onChange({ color: null })}
                        title={de ? "Farbe entfernen" : "Remove color"}
                        style={{ background: "none", border: "none", cursor: "pointer", color: "#ef4444", padding: "2px" }}
                    >
                        <X size={12} />
                    </button>
                )}
            </div>
        </div>
    );
}

// Punkt 7 — popover for editing a tab's icon and color (stored in viewSettings JSON).
function TabVisualsPopover({
    tabName,
    visuals,
    darkMode,
    language,
    onChange,
    onRename,
    onDissolve,
    onClose,
    anchorRect,
}: {
    tabName: string;
    visuals: { color?: string; icon?: string };
    darkMode: boolean;
    language: string;
    anchorRect?: DOMRect | null;
    onChange: (updates: { color?: string | null; icon?: string | null }) => void;
    onRename: (newName: string) => void;
    onDissolve: () => void;
    onClose: () => void;
}) {
    const [iconPickerOpen, setIconPickerOpen] = useState(false);
    const [renameValue, setRenameValue] = useState(tabName);
    const containerRef = useRef<HTMLDivElement>(null);
    const onCloseRef = useRef(onClose);
    useEffect(() => { onCloseRef.current = onClose; }, [onClose]);
    useEffect(() => {
        const onDoc = (e: MouseEvent) => {
            if (containerRef.current && !containerRef.current.contains(e.target as Node)) onCloseRef.current();
        };
        document.addEventListener("mousedown", onDoc);
        return () => document.removeEventListener("mousedown", onDoc);
    }, []);
    const de = language === "de";
    const labelStyle = { fontSize: "0.75rem", color: darkMode ? "#9ca3af" : "#666", flex: 1 } as const;
    return (
        <div
            ref={containerRef}
            style={{
                position: "fixed",
                top: anchorRect ? anchorRect.bottom + 6 : -9999,
                left: anchorRect ? anchorRect.left : -9999,
                zIndex: 10000,
                background: darkMode ? "#1e1e2e" : "#fff",
                border: `1px solid ${darkMode ? "#444" : "#e5e7eb"}`,
                borderRadius: "10px",
                padding: "12px",
                boxShadow: "0 8px 24px rgba(0,0,0,0.18)",
                minWidth: "230px",
                display: "flex",
                flexDirection: "column",
                gap: "10px",
            }}
            onClick={(e) => e.stopPropagation()}
        >
            {/* Header */}
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
                <span style={{ fontSize: "0.78rem", fontWeight: 700, color: darkMode ? "#d1d5db" : "#333" }}>
                    {de ? "Tab bearbeiten" : "Edit tab"}
                </span>
                <button onClick={onClose} style={{ background: "none", border: "none", cursor: "pointer", color: darkMode ? "#9ca3af" : "#888", padding: "2px" }}>
                    <X size={14} />
                </button>
            </div>
            {/* Rename */}
            <div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
                <span style={labelStyle}>{de ? "Name" : "Name"}</span>
                <input
                    value={renameValue}
                    onChange={(e) => setRenameValue(e.target.value)}
                    onBlur={() => { if (renameValue.trim() && renameValue.trim() !== tabName) onRename(renameValue.trim()); }}
                    onKeyDown={(e) => { if (e.key === "Enter") { if (renameValue.trim() && renameValue.trim() !== tabName) onRename(renameValue.trim()); (e.target as HTMLInputElement).blur(); } }}
                    style={{ flex: 1, fontSize: "0.8rem", border: `1px solid ${darkMode ? "#444" : "#e5e7eb"}`, borderRadius: "6px", padding: "4px 8px", background: darkMode ? "#2a2a3a" : "#f9f9f9", color: darkMode ? "#e5e7eb" : "#222", outline: "none" }}
                />
            </div>
            {/* Icon */}
            <div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
                <span style={labelStyle}>{de ? "Icon" : "Icon"}</span>
                <button
                    onClick={() => setIconPickerOpen((v) => !v)}
                    style={{ width: "32px", height: "32px", borderRadius: "8px", border: `1px solid ${darkMode ? "#444" : "#e5e7eb"}`, background: darkMode ? "#2a2a3a" : "#fff", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}
                >
                    <ProjectIcon icon={visuals.icon} size={16} color={visuals.color || (darkMode ? "#d1d5db" : "#555")} />
                </button>
                {visuals.icon && (
                    <button onClick={() => onChange({ icon: null })} title={de ? "Icon entfernen" : "Remove icon"} style={{ background: "none", border: "none", cursor: "pointer", color: "#ef4444", padding: "2px" }}>
                        <X size={12} />
                    </button>
                )}
            </div>
            {iconPickerOpen && (
                <div style={{ position: "absolute", top: "110px", left: "10px", zIndex: 110 }}>
                    <IconPicker
                        selectedIcon={visuals.icon || ""}
                        onSelect={(name) => { onChange({ icon: name }); setIconPickerOpen(false); }}
                        darkMode={darkMode}
                    />
                </div>
            )}
            {/* Color */}
            <div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
                <span style={labelStyle}>{de ? "Farbe" : "Color"}</span>
                <input
                    type="color"
                    value={visuals.color || "#6366f1"}
                    onChange={(e) => onChange({ color: e.target.value })}
                    style={{ width: "32px", height: "32px", border: "none", cursor: "pointer", padding: 0, borderRadius: "6px" }}
                />
                {visuals.color && (
                    <button onClick={() => onChange({ color: null })} title={de ? "Farbe entfernen" : "Remove color"} style={{ background: "none", border: "none", cursor: "pointer", color: "#ef4444", padding: "2px" }}>
                        <X size={12} />
                    </button>
                )}
            </div>
            {/* Dissolve / delete */}
            <div style={{ borderTop: `1px solid ${darkMode ? "#374151" : "#e5e7eb"}`, paddingTop: "8px" }}>
                <button
                    onClick={() => { onDissolve(); onClose(); }}
                    style={{ width: "100%", display: "flex", alignItems: "center", gap: "8px", padding: "6px 8px", fontSize: "0.8rem", color: "#ef4444", background: "none", border: "none", cursor: "pointer", borderRadius: "6px", textAlign: "left" }}
                    onMouseEnter={(e) => (e.currentTarget.style.background = "rgba(239,68,68,0.08)")}
                    onMouseLeave={(e) => (e.currentTarget.style.background = "none")}
                >
                    <Trash2 size={13} />
                    {de ? "Tab auflösen (Listen bleiben)" : "Dissolve tab (lists stay)"}
                </button>
            </div>
        </div>
    );
}

// Projects Sidebar Component
const projectIconsGlobal: { name: string; icon: IconDefinition }[] = [
    { name: "folder", icon: faFolder }, { name: "briefcase", icon: faBriefcase },
    { name: "bullseye", icon: faBullseye }, { name: "rocket", icon: faRocket },
    { name: "star", icon: faStar }, { name: "lightbulb", icon: faLightbulb },
    { name: "fire", icon: faFire }, { name: "palette", icon: faPalette },
    { name: "music", icon: faMusic }, { name: "mobile", icon: faMobileScreen },
    { name: "laptop", icon: faLaptop }, { name: "globe", icon: faGlobe },
    { name: "house", icon: faHouse }, { name: "building", icon: faBuilding },
    { name: "chart-bar", icon: faChartBar }, { name: "chart-line", icon: faChartLine },
    { name: "wrench", icon: faWrench }, { name: "bolt", icon: faBolt },
    { name: "gamepad", icon: faGamepad }, { name: "pen", icon: faPen },
    { name: "book", icon: faBook }, { name: "graduation-cap", icon: faGraduationCap },
    { name: "flask", icon: faFlask }, { name: "microscope", icon: faMicroscope },
    { name: "dumbbell", icon: faDumbbell }, { name: "utensils", icon: faUtensils },
    { name: "plane", icon: faPlane }, { name: "leaf", icon: faLeaf },
    { name: "heart", icon: faHeart }, { name: "cart-shopping", icon: faCartShopping },
    { name: "coins", icon: faCoins }, { name: "gift", icon: faGift },
    { name: "camera", icon: faCamera }, { name: "film", icon: faFilm },
    { name: "broom", icon: faBroom }, { name: "paw", icon: faPaw },
    { name: "earth", icon: faEarthAmericas }, { name: "lock", icon: faLock },
    { name: "check", icon: faCheck }, { name: "code", icon: faCode },
    { name: "cube", icon: faCube }, { name: "users", icon: faUsers },
    { name: "car", icon: faCar }, { name: "mountain", icon: faMountain },
    { name: "umbrella", icon: faUmbrella }, { name: "clock", icon: faClock },
    { name: "tag", icon: faTag },
];

// Helper to render a project icon (FA name, MDI name, or legacy emoji)
function ProjectIcon({ icon, size = 18, color }: { icon?: string | null; size?: number; color?: string }) {
    if (!icon) return <FontAwesomeIcon icon={faFolder} style={{ fontSize: size, color }} />;
    // Normalise legacy "faHeart" → "heart" prefix style
    const normalised = icon.startsWith("fa") && icon.length > 2 && icon[2] === icon[2].toUpperCase()
        ? icon.slice(2, 3).toLowerCase() + icon.slice(3)
        : icon;
    // Check unified icon registry (FA + MDI)
    const found = allIcons.find((i) => i.name === normalised || i.name === icon);
    if (found) {
        if (found.type === "fa") {
            return <FontAwesomeIcon icon={found.icon as import("@fortawesome/free-solid-svg-icons").IconDefinition} style={{ fontSize: size, color }} />;
        }
        return <MdiIcon path={found.icon as string} size={size / 24} color={color} />;
    }
    // Legacy: check old projectIconsGlobal for backwards compat
    const legacy = projectIconsGlobal.find((i) => i.name === normalised || i.name === icon);
    if (legacy) return <FontAwesomeIcon icon={legacy.icon} style={{ fontSize: size, color }} />;
    // Legacy emoji fallback
    return <span style={{ fontSize: size, lineHeight: 1 }}>{icon}</span>;
}

function ProjectsSidebar({ darkMode, language, projects, onProjectsChanged, onClose, tasks, activeProjectFilter, onSetProjectFilter }: {
    darkMode: boolean;
    language: string;
    projects: { id: string; name: string; icon?: string | null; color?: string | null }[];
    onProjectsChanged: () => void;
    onClose: () => void;
    tasks: Task[];
    activeProjectFilter: string | null;
    onSetProjectFilter: (id: string | null) => void;
}) {
    const [newProjectName, setNewProjectName] = useState("");
    const [newProjectColor, setNewProjectColor] = useState("#3b82f6");
    const [newProjectIcon, setNewProjectIcon] = useState("folder");
    const [showNewIconPicker, setShowNewIconPicker] = useState(false);
    const [editingId, setEditingId] = useState<string | null>(null);
    const [editName, setEditName] = useState("");
    const [editColor, setEditColor] = useState("");
    const [editIcon, setEditIcon] = useState("folder");
    const [showEditIconPicker, setShowEditIconPicker] = useState(false);
    const [expandedProjects, setExpandedProjects] = useState<Set<string>>(new Set());

    const t = {
        projects: language === "de" ? "Projekte" : "Projects",
        desc: language === "de" ? "Aufgaben mit farbcodierten Projekten organisieren" : "Organize tasks with color-coded projects",
        noProjects: language === "de" ? "Noch keine Projekte erstellt" : "No projects yet",
        addProject: language === "de" ? "Projekt hinzufügen" : "Add Project",
        name: language === "de" ? "Name" : "Name",
        cancel: language === "de" ? "Abbrechen" : "Cancel",
        save: language === "de" ? "Speichern" : "Save",
        color: language === "de" ? "Farbe" : "Color",
        deleteConfirm: (name: string) => language === "de" ? `Projekt "${name}" löschen?` : `Delete project "${name}"?`,
        filterOnly: language === "de" ? "Nur dieses Projekt anzeigen" : "Show only this project",
        clearFilter: language === "de" ? "Filter aufheben" : "Clear filter",
        showTasks: language === "de" ? "Aufgaben einblenden" : "Show tasks",
        hideTasks: language === "de" ? "Aufgaben ausblenden" : "Hide tasks",
        noTasks: language === "de" ? "Keine Aufgaben" : "No tasks",
        filteringBy: language === "de" ? "Filter aktiv:" : "Filtering by:",
    };

    const tasksByProject = useMemo(() => {
        const map = new Map<string, Task[]>();
        tasks.forEach((task) => {
            if (!task.projectId || task.parentTaskId) return;
            const arr = map.get(task.projectId) || [];
            arr.push(task);
            map.set(task.projectId, arr);
        });
        return map;
    }, [tasks]);

    const toggleExpanded = (id: string) => {
        setExpandedProjects((prev) => {
            const next = new Set(prev);
            if (next.has(id)) next.delete(id);
            else next.add(id);
            return next;
        });
    };

    const createProject = () => {
        if (!newProjectName.trim()) return;
        fetch("/api/projects", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: newProjectName.trim(), color: newProjectColor, icon: newProjectIcon }) })
            .then(() => { onProjectsChanged(); setNewProjectName(""); setNewProjectIcon("folder"); });
    };

    const updateProject = (id: string) => {
        fetch("/api/projects", { method: "PATCH", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ id, name: editName, color: editColor, icon: editIcon }) })
            .then(() => { onProjectsChanged(); setEditingId(null); });
    };

    const deleteProject = (id: string, name: string) => {
        if (confirm(t.deleteConfirm(name))) {
            fetch(`/api/projects?id=${id}`, { method: "DELETE" }).then(() => onProjectsChanged());
        }
    };

    return (
        <>
            <div onClick={onClose} style={{ position: "fixed", inset: 0, zIndex: 999, background: "rgba(0,0,0,0.3)" }} />
            <div style={{
                position: "fixed", right: 0, top: 0, bottom: 0, width: "min(380px, 90vw)", zIndex: 1000,
                background: darkMode ? "#1e1e2e" : "#fff",
                borderLeft: `1px solid ${darkMode ? "#333" : "#e5e7eb"}`,
                display: "flex", flexDirection: "column",
                boxShadow: "-4px 0 24px rgba(0,0,0,0.12)",
            }}>
                {/* Header */}
                <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "16px 20px", borderBottom: `1px solid ${darkMode ? "#333" : "#e5e7eb"}` }}>
                    <h2 style={{ fontSize: "1.1rem", fontWeight: 700, display: "flex", alignItems: "center", gap: "8px", color: darkMode ? "#f0f0f0" : "#333" }}>
                        <FolderOpen size={20} /> {t.projects}
                    </h2>
                    <button onClick={onClose} style={{ background: "none", border: "none", cursor: "pointer", padding: "6px", color: darkMode ? "#9ca3af" : "#666", borderRadius: "6px" }}>
                        <X size={20} />
                    </button>
                </div>

                {/* Add project form — at top */}
                <div style={{ padding: "16px 20px", borderBottom: `1px solid ${darkMode ? "#333" : "#e5e7eb"}`, background: darkMode ? "#1e1e2e" : "#fff" }}>
                    <p style={{ fontSize: "0.8rem", fontWeight: 600, color: darkMode ? "#9ca3af" : "#888", marginBottom: "10px" }}>{t.addProject}</p>
                    <div style={{ display: "flex", gap: "8px", alignItems: "center" }}>
                        <div style={{ position: "relative" }}>
                            <button onClick={() => setShowNewIconPicker(!showNewIconPicker)} style={{ width: "40px", height: "40px", borderRadius: "10px", border: `1px solid ${darkMode ? "#555" : "#e5e7eb"}`, background: darkMode ? "#2a2a3a" : "#fff", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}>
                                <ProjectIcon icon={newProjectIcon} size={18} color={darkMode ? "#d1d5db" : "#555"} />
                            </button>
                            {showNewIconPicker && (
                                <div style={{ position: "absolute", top: "100%", left: 0, marginTop: "4px", zIndex: 50 }}>
                                    <IconPicker selectedIcon={newProjectIcon} onSelect={(name) => { setNewProjectIcon(name); setShowNewIconPicker(false); }} darkMode={darkMode} />
                                </div>
                            )}
                        </div>
                        <input type="color" value={newProjectColor} onChange={(e) => setNewProjectColor(e.target.value)} style={{ width: "32px", height: "32px", border: "none", cursor: "pointer", padding: 0, borderRadius: "8px" }} />
                        <input type="text" value={newProjectName} onChange={(e) => setNewProjectName(e.target.value)} placeholder={t.name} className="weekly-input" style={{ flex: 1, padding: "8px 12px", fontSize: "0.9rem" }} onKeyDown={(e) => { if (e.key === "Enter") createProject(); }} />
                        <button onClick={createProject} className="weekly-btn-primary" style={{ padding: "8px 16px", fontSize: "0.85rem", whiteSpace: "nowrap" }}>
                            <Plus size={14} /> {t.addProject}
                        </button>
                    </div>
                </div>

                {/* Active filter banner */}
                {activeProjectFilter && (
                    <div style={{ padding: "8px 20px", background: darkMode ? "#1e3a5f" : "#dbeafe", display: "flex", alignItems: "center", gap: "8px", fontSize: "0.8rem", color: darkMode ? "#bfdbfe" : "#1e40af" }}>
                        <Filter size={14} />
                        <span style={{ flex: 1 }}>
                            {t.filteringBy} {projects.find((p) => p.id === activeProjectFilter)?.name || ""}
                        </span>
                        <button onClick={() => onSetProjectFilter(null)} style={{ background: "none", border: "none", cursor: "pointer", color: darkMode ? "#bfdbfe" : "#1e40af", padding: "2px 6px", fontSize: "0.75rem", textDecoration: "underline" }}>
                            {t.clearFilter}
                        </button>
                    </div>
                )}

                {/* Scrollable content */}
                <div style={{ flex: 1, overflowY: "auto", padding: "16px 20px", display: "flex", flexDirection: "column", gap: "12px" }}>
                    <p style={{ fontSize: "0.8rem", color: darkMode ? "#9ca3af" : "#888" }}>{t.desc}</p>

                    {projects.length === 0 ? (
                        <div style={{ textAlign: "center", padding: "32px 16px" }}>
                            <div style={{ width: "56px", height: "56px", borderRadius: "50%", background: darkMode ? "#2a2a3a" : "#f3f4f6", display: "flex", alignItems: "center", justifyContent: "center", margin: "0 auto 12px" }}><ProjectIcon icon="folder" size={24} color={darkMode ? "#9ca3af" : "#999"} /></div>
                            <p style={{ fontSize: "0.9rem", color: "#aaa", fontStyle: "italic" }}>{t.noProjects}</p>
                        </div>
                    ) : (
                        projects.map((p) => {
                            const projectTasks = tasksByProject.get(p.id) || [];
                            const isExpanded = expandedProjects.has(p.id);
                            const isFiltered = activeProjectFilter === p.id;
                            return (
                                <div key={p.id} style={{ display: "flex", flexDirection: "column", borderRadius: "12px", background: darkMode ? "#2a2a3a" : "#f9fafb", borderLeft: `4px solid ${p.color || "#999"}`, outline: isFiltered ? `2px solid ${p.color || "#3b82f6"}` : "none" }}>
                                    <div style={{ display: "flex", alignItems: "center", gap: "10px", padding: "10px 14px" }}>
                                        {editingId === p.id ? (
                                            <div style={{ display: "flex", flexDirection: "column", gap: "10px", width: "100%" }}>
                                                <div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
                                                    <div style={{ position: "relative" }}>
                                                        <button onClick={() => setShowEditIconPicker(!showEditIconPicker)} style={{ width: "40px", height: "40px", borderRadius: "10px", border: `1px solid ${darkMode ? "#555" : "#e5e7eb"}`, background: darkMode ? "#1e1e2e" : "#fff", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center" }}>
                                                            <ProjectIcon icon={editIcon} size={18} color={darkMode ? "#d1d5db" : "#555"} />
                                                        </button>
                                                        {showEditIconPicker && (
                                                            <div style={{ position: "absolute", top: "100%", left: 0, marginTop: "4px", zIndex: 50 }}>
                                                                <IconPicker selectedIcon={editIcon} onSelect={(name) => { setEditIcon(name); setShowEditIconPicker(false); }} darkMode={darkMode} />
                                                            </div>
                                                        )}
                                                    </div>
                                                    <input type="text" value={editName} onChange={(e) => setEditName(e.target.value)} className="weekly-input" style={{ flex: 1, padding: "8px 12px", fontSize: "0.9rem" }} onKeyDown={(e) => { if (e.key === "Enter") updateProject(p.id); if (e.key === "Escape") setEditingId(null); }} autoFocus />
                                                </div>
                                                <div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
                                                    <input type="color" value={editColor} onChange={(e) => setEditColor(e.target.value)} style={{ width: "32px", height: "32px", border: "none", cursor: "pointer", padding: 0, borderRadius: "8px" }} />
                                                    <span style={{ fontSize: "0.8rem", color: darkMode ? "#9ca3af" : "#888" }}>{t.color}</span>
                                                    <div style={{ flex: 1 }} />
                                                    <button onClick={() => setEditingId(null)} style={{ padding: "6px 14px", fontSize: "0.8rem", background: "none", border: `1px solid ${darkMode ? "#555" : "#ddd"}`, borderRadius: "8px", cursor: "pointer", color: darkMode ? "#9ca3af" : "#666" }}>{t.cancel}</button>
                                                    <button onClick={() => updateProject(p.id)} className="weekly-btn-primary" style={{ padding: "6px 14px", fontSize: "0.8rem" }}><Check size={14} /> {t.save}</button>
                                                </div>
                                            </div>
                                        ) : (
                                            <>
                                                <button onClick={() => toggleExpanded(p.id)} style={{ background: "none", border: "none", cursor: "pointer", padding: "2px", color: darkMode ? "#9ca3af" : "#6b7280", display: "flex", alignItems: "center" }} title={isExpanded ? t.hideTasks : t.showTasks}>
                                                    {isExpanded ? <ChevronDown size={16} /> : <ChevronRight size={16} />}
                                                </button>
                                                <ProjectIcon icon={p.icon} size={20} color={p.color || "#999"} />
                                                <div style={{ flex: 1, minWidth: 0 }}>
                                                    <span style={{ fontSize: "0.9rem", fontWeight: 600, display: "block", color: darkMode ? "#f0f0f0" : "#333" }}>{p.name}</span>
                                                    <span style={{ fontSize: "0.7rem", color: darkMode ? "#9ca3af" : "#888" }}>{projectTasks.length}</span>
                                                </div>
                                                <button onClick={() => onSetProjectFilter(isFiltered ? null : p.id)} style={{ padding: "6px", opacity: isFiltered ? 1 : 0.5, cursor: "pointer", background: isFiltered ? (darkMode ? "#3b3b5f" : "#e0e7ff") : "none", border: "none", borderRadius: "6px", color: isFiltered ? (p.color || "#3b82f6") : (darkMode ? "#ccc" : "#333") }} title={isFiltered ? t.clearFilter : t.filterOnly}>
                                                    <Filter size={15} />
                                                </button>
                                                <button onClick={() => { setEditingId(p.id); setEditName(p.name); setEditColor(p.color || "#999"); setEditIcon(p.icon || "folder"); setShowEditIconPicker(false); }} style={{ padding: "6px", opacity: 0.5, cursor: "pointer", background: "none", border: "none", borderRadius: "6px", color: darkMode ? "#ccc" : "#333" }} title="Edit">
                                                    <Pencil size={15} />
                                                </button>
                                                <button onClick={() => deleteProject(p.id, p.name)} style={{ padding: "6px", opacity: 0.5, cursor: "pointer", color: "#ef4444", background: "none", border: "none", borderRadius: "6px" }} title="Delete">
                                                    <Trash2 size={15} />
                                                </button>
                                            </>
                                        )}
                                    </div>
                                    {isExpanded && editingId !== p.id && (
                                        <div style={{ padding: "0 14px 12px 38px", display: "flex", flexDirection: "column", gap: "4px" }}>
                                            {projectTasks.length === 0 ? (
                                                <span style={{ fontSize: "0.8rem", color: darkMode ? "#6b7280" : "#9ca3af", fontStyle: "italic" }}>{t.noTasks}</span>
                                            ) : (
                                                projectTasks.map((task) => (
                                                    <div key={task.id} style={{ fontSize: "0.82rem", color: darkMode ? "#d1d5db" : "#374151", padding: "3px 6px", borderRadius: "4px", textDecoration: task.completed ? "line-through" : "none", opacity: task.completed ? 0.6 : 1, display: "flex", alignItems: "center", gap: "6px" }}>
                                                        <span style={{ width: "6px", height: "6px", borderRadius: "50%", background: p.color || "#999", flexShrink: 0 }} />
                                                        <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{task.title}</span>
                                                    </div>
                                                ))
                                            )}
                                        </div>
                                    )}
                                </div>
                            );
                        })
                    )}
                </div>
            </div>
        </>
    );
}

// Notes Sidebar Component
interface NotesSidebarProps {
    task: Task;
    onClose: () => void;
    updateTaskNotes: (id: string, notes: string) => void;
    updateTaskUrl: (id: string, url: string) => void;
}

function NotesSidebar({ task, onClose, updateTaskNotes, updateTaskUrl }: NotesSidebarProps) {
    const [isVisible, setIsVisible] = useState(false);
    const [sidebarWidth, setSidebarWidth] = useState(500);
    const [urlValue, setUrlValue] = useState(task.url || "");
    const isResizing = useRef(false);

    useEffect(() => { setUrlValue(task.url || ""); }, [task.url]);

    useEffect(() => {
        const handleMouseMove = (e: MouseEvent) => {
            if (!isResizing.current) return;
            const newWidth = window.innerWidth - e.clientX;
            setSidebarWidth(Math.max(320, Math.min(newWidth, window.innerWidth * 0.9)));
        };
        const handleMouseUp = () => {
            if (isResizing.current) {
                isResizing.current = false;
                document.body.style.cursor = '';
                document.body.style.userSelect = '';
            }
        };
        window.addEventListener('mousemove', handleMouseMove);
        window.addEventListener('mouseup', handleMouseUp);
        return () => {
            window.removeEventListener('mousemove', handleMouseMove);
            window.removeEventListener('mouseup', handleMouseUp);
        };
    }, []);

    useEffect(() => {
        const timer = setTimeout(() => setIsVisible(true), 10);
        return () => clearTimeout(timer);
    }, []);

    const handleClose = () => {
        setIsVisible(false);
        setTimeout(onClose, 300);
    };

    const handleUrlBlur = () => {
        const normalised = urlValue.trim()
            ? urlValue.trim().startsWith("http") ? urlValue.trim() : `https://${urlValue.trim()}`
            : "";
        if (normalised !== (task.url || "")) {
            updateTaskUrl(task.id, normalised);
        }
    };

    return (
        <>
            <div
                className={`weekly-modal-overlay ${isVisible ? "show" : ""}`}
                onClick={handleClose}
                style={{ zIndex: 1999 }}
            />
            <div className={`weekly-notes-sidebar ${isVisible ? "open" : ""}`} style={{ width: `${sidebarWidth}px` }}>
                {/* Resize handle */}
                <div
                    onMouseDown={(e) => {
                        e.preventDefault();
                        isResizing.current = true;
                        document.body.style.cursor = 'col-resize';
                        document.body.style.userSelect = 'none';
                    }}
                    style={{
                        position: 'absolute',
                        left: 0,
                        top: 0,
                        bottom: 0,
                        width: '6px',
                        cursor: 'col-resize',
                        zIndex: 10,
                    }}
                    title="Drag to resize"
                />
                <header className="weekly-notes-sidebar-header">
                    <h2 className="weekly-notes-sidebar-title">Notes: {task.title}</h2>
                    <button className="weekly-notes-sidebar-close" onClick={handleClose}>
                        ×
                    </button>
                </header>
                <div className="weekly-notes-sidebar-content">
                    {/* URL field */}
                    <div style={{ marginBottom: "12px" }}>
                        <label style={{ display: "block", fontSize: "0.7rem", fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.05em", color: "var(--weekly-text-muted, #999)", marginBottom: "4px" }}>
                            Link
                        </label>
                        <div style={{ display: "flex", alignItems: "center", gap: "6px" }}>
                            <input
                                type="url"
                                value={urlValue}
                                onChange={(e) => setUrlValue(e.target.value)}
                                onBlur={handleUrlBlur}
                                onKeyDown={(e) => { if (e.key === "Enter") (e.target as HTMLInputElement).blur(); }}
                                placeholder="https://..."
                                style={{ flex: 1, fontSize: "0.82rem", border: "1px solid var(--weekly-border, #ddd)", borderRadius: "4px", padding: "5px 8px", background: "var(--weekly-bg, white)", color: "var(--weekly-text, #333)", outline: "none" }}
                            />
                            {urlValue && (
                                <button
                                    onClick={() => { setUrlValue(""); updateTaskUrl(task.id, ""); }}
                                    title="Remove link"
                                    style={{ background: "none", border: "none", cursor: "pointer", color: "#999", padding: "4px" }}
                                >
                                    <svg viewBox="0 0 24 24" width="13" height="13" stroke="currentColor" strokeWidth="2.5" fill="none" strokeLinecap="round" strokeLinejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
                                </button>
                            )}
                            {urlValue && (
                                <a
                                    href={urlValue.startsWith("http") ? urlValue : `https://${urlValue}`}
                                    target="_blank"
                                    rel="noopener noreferrer"
                                    title="Open link"
                                    style={{ color: "#2563eb", display: "inline-flex", padding: "4px" }}
                                >
                                    <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
                                        <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
                                        <polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/>
                                    </svg>
                                </a>
                            )}
                        </div>
                    </div>

                    {/* Notes */}
                    <div>
                        <label style={{ display: "block", fontSize: "0.7rem", fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.05em", color: "var(--weekly-text-muted, #999)", marginBottom: "4px" }}>
                            Notes
                        </label>
                        <RichTextEditor
                            value={task.markdownContent || ""}
                            onChange={(html) => updateTaskNotes(task.id, html)}
                            placeholder="Add details, notes, or links..."
                            minHeight="300px"
                        />
                    </div>

                    <div className="weekly-modal-actions" style={{ marginTop: '24px' }}>
                        <button
                            className="weekly-btn weekly-btn-secondary"
                            onClick={handleClose}
                            style={{ width: '100%' }}
                        >
                            Close
                        </button>
                    </div>
                </div>
            </div>
        </>
    );
}


