"use client";

import { keepPreviousData, useInfiniteQuery, useMutation, useQueries, useQuery, useQueryClient } from "@tanstack/react-query";
import type { InfiniteData } from "@tanstack/react-query";
import clsx from "clsx";
import {
  Archive,
  ArrowDownUp,
  Bold,
  Check,
  CheckCheck,
  Download,
  FileArchive,
  FileImage,
  FilePenLine,
  FileSpreadsheet,
  Folder as FolderIcon,
  FolderSymlink,
  Inbox,
  LogOut,
  MailOpen,
  Mail,
  MailPlus,
  Italic,
  Languages,
  Link,
  List,
  Palette,
  Pencil,
  RefreshCw,
  Search,
  Send,
  Share2,
  Music2,
  MoreHorizontal,
  ShieldAlert,
  ShieldCheck,
  Star,
  SlidersHorizontal,
  Trash2,
  Upload,
  UserPlus,
  UserRound,
  Users,
  Video,
  X,
  AlertTriangle,
  CircleAlert,
  CalendarDays,
  ChevronDown,
  ChevronLeft,
  Clock3,
  ChevronRight,
  ChevronUp,
  Forward,
  MapPin,
  Menu,
  Plus,
  Reply,
  ReplyAll,
  Printer,
  FileText,
  Filter,
  Paperclip,
  ListTodo,
  Underline,
  Tag as TagIcon,
} from "lucide-react";
import { ChangeEvent, useEffect, useMemo, useRef, useState } from "react";
import type { MouseEvent as ReactMouseEvent, ReactNode } from "react";
import type { CSSProperties } from "react";
import { createPortal } from "react-dom";
import dynamic from "next/dynamic";
import QRCode from "qrcode";
import packageJson from "../package.json";
import { api } from "@/lib/api";
import { useBranding } from "@/lib/branding";
import { isGoogleAddonEdition, isNativeZimbraAddonEdition, normalizeProductEdition } from "@/lib/editions";
import { resolveProductTierLabelKey } from "@/lib/product-tier-labels";
import { googleDriveAttachmentLabel, googleDriveDownloadUrl, googleDriveOpenUrl, isGoogleDriveMimeType } from "@/lib/addons/google";
import { buildDriveFolderTree, findDriveFolderBreadcrumbs, findDriveFolderParentId, findDriveFolderPath } from "@/lib/addons/google-drive-tree";
import { resolveWebmailHost, siteConfig } from "@/lib/site-config";
import { DEFAULT_TIME_ZONE } from "@/lib/time-zone";
import { DEFAULT_LOCALE, createTranslator, localeOptions, normalizeLocale, type AppLocale, type TranslationKey } from "@/lib/i18n";
import type { CalendarEvent, CalendarReminderNotification, CalendarSource, CalendarStatus, Contact, ContactFolder, DriveFile, DriveStatus, Folder, MailFilterRule, MailMigrationConnectionResult, MailMigrationJob, MailQuota, MailSignature, MessageDetail, MessagePage, MessageSummary, NativeZimbraShareEntry, NativeZimbraTaskList, SavedSearch, ShareNotification, Tag } from "@/lib/types";
import { ComposeDialog } from "./compose-dialog";
import { LoginScreen } from "./login-screen";
import { BrandLogo } from "./brand-logo";
import { BrowserExitGuard } from "./browser-exit-guard";
import { GoogleTasksTab } from "./google-tasks-tab";
import { NativeZimbraTasksAddonTab } from "./native-zimbra-tasks-tab";
import { ShareRecipientAutocomplete } from "./share-recipient-autocomplete";
import { ContactAvatar } from "./contact-avatar";
import type { ComposeSeed } from "@/lib/types";

type ThemeName = "cyan" | "graphite" | "golden" | "rose" | "amber" | "indigo" | "mint" | "sunset";
type FontScale = "compact" | "comfortable" | "large";
type MessageSortOrder = "newest" | "oldest";

type AdvancedMailSearch = {
  keywords: string;
  from: string;
  to: string;
  subject: string;
  after: string;
  before: string;
  hasAttachments: boolean;
  unreadOnly: boolean;
};

const emptyAdvancedMailSearch: AdvancedMailSearch = {
  keywords: "",
  from: "",
  to: "",
  subject: "",
  after: "",
  before: "",
  hasAttachments: false,
  unreadOnly: false,
};

type Preferences = {
  theme: ThemeName;
  fontScale: FontScale;
  timeZone: string;
  locale: AppLocale;
};

type MailSelectionItem = {
  key: string;
  uid: string;
  source: string;
};

type FolderMenuState = {
  folder: Folder;
  x: number;
  y: number;
};

type MenuPosition = {
  left: number;
  top: number;
};

type TagEditorState = {
  mode: "create" | "edit";
  tag?: Tag;
};

type FolderEditorState = {
  folder: Folder;
};

type FolderShareState = {
  folder: Folder;
  email: string;
  permissions: string;
};

type BriefcaseShareState = {
  folderId: string;
  folderName: string;
};

type ConfirmDialogState = {
  title: string;
  message: string;
  confirmLabel: string;
  tone?: "default" | "danger";
  onConfirm: () => void | Promise<void>;
};

type AttachmentSavePickerState = {
  uid: string;
  folder: string;
  parts: string[];
};

type DriveUploadPickerState = {
  files: File[];
};

type ReaderRenderCache = {
  html: string;
  text: string;
  preview: string;
  attachments: string;
  htmlBody: string;
  visibleAttachmentKey: string;
  visibleAttachments: MessageDetail["attachments"];
  plainTextBody: string;
  renderedReaderHtml: string;
  canRenderHtml: boolean;
};

const readerRenderCache = new Map<string, ReaderRenderCache>();

type CalendarNotice = {
  tone: "success" | "error" | "info";
  message: string;
};

type CalendarEventDraft = {
  summary: string;
  allDay: boolean;
  startDate: string;
  endDate: string;
  startTime: string;
  endTime: string;
  location: string;
  description: string;
};

const fallbackTimeZoneValues = [
  "Africa/Abidjan",
  "Africa/Cairo",
  "Africa/Casablanca",
  "Africa/Johannesburg",
  "Africa/Lagos",
  "Africa/Nairobi",
  "America/Anchorage",
  "America/Argentina/Buenos_Aires",
  "America/Bogota",
  "America/Caracas",
  "America/Chicago",
  "America/Denver",
  "America/Los_Angeles",
  "America/Mexico_City",
  "America/New_York",
  "America/Phoenix",
  "America/Santiago",
  "America/Sao_Paulo",
  "America/St_Johns",
  "America/Toronto",
  "America/Vancouver",
  "Asia/Amman",
  "Asia/Bahrain",
  DEFAULT_TIME_ZONE,
  "Asia/Colombo",
  "Asia/Dhaka",
  "Asia/Dubai",
  "Asia/Ho_Chi_Minh",
  "Asia/Hong_Kong",
  "Asia/Jakarta",
  "Asia/Jerusalem",
  "Asia/Karachi",
  "Asia/Kathmandu",
  "Asia/Kolkata",
  "Asia/Kuala_Lumpur",
  "Asia/Manila",
  "Asia/Riyadh",
  "Asia/Seoul",
  "Asia/Shanghai",
  "Asia/Singapore",
  "Asia/Taipei",
  "Asia/Tokyo",
  "Asia/Yangon",
  "Atlantic/Reykjavik",
  "Australia/Adelaide",
  "Australia/Brisbane",
  "Australia/Darwin",
  "Australia/Melbourne",
  "Australia/Perth",
  "Australia/Sydney",
  "Europe/Amsterdam",
  "Europe/Athens",
  "Europe/Berlin",
  "Europe/Brussels",
  "Europe/Helsinki",
  "Europe/Istanbul",
  "Europe/Lisbon",
  "Europe/London",
  "Europe/Madrid",
  "Europe/Moscow",
  "Europe/Paris",
  "Europe/Rome",
  "Europe/Stockholm",
  "Europe/Zurich",
  "Pacific/Auckland",
  "Pacific/Fiji",
  "Pacific/Guam",
  "Pacific/Honolulu",
  "Pacific/Tongatapu",
  "UTC",
] as const;

const defaultPreferences: Preferences = {
  theme: "cyan",
  fontScale: "comfortable",
  timeZone: DEFAULT_TIME_ZONE,
  locale: "en-US",
};

const fontScaleOptions: FontScale[] = ["compact", "comfortable", "large"];

function isThemeName(value: string): value is ThemeName {
  return value in themes;
}

function normalizeThemeName(value: string, fallback: ThemeName): ThemeName {
  const normalized = value.trim().toLowerCase();
  if (normalized === "emerald") return "golden";
  return isThemeName(normalized) ? normalized : fallback;
}

function isFontScale(value: string): value is FontScale {
  return fontScaleOptions.includes(value as FontScale);
}

function supportedTimeZoneValues() {
  if (typeof Intl === "undefined") return [...fallbackTimeZoneValues];
  const supportedValuesOf = (Intl as typeof Intl & { supportedValuesOf?: (key: string) => string[] }).supportedValuesOf;
  try {
    const values = supportedValuesOf?.call(Intl, "timeZone") ?? [];
    return values.length ? values : [...fallbackTimeZoneValues];
  } catch {
    return [...fallbackTimeZoneValues];
  }
}

function isValidTimeZone(value: string) {
  const clean = value.trim();
  if (!clean) return false;
  if (clean === "UTC") return true;
  try {
    new Intl.DateTimeFormat("en-US", { timeZone: clean }).format(new Date());
    return true;
  } catch {
    return false;
  }
}

function normalizeTimeZone(value?: string | null) {
  const clean = (value || "").trim();
  return isValidTimeZone(clean) ? clean : DEFAULT_TIME_ZONE;
}

function formatTimeZoneName(value: string) {
  if (value === "UTC") return "UTC";
  const parts = value.split("/");
  const city = (parts[parts.length - 1] || value).replace(/_/g, " ");
  const region = parts.length > 1 ? parts[0].replace(/_/g, " ") : "";
  return region ? `${city} - ${region}` : city;
}

function timeZoneOffsetLabel(value: string) {
  if (value === "UTC") return "GMT+00:00";
  try {
    const date = new Date();
    const part = new Intl.DateTimeFormat("en-US", {
      timeZone: value,
      timeZoneName: "longOffset",
      hour: "2-digit",
      minute: "2-digit",
      hour12: false,
    }).formatToParts(date).find((item) => item.type === "timeZoneName")?.value;
    return part && part !== "GMT" ? part : "GMT+00:00";
  } catch {
    return "GMT+00:00";
  }
}

function buildTimeZoneOptions() {
  const uniqueValues = Array.from(new Set([DEFAULT_TIME_ZONE, ...supportedTimeZoneValues()])).filter(isValidTimeZone);
  return uniqueValues
    .map((value) => ({
      value,
      label: `(${timeZoneOffsetLabel(value)}) ${formatTimeZoneName(value)}`,
    }))
    .sort((a, b) => {
      if (a.value === DEFAULT_TIME_ZONE) return -1;
      if (b.value === DEFAULT_TIME_ZONE) return 1;
      return a.label.localeCompare(b.label);
    });
}

function formatBuildLabel(version: string, buildId: string) {
  if (buildId) return `${version} (${buildId.slice(0, 8)})`;
  return version;
}

function formatProductTierLabel(tier: string | undefined, edition: string, t: ReturnType<typeof createTranslator>) {
  const labelKey = resolveProductTierLabelKey(tier, edition);
  return t(labelKey);
}

function formatBuildTime(value: string) {
  if (!value) return "Unknown";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "Unknown";
  return new Intl.DateTimeFormat("en-GB", {
    dateStyle: "medium",
    timeStyle: "short",
    hour12: false,
  }).format(date);
}

function calendarDisplayLocale(locale: AppLocale) {
  return `${locale}-u-ca-gregory`;
}

function formatCalendarReminderLabel(reminder: CalendarReminderNotification, locale: AppLocale) {
  const event = reminder.event;
  const timeZone = event.time_zone || DEFAULT_TIME_ZONE;
  const displayLocale = calendarDisplayLocale(locale);
  if (event.all_day) {
    const date = new Date(`${event.start.slice(0, 10)}T00:00:00`);
    if (Number.isNaN(date.getTime())) return "All day";
    return `${new Intl.DateTimeFormat(displayLocale, { dateStyle: "medium" }).format(date)} • All day`;
  }
  const start = new Date(event.start);
  if (Number.isNaN(start.getTime())) return event.start || "Reminder";
  return new Intl.DateTimeFormat(displayLocale, {
    dateStyle: "medium",
    timeStyle: "short",
    timeZone,
  }).format(start);
}

const GoogleCalendarAddonTab = dynamic(
  () => import("@/components/google-calendar-tab").then((module) => module.GoogleCalendarTab),
  {
    ssr: false,
    loading: () => <div className="control-surface min-h-12 rounded-xl p-4" aria-busy="true" />,
  }
);

const NativeZimbraCalendarAddonTab = dynamic(
  () => import("@/components/native-zimbra-calendar-tab").then((module) => module.NativeZimbraCalendarTab),
  {
    ssr: false,
    loading: () => <div className="control-surface min-h-12 rounded-xl p-4" aria-busy="true" />,
  }
);

const DriveFolderTree = dynamic(
  () => import("@/components/google-drive-tree").then((module) => module.DriveFolderTree),
  {
    ssr: false,
    loading: () => <div className="min-h-10 p-3" aria-busy="true" />,
  }
);

function mapMessagePages(
  data: InfiniteData<MessagePage> | undefined,
  transform: (message: MessageSummary) => MessageSummary | null
): InfiniteData<MessagePage> | undefined {
  if (!data) return data;
  return {
    ...data,
    pages: data.pages.map((page) => ({
      ...page,
      messages: page.messages.flatMap((message) => {
        const next = transform(message);
        return next ? [next] : [];
      })
    }))
  };
}

function updateMessagePages(
  data: InfiniteData<MessagePage> | undefined,
  update: (message: MessageSummary) => MessageSummary
): InfiniteData<MessagePage> | undefined {
  return mapMessagePages(data, (message) => update(message));
}

function normalizeMessageContent(value: string): string {
  return value
    .replace(/<style[\s\S]*?<\/style>/gi, " ")
    .replace(/<script[\s\S]*?<\/script>/gi, " ")
    .replace(/<[^>]+>/g, " ")
    .replace(/&nbsp;/gi, " ")
    .replace(/\s+/g, " ")
    .trim();
}

function detailLooksPreviewOnly(
  message:
    | Pick<MessageDetail, "html" | "text" | "preview">
    | MessageDetail["conversation_messages"][number]
    | undefined
): boolean {
  if (!message) return true;
  const preview = normalizeMessageContent(message.preview || "");
  const text = normalizeMessageContent(message.text || "");
  const html = normalizeMessageContent(message.html || "");
  const body = text || html;
  if (!body) return true;
  if (!preview) return false;
  const veryCloseLength = Math.abs(body.length - preview.length) <= 80;
  return veryCloseLength && (body === preview || body.startsWith(preview) || preview.startsWith(body));
}

const timeZoneOptions = buildTimeZoneOptions();

const themes: Record<ThemeName, { accent: string; active: string; shell: string; name: string; description: string; preview: string }> = {
  cyan: {
    accent: "#0891b2",
    active: "bg-cyan-50 text-cyan-800 border-cyan-200",
    shell: "from-slate-50 via-cyan-50 to-lime-50",
    name: "Coastal",
    description: "Clean sea-glass blue for a light, calm workspace.",
    preview: "bg-gradient-to-br from-cyan-500 via-sky-400 to-teal-300"
  },
  graphite: {
    accent: "#334155",
    active: "bg-[color-mix(in_srgb,#1e3a8a_7%,white)] text-slate-700 border-[color-mix(in_srgb,#1e3a8a_22%,white)] shadow-sm",
    shell: "from-zinc-50 via-slate-50 to-stone-50",
    name: "Graphite",
    description: "Neutral charcoal with restrained contrast.",
    preview: "bg-gradient-to-br from-slate-700 via-slate-500 to-slate-300"
  },
  golden: {
    accent: "#d99a00",
    active: "bg-yellow-50 text-yellow-900 border-yellow-200",
    shell: "from-slate-50 via-yellow-50 to-amber-50",
    name: "Golden",
    description: "Soft honey yellow with a warm, focused tone.",
    preview: "bg-gradient-to-br from-yellow-400 via-amber-300 to-lime-100"
  },
  rose: {
    accent: "#ec4899",
    active: "bg-pink-50 text-pink-800 border-pink-200",
    shell: "from-slate-50 via-pink-50 to-rose-50",
    name: "Pink",
    description: "Soft pink with a warmer conversational feel.",
    preview: "bg-gradient-to-br from-pink-500 via-rose-400 to-fuchsia-300"
  },
  indigo: {
    accent: "#4f46e5",
    active: "bg-indigo-50 text-indigo-800 border-indigo-200",
    shell: "from-slate-50 via-indigo-50 to-sky-50",
    name: "Indigo",
    description: "Violet-blue for a sharper editorial edge.",
    preview: "bg-gradient-to-br from-indigo-600 via-indigo-500 to-sky-400"
  },
  amber: {
    accent: "#1e3a8a",
    active: "bg-[color-mix(in_srgb,var(--accent)_10%,white)] text-[#1e3a8a] border-[color-mix(in_srgb,var(--accent)_28%,white)] shadow-sm",
    shell: "from-[#eef3ff] via-[#f7f9ff] to-[#e6edff]",
    name: "Midnight",
    description: "Deep navy with a quiet, focused surface.",
    preview: "bg-gradient-to-br from-[#081534] via-[#122a63] to-[#2647a3]"
  },
  mint: {
    accent: "#0f766e",
    active: "bg-teal-50 text-teal-800 border-teal-200",
    shell: "from-slate-50 via-teal-50 to-emerald-50",
    name: "Mint",
    description: "Cool teal with a quieter utility feel.",
    preview: "bg-gradient-to-br from-teal-600 via-teal-500 to-emerald-300"
  },
  sunset: {
    accent: "#ea580c",
    active: "bg-orange-50 text-orange-800 border-orange-200",
    shell: "from-rose-50 via-orange-50 to-amber-50",
    name: "Sunset",
    description: "Warm orange for a more energetic surface.",
    preview: "bg-gradient-to-br from-orange-500 via-amber-400 to-rose-300"
  }
};

const themeOrder: ThemeName[] = ["graphite", "cyan", "golden", "rose", "amber", "indigo", "mint", "sunset"];

const tagColorOptions = [
  { value: 0, label: "Blue", hex: "#60a5fa" },
  { value: 2, label: "Cyan", hex: "#22d3ee" },
  { value: 3, label: "Green", hex: "#4ade80" },
  { value: 4, label: "Purple", hex: "#a78bfa" },
  { value: 5, label: "Red", hex: "#fb7185" },
  { value: 6, label: "Yellow", hex: "#facc15" },
  { value: 7, label: "Pink", hex: "#f472b6" },
  { value: 8, label: "Gray", hex: "#94a3b8" },
  { value: 9, label: "Orange", hex: "#fb923c" }
] as const;

const folderColorOptions = [
  { value: 1, label: "Blue", hex: "#60a5fa" },
  { value: 2, label: "Cyan", hex: "#22d3ee" },
  { value: 3, label: "Green", hex: "#4ade80" },
  { value: 4, label: "Purple", hex: "#a78bfa" },
  { value: 5, label: "Red", hex: "#fb7185" },
  { value: 6, label: "Yellow", hex: "#facc15" },
  { value: 7, label: "Pink", hex: "#f472b6" },
  { value: 8, label: "Gray", hex: "#94a3b8" },
  { value: 9, label: "Orange", hex: "#fb923c" },
] as const;

const MESSAGE_PAGE_SIZE = 30;

type MailWorkspaceProps = {
  tenantDomain?: string;
  entryDomain?: string;
};

export function MailWorkspace({ tenantDomain = "", entryDomain = resolveWebmailHost() }: MailWorkspaceProps) {
  const queryClient = useQueryClient();
  const me = useQuery({ queryKey: ["me"], queryFn: api.me, retry: false });
  const appConfig = useQuery({
    queryKey: ["app-config", tenantDomain],
    queryFn: () => api.config(tenantDomain),
    staleTime: 0,
    refetchOnMount: "always",
    refetchOnWindowFocus: true,
    retry: false,
  });
  const accountScope = me.data?.email?.trim().toLowerCase() || "";
  const accountProfile = useQuery({
    queryKey: ["account-profile", accountScope],
    queryFn: api.accountProfile,
    enabled: Boolean(accountScope),
    staleTime: 30_000,
  });
  const workspaceFiltersQueryKey = useMemo(() => ["workspace-filters", accountScope], [accountScope]);
  const [folder, setFolder] = useState("INBOX");
  const [selectedUid, setSelectedUid] = useState<string | null>(null);
  const [selectedFolder, setSelectedFolder] = useState("INBOX");
  const [selectedDetailTarget, setSelectedDetailTarget] = useState<{ folder: string; uid: string; view: "message" | "conversation" } | null>(null);
  const [selectedThreadUid, setSelectedThreadUid] = useState<string | null>(null);
  const [selectedThreadDetailTarget, setSelectedThreadDetailTarget] = useState<{ folder: string; uid: string } | null>(null);
  const [selectedThreadSummary, setSelectedThreadSummary] = useState<MessageSummary | null>(null);
  const [expandedConversationId, setExpandedConversationId] = useState("");
  const [conversationExpandOnly, setConversationExpandOnly] = useState(false);
  const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
  const [lastSelectedIndex, setLastSelectedIndex] = useState<number | null>(null);
  const [search, setSearch] = useState("");
  const [globalSearch, setGlobalSearch] = useState(false);
  const [advancedSearchOpen, setAdvancedSearchOpen] = useState(false);
  const [advancedSearch, setAdvancedSearch] = useState<AdvancedMailSearch>(emptyAdvancedMailSearch);
  const [savedSearchName, setSavedSearchName] = useState("");
  const [messageSortOrder, setMessageSortOrder] = useState<MessageSortOrder>("newest");
  const [newFolderName, setNewFolderName] = useState("");
  const [folderMenu, setFolderMenu] = useState<FolderMenuState | null>(null);
  const [folderEditor, setFolderEditor] = useState<FolderEditorState | null>(null);
  const [folderShareEditor, setFolderShareEditor] = useState<FolderShareState | null>(null);
  const [confirmDialog, setConfirmDialog] = useState<ConfirmDialogState | null>(null);
  const [attachmentSavePicker, setAttachmentSavePicker] = useState<AttachmentSavePickerState | null>(null);
  const [driveUploadPicker, setDriveUploadPicker] = useState<DriveUploadPickerState | null>(null);
  const [tagMenuPosition, setTagMenuPosition] = useState<MenuPosition | null>(null);
  const [tagEditor, setTagEditor] = useState<TagEditorState | null>(null);
  const [originalOpen, setOriginalOpen] = useState(false);
  const [listWidth, setListWidth] = useState(560);
  const [activeSection, setActiveSection] = useState<"email" | "contacts" | "calendar" | "tasks" | "drive" | "preferences">("email");
  const [composeOpen, setComposeOpen] = useState(false);
  const [settingsTab, setSettingsTab] = useState<"preferences" | "information" | "sharing" | "account" | "security" | "signature" | "filters" | "import" | "migration" | "ooo">("preferences");
  const [replyTo, setReplyTo] = useState<ComposeSeed>();
  const [calendarNotice, setCalendarNotice] = useState<CalendarNotice | null>(null);
  const [calendarInviteResponses, setCalendarInviteResponses] = useState<Record<string, "accepted" | "tentative" | "declined">>({});
  const [handledReadReceipts, setHandledReadReceipts] = useState<Record<string, boolean>>({});
  const [calendarFocusEventId, setCalendarFocusEventId] = useState("");
  const [visibleCalendarReminders, setVisibleCalendarReminders] = useState<CalendarReminderNotification[]>([]);
  const [driveNotice, setDriveNotice] = useState<CalendarNotice | null>(null);
  const [driveSearch, setDriveSearch] = useState("");
  const [driveFolderSearch, setDriveFolderSearch] = useState("");
  const [driveNewFolderName, setDriveNewFolderName] = useState("");
  const [briefcaseFolderMenuId, setBriefcaseFolderMenuId] = useState("");
  const [driveFolderManagementOpen, setDriveFolderManagementOpen] = useState(false);
  const [openDriveActionMenuId, setOpenDriveActionMenuId] = useState<string | null>(null);
  const driveUploadInputRef = useRef<HTMLInputElement | null>(null);
  const [driveDragFileId, setDriveDragFileId] = useState("");
  const [driveDragTargetId, setDriveDragTargetId] = useState("");
  const [dragOverTarget, setDragOverTarget] = useState("");
  const [mailboxRefreshSpin, setMailboxRefreshSpin] = useState(false);
  const mailboxRefreshTimer = useRef<number | null>(null);
  const sessionWarningTimer = useRef<number | null>(null);
  const sessionExpiryTimer = useRef<number | null>(null);
  const sessionCountdownTimer = useRef<number | null>(null);
  const sessionKeepAlivePending = useRef(false);
  const sessionKeepAliveLastRefresh = useRef(0);
  const seenCalendarReminderIds = useRef(new Set<string>());
  const messagesScrollRef = useRef<HTMLDivElement | null>(null);
  const currentAccountRef = useRef("");
  const [isCompactViewport, setIsCompactViewport] = useState(false);
  const [sidebarOpen, setSidebarOpen] = useState(false);
  const [mobileMailPane, setMobileMailPane] = useState<"list" | "reader">("list");
  const [sessionWarningOpen, setSessionWarningOpen] = useState(false);
  const [sessionCountdownSeconds, setSessionCountdownSeconds] = useState(0);
  const [sessionKeepAliveBusy, setSessionKeepAliveBusy] = useState(false);
  const [acknowledgedLicenseWarningKey, setAcknowledgedLicenseWarningKey] = useState("");
  const [preferences, setPreferences] = useState<Preferences>(defaultPreferences);
  const [buildId, setBuildId] = useState("");
  const [buildTime, setBuildTime] = useState("");
  const productConfig = appConfig.data?.product;
  const licenseStatus = appConfig.data?.license;
  const licenseWarningSeverity = String(licenseStatus?.warning_severity || "");
  const licenseWarningKey = `${me.data?.email || ""}:${licenseStatus?.warning_started_at || ""}:${licenseWarningSeverity}`;
  const supportOnlyWarning = Boolean(
    licenseStatus?.user_warning &&
      licenseStatus.support_upgrade_active === false &&
      licenseStatus.status === "active" &&
      licenseStatus.activated &&
      !licenseStatus.activation_blocked &&
      !licenseStatus.hard_block &&
      !licenseStatus.over_deployment &&
      !licenseStatus.over_quota
  );
  const activeEdition = normalizeProductEdition(productConfig?.edition);
  const productTier = (productConfig?.tier ?? "").trim().toLowerCase();
  const productFeatures = productConfig?.features ?? {};
  const resolveFeature = (key: string, fallbackEnabled: boolean, fallbackVisible = fallbackEnabled) => {
    const feature = productFeatures[key];
    return {
      enabled: feature?.enabled ?? fallbackEnabled,
      visible: feature?.visible ?? fallbackVisible,
      locked: feature?.locked ?? false,
      requiredTier: feature?.required_tier ?? (feature?.locked ? "Pro" : ""),
    };
  };
  const calendarFeature = resolveFeature("calendar", productConfig?.capabilities.calendar ?? false);
  const tasksFallbackEnabled =
    (isNativeZimbraAddonEdition(activeEdition) && (productConfig?.capabilities.tasks_native_zimbra ?? false)) ||
    (isGoogleAddonEdition(activeEdition) && (productConfig?.capabilities.tasks_google ?? false));
  const tasksFeature = resolveFeature("tasks", tasksFallbackEnabled);
  const useBriefcaseTab = isNativeZimbraAddonEdition(activeEdition) || productTier === "free";
  const driveFeature = resolveFeature(useBriefcaseTab ? "briefcase" : "drive", productConfig?.capabilities.drive ?? false);
  const mailFolderShareFeature = resolveFeature("share_mail_folder", productConfig?.capabilities.share_mail_folder ?? true, true);
  const contactFolderShareFeature = resolveFeature("share_contact_folder", productConfig?.capabilities.share_contact_folder ?? true, true);
  const showCalendarSection = calendarFeature.visible;
  const showTasksSection = tasksFeature.visible;
  const showDriveSection = driveFeature.visible;
  const enableCalendarSection = calendarFeature.enabled && !calendarFeature.locked;
  const enableTasksSection = tasksFeature.enabled && !tasksFeature.locked;
  const enableDriveSection = driveFeature.enabled && !driveFeature.locked;
  const canShareMailFolders = mailFolderShareFeature.enabled && !mailFolderShareFeature.locked;
  const canShareContactFolders = contactFolderShareFeature.enabled && !contactFolderShareFeature.locked;
  const calendarServiceLabel = "Calendar";
  const driveServiceLabel = useBriefcaseTab ? "Briefcase" : "Drive";
  const driveRootLabel = useBriefcaseTab ? "Briefcase" : driveServiceLabel;
  const driveTabLabel = useBriefcaseTab ? "Briefcase" : "Drive";
  const driveBrowseRootLabel = isNativeZimbraAddonEdition(activeEdition) ? "Folders" : driveRootLabel;
  const allowDriveLink = !isNativeZimbraAddonEdition(activeEdition);
  const calendarTimeZone = normalizeTimeZone(preferences.timeZone);
  const [calendarFetchWindow] = useState(() => ({
    start: new Date(Date.now() - 180 * 24 * 60 * 60 * 1000).toISOString(),
    end: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString(),
  }));
  const [selectedCalendarId, setSelectedCalendarId] = useState<string>("__all__");
  const [selectedContactFolderId, setSelectedContactFolderId] = useState("");
  const [driveSaveFolderId, setDriveSaveFolderId] = useState("");
  const [driveSaveFolderName, setDriveSaveFolderName] = useState("");
  const [driveBrowseFolderId, setDriveBrowseFolderId] = useState("");
  const [mailBooted, setMailBooted] = useState(false);
  const [postListDataReady, setPostListDataReady] = useState(false);
  const shouldLoadDeferredMailData = Boolean(me.data && mailBooted && postListDataReady);
  const shouldLoadContactData = Boolean(
    shouldLoadDeferredMailData ||
      activeSection === "contacts" ||
      activeSection === "calendar" ||
      activeSection === "tasks" ||
      activeSection === "preferences" ||
      composeOpen ||
      folderShareEditor
  );
  const shouldLoadComposeData = Boolean(shouldLoadDeferredMailData || composeOpen || replyTo);
  const shouldLoadAddonStatus = Boolean(
    shouldLoadDeferredMailData ||
      composeOpen ||
      activeSection === "calendar" ||
      activeSection === "tasks" ||
      activeSection === "drive" ||
      activeSection === "preferences" ||
      attachmentSavePicker ||
      driveUploadPicker
  );

  const mailPollingInterval = useQuery({
    queryKey: ["mail-polling-interval"],
    queryFn: api.mailPollingInterval,
    enabled: Boolean(me.data),
    staleTime: 15 * 60_000,
    refetchOnWindowFocus: false,
    retry: false,
  });
  const mailPollingMs = mailPollingInterval.data?.interval_ms ?? 5 * 60_000;

  const folders = useQuery({
    queryKey: ["folders"],
    queryFn: () => api.folders(),
    enabled: Boolean(me.data && mailBooted),
    staleTime: 60_000,
    refetchOnWindowFocus: false,
    refetchInterval: mailPollingMs,
  });
  const contacts = useQuery({
    queryKey: ["contacts", selectedContactFolderId],
    queryFn: () => api.contacts(selectedContactFolderId),
    enabled: shouldLoadContactData,
    staleTime: 60_000,
    refetchOnWindowFocus: false,
  });
  const galContacts = useQuery({
    queryKey: ["contacts", "gal"],
    queryFn: api.galContacts,
    enabled: shouldLoadContactData,
    staleTime: 5 * 60_000,
    refetchOnWindowFocus: false,
  });
  const contactFolders = useQuery({
    queryKey: ["contact-folders"],
    queryFn: api.contactFolders,
    enabled: shouldLoadContactData,
    staleTime: 60_000,
    refetchOnWindowFocus: false,
  });
  const emailedContactsFolderId = useMemo(
    () =>
      contactFolders.data?.folders.find((folder) => {
        const target = `${folder.abs_path} ${folder.name}`.trim().toLowerCase();
        return target.includes("emailed") && target.includes("contact");
      })?.id ?? "",
    [contactFolders.data?.folders]
  );
  const emailedContacts = useQuery({
    queryKey: ["contacts", "emailed"],
    queryFn: () => api.contacts(emailedContactsFolderId),
    enabled: Boolean(shouldLoadContactData && emailedContactsFolderId),
    staleTime: 60_000,
    refetchOnWindowFocus: false,
  });
  const contactFolderContactQueries = useQueries({
    queries: (contactFolders.data?.folders ?? [])
      .filter((folderItem) => Boolean(folderItem.id && folderItem.id !== selectedContactFolderId && folderItem.id !== emailedContactsFolderId))
      .map((folderItem) => ({
        queryKey: ["contacts", folderItem.id],
        queryFn: () => api.contacts(folderItem.id),
        enabled: shouldLoadContactData,
        staleTime: 60_000,
        refetchOnWindowFocus: false,
      })),
  });
  const quota = useQuery({
    queryKey: ["quota", folder],
    queryFn: () => api.quota(folder),
    enabled: shouldLoadDeferredMailData,
    staleTime: 60_000,
  });
  const signatures = useQuery({
    queryKey: ["signatures"],
    queryFn: api.signatures,
    enabled: shouldLoadComposeData,
    staleTime: 5 * 60_000,
    retry: false,
  });
  const saveSignatures = useMutation({
    mutationFn: api.updateSignatures,
    onSuccess: async (data) => {
      queryClient.setQueryData(["signatures"], data);
      await queryClient.invalidateQueries({ queryKey: ["signatures"] });
    },
  });
  const workspacePreferences = useQuery({
    queryKey: ["workspace-preferences"],
    queryFn: api.workspacePreferences,
    enabled: Boolean(me.data),
    staleTime: 5 * 60_000,
    refetchOnWindowFocus: false,
  });
  const persistedMessageViewMode = workspacePreferences.data?.message_view_mode === "message" ? "message" : "conversation";
  const [messageViewModeOverride, setMessageViewModeOverride] = useState<"conversation" | "message" | null>(null);
  const messageViewMode = messageViewModeOverride ?? persistedMessageViewMode;
  const messageListQueryKey = (source: string, view: "conversation" | "message" = messageViewMode, sortOrder: MessageSortOrder = messageSortOrder) => ["messages", source, view, sortOrder] as const;
  const workspaceFilters = useQuery({
    queryKey: workspaceFiltersQueryKey,
    queryFn: api.workspaceFilters,
    enabled: Boolean(shouldLoadDeferredMailData || activeSection === "preferences"),
    staleTime: 5 * 60_000,
    refetchOnWindowFocus: false,
    retry: false,
  });
  const saveWorkspacePreferences = useMutation({
    mutationFn: api.updateWorkspacePreferences,
    onSuccess: (data) => {
      queryClient.setQueryData(["workspace-preferences"], data);
      const nextMode = data.message_view_mode === "message" ? "message" : "conversation";
      setMessageViewModeOverride((current) => (current === nextMode ? null : current));
    },
  });
  const persistWorkspacePreferences = (nextPreferences: Preferences, nextMessageViewMode = messageViewMode) => {
    saveWorkspacePreferences.mutate({
      drive_save_folder_id: workspacePreferences.data?.drive_save_folder_id || driveSaveFolderId,
      drive_save_folder_name: workspacePreferences.data?.drive_save_folder_name || driveSaveFolderName,
      message_view_mode: nextMessageViewMode,
      theme: nextPreferences.theme,
      font_scale: nextPreferences.fontScale,
      time_zone: normalizeTimeZone(nextPreferences.timeZone),
      locale: normalizeLocale(nextPreferences.locale),
    });
  };
  const saveWorkspaceFilters = useMutation({
    mutationFn: api.updateWorkspaceFilters,
    onSuccess: (data) => {
      queryClient.setQueryData(workspaceFiltersQueryKey, data);
      queryClient.invalidateQueries({ queryKey: workspaceFiltersQueryKey });
      setMessageFilterRules(data.rules ?? []);
    },
  });
  const persistDriveSaveFolder = (folderId: string, folderName: string) => {
    setDriveSaveFolderId(folderId);
    setDriveSaveFolderName(folderName);
    persistWorkspacePreferences(preferences);
  };
  const persistMessageViewMode = (messageViewMode: "conversation" | "message") => {
    setMessageViewModeOverride(messageViewMode);
    persistWorkspacePreferences(preferences, messageViewMode);
  };
  const [messageFilterRules, setMessageFilterRules] = useState<MailFilterRule[]>([]);
  const composeContacts = useMemo(() => {
    const folderContacts = contactFolderContactQueries.flatMap((query) => query.data?.contacts ?? []);
    const merged = [...(galContacts.data?.contacts ?? []), ...(contacts.data?.contacts ?? []), ...(emailedContacts.data?.contacts ?? []), ...folderContacts];
    const seen = new Set<string>();
    return merged.filter((contact) => {
      const key = contact.email.trim().toLowerCase();
      if (!key || seen.has(key)) return false;
      seen.add(key);
      return true;
    });
  }, [galContacts.data?.contacts, contacts.data?.contacts, emailedContacts.data?.contacts, contactFolderContactQueries]);
  const tags = useQuery({
    queryKey: ["tags"],
    queryFn: api.tags,
    enabled: shouldLoadDeferredMailData,
    staleTime: 60_000,
    refetchOnWindowFocus: false,
  });
  const savedSearches = useQuery({
    queryKey: ["saved-searches"],
    queryFn: api.savedSearches,
    enabled: shouldLoadDeferredMailData,
    staleTime: 60_000,
    refetchOnWindowFocus: false,
  });
  const createSavedSearch = useMutation({
    mutationFn: ({ name, query }: { name: string; query: string }) => api.createSavedSearch(name, query),
    onSuccess: () => queryClient.invalidateQueries({ queryKey: ["saved-searches"] }),
  });
  const deleteSavedSearch = useMutation({
    mutationFn: (id: string) => api.deleteSavedSearch(id),
    onSuccess: () => queryClient.invalidateQueries({ queryKey: ["saved-searches"] }),
  });
  const shareNotifications = useQuery({
    queryKey: ["share-notifications"],
    queryFn: api.shareNotifications,
    enabled: shouldLoadDeferredMailData,
    staleTime: 15_000,
    refetchInterval: 30_000,
    refetchOnWindowFocus: false,
  });
  const messages = useInfiniteQuery({
    queryKey: messageListQueryKey(folder),
    initialPageParam: 0,
    queryFn: ({ pageParam = 0 }) => api.messages(folder, MESSAGE_PAGE_SIZE, pageParam, messageViewMode, messageSortOrder),
    getNextPageParam: (lastPage, pages) => (lastPage.has_more ? pages.reduce((total, page) => total + page.messages.length, 0) : undefined),
    enabled: Boolean(me.data && workspacePreferences.data),
    staleTime: 60_000,
    refetchOnWindowFocus: false,
    refetchInterval: mailPollingMs,
  });
  useEffect(() => {
    if (!messages.isSuccess || mailBooted) {
      return;
    }
    setMailBooted(true);
    setPostListDataReady(false);
    const timer = window.setTimeout(() => setPostListDataReady(true), 900);
    return () => window.clearTimeout(timer);
  }, [mailBooted, messages.isSuccess]);
  const prefetchedMessageRef = useRef("");
  const calendarDetailRetryRef = useRef("");
  useEffect(() => {
    if (!tagMenuPosition) return;
    const closeMenu = () => setTagMenuPosition(null);
    const closeOnEscape = (event: KeyboardEvent) => {
      if (event.key === "Escape") closeMenu();
    };
    window.addEventListener("click", closeMenu);
    window.addEventListener("resize", closeMenu);
    window.addEventListener("scroll", closeMenu, true);
    window.addEventListener("keydown", closeOnEscape);
    return () => {
      window.removeEventListener("click", closeMenu);
      window.removeEventListener("resize", closeMenu);
      window.removeEventListener("scroll", closeMenu, true);
      window.removeEventListener("keydown", closeOnEscape);
    };
  }, [tagMenuPosition]);
  const readerTargetUid = selectedThreadDetailTarget?.uid || selectedDetailTarget?.uid || selectedUid || "";
  const readerTargetFolder = selectedThreadDetailTarget?.folder || selectedDetailTarget?.folder || selectedFolder;
  const conversationTargetUid = selectedDetailTarget?.uid || selectedUid || "";
  const shouldFetchReaderDetail = Boolean(
    selectedThreadDetailTarget?.uid ||
      (selectedDetailTarget?.uid && selectedDetailTarget.view !== "conversation" && !conversationExpandOnly)
  );
  const detail = useQuery({
    queryKey: ["message", readerTargetFolder || "", readerTargetUid || "", "message"],
    queryFn: () => api.message(readerTargetFolder, readerTargetUid as string, "message"),
    enabled: shouldFetchReaderDetail,
    staleTime: 0,
    gcTime: 15 * 60_000,
    refetchOnMount: "always",
    refetchOnWindowFocus: false,
  });
  const conversationFocusedMessageDetail = useQuery({
    queryKey: ["message-thread-detail", readerTargetFolder, conversationTargetUid || ""],
    queryFn: () => api.message(readerTargetFolder, conversationTargetUid as string, "conversation"),
    enabled: selectedDetailTarget?.view === "conversation" && Boolean(conversationTargetUid),
    staleTime: 0,
    gcTime: 15 * 60_000,
    refetchOnMount: "always",
    refetchOnWindowFocus: false,
  });

  useEffect(() => {
    if (!workspacePreferences.data) return;
    setDriveSaveFolderId(workspacePreferences.data.drive_save_folder_id || "");
    setDriveSaveFolderName(workspacePreferences.data.drive_save_folder_name || "");
    setPreferences((current) => {
      const nextTheme = normalizeThemeName(workspacePreferences.data.theme || "", current.theme);
      const nextFontScale = isFontScale(workspacePreferences.data.font_scale) ? workspacePreferences.data.font_scale : current.fontScale;
      const nextTimeZone = normalizeTimeZone(workspacePreferences.data.time_zone || current.timeZone);
      const nextLocale = normalizeLocale(workspacePreferences.data.locale || current.locale);
      if (current.theme === nextTheme && current.fontScale === nextFontScale && current.timeZone === nextTimeZone && current.locale === nextLocale) {
        return current;
      }
      return {
        ...current,
        theme: nextTheme,
        fontScale: nextFontScale,
        timeZone: nextTimeZone,
        locale: nextLocale,
      };
    });
  }, [workspacePreferences.data, setDriveSaveFolderId, setDriveSaveFolderName]);
  useEffect(() => {
    setOpenDriveActionMenuId(null);
  }, [activeSection, driveBrowseFolderId, driveSearch]);
  useEffect(() => {
    if (typeof document === "undefined") return;
    const metaBuildId = document.querySelector('meta[name="build-id"]')?.getAttribute("content") || "";
    const metaBuildTime = document.querySelector('meta[name="build-time"]')?.getAttribute("content") || "";
    setBuildId(metaBuildId);
    setBuildTime(metaBuildTime);
  }, []);
  useEffect(() => {
    const notification = pendingShareFocusRef.current;
    const folderList = folders.data?.folders ?? [];
    if (!notification || !folderList.length) return;
    if ((notification.item_view || "").trim().toLowerCase() === "appointment") {
      pendingShareFocusRef.current = null;
      return;
    }
    const matched = findSharedFolderForNotification(folderList, notification);
    if (!matched) return;
    pendingShareFocusRef.current = null;
    if (activeSection !== "email") {
      setActiveSection("email");
    }
    setFolder(matched.path);
    setSelectedFolder(matched.path);
    setSelectedUid(null);
    setSelectedDetailTarget(null);
    setSelectedThreadDetailTarget(null);
    setSelectedThreadUid(null);
    setMobileMailPane("list");
    setSharedFolderHighlightPath(matched.path);
    setSharedFolderHighlightPulse(true);
    if (shareHighlightTimerRef.current) {
      window.clearTimeout(shareHighlightTimerRef.current);
    }
    shareHighlightTimerRef.current = window.setTimeout(() => {
      setSharedFolderHighlightPath("");
      setSharedFolderHighlightPulse(false);
      shareHighlightTimerRef.current = null;
    }, 3000);
  }, [activeSection, folders.data?.folders]);
  useEffect(() => () => {
    if (shareHighlightTimerRef.current) {
      window.clearTimeout(shareHighlightTimerRef.current);
    }
  }, []);
  useEffect(() => {
    setMessageViewModeOverride((current) => (current === persistedMessageViewMode ? null : current));
  }, [persistedMessageViewMode]);
  useEffect(() => {
    if (!workspaceFilters.data) return;
    const nextRules = (workspaceFilters.data.rules ?? []).map((rule, index) => ({ ...rule, order: index }));
    setMessageFilterRules((current) => (current.length > 0 ? current : nextRules));
  }, [workspaceFilters.data, setMessageFilterRules]);
  const calendarStatus = useQuery({
    queryKey: ["calendar-status"],
    queryFn: api.calendarStatus,
    enabled: Boolean(shouldLoadAddonStatus && enableCalendarSection),
    staleTime: 60_000,
    retry: false,
  });
  const driveStatus = useQuery({
    queryKey: ["drive-status"],
    queryFn: api.driveStatus,
    enabled: Boolean(shouldLoadAddonStatus && enableDriveSection),
    staleTime: 60_000,
    retry: false,
  });
  const calendarSources = useQuery({
    queryKey: ["calendar-sources"],
    queryFn: api.calendars,
    enabled: Boolean(me.data && mailBooted && enableCalendarSection && calendarStatus.data?.configured && (calendarStatus.data.connected || calendarStatus.data.mode === "public")),
    staleTime: 60_000,
    retry: false,
  });
  const nativeZimbraTaskLists = useQuery({
    queryKey: ["native-zimbra-task-lists"],
    queryFn: api.nativeZimbraTaskLists,
    enabled: Boolean(me.data && mailBooted && enableTasksSection && isNativeZimbraAddonEdition(activeEdition) && calendarStatus.data?.configured && (calendarStatus.data.connected || calendarStatus.data.mode === "public")),
    staleTime: 30_000,
    refetchOnWindowFocus: false,
  });
  const calendar = useQuery({
    queryKey: ["calendar", selectedCalendarId, calendarTimeZone, calendarFetchWindow.start, calendarFetchWindow.end],
    queryFn: () => api.calendar(selectedCalendarId, calendarTimeZone, calendarFetchWindow.start, calendarFetchWindow.end),
    enabled: Boolean(me.data && mailBooted && enableCalendarSection && calendarStatus.data?.configured && (calendarStatus.data.connected || calendarStatus.data.mode === "public")),
    staleTime: 5 * 60_000,
    refetchOnWindowFocus: false,
    retry: false,
  });
  const calendarReminders = useQuery({
    queryKey: ["calendar-reminders"],
    queryFn: api.calendarReminders,
    enabled: Boolean(me.data && mailBooted && enableCalendarSection && calendarStatus.data?.configured && (calendarStatus.data.connected || calendarStatus.data.mode === "public")),
    staleTime: 5_000,
    refetchInterval: 15_000,
    refetchOnWindowFocus: false,
    retry: false,
  });
  const driveContents = useQuery({
    queryKey: ["drive-contents", driveBrowseFolderId, driveSearch],
    queryFn: () => api.driveContents(driveBrowseFolderId, driveSearch, 50),
    enabled: Boolean(me.data && mailBooted && enableDriveSection && activeSection === "drive" && driveStatus.data?.connected),
    staleTime: 5 * 60_000,
    refetchOnWindowFocus: false,
    retry: false,
  });
  const driveWritable = driveStatus.data?.writable ?? false;
  const nativeZimbraDrive = isNativeZimbraAddonEdition(activeEdition);
  const driveSelectedFolder = useQuery({
    queryKey: ["drive-folder", driveSaveFolderId],
    queryFn: () => api.driveFile(driveSaveFolderId),
    enabled: Boolean(me.data && mailBooted && enableDriveSection && driveStatus.data?.connected && driveSaveFolderId),
    staleTime: 5 * 60_000,
    refetchOnWindowFocus: false,
    retry: false,
  });
  const driveFolders = useQuery({
    queryKey: ["drive-folders", driveFolderSearch],
    queryFn: () => api.driveFolders(driveFolderSearch, 50),
    enabled: Boolean(me.data && mailBooted && enableDriveSection && driveStatus.data?.connected && (activeSection === "drive" || attachmentSavePicker || driveUploadPicker)),
    staleTime: 5 * 60_000,
    refetchOnWindowFocus: false,
    retry: false,
  });
  const connectCalendar = useMutation({
    mutationFn: api.calendarConnectUrl,
    onSuccess: ({ url }) => {
      window.location.href = url;
    },
    onError: (error) => {
      setCalendarNotice({ tone: "error", message: error instanceof Error ? error.message : "Google Calendar connection is not configured." });
    },
  });
  const resyncCalendar = useMutation({
    mutationFn: api.calendarResync,
    onSuccess: async (payload) => {
      setCalendarNotice({
        tone: "success",
        message: payload.watch_supported
          ? t("calendar.refreshedWithNotifications", { count: payload.calendars.length })
          : t("calendar.refreshedLimitedNotifications"),
      });
      await queryClient.invalidateQueries({ queryKey: ["calendar-status"] });
      await queryClient.invalidateQueries({ queryKey: ["calendar-sources"] });
      await queryClient.invalidateQueries({ queryKey: ["calendar"] });
    },
    onError: (error) => {
      setCalendarNotice({ tone: "error", message: error instanceof Error ? error.message : t("calendar.unableRefresh", { service: calendarServiceLabel }) });
    },
  });
  const disconnectCalendar = useMutation({
    mutationFn: api.disconnectCalendar,
    onSuccess: async () => {
      setSelectedCalendarId("__all__");
      setCalendarNotice({ tone: "success", message: t("calendar.disconnected", { service: calendarServiceLabel }) });
      await queryClient.invalidateQueries({ queryKey: ["calendar-status"] });
      await queryClient.invalidateQueries({ queryKey: ["calendar-sources"] });
      await queryClient.invalidateQueries({ queryKey: ["calendar"] });
    }
  });
  const connectDrive = useMutation({
    mutationFn: api.driveAuthUrl,
    onSuccess: ({ url }) => {
      window.location.href = url;
    },
    onError: (error) => {
      setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : "Google Drive connection is not configured." });
    },
  });
  const disconnectDrive = useMutation({
    mutationFn: api.disconnectDrive,
    onSuccess: async () => {
      setDriveNotice({ tone: "success", message: t("drive.disconnected", { drive: driveServiceLabel }) });
      setDriveSaveFolderId("");
      setDriveSaveFolderName("");
      setDriveBrowseFolderId("");
      setDriveNewFolderName("");
      setDriveDragFileId("");
      setDriveDragTargetId("");
      await queryClient.invalidateQueries({ queryKey: ["drive-status"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-files"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-folders"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-contents"] });
    }
  });
  const createDriveFolder = useMutation({
    mutationFn: api.driveCreateFolder,
    onSuccess: async (data) => {
      setDriveNotice({ tone: "success", message: t("drive.folderCreated", { drive: driveServiceLabel }) });
      setDriveNewFolderName("");
      if (data?.file) {
        queryClient.setQueryData<{ folders: DriveFile[] }>(["drive-folders"], (current) => {
          const folders = current?.folders ?? [];
          const nextFolders = folders.some((item) => item.id === data.file.id)
            ? folders.map((item) => (item.id === data.file.id ? data.file : item))
            : [data.file, ...folders];
          return { folders: nextFolders };
        });
        queryClient.setQueryData<{ folders: DriveFile[]; files: DriveFile[] }>(["drive-contents", "", ""], (current) => {
          const folders = current?.folders ?? [];
          const nextFolders = folders.some((item) => item.id === data.file.id)
            ? folders.map((item) => (item.id === data.file.id ? data.file : item))
            : [data.file, ...folders];
          return { folders: nextFolders, files: current?.files ?? [] };
        });
      }
      await queryClient.invalidateQueries({ queryKey: ["drive-files"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-folders"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-contents"] });
    }
  });
  const updateDriveFolderColor = useMutation({
    mutationFn: ({ folderId, color, rgb }: { folderId: string; color: number; rgb: string }) => api.driveUpdateFolderColor(folderId, { color, rgb }),
    onSuccess: async () => {
      setBriefcaseFolderMenuId("");
      setDriveNotice({ tone: "success", message: t("drive.folderColorUpdated") });
      await queryClient.invalidateQueries({ queryKey: ["drive-folders"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-contents"] });
    },
    onError: (error) => {
      setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : t("drive.unableUpdateFolderColor") });
    },
  });
  const uploadDriveFiles = useMutation({
    mutationFn: async ({ files, folderId }: { files: File[]; folderId: string }) => {
      const uploaded: string[] = [];
      for (const file of files) {
        const contentBase64 = await fileToBase64(file);
        const result = await api.driveUpload({
          filename: file.name,
          content_type: file.type || "application/octet-stream",
          content_base64: contentBase64,
          folder_id: folderId,
        });
        uploaded.push(result.file.name);
      }
      return uploaded;
    },
    onMutate: ({ files }) => {
      setDriveNotice({ tone: "info", message: t("drive.uploadingFiles", { count: files.length, drive: driveServiceLabel }) });
    },
    onSuccess: async (names) => {
      setDriveNotice({
        tone: "success",
        message: names.length ? t("drive.uploadedNames", { drive: driveServiceLabel, names: names.join(", ") }) : t("drive.uploadedFiles", { drive: driveServiceLabel })
      });
      await queryClient.invalidateQueries({ queryKey: ["drive-files"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-folders"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-contents"] });
    },
    onError: (error) => {
      setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : t("drive.unableUploadFile", { drive: driveServiceLabel }) });
    }
  });
  const shareNativeBriefcaseFolder = useMutation({
    mutationFn: ({ resourceId, email, permissions }: { resourceId: string; email: string; permissions: string }) =>
      api.nativeZimbraShareBriefcase({ resource_id: resourceId, email, permissions }),
    onSuccess: async (_data, variables) => {
      setDriveNotice({ tone: "success", message: t("drive.sharingUpdated") });
      await queryClient.invalidateQueries({ queryKey: ["native-zimbra-briefcase-shares"] });
      await queryClient.invalidateQueries({ queryKey: ["native-zimbra-briefcase-shares", variables.resourceId] });
      await queryClient.invalidateQueries({ queryKey: ["native-zimbra-mounted-briefcase-shares"] });
      await queryClient.invalidateQueries({ queryKey: ["native-zimbra-outgoing-briefcase-shares"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-folders"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-contents"] });
      setBriefcaseShareEditor(null);
    },
    onError: (error) => {
      setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : t("drive.unableUpdateSharing") });
    },
  });
  const revokeNativeBriefcaseShare = useMutation({
    mutationFn: ({ resourceId, email }: { resourceId: string; email: string }) =>
      api.nativeZimbraRevokeBriefcaseShare({ resource_id: resourceId, email }),
    onSuccess: async (_data, variables) => {
      setDriveNotice({ tone: "success", message: t("drive.sharingUpdated") });
      await queryClient.invalidateQueries({ queryKey: ["native-zimbra-briefcase-shares"] });
      await queryClient.invalidateQueries({ queryKey: ["native-zimbra-briefcase-shares", variables.resourceId] });
      await queryClient.invalidateQueries({ queryKey: ["native-zimbra-mounted-briefcase-shares"] });
      await queryClient.invalidateQueries({ queryKey: ["native-zimbra-outgoing-briefcase-shares"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-folders"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-contents"] });
      setBriefcaseShareEditor(null);
    },
    onError: (error) => {
      setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : t("drive.unableUpdateSharing") });
    },
  });
  const unmountNativeBriefcaseShare = useMutation({
    mutationFn: (resourceId: string) => api.nativeZimbraUnmountBriefcaseShare(resourceId),
    onSuccess: async () => {
      setDriveNotice({ tone: "success", message: t("drive.sharedBriefcaseRemoved") });
      await queryClient.invalidateQueries({ queryKey: ["native-zimbra-mounted-briefcase-shares"] });
      await queryClient.invalidateQueries({ queryKey: ["native-zimbra-outgoing-briefcase-shares"] });
      await queryClient.invalidateQueries({ queryKey: ["share-notifications"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-folders"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-contents"] });
    },
    onError: (error) => {
      setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : t("drive.unableRemoveSharedBriefcase") });
    },
  });

  useEffect(() => {
    if (typeof window === "undefined") return;
    const url = new URL(window.location.href);
    const connected = url.searchParams.get("calendar");
    const error = url.searchParams.get("calendar_error");
    const driveConnected = url.searchParams.get("drive");
    const driveError = url.searchParams.get("drive_error");
    if (!connected && !error && !driveConnected && !driveError) return;
    const nextSection = driveConnected || driveError ? "drive" : "calendar";
    setActiveSection(
      nextSection === "drive" && !enableDriveSection
        ? "email"
        : nextSection === "calendar" && !enableCalendarSection
          ? "email"
          : nextSection
    );
    if (connected === "connected") {
      setCalendarNotice({ tone: "success", message: t("calendar.connected", { service: calendarServiceLabel }) });
    } else if (error) {
      setCalendarNotice({ tone: "error", message: error });
    }
    if (driveConnected === "connected") {
      setDriveNotice({ tone: "success", message: t("drive.connected", { drive: driveServiceLabel }) });
    } else if (driveError) {
      setDriveNotice({ tone: "error", message: driveError });
    }
    url.searchParams.delete("calendar");
    url.searchParams.delete("calendar_error");
    url.searchParams.delete("drive");
    url.searchParams.delete("drive_error");
    window.history.replaceState({}, "", url.toString());
  }, [enableCalendarSection, enableDriveSection]);

  useEffect(() => {
    const available = calendarSources.data?.calendars ?? [];
    if (!available.length) return;
    if (selectedCalendarId === "__all__") {
      return;
    }
    if (selectedCalendarId === "primary") return;
    if (available.some((item) => item.id === selectedCalendarId)) return;
    const fallback = available.find((item) => item.primary)?.id ?? available[0]?.id;
    if (fallback) setSelectedCalendarId(fallback);
  }, [calendarSources.data?.calendars, selectedCalendarId, setSelectedCalendarId]);
  function dismissCalendarReminder(notificationId: string) {
    setVisibleCalendarReminders((current) => current.filter((item) => item.id !== notificationId));
    void api.ackCalendarReminder(notificationId).catch(() => undefined);
  }

  function showCalendarBrowserNotification(notification: CalendarReminderNotification) {
    if (typeof window === "undefined" || !("Notification" in window) || Notification.permission !== "granted") {
      return false;
    }
    const title = `Reminder: ${notification.event.summary}`;
    const body = `${notification.calendar_summary || t("sharing.calendar")} • ${formatCalendarReminderLabel(notification, preferences.locale)}`;
    const browserNotification = new Notification(title, {
      body,
      tag: notification.id,
    });
    browserNotification.onclick = () => {
      window.focus();
      setActiveSection("calendar");
      dismissCalendarReminder(notification.id);
      browserNotification.close();
    };
    return true;
  }

  useEffect(() => {
    const notifications = calendarReminders.data?.notifications ?? [];
    if (!notifications.length) return;
    const nextNotifications: CalendarReminderNotification[] = [];
    for (const notification of notifications) {
      if (seenCalendarReminderIds.current.has(notification.id)) continue;
      seenCalendarReminderIds.current.add(notification.id);
      nextNotifications.push(notification);
    }
    if (!nextNotifications.length) return;
    setVisibleCalendarReminders((current) => [...nextNotifications, ...current].slice(0, 4));
    for (const notification of nextNotifications) {
      if (showCalendarBrowserNotification(notification)) {
        void api.ackCalendarReminder(notification.id).catch(() => undefined);
        continue;
      }
      if (typeof window !== "undefined" && "Notification" in window && Notification.permission === "default") {
        void Notification.requestPermission().then((permission) => {
          if (permission === "granted" && showCalendarBrowserNotification(notification)) {
            void api.ackCalendarReminder(notification.id).catch(() => undefined);
          }
        }).catch(() => undefined);
      }
    }
  }, [calendarReminders.data?.notifications]);
  useEffect(() => {
    if (activeSection === "calendar" && !enableCalendarSection) setActiveSection("email");
    if (activeSection === "tasks" && !enableTasksSection) setActiveSection("email");
    if (activeSection === "drive" && !enableDriveSection) setActiveSection("email");
  }, [activeSection, enableCalendarSection, enableDriveSection, enableTasksSection]);
  useEffect(() => {
    const available = contactFolders.data?.folders ?? [];
    if (!available.length) return;
    if (selectedContactFolderId && available.some((item) => item.id === selectedContactFolderId)) return;
    const defaultFolder = available.find((item) => item.abs_path === "/Contacts")?.id ?? available[0]?.id ?? "";
    if (defaultFolder && defaultFolder !== selectedContactFolderId) {
      setSelectedContactFolderId(defaultFolder);
    }
  }, [contactFolders.data?.folders, selectedContactFolderId, setSelectedContactFolderId]);
  const createFolder = useMutation({
    mutationFn: api.createFolder,
    onSuccess: (data) => {
      queryClient.setQueryData(["folders"], data);
      queryClient.invalidateQueries({ queryKey: ["folders"] });
      setNewFolderName("");
    }
  });
  const renameFolder = useMutation({
    mutationFn: ({ folderId, name }: { folderId: string; name: string }) => api.renameFolder(folderId, name),
    onSuccess: (data) => {
      queryClient.setQueryData(["folders"], data);
      queryClient.invalidateQueries({ queryKey: ["folders"] });
      queryClient.invalidateQueries({ queryKey: ["messages"] });
    }
  });
  const updateFolderColor = useMutation({
    mutationFn: ({ folderId, color, rgb }: { folderId: string; color: number; rgb: string }) => api.updateFolderColor(folderId, { color, rgb }),
    onSuccess: (data) => {
      queryClient.setQueryData(["folders"], data);
      queryClient.invalidateQueries({ queryKey: ["folders"] });
      queryClient.invalidateQueries({ queryKey: ["messages"] });
    }
  });
  const deleteFolder = useMutation({
    mutationFn: (folderId: string) => api.deleteFolder(folderId),
    onSuccess: (data, folderId) => {
      queryClient.setQueryData(["folders"], data);
      queryClient.invalidateQueries({ queryKey: ["folders"] });
      queryClient.removeQueries({ queryKey: ["messages", folderId] });
      queryClient.removeQueries({ queryKey: ["message", folderId] });
      if (folder === folderId || selectedFolder === folderId) {
        switchFolder("INBOX");
      }
    }
  });
  const emptyFolder = useMutation({
    mutationFn: (folderId: string) => api.emptyFolder(folderId),
    onSuccess: (data, folderId) => {
      queryClient.setQueryData(["folders"], data);
      queryClient.invalidateQueries({ queryKey: ["folders"] });
      queryClient.invalidateQueries({ queryKey: ["messages", folderId] });
      if (folder === folderId || selectedFolder === folderId) {
        setSelectedUid(null);
        setSelectedDetailTarget(null);
        setSelectedKeys([]);
      }
    }
  });
  const createTag = useMutation({
    mutationFn: api.createTag,
    onSuccess: (data) => {
      queryClient.setQueryData(["tags"], data);
      queryClient.invalidateQueries({ queryKey: ["tags"] });
    }
  });
  const renameTag = useMutation({
    mutationFn: ({ tagId, name, color }: { tagId: string; name?: string; color?: number }) => api.updateTag(tagId, { name, color }),
    onSuccess: (data) => {
      queryClient.setQueryData(["tags"], data);
      queryClient.invalidateQueries({ queryKey: ["tags"] });
      queryClient.invalidateQueries({ queryKey: ["messages"] });
      queryClient.invalidateQueries({ queryKey: ["message"] });
    }
  });
  const deleteTag = useMutation({
    mutationFn: (tagId: string) => api.deleteTag(tagId),
    onSuccess: (data, tagId) => {
      queryClient.setQueryData(["tags"], data);
      queryClient.invalidateQueries({ queryKey: ["tags"] });
      queryClient.invalidateQueries({ queryKey: ["messages"] });
      queryClient.invalidateQueries({ queryKey: ["message"] });
      if (folder === `TAG:${tagId}`) {
        switchFolder("INBOX");
      }
    }
  });

  const deleteMessage = useMutation({
    mutationFn: ({ uid, source, view }: { uid: string; source: string; view: "conversation" | "message" }) => api.deleteMessage(source, uid, view),
    onMutate: async ({ uid, source }) => {
      const listKey = messageListQueryKey(source);
      await queryClient.cancelQueries({ queryKey: listKey });
      const previous = queryClient.getQueryData<InfiniteData<MessagePage>>(listKey);
      queryClient.setQueryData<InfiniteData<MessagePage>>(listKey, (old) =>
        mapMessagePages(old, (message) => (message.uid === uid ? null : message))
      );
      if (selectedUid === uid) {
        setSelectedUid(null);
        setSelectedDetailTarget(null);
      }
      return { previous, source };
    },
    onError: (_error, _vars, context) => {
      if (context) queryClient.setQueryData(messageListQueryKey(context.source), context.previous);
    },
    onSettled: (_data, _error, vars) => {
      queryClient.invalidateQueries({ queryKey: ["messages", vars.source] });
      queryClient.invalidateQueries({ queryKey: ["folders"] });
      void queryClient.refetchQueries({ queryKey: ["folders"], exact: true });
    }
  });

  const moveMessage = useMutation({
    mutationFn: ({ uid, target, source, view }: { uid: string; target: string; source: string; view: "conversation" | "message" }) => api.moveMessage(source, uid, target, view),
    onMutate: async ({ uid, source }) => {
      const listKey = messageListQueryKey(source);
      await queryClient.cancelQueries({ queryKey: listKey });
      const previous = queryClient.getQueryData<InfiniteData<MessagePage>>(listKey);
      queryClient.setQueryData<InfiniteData<MessagePage>>(listKey, (old) =>
        mapMessagePages(old, (message) => (message.uid === uid ? null : message))
      );
      if (selectedUid === uid) {
        setSelectedUid(null);
        setSelectedDetailTarget(null);
      }
      return { previous, source };
    },
    onError: (_error, _vars, context) => {
      if (context) queryClient.setQueryData(messageListQueryKey(context.source), context.previous);
    },
    onSettled: () => {
      queryClient.invalidateQueries({ queryKey: ["messages"] });
      queryClient.invalidateQueries({ queryKey: ["folders"] });
    }
  });

  const updateFlags = useMutation({
    mutationFn: ({ uid, source, seen, starred, view }: { uid: string; source: string; seen?: boolean; starred?: boolean; view: "conversation" | "message" }) =>
      api.updateFlags(source, uid, { seen, starred }, view),
    onMutate: async ({ uid, source, seen, starred, view }) => {
      const targetView = view || messageViewMode;
      const matchesTarget = (message: { uid?: string; open_uid?: string; conversation_id?: string }) =>
        message.uid === uid || message.open_uid === uid || message.conversation_id === uid;
      const adjustFolderCounts = (old: { folders: Folder[]; starred_unread_count: number } | undefined, deltaUnread: number, deltaStarredUnread: number) => {
        if (!old) return old;
        const normalizedSource = source.trim().toLowerCase();
        const folders = old.folders.map((folder) => {
          const matchesFolder =
            folder.path.trim().toLowerCase() === normalizedSource ||
            folder.abs_path.trim().toLowerCase() === normalizedSource ||
            folder.name.trim().toLowerCase() === normalizedSource;
          if (!matchesFolder || deltaUnread === 0) return folder;
          return {
            ...folder,
            unread_count: Math.max(0, folder.unread_count + deltaUnread),
          };
        });
        return {
          folders,
          starred_unread_count: Math.max(0, old.starred_unread_count + deltaStarredUnread),
        };
      };
      await queryClient.cancelQueries({ queryKey: ["messages", source] });
      if (starred !== undefined) {
        await queryClient.cancelQueries({ queryKey: ["messages", "STARRED"] });
      }
      const previousLists = queryClient.getQueriesData<InfiniteData<MessagePage>>({ queryKey: ["messages", source] });
      const previousStarredList = queryClient.getQueriesData<InfiniteData<MessagePage>>({ queryKey: ["messages", "STARRED"] });
      const previousDetails = queryClient.getQueriesData<{ message: MessageDetail }>({ queryKey: ["message", source] });
      const previousThreadDetails = queryClient.getQueriesData<{ message: MessageDetail }>({ queryKey: ["message-thread-detail", source] });
      const previousFolders = queryClient.getQueryData<{ folders: Folder[]; starred_unread_count: number }>(["folders"]);
      const previousTags = queryClient.getQueryData<{ tags: Tag[] }>(["tags"]);
      const currentMessageDetail =
        previousDetails[0]?.[1]?.message ??
        previousThreadDetails[0]?.[1]?.message;
      const currentMessageSummary =
        previousLists[0]?.[1]?.pages.flatMap((page) => page.messages).find((message) => matchesTarget(message));
      const currentMessage =
        currentMessageDetail ?? currentMessageSummary;
      const currentMessageItems = targetView === "conversation"
        ? currentMessageDetail?.conversation_messages?.length
          ? currentMessageDetail.conversation_messages
          : currentMessage
            ? [currentMessage]
            : []
        : currentMessage
          ? [currentMessage]
          : [];
      const affectedItems = seen === undefined ? [] : currentMessageItems.filter((message) => message.seen !== seen);
      const unreadDeltaCount = seen === undefined ? 0 : (seen ? -affectedItems.length : affectedItems.length);
      const tagUnreadDeltas = new Map<string, number>();
      if (seen !== undefined) {
        for (const item of affectedItems) {
          for (const tagName of item.tags ?? []) {
            tagUnreadDeltas.set(tagName, (tagUnreadDeltas.get(tagName) ?? 0) + (seen ? -1 : 1));
          }
        }
      }
      const patchFlags = <T extends { seen: boolean; starred: boolean; flags: string[] }>(message: T): T => ({
        ...message,
        seen: seen ?? message.seen,
        starred: starred ?? message.starred,
        flags: nextFlags(message.flags, seen, starred)
      });
      const patchDetail = (detail: MessageDetail): MessageDetail => {
        const patchWholeDetail = matchesTarget(detail);
        const nextConversationMessages = detail.conversation_messages?.map((message) =>
          targetView === "conversation" || matchesTarget(message)
            ? patchFlags(message)
            : message
        );
        const nextDetail = patchWholeDetail ? patchFlags(detail) : detail;
        return nextConversationMessages ? { ...nextDetail, conversation_messages: nextConversationMessages } : nextDetail;
      };
      queryClient.setQueriesData<InfiniteData<MessagePage>>({ queryKey: ["messages", source] }, (old) =>
        updateMessagePages(old, (message) => (matchesTarget(message) ? patchFlags(message) : message))
      );
      queryClient.setQueriesData<{ message: MessageDetail }>({ queryKey: ["message", source] }, (old) =>
        old ? { message: patchDetail(old.message) } : old
      );
      queryClient.setQueriesData<{ message: MessageDetail }>({ queryKey: ["message-thread-detail", source] }, (old) =>
        old ? { message: patchDetail(old.message) } : old
      );
      if (starred === false) {
        queryClient.setQueriesData<InfiniteData<MessagePage>>({ queryKey: ["messages", "STARRED"] }, (old) =>
          mapMessagePages(old, (message) => (matchesTarget(message) ? null : message))
        );
        if (source === "STARRED" && selectedUid === uid) {
          setSelectedUid(null);
          setSelectedDetailTarget(null);
          setSelectedKeys([]);
        }
      }
      if (starred !== undefined) {
        queryClient.setQueryData(["folders"], (old: { folders: Folder[]; starred_unread_count: number } | undefined) => {
          if (!old) return old;
          const wasStarredUnread = Boolean(currentMessage?.starred && !currentMessage?.seen);
          const nextStarred = starred ?? currentMessage?.starred ?? false;
          const nextSeen = seen ?? currentMessage?.seen ?? false;
          const isStarredUnread = Boolean(nextStarred && !nextSeen);
          const delta = (isStarredUnread ? 1 : 0) - (wasStarredUnread ? 1 : 0);
          return adjustFolderCounts(old, unreadDeltaCount, delta);
        });
      } else if (seen !== undefined) {
        queryClient.setQueryData(["folders"], (old: { folders: Folder[]; starred_unread_count: number } | undefined) => {
          if (!old) return old;
          const wasStarredUnread = Boolean(currentMessage?.starred && !currentMessage?.seen);
          const isStarredUnread = Boolean((currentMessage?.starred ?? false) && !seen);
          const delta = (isStarredUnread ? 1 : 0) - (wasStarredUnread ? 1 : 0);
          return adjustFolderCounts(old, unreadDeltaCount, delta);
        });
      }
      if (seen !== undefined) {
        queryClient.setQueryData(["tags"], (old: { tags: Tag[] } | undefined) => {
          if (!old || !tagUnreadDeltas.size) return old;
          return {
            tags: old.tags.map((tag) => {
              const delta = tagUnreadDeltas.get(tag.name);
              if (!delta) return tag;
              return {
                ...tag,
                unread_count: Math.max(0, tag.unread_count + delta),
              };
            }),
          };
        });
      }
      return { previousLists, previousStarredList, previousDetails, previousThreadDetails, previousFolders, previousTags, uid, source, view: targetView };
    },
    onError: (_error, _vars, context) => {
      if (!context) return;
      context.previousLists.forEach(([queryKey, data]) => {
        queryClient.setQueryData(queryKey, data);
      });
      context.previousStarredList.forEach(([queryKey, data]) => {
        queryClient.setQueryData(queryKey, data);
      });
      context.previousDetails.forEach(([queryKey, data]) => {
        queryClient.setQueryData(queryKey, data);
      });
      context.previousThreadDetails.forEach(([queryKey, data]) => {
        queryClient.setQueryData(queryKey, data);
      });
      queryClient.setQueryData(["folders"], context.previousFolders);
      queryClient.setQueryData(["tags"], context.previousTags);
    },
    onSettled: (_data, _error, vars) => {
      if (vars.seen !== undefined) {
        queryClient.invalidateQueries({ queryKey: ["folders"] });
        queryClient.invalidateQueries({ queryKey: ["tags"] });
      }
      if (vars.starred !== undefined) {
        queryClient.invalidateQueries({ queryKey: ["folders"] });
        queryClient.invalidateQueries({ queryKey: ["messages", "STARRED"] });
        queryClient.invalidateQueries({ queryKey: ["messages", vars.source] });
        queryClient.invalidateQueries({ queryKey: ["message", vars.source, vars.uid, vars.view] });
        queryClient.invalidateQueries({ queryKey: ["message-thread-detail", vars.source] });
      }
    }
  });
  const shareFolder = useMutation({
    mutationFn: ({ folderId, email, permissions }: { folderId: string; email: string; permissions: string }) => api.shareFolder(folderId, { email, permissions }),
    onSuccess: (data) => {
      queryClient.setQueryData(["folders"], data);
      queryClient.invalidateQueries({ queryKey: ["folders"] });
      queryClient.invalidateQueries({ queryKey: ["native-zimbra-calendar-shares"] });
      queryClient.invalidateQueries({ queryKey: ["native-zimbra-task-shares"] });
      queryClient.invalidateQueries({ queryKey: ["native-zimbra-briefcase-shares"] });
      void queryClient.refetchQueries({ queryKey: ["folders"], exact: true });
      setFolderShareEditor(null);
    }
  });
  const revokeFolderShare = useMutation({
    mutationFn: ({ folderId, email }: { folderId: string; email: string }) => api.revokeFolderShare(folderId, { email }),
    onSuccess: (data) => {
      queryClient.setQueryData(["folders"], data);
      queryClient.invalidateQueries({ queryKey: ["folders"] });
      queryClient.invalidateQueries({ queryKey: ["native-zimbra-calendar-shares"] });
      queryClient.invalidateQueries({ queryKey: ["native-zimbra-task-shares"] });
      queryClient.invalidateQueries({ queryKey: ["native-zimbra-briefcase-shares"] });
      void queryClient.refetchQueries({ queryKey: ["folders"] });
      setFolderShareEditor(null);
    }
  });
  const acceptShareNotification = useMutation({
    mutationFn: (notificationId: string) => api.acceptShareNotification(notificationId),
    onSuccess: async (data) => {
      pendingShareFocusRef.current = (data.notification.item_view || "").trim().toLowerCase() === "appointment" ? null : data.notification;
      await refreshAfterShareAccept(data.notification);
    }
  });
  const declineShareNotification = useMutation({
    mutationFn: (notificationId: string) => api.declineShareNotification(notificationId),
    onSuccess: async (data) => {
      await refreshAfterShareDecline(data.notification);
    }
  });
  const acceptShareInvite = useMutation({
    mutationFn: api.acceptShareInvite,
    onSuccess: async (data) => {
      pendingShareFocusRef.current = (data.notification.item_view || "").trim().toLowerCase() === "appointment" ? null : data.notification;
      await refreshAfterShareAccept(data.notification);
    },
    onError: (error) => {
      setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : t("sharing.unableAcceptFolder") });
    }
  });
  const acceptMessageShareInvite = useMutation({
    mutationFn: ({ uid, part, mount_name }: { uid: string; part: string; mount_name?: string }) => api.acceptMessageShareInvite(uid, { part, mount_name }),
    onSuccess: async (data) => {
      pendingShareFocusRef.current = (data.notification.item_view || "").trim().toLowerCase() === "appointment" ? null : data.notification;
      await refreshAfterShareAccept(data.notification);
    },
    onError: (error) => {
      setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : t("sharing.unableAcceptFolder") });
    }
  });
  const declineMessageShareInvite = useMutation({
    mutationFn: ({ uid, part }: { uid: string; part?: string }) => api.declineMessageShareInvite(uid, { part }),
    onSuccess: async (data) => {
      await refreshAfterShareDecline(data.notification);
    },
    onError: (error) => {
      setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : t("sharing.unableAcceptFolder") });
    }
  });
  const respondCalendarInvite = useMutation({
    mutationFn: (payload: {
      message: MessageDetail;
      invite: NonNullable<MessageDetail["calendar_invite"]>;
      response: "accepted" | "tentative" | "declined";
    }) => api.respondCalendarInvite(payload),
    onSuccess: async (_data, variables) => {
      const responseKey = `${variables.message.open_uid || variables.message.uid}:${variables.invite.uid || variables.invite.summary}`.toLowerCase();
      setCalendarInviteResponses((current) => ({ ...current, [responseKey]: variables.response }));
      const statusLabel =
        variables.response === "accepted" ? t("calendar.accepted") :
        variables.response === "tentative" ? t("calendar.markedTentative") :
        t("calendar.declined");
      setCalendarNotice({ tone: "success", message: t("calendar.responseSynced", { status: statusLabel }) });
      await queryClient.invalidateQueries({ queryKey: ["message"] });
      await queryClient.invalidateQueries({ queryKey: ["messages"] });
      await queryClient.invalidateQueries({ queryKey: ["calendar"] });
      await queryClient.invalidateQueries({ queryKey: ["calendar-reminders"] });
      if (variables.response === "declined") {
        return;
      }
      const refreshedCalendar = await queryClient.fetchQuery({
        queryKey: ["calendar", selectedCalendarId, calendarTimeZone, calendarFetchWindow.start, calendarFetchWindow.end],
        queryFn: () => api.calendar(selectedCalendarId, calendarTimeZone, calendarFetchWindow.start, calendarFetchWindow.end),
      });
      const inviteUid = variables.invite.uid.trim().toLowerCase();
      const matchedEvent = refreshedCalendar.events.find((event) => {
        const sameUid =
          Boolean(inviteUid) &&
          ((event.ical_uid || "").trim().toLowerCase() === inviteUid ||
            (event.id || "").trim().toLowerCase() === inviteUid);
        const sameSummary = event.summary.trim().toLowerCase() === variables.invite.summary.trim().toLowerCase();
        const sameStart = event.start.trim() === variables.invite.start.trim();
        const sameEnd = event.end.trim() === variables.invite.end.trim();
        return sameUid || (sameSummary && sameStart && sameEnd);
      });
      if (enableCalendarSection) {
        setActiveSection("calendar");
      }
      if (matchedEvent) {
        setCalendarFocusEventId(matchedEvent.ical_uid || matchedEvent.id);
      }
      const replyUid = variables.message.open_uid || variables.message.uid;
      await deleteSelection(
        [{ key: `${variables.message.folder || selectedFolder}:${replyUid}`, uid: replyUid, source: variables.message.folder || selectedFolder }],
        "message"
      );
    },
    onError: (error) => {
      setCalendarNotice({ tone: "error", message: error instanceof Error ? error.message : t("calendar.unableSendReply") });
    },
  });
  const sendReadReceipt = useMutation({
    mutationFn: (uid: string) => api.sendReadReceipt(uid),
    onSuccess: (_data, uid) => setHandledReadReceipts((current) => ({ ...current, [uid]: true })),
  });
  const refreshAfterShareAccept = async (notification: ShareNotification) => {
    queryClient.setQueryData<{ notifications: ShareNotification[] }>(["share-notifications"], (current) => {
      if (!current) return current;
      return {
        ...current,
        notifications: current.notifications.map((item) =>
          shareNotificationsMatch(item, notification) ? { ...item, status: "accepted" } : item
        ),
      };
    });
    await queryClient.invalidateQueries({ queryKey: ["share-notifications"] });
    await queryClient.invalidateQueries({ queryKey: ["folders"] });
    await queryClient.invalidateQueries({ queryKey: ["contact-folders"] });
    await queryClient.invalidateQueries({ queryKey: ["contacts"] });
    await queryClient.invalidateQueries({ queryKey: ["messages"] });

    const view = (notification.item_view || "").trim().toLowerCase();
    if (view === "contact" || view === "contacts") {
      setDriveNotice({ tone: "success", message: t("sharing.folderAccepted") });
      await queryClient.refetchQueries({ queryKey: ["contact-folders"], exact: true });
      if (activeSection === "contacts") {
        await queryClient.refetchQueries({ queryKey: ["contacts"], type: "active" });
      }
      return;
    }
    if (view === "appointment") {
      setCalendarNotice({ tone: "success", message: t("sharing.calendarAccepted") });
      await queryClient.invalidateQueries({ queryKey: ["calendar"] });
      await queryClient.invalidateQueries({ queryKey: ["calendar-sources"] });
      await queryClient.invalidateQueries({ queryKey: ["calendar-reminders"] });
      await queryClient.refetchQueries({ queryKey: ["calendar"], type: "active" });
      if (enableCalendarSection) {
        setActiveSection("calendar");
      }
      return;
    }

    setDriveNotice({ tone: "success", message: t("sharing.folderAccepted") });
    await queryClient.invalidateQueries({ queryKey: ["native-zimbra-task-lists"] });
    await queryClient.invalidateQueries({ queryKey: ["native-zimbra-mounted-briefcase-shares"] });
    await queryClient.invalidateQueries({ queryKey: ["drive-folders"] });
    await queryClient.invalidateQueries({ queryKey: ["drive-contents"] });
  };

  const refreshAfterShareDecline = async (notification: ShareNotification) => {
    queryClient.setQueryData<{ notifications: ShareNotification[] }>(["share-notifications"], (current) => {
      if (!current) return current;
      return {
        ...current,
        notifications: current.notifications.map((item) =>
          shareNotificationsMatch(item, notification) ? { ...item, status: "declined" } : item
        ),
      };
    });
    await queryClient.invalidateQueries({ queryKey: ["share-notifications"] });
    await queryClient.invalidateQueries({ queryKey: ["messages"] });
    await queryClient.invalidateQueries({ queryKey: ["folders"] });
    await queryClient.invalidateQueries({ queryKey: ["contact-folders"] });
    await queryClient.invalidateQueries({ queryKey: ["contacts"] });
  };

  const hideShareInviteMessage = async (message?: MessageDetail) => {
    if (!message) return;
    const source = message.folder || selectedFolder || folder || "INBOX";
    const ids = new Set([message.uid, message.open_uid, message.conversation_id].filter((value): value is string => Boolean(value)));
    if (!ids.size) return;
    queryClient.setQueriesData<InfiniteData<MessagePage>>({ queryKey: ["messages"] }, (old) =>
      mapMessagePages(old, (item) => {
        const itemIds = [item.uid, item.open_uid, item.conversation_id].filter((value): value is string => Boolean(value));
        const sameMessage = itemIds.some((value) => ids.has(value));
        const sameSource = !item.folder || !source || item.folder === source;
        return sameMessage && sameSource ? null : item;
      })
    );
    if (selectedUid && ids.has(selectedUid)) {
      setSelectedUid(null);
      setSelectedDetailTarget(null);
      setSelectedThreadDetailTarget(null);
      setSelectedThreadSummary(null);
      setConversationExpandOnly(false);
      setExpandedConversationId("");
    }
    await queryClient.invalidateQueries({ queryKey: ["messages"] });
    await queryClient.invalidateQueries({ queryKey: ["mail-search"] });
    await queryClient.refetchQueries({ queryKey: ["folders"], exact: true });
  };

  const matchingShareNotificationForInvite = (invite: NonNullable<ReturnType<typeof parseZimbraShareXml>>, notifications: ShareNotification[]) => {
    const normalizedInviteGrantor = invite.grantor_email.trim().toLowerCase();
    const normalizedInviteName = invite.item_name.trim().toLowerCase();
    const normalizedInviteItemId = invite.item_id.trim();
    return notifications.find((item) => invite.share_id && item.id === invite.share_id)
      ?? notifications.find((item) =>
        normalizedInviteItemId &&
        item.item_id === normalizedInviteItemId &&
        (!normalizedInviteGrantor || item.grantor_email.trim().toLowerCase() === normalizedInviteGrantor)
      )
      ?? notifications.find((item) =>
        normalizedInviteName &&
        item.item_name.trim().toLowerCase() === normalizedInviteName &&
        (!normalizedInviteGrantor || item.grantor_email.trim().toLowerCase() === normalizedInviteGrantor)
      )
      ?? null;
  };

  const loadMatchingShareNotification = async (invite: NonNullable<ReturnType<typeof parseZimbraShareXml>>) => {
    const cachedNotifications = shareNotifications.data?.notifications ?? [];
    let notifications = cachedNotifications;
    try {
      const freshNotifications = await queryClient.fetchQuery({
        queryKey: ["share-notifications"],
        queryFn: api.shareNotifications,
        staleTime: 0,
      });
      notifications = freshNotifications.notifications.length ? freshNotifications.notifications : cachedNotifications;
    } catch {
      notifications = cachedNotifications;
    }
    return matchingShareNotificationForInvite(invite, notifications);
  };

  const acceptNativeShareInvite = async (invite: ReturnType<typeof parseZimbraShareXml>, message?: MessageDetail) => {
    if (!invite) {
      setDriveNotice({ tone: "error", message: t("sharing.unableReadNativeData") });
      return;
    }
    const normalizedInviteItemId = invite.item_id.trim();
    const matched = await loadMatchingShareNotification(invite);
    if (matched) {
      try {
        await acceptShareNotification.mutateAsync(matched.id);
        await hideShareInviteMessage(message);
        return;
      } catch (error) {
        if (!normalizedInviteItemId) {
          setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : t("sharing.unableAcceptFolder") });
          return;
        }
      }
    }
    if (!normalizedInviteItemId) {
      setDriveNotice({ tone: "error", message: t("sharing.noMatchingNativeShare") });
      return;
    }
    await acceptShareInvite.mutateAsync({
      grantor_id: invite.grantor_id,
      grantor_email: invite.grantor_email,
      grantor_name: invite.grantor_name,
      item_id: invite.item_id,
      item_name: invite.item_name,
      item_view: invite.view || "message",
      item_perm: invite.perm || "r",
      mount_name: invite.item_name,
    });
    await hideShareInviteMessage(message);
  };
  const acceptNativeShareInviteAttachment = async (message: MessageDetail, attachment: MessageDetail["attachments"][number]) => {
    if (!attachment.part) {
      setDriveNotice({ tone: "error", message: t("sharing.inviteAttachmentMissing") });
      return;
    }
    await acceptMessageShareInvite.mutateAsync({
      uid: message.open_uid || message.uid,
      part: attachment.part,
      mount_name: cleanAttachmentDisplayName(attachment.filename).replace(/\.[^.]+$/, "") || t("sharing.sharedFolder"),
    });
    await hideShareInviteMessage(message);
  };
  const declineNativeShareInvite = async (invite: ReturnType<typeof parseZimbraShareXml>, message: MessageDetail) => {
    if (!invite) {
      await declineMessageShareInvite.mutateAsync({ uid: message.open_uid || message.uid });
      await hideShareInviteMessage(message);
      return;
    }
    const matched = await loadMatchingShareNotification(invite);
    if (matched) {
      await declineShareNotification.mutateAsync(matched.id);
    } else {
      await declineMessageShareInvite.mutateAsync({ uid: message.open_uid || message.uid });
    }
    await hideShareInviteMessage(message);
  };
  const declineNativeShareInviteAttachment = async (message: MessageDetail, attachment?: MessageDetail["attachments"][number]) => {
    await declineMessageShareInvite.mutateAsync({
      uid: message.open_uid || message.uid,
      part: attachment?.part || "",
    });
    await hideShareInviteMessage(message);
  };
  const updateMessageTags = useMutation({
    mutationFn: ({ uid, source, add, remove, view }: { uid: string; source: string; add?: string[]; remove?: string[]; view: "conversation" | "message" }) =>
      api.updateMessageTags(source, uid, { add, remove }, view),
    onMutate: async ({ uid, source, add, remove, view }) => {
      const targetView = view || messageViewMode;
      const matchesTarget = (message: { uid?: string; open_uid?: string; conversation_id?: string }) =>
        message.uid === uid || message.open_uid === uid || message.conversation_id === uid;
      await queryClient.cancelQueries({ queryKey: ["messages", source] });
      await queryClient.cancelQueries({ queryKey: ["message", source] });
      await queryClient.cancelQueries({ queryKey: ["message-thread-detail"] });
      await queryClient.cancelQueries({ queryKey: ["tags"] });

      const previousList = queryClient.getQueryData<InfiniteData<MessagePage>>(messageListQueryKey(source, targetView));
      const previousDetail = queryClient.getQueryData<{ message: MessageDetail }>(["message", source, uid, targetView]);
      const previousMessageDetails = queryClient.getQueriesData<{ message: MessageDetail }>({ queryKey: ["message", source] });
      const previousThreadDetails = queryClient.getQueriesData<{ message: MessageDetail }>({ queryKey: ["message-thread-detail"] });
      const previousTags = queryClient.getQueryData<{ tags: Tag[] }>(["tags"]);
      const previousMessageDetailMatch = previousMessageDetails
        .map(([, data]) => data?.message)
        .find((message) => message && (matchesTarget(message) || message.conversation_messages?.some((item) => matchesTarget(item))));
      const previousThreadDetailMatch = previousThreadDetails
        .map(([, data]) => data?.message)
        .find((message) => message && matchesTarget(message));
      const detailTarget =
        previousDetail?.message && matchesTarget(previousDetail.message)
          ? previousDetail.message
          : previousDetail?.message.conversation_messages?.find((message) => matchesTarget(message)) ||
            (previousMessageDetailMatch && matchesTarget(previousMessageDetailMatch)
              ? previousMessageDetailMatch
              : previousMessageDetailMatch?.conversation_messages?.find((message) => matchesTarget(message))) ||
            previousThreadDetailMatch ||
            (selectedActionTargetUid === uid ? selectedActionDetail : undefined);
      const messageSeen =
        detailTarget?.seen ??
        previousList?.pages.flatMap((page) => page.messages).find((message) => matchesTarget(message))?.seen ??
        false;
      const currentTags =
        detailTarget?.tags ??
        previousList?.pages.flatMap((page) => page.messages).find((message) => matchesTarget(message))?.tags ??
        [];
      const addSet = new Set((add ?? []).map((item) => item.trim()).filter(Boolean));
      const removeSet = new Set((remove ?? []).map((item) => item.trim()).filter(Boolean));
      const nextTags = currentTags.filter((item: string) => !removeSet.has(item));
      for (const name of addSet) {
        if (!nextTags.includes(name)) nextTags.push(name);
      }

      const patch = <T extends { uid?: string; open_uid?: string; conversation_id?: string; tags: string[] }>(message: T): T => (
        matchesTarget(message) ? { ...message, tags: nextTags } : message
      );
      const patchDetail = (detail: MessageDetail): MessageDetail => {
        let changed = false;
        let nextDetail = detail;
        if (matchesTarget(detail)) {
          nextDetail = { ...nextDetail, tags: nextTags };
          changed = true;
        }
        if (detail.conversation_messages?.length) {
          const nextConversationMessages = detail.conversation_messages.map((message) => {
            if (targetView !== "conversation" && !matchesTarget(message)) return message;
            changed = true;
            return { ...message, tags: nextTags };
          });
          if (changed) {
            nextDetail = { ...nextDetail, conversation_messages: nextConversationMessages };
          }
        }
        return changed ? nextDetail : detail;
      };

      queryClient.setQueryData<InfiniteData<MessagePage>>(messageListQueryKey(source, targetView), (old) =>
        updateMessagePages(old, (message) => patch(message))
      );
      queryClient.setQueryData(["message", source, uid, targetView], (old: { message: MessageDetail } | undefined) =>
        old ? { message: patchDetail(old.message) } : old
      );
      queryClient.setQueriesData<{ message: MessageDetail }>({ queryKey: ["message", source] }, (old) =>
        old ? { message: patchDetail(old.message) } : old
      );
      queryClient.setQueriesData<{ message: MessageDetail }>({ queryKey: ["message-thread-detail"] }, (old) =>
        old ? { message: patchDetail(old.message) } : old
      );
      queryClient.setQueryData(["tags"], (old: { tags: Tag[] } | undefined) => {
        if (!old) return old;
        return {
          tags: old.tags.map((tag) => {
            const hadTag = currentTags.includes(tag.name);
            const hasTag = nextTags.includes(tag.name);
            if (!messageSeen) {
              if (!hadTag && hasTag) return { ...tag, unread_count: tag.unread_count + 1 };
              if (hadTag && !hasTag) return { ...tag, unread_count: Math.max(0, tag.unread_count - 1) };
            }
            return tag;
          })
        };
      });

      return { previousList, previousDetail, previousMessageDetails, previousThreadDetails, previousTags, uid, source, view: targetView };
    },
    onError: (_error, _vars, context) => {
      if (!context) return;
      queryClient.setQueryData<InfiniteData<MessagePage>>(messageListQueryKey(context.source, context.view), context.previousList);
      queryClient.setQueryData(["message", context.source, context.uid, context.view], context.previousDetail);
      for (const [queryKey, data] of context.previousMessageDetails) {
        queryClient.setQueryData(queryKey, data);
      }
      for (const [queryKey, data] of context.previousThreadDetails) {
        queryClient.setQueryData(queryKey, data);
      }
      queryClient.setQueryData(["tags"], context.previousTags);
    },
    onSettled: (_data, _error, vars) => {
      queryClient.invalidateQueries({ queryKey: ["messages"] });
      queryClient.refetchQueries({ queryKey: ["messages"], type: "active" });
      queryClient.invalidateQueries({ queryKey: ["message", vars.source, vars.uid, vars.view] });
      queryClient.invalidateQueries({ queryKey: ["message-thread-detail", vars.source] });
      queryClient.invalidateQueries({ queryKey: ["tags"] });
      queryClient.refetchQueries({ queryKey: ["tags"], type: "active" });
    }
  });
  const saveAttachmentToDrive = useMutation({
    mutationFn: ({ uid, part, folder, folderId }: { uid: string; part: string; folder: string; folderId: string }) => api.driveSaveAttachment(uid, part, folder, folderId),
    onMutate: () => {
      setDriveNotice({ tone: "info", message: t("drive.savingAttachment", { drive: driveServiceLabel }) });
    },
    onSuccess: async (data) => {
      setDriveNotice({ tone: "success", message: t("drive.attachmentSavedAs", { drive: driveServiceLabel, name: data.file.name }) });
      await queryClient.invalidateQueries({ queryKey: ["drive-files"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-contents"] });
    },
    onError: (error) => {
      setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : t("drive.unableSaveAttachment", { drive: driveServiceLabel }) });
    }
  });
  const saveAllAttachmentsToDrive = useMutation({
    mutationFn: async ({ uid, parts, folder, folderId }: { uid: string; parts: string[]; folder: string; folderId: string }) => {
      const files: DriveFile[] = [];
      for (const part of parts) {
        const result = await api.driveSaveAttachment(uid, part, folder, folderId);
        files.push(result.file);
      }
      return files;
    },
    onMutate: () => {
      setDriveNotice({ tone: "info", message: t("drive.savingAllAttachments", { drive: driveServiceLabel }) });
    },
    onSuccess: async (files) => {
      const labels = files.map((file) => file.name).filter(Boolean);
      setDriveNotice({
        tone: "success",
        message: labels.length ? t("drive.allAttachmentsSavedAs", { drive: driveServiceLabel, names: labels.join(", ") }) : t("drive.allAttachmentsSaved", { drive: driveServiceLabel })
      });
      await queryClient.invalidateQueries({ queryKey: ["drive-files"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-contents"] });
    },
    onError: (error) => {
      setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : t("drive.unableSaveAttachments", { drive: driveServiceLabel }) });
    }
  });
  const openAttachmentSavePicker = (message: MessageDetail, parts: string[]) => {
    const normalizedParts = parts.map((part) => part.trim()).filter(Boolean);
    if (!normalizedParts.length) return;
    setAttachmentSavePicker({
      uid: message.uid,
      folder: message.folder || "INBOX",
      parts: normalizedParts,
    });
  };
  const saveAttachmentsToFolder = async (folderId: string) => {
    if (!attachmentSavePicker) return;
    const payload = attachmentSavePicker;
    if (payload.parts.length === 1) {
      await saveAttachmentToDrive.mutateAsync({
        uid: payload.uid,
        part: payload.parts[0],
        folder: payload.folder,
        folderId,
      });
    } else {
      await saveAllAttachmentsToDrive.mutateAsync({
        uid: payload.uid,
        parts: payload.parts,
        folder: payload.folder,
        folderId,
      });
    }
    setAttachmentSavePicker(null);
  };
  const uploadFilesToFolder = async (files: File[], folderId: string) => {
    await uploadDriveFiles.mutateAsync({ files, folderId });
    setDriveUploadPicker(null);
  };
  const deleteDriveFile = useMutation({
    mutationFn: api.driveDeleteFile,
    onMutate: (fileId) => {
      setDriveNotice({ tone: "info", message: t("drive.movingToTrash", { drive: driveServiceLabel }) });
    },
    onSuccess: async () => {
      setDriveNotice({ tone: "success", message: t("drive.itemMovedToTrash", { drive: driveServiceLabel }) });
      await queryClient.invalidateQueries({ queryKey: ["drive-contents"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-files"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-folders"] });
    },
    onError: (error) => {
      setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : t("drive.unableDeleteItem", { drive: driveServiceLabel }) });
    }
  });
  const confirmDeleteDriveFolder = (folderId: string, folderName: string) => {
    setConfirmDialog({
      title: t("drive.deleteFolderTitle", { drive: driveServiceLabel }),
      message: t("drive.deleteFolderMessage", { name: folderName }),
      confirmLabel: t("drive.deleteFolder"),
      tone: "danger",
      onConfirm: async () => {
        await deleteDriveFile.mutateAsync(folderId);
      },
    });
  };
  const confirmDeleteDriveFile = (fileId: string) => {
    setConfirmDialog({
      title: "Move file to trash?",
      message: `This moves the file to ${driveServiceLabel} trash.`,
      confirmLabel: "Move to trash",
      tone: "danger",
      onConfirm: async () => {
        await deleteDriveFile.mutateAsync(fileId);
      },
    });
  };
  const moveDriveFile = useMutation({
    mutationFn: ({ fileId, parentId }: { fileId: string; parentId: string }) => api.driveMoveFile(fileId, parentId),
    onMutate: ({ fileId, parentId }) => {
      setDriveNotice({ tone: "info", message: t("drive.movingToFolder") });
      setDriveDragFileId(fileId);
      setDriveDragTargetId(parentId);
    },
    onSuccess: async () => {
      setDriveNotice({ tone: "success", message: t("drive.fileMoved") });
      setDriveDragFileId("");
      setDriveDragTargetId("");
      await queryClient.invalidateQueries({ queryKey: ["drive-contents"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-files"] });
      await queryClient.invalidateQueries({ queryKey: ["drive-folders"] });
    },
    onError: (error) => {
      setDriveNotice({ tone: "error", message: error instanceof Error ? error.message : t("drive.unableMoveFile", { drive: driveServiceLabel }) });
      setDriveDragFileId("");
      setDriveDragTargetId("");
    }
  });

  const logout = useMutation({
    mutationFn: api.logout,
    onSuccess: () => {
      performClientLogout();
    },
    onError: () => {
      performClientLogout();
    },
  });

  useEffect(
    () => () => {
      if (mailboxRefreshTimer.current) {
        window.clearTimeout(mailboxRefreshTimer.current);
      }
      clearSessionTimers();
    },
    []
  );

  useEffect(() => {
    if (!me.data?.session_expires_at) {
      clearSessionTimers();
      return;
    }
    sessionKeepAliveLastRefresh.current = Date.now();
    scheduleSessionTimers(me.data.session_expires_at, me.data.session_ttl_seconds);
  }, [me.data?.session_expires_at, me.data?.session_ttl_seconds]);

  useEffect(() => {
    if (!me.data?.session_expires_at) return;
    const sessionTtlMs = Math.max(60, me.data.session_ttl_seconds || 0) * 1000;
    const refreshThresholdMs = Math.min(15 * 60_000, Math.max(10_000, sessionTtlMs / 2));
    const activityThrottleMs = 5 * 60_000;
    const refreshOnActivity = () => {
      if (sessionKeepAlivePending.current) return;
      const expiresAtMs = me.data.session_expires_at * 1000;
      const remainingMs = expiresAtMs - Date.now();
      if (remainingMs > refreshThresholdMs && Date.now() - sessionKeepAliveLastRefresh.current < activityThrottleMs) {
        return;
      }
      sessionKeepAliveLastRefresh.current = Date.now();
      void keepSessionAlive();
    };
    const handleVisibilityChange = () => {
      if (document.visibilityState === "visible") {
        refreshOnActivity();
      }
    };
    const events: (keyof WindowEventMap)[] = ["pointerdown", "keydown", "focus", "scroll"];
    for (const eventName of events) {
      window.addEventListener(eventName, refreshOnActivity, { passive: true });
    }
    document.addEventListener("visibilitychange", handleVisibilityChange);
    return () => {
      for (const eventName of events) {
        window.removeEventListener(eventName, refreshOnActivity);
      }
      document.removeEventListener("visibilitychange", handleVisibilityChange);
    };
  }, [keepSessionAlive, me.data?.session_expires_at, me.data?.session_ttl_seconds]);

  const effectiveThemeName = normalizeThemeName(workspacePreferences.data?.theme || "", preferences.theme);
  const activeTheme = themes[effectiveThemeName] ?? themes.cyan;
  const t = useMemo(() => createTranslator(preferences.locale), [preferences.locale]);
  const lockedFeatureTooltip = t("feature.upgradeToUnlock");
  const fontClass = preferences.fontScale === "compact" ? "text-[13px]" : preferences.fontScale === "large" ? "text-[16px]" : "text-[14px]";
  const loadedMessages = useMemo(
    () => messages.data?.pages.flatMap((page) => page.messages) ?? [],
    [messages.data?.pages]
  );
  const searchTerm = search.trim();
  const searchResults = useQuery({
    queryKey: ["mail-search", folder, globalSearch, searchTerm],
    queryFn: () => api.searchAll(searchTerm, globalSearch ? "" : folder),
    enabled: Boolean(me.data && searchTerm.length > 1),
    staleTime: 30_000,
    refetchOnWindowFocus: false,
  });
  const allMessages = useMemo(
    () => (searchTerm.length > 1 ? sortMessageSummaries(searchResults.data?.messages ?? [], messageSortOrder) : loadedMessages),
    [loadedMessages, messageSortOrder, searchResults.data?.messages, searchTerm.length]
  );
  useEffect(() => {
    const updateViewport = () => setIsCompactViewport(window.innerWidth < 1280);
    updateViewport();
    window.addEventListener("resize", updateViewport);
    return () => window.removeEventListener("resize", updateViewport);
  }, []);
  useEffect(() => {
    if (!isCompactViewport) setSidebarOpen(false);
  }, [isCompactViewport]);
  useEffect(() => {
    if (activeSection !== "email") setMobileMailPane("list");
  }, [activeSection]);
  const inboxFolder = useMemo(
    () => (folders.data?.folders ?? []).find((item) => isInboxFolder(item)),
    [folders.data?.folders]
  );
  const sentFolder = useMemo(
    () => (folders.data?.folders ?? []).find((item) => isSentFolderPath(item.abs_path) || isSentFolderPath(item.name)),
    [folders.data?.folders]
  );
  const draftsFolder = useMemo(
    () => (folders.data?.folders ?? []).find((item) => item.abs_path === "/Drafts" || item.name.trim().toLowerCase() === "drafts"),
    [folders.data?.folders]
  );
  const tagMap = useMemo(
    () => new Map((tags.data?.tags ?? []).map((item) => [item.id, item])),
    [tags.data?.tags]
  );
  const tagsByName = useMemo(
    () => new Map((tags.data?.tags ?? []).map((item) => [item.name, item])),
    [tags.data?.tags]
  );
  const unreadCount = inboxFolder?.unread_count ?? allMessages.filter((message) => !message.seen).length;
  const sentCount = sentFolder?.unread_count ?? 0;
  const starredCount = folders.data?.starred_unread_count ?? allMessages.filter((message) => message.starred && !message.seen).length;
  const draftsCount = draftsFolder?.total_count ?? 0;
  const inboxDropTarget = inboxFolder?.path || "INBOX";
  const junkFolder = useMemo(
    () => (folders.data?.folders ?? []).find((item) => item.abs_path === "/Junk" || item.abs_path === "/Spam" || ["junk", "spam"].includes(item.name.trim().toLowerCase())),
    [folders.data?.folders]
  );
  const currentFolderRecord = useMemo(
    () => (folders.data?.folders ?? []).find((item) => item.path === folder || item.abs_path === folder || displayFolder(item.name) === displayFolder(folder)),
    [folders.data?.folders, folder]
  );
  const activeFolderLabel = useMemo(() => {
    if (folder.toUpperCase() === "STARRED") return "Starred";
    if (folder.toUpperCase() === "INBOX") return "Inbox";
    if (folder.toUpperCase().startsWith("TAG:")) return tagMap.get(folder.slice(4))?.name ?? "Tag";
    return currentFolderRecord?.name ?? folder;
  }, [folder, currentFolderRecord, tagMap]);
  const driveFolderTree = useMemo(
    () => buildDriveFolderTree(driveFolders.data?.folders ?? []),
    [driveFolders.data?.folders]
  );
  const manageableBriefcaseFolders = useMemo(
    () =>
      (driveFolders.data?.folders ?? []).filter((item) => {
        const normalized = item.name.trim().toLowerCase();
        return item.id && normalized !== "trash";
      }),
    [driveFolders.data?.folders]
  );
  const browsedDriveCurrentFolder = useQuery({
    queryKey: ["drive-folder", "browse", driveBrowseFolderId],
    queryFn: () => api.driveFile(driveBrowseFolderId),
    enabled: Boolean(me.data && mailBooted && enableDriveSection && driveStatus.data?.connected && driveBrowseFolderId),
    staleTime: 5 * 60_000,
    refetchOnWindowFocus: false,
    retry: false,
  });
  const selectedDriveFolderName = useMemo(
    () => {
      const name = driveSelectedFolder.data?.file?.name ?? driveSaveFolderName ?? (driveFolders.data?.folders ?? []).find((item) => item.id === driveSaveFolderId)?.name ?? "";
      return isNativeZimbraAddonEdition(activeEdition) && name === "Root" ? driveRootLabel : name;
    },
    [activeEdition, driveFolders.data?.folders, driveSaveFolderName, driveSaveFolderId, driveSelectedFolder.data?.file?.name, driveRootLabel, driveServiceLabel]
  );
  const selectedDriveFolderPath = useMemo(
    () => (driveSaveFolderId ? findDriveFolderPath(driveFolderTree, driveSaveFolderId) : []),
    [driveFolderTree, driveSaveFolderId]
  );
  const browsedDriveFolderPath = useMemo(
    () => (driveBrowseFolderId ? findDriveFolderPath(driveFolderTree, driveBrowseFolderId) : []),
    [driveFolderTree, driveBrowseFolderId]
  );
  const browsedDriveBreadcrumbs = useMemo(
    () => (driveBrowseFolderId ? findDriveFolderBreadcrumbs(driveFolderTree, driveBrowseFolderId) : []),
    [driveFolderTree, driveBrowseFolderId]
  );
  const browsedDriveDisplayBreadcrumbs = useMemo(
    () => browsedDriveBreadcrumbs.filter((crumb) => crumb.name !== driveServiceLabel),
    [browsedDriveBreadcrumbs, driveServiceLabel]
  );
  const browsedDriveParentId = useMemo(
    () => browsedDriveCurrentFolder.data?.file?.parent_ids.find((value) => value && value !== driveBrowseFolderId) ?? "",
    [browsedDriveCurrentFolder.data?.file?.parent_ids, driveBrowseFolderId]
  );
  const browsedDriveParentDestination = browsedDriveParentId === "1" || browsedDriveParentId === "root" ? "" : browsedDriveParentId;
  const browsedDriveCurrentFolderName = browsedDriveCurrentFolder.data?.file?.name ?? "";
  const browsedDriveCurrentFolderRecord = browsedDriveCurrentFolder.data?.file ?? (driveFolders.data?.folders ?? []).find((item) => item.id === driveBrowseFolderId) ?? null;
  const driveCanWriteCurrentFolder = (driveWritable || nativeZimbraDrive) && canWriteDriveFolder(browsedDriveCurrentFolderRecord);
  const driveCanCreateFolder = driveCanWriteCurrentFolder;
  const browsedDriveCurrentFolderShareable = Boolean(
    nativeZimbraDrive &&
    driveCanWriteCurrentFolder &&
    driveBrowseFolderId &&
    browsedDriveCurrentFolderName.trim() &&
    browsedDriveCurrentFolderName.trim().toLowerCase() !== "trash"
  );
  const browsedDriveShowParentRow = Boolean(
    driveBrowseFolderId &&
    browsedDriveParentId &&
    !(isNativeZimbraAddonEdition(activeEdition) && browsedDriveCurrentFolderName === driveServiceLabel)
  );
  const briefcaseShareNotifications = useMemo(
    () => (shareNotifications.data?.notifications ?? []).filter((item) => isBriefcaseShareNotification(item)),
    [shareNotifications.data?.notifications]
  );
  const mountedBriefcaseShares = useQuery({
    queryKey: ["native-zimbra-mounted-briefcase-shares"],
    queryFn: api.nativeZimbraMountedBriefcaseShares,
    enabled: Boolean(me.data && mailBooted && enableDriveSection && isNativeZimbraAddonEdition(activeEdition) && driveStatus.data?.connected),
    staleTime: 30_000,
    refetchOnWindowFocus: false,
  });
  const outgoingBriefcaseShares = useQuery({
    queryKey: ["native-zimbra-outgoing-briefcase-shares"],
    queryFn: api.nativeZimbraOutgoingBriefcaseShares,
    enabled: Boolean(me.data && mailBooted && enableDriveSection && isNativeZimbraAddonEdition(activeEdition) && driveStatus.data?.connected),
    staleTime: 30_000,
    refetchOnWindowFocus: false,
  });
  const pendingBriefcaseShareNotifications = useMemo(
    () => briefcaseShareNotifications.filter((item) => {
      return isPendingShareNotification(item) && !findDriveFolderForShareNotification(mountedBriefcaseShares.data?.folders ?? [], item);
    }),
    [briefcaseShareNotifications, mountedBriefcaseShares.data?.folders]
  );
  const filteredMessages = useMemo(() => {
    const q = search.trim().toLowerCase();
    if (q.length > 1) return allMessages;
    if (!q) return allMessages;
    return allMessages.filter((message) =>
      [message.subject, message.sender_name, message.sender_email, message.to, message.preview].join(" ").toLowerCase().includes(q)
    );
  }, [allMessages, search]);
  const visibleMessages = filteredMessages;
  const selectedSummary = useMemo(() => {
    if (selectedThreadSummary) return selectedThreadSummary;
    if (!selectedUid) return undefined;
    return visibleMessages.find((message) =>
      (message.folder || folder) === selectedFolder &&
      (message.uid === selectedUid || message.open_uid === selectedUid || message.conversation_id === selectedUid)
    );
  }, [folder, selectedFolder, selectedThreadSummary, selectedUid, visibleMessages]);
  const resolvedDetailMessage = useMemo(() => {
    const detailMessage = detail.data?.message;
    const targetUid = selectedThreadDetailTarget?.uid || selectedDetailTarget?.uid || selectedUid || "";
    const targetView = selectedThreadDetailTarget ? "message" : (selectedDetailTarget?.view || messageViewMode);
    if (!detailMessage || !targetUid) return undefined;
    if (selectedThreadDetailTarget) {
      const matchesThreadTarget =
        detailMessage.uid === targetUid ||
        detailMessage.open_uid === targetUid;
      return matchesThreadTarget ? detailMessage : undefined;
    }
    if (targetView === "conversation") {
      const conversationTarget = detailMessage.conversation_id || detailMessage.uid;
      return conversationTarget === targetUid ? detailMessage : undefined;
    }
    const matchesMessageTarget =
      detailMessage.uid === targetUid ||
      detailMessage.open_uid === targetUid;
    return matchesMessageTarget ? detailMessage : undefined;
  }, [detail.data?.message, messageViewMode, selectedDetailTarget?.uid, selectedDetailTarget?.view, selectedThreadDetailTarget?.uid, selectedUid]);
  const selectedDetail = useMemo<MessageDetail | undefined>(() => {
    const detailTarget = selectedThreadDetailTarget || selectedDetailTarget;
    if (!detailTarget?.uid) return undefined;
    const detailMessage = resolvedDetailMessage;
    const summaryMessage = selectedSummary;
    const summaryIsCalendar = Boolean(summaryMessage && messageHasCalendarInvite(summaryMessage));
    const allowProvisionalDetail = !selectedThreadDetailTarget;
    const provisionalDetail = allowProvisionalDetail && summaryMessage && !summaryIsCalendar
      ? {
          ...summaryMessage,
          open_uid: summaryMessage.open_uid || summaryMessage.uid,
          html: summaryMessage.preview ? `<pre style="white-space:pre-wrap;word-break:break-word;margin:0">${escapeHtml(summaryMessage.preview)}</pre>` : "",
          text: summaryMessage.preview || "",
          share_xml: "",
          calendar_invite: null,
          cc: "",
          bcc: "",
          headers: [],
          attachments: [],
          conversation_messages: [],
        }
      : undefined;
    if (summaryIsCalendar && detailMessage && !detailMessage.calendar_invite) {
      return undefined;
    }
    if (detailMessage) {
      return summaryMessage ? {
        ...detailMessage,
        subject: detailMessage.subject && detailMessage.subject !== "(no subject)" ? detailMessage.subject : summaryMessage.subject,
        sender_name: detailMessage.sender_name || summaryMessage.sender_name,
        sender_email: detailMessage.sender_email || summaryMessage.sender_email,
        to: detailMessage.to || summaryMessage.to,
        date: detailMessage.date || summaryMessage.date,
        folder: detailMessage.folder || detailTarget.folder || summaryMessage.folder || selectedFolder,
        preview: detailMessage.preview || summaryMessage.preview,
        text: detailMessage.text || summaryMessage.preview || "",
        html: detailMessage.html || (summaryMessage.preview ? `<pre style="white-space:pre-wrap;word-break:break-word;margin:0">${escapeHtml(summaryMessage.preview)}</pre>` : ""),
      } : detailMessage;
    }
    if (provisionalDetail) {
      return provisionalDetail;
    }
    if (allowProvisionalDetail && detail.data?.message && !summaryIsCalendar) {
      const fallbackMessage = detail.data.message;
      return {
        ...fallbackMessage,
        folder: fallbackMessage.folder || detailTarget.folder || summaryMessage?.folder || selectedFolder,
        subject: fallbackMessage.subject && fallbackMessage.subject !== "(no subject)" ? fallbackMessage.subject : summaryMessage?.subject || fallbackMessage.subject,
        sender_name: fallbackMessage.sender_name || summaryMessage?.sender_name || "",
        sender_email: fallbackMessage.sender_email || summaryMessage?.sender_email || "",
        to: fallbackMessage.to || summaryMessage?.to || "",
        date: fallbackMessage.date || summaryMessage?.date || "",
        preview: fallbackMessage.preview || summaryMessage?.preview || "",
        text: fallbackMessage.text || summaryMessage?.preview || "",
        html: fallbackMessage.html || (summaryMessage?.preview ? `<pre style="white-space:pre-wrap;word-break:break-word;margin:0">${escapeHtml(summaryMessage.preview)}</pre>` : ""),
      };
    }
    return undefined;
  }, [detail.data?.message, resolvedDetailMessage, selectedFolder, selectedSummary, selectedThreadDetailTarget, selectedThreadDetailTarget?.folder, selectedThreadDetailTarget?.uid, selectedDetailTarget?.folder, selectedDetailTarget?.uid, selectedUid]);

  useEffect(() => {
    const summary = selectedSummary;
    const loadedMessage = detail.data?.message;
    if (!summary || !loadedMessage || loadedMessage.calendar_invite || !messageHasCalendarInvite(summary)) return;
    const retryKey = `${selectedDetailTarget?.folder || selectedFolder}:${selectedDetailTarget?.uid || selectedUid}`;
    if (!retryKey || calendarDetailRetryRef.current === retryKey || detail.isFetching) return;
    calendarDetailRetryRef.current = retryKey;
    void detail.refetch();
  }, [detail.data?.message, detail.isFetching, detail.refetch, selectedDetailTarget?.folder, selectedDetailTarget?.uid, selectedFolder, selectedSummary, selectedUid]);
  const selectedConversationMessages = useMemo(() => {
    if (messageViewMode !== "conversation") return [];
    const thread = (selectedDetail?.conversation_messages ?? []).length
      ? selectedDetail!.conversation_messages
      : conversationFocusedMessageDetail.data?.message?.conversation_messages ?? [];
    return thread
      .filter((message) => {
        const folder = (message.folder || "").trim().toLowerCase();
        return folder !== "3" && folder !== "trash" && folder !== "/trash";
      })
      .slice()
      .sort((left, right) => {
        const leftTime = Date.parse(left.date || "") || 0;
        const rightTime = Date.parse(right.date || "") || 0;
        return rightTime - leftTime;
      });
  }, [messageViewMode, selectedDetail?.conversation_messages, conversationFocusedMessageDetail.data?.message?.conversation_messages]);
  const focusedConversationUid = readerTargetUid;
  const selectedConversationMessage = useMemo(() => {
    if (!selectedDetail || selectedConversationMessages.length <= 1) return undefined;
    return selectedConversationMessages.find((item) => item.uid === selectedThreadUid || item.uid === selectedThreadDetailTarget?.uid || item.uid === selectedDetailTarget?.uid) || selectedConversationMessages[0];
  }, [selectedConversationMessages, selectedDetail, readerTargetUid, selectedDetailTarget?.uid, selectedThreadDetailTarget?.uid, selectedThreadUid]);
  const resolvedConversationFocusedMessage = useMemo(() => {
    const detailMessage = conversationFocusedMessageDetail.data?.message;
    const targetUid = focusedConversationUid || selectedDetail?.uid || selectedUid;
    if (!detailMessage || !targetUid) return undefined;
    const belongsToTarget =
      detailMessage.uid === targetUid ||
      detailMessage.open_uid === targetUid ||
      detailMessage.conversation_id === targetUid ||
      detailMessage.conversation_messages.some((item) => item.uid === targetUid);
    if (!belongsToTarget && selectedDetailTarget?.view !== "conversation") return undefined;
    return detailMessage;
  }, [conversationFocusedMessageDetail.data?.message, focusedConversationUid, selectedDetail?.uid, selectedDetailTarget?.view, selectedUid]);
  const conversationThreadFocused = Boolean(
    selectedDetail &&
      selectedConversationMessages.length > 1 &&
      (selectedThreadUid || selectedThreadDetailTarget?.uid) &&
      readerTargetUid &&
      readerTargetUid !== selectedDetail.uid
  );
  const activeReaderDetail = useMemo(() => {
    if (!selectedDetail) return undefined;
    if (selectedThreadDetailTarget) return selectedDetail;
    if (messageViewMode !== "conversation") return selectedDetail;
    const focusedMessage = resolvedConversationFocusedMessage;
    const selectedHasInvite = Boolean(selectedDetail.calendar_invite);
    if (focusedMessage?.calendar_invite) {
      return {
        ...selectedDetail,
        ...focusedMessage,
        conversation_messages: selectedConversationMessages,
      };
    }
    if (!selectedConversationMessage) {
      if (focusedMessage && (detailLooksPreviewOnly(selectedDetail) || !detailLooksPreviewOnly(focusedMessage))) {
        return {
          ...selectedDetail,
          ...focusedMessage,
          conversation_messages: selectedConversationMessages,
        };
      }
      return selectedDetail;
    }
    if (selectedHasInvite && !selectedConversationMessage.calendar_invite) {
      return {
        ...selectedDetail,
        conversation_messages: selectedConversationMessages,
      };
    }
    if (detailLooksPreviewOnly(selectedConversationMessage) && !focusedMessage) {
      return {
        ...selectedDetail,
        conversation_messages: selectedConversationMessages,
      };
    }
    if (focusedMessage && (detailLooksPreviewOnly(selectedConversationMessage) || !detailLooksPreviewOnly(focusedMessage))) {
      return {
        ...selectedDetail,
        ...focusedMessage,
        conversation_messages: selectedConversationMessages,
      };
    }
    return {
      ...selectedDetail,
      ...selectedConversationMessage,
      conversation_messages: selectedConversationMessages,
    };
  }, [
    messageViewMode,
    resolvedConversationFocusedMessage,
    selectedConversationMessage,
    selectedConversationMessages,
    selectedDetail
  ]);
  const selectedActionDetail = activeReaderDetail ?? selectedDetail;
  const selectedActionTargetUid =
    selectedActionDetail?.uid || selectedUid || "";
  const conversationThreadSelected = Boolean(
    selectedConversationMessages.length > 1 &&
      expandedConversationId === (selectedDetail?.conversation_id || selectedDetail?.uid || selectedUid || "") &&
      conversationThreadFocused
  );
  const selectedItems = useMemo(() => {
    const selected = new Set(selectedKeys);
    return visibleMessages
      .filter((message) => selected.has(messageKey(message)))
      .map((message) => messageToSelection(message));
  }, [selectedKeys, visibleMessages]);
  useEffect(() => {
    const firstMessage = loadedMessages[0];
    if (!firstMessage || folder !== "INBOX") return;
    const cacheKey = `${folder}:${messageViewMode}:${firstMessage.uid}`;
    if (prefetchedMessageRef.current === cacheKey) return;
    prefetchedMessageRef.current = cacheKey;
    const targetUid = firstMessage.open_uid || firstMessage.uid;
    void queryClient.prefetchQuery({
      queryKey: ["message", firstMessage.folder || folder, targetUid, "message"],
      queryFn: () => api.message(firstMessage.folder || folder, targetUid, "message"),
    });
  }, [folder, loadedMessages, messageViewMode, queryClient]);

  const previousMessageViewModeRef = useRef(messageViewMode);
  useEffect(() => {
    if (previousMessageViewModeRef.current === messageViewMode) return;
    previousMessageViewModeRef.current = messageViewMode;
    setExpandedConversationId("");
    setSelectedUid(null);
    setSelectedDetailTarget(null);
    setSelectedKeys([]);
    setOriginalOpen(false);
  }, [messageViewMode]);

  const activeSelection = selectedItems.length
    ? selectedItems
    : selectedUid
      ? [{ key: `${selectedFolder}:${selectedUid}`, uid: selectedUid, source: selectedFolder }]
      : [];
  const currentReaderDetail = activeReaderDetail ?? selectedDetail;
  const selectedActionSource = selectedActionDetail?.folder || selectedFolder;
  const readerActionIsConversation = messageViewMode === "conversation" && Boolean(selectedActionDetail?.conversation_count && selectedActionDetail.conversation_count > 1);
  const readerActionUid = readerActionIsConversation
    ? (selectedActionDetail?.conversation_id || selectedActionDetail?.uid || "")
    : (selectedActionDetail?.open_uid || selectedActionDetail?.uid || "");
  const readerActionView: "conversation" | "message" = readerActionIsConversation ? "conversation" : "message";
  const currentReaderSummary = useMemo(() => {
    if (selectedThreadSummary) return selectedThreadSummary;
    if (selectedSummary) return selectedSummary;
    if (!currentReaderDetail) return undefined;
    return visibleMessages.find(
      (message) =>
        (message.uid === currentReaderDetail.open_uid ||
          message.uid === currentReaderDetail.uid ||
          message.open_uid === currentReaderDetail.open_uid ||
          message.open_uid === currentReaderDetail.uid ||
          message.conversation_id === currentReaderDetail.conversation_id) &&
        (message.folder || folder) === selectedActionSource
    );
  }, [currentReaderDetail, folder, selectedActionSource, selectedSummary, selectedThreadSummary, visibleMessages]);
  const readerInstanceKey = `${messageViewMode}:${readerTargetFolder}:${currentReaderDetail?.uid || readerTargetUid || "empty"}`;
  const readerHasDetail = Boolean(currentReaderDetail);
  const readerLoading = Boolean(selectedUid) && !conversationExpandOnly && !detail.isError && (
    Boolean(selectedThreadDetailTarget?.uid && !resolvedDetailMessage) ||
    (!readerHasDetail && detail.isLoading) ||
    (!readerHasDetail && detail.isFetching) ||
    (!readerHasDetail && Boolean(selectedSummary && messageHasCalendarInvite(selectedSummary) && detail.data?.message && !detail.data.message.calendar_invite)) ||
    (!readerHasDetail && messageViewMode === "conversation" && conversationFocusedMessageDetail.isFetching && detailLooksPreviewOnly(activeReaderDetail ?? selectedDetail))
  );
  const currentFolderSource = currentFolderRecord?.abs_path || currentFolderRecord?.name || selectedFolder;
  const currentFolderCanDeleteMessages = canDeleteMessagesInFolder(currentFolderRecord);
  const pendingSelectionRef = useRef<{ uid: string; source: string; view: "conversation" | "message" } | null>(null);
  const pendingShareFocusRef = useRef<ShareNotification | null>(null);
  const shareHighlightTimerRef = useRef<number | null>(null);
  const [sharedFolderHighlightPath, setSharedFolderHighlightPath] = useState("");
  const [sharedFolderHighlightPulse, setSharedFolderHighlightPulse] = useState(false);
  const [briefcaseShareEditor, setBriefcaseShareEditor] = useState<BriefcaseShareState | null>(null);
  const lastListSelectionKeyRef = useRef<string>("");
  function resolveNextVisibleMessage(messages: MessageSummary[], selectedKey: string, excludedKeys: string[]) {
    const currentIndex = messages.findIndex((message) => messageKey(message) === selectedKey);
    const remaining = messages.filter((message) => !excludedKeys.includes(messageKey(message)));
    if (!remaining.length) {
      return null;
    }
    const nextMessage =
      currentIndex >= 0
        ? messages.slice(currentIndex + 1).find((message) => !excludedKeys.includes(messageKey(message))) ||
          messages.slice(0, currentIndex).reverse().find((message) => !excludedKeys.includes(messageKey(message))) ||
          remaining[0]
        : remaining[0];
    return { uid: nextMessage.uid, source: nextMessage.folder || currentFolderSource, view: messageViewMode };
  }
  const originalMessageUid =
    currentReaderDetail?.open_uid ||
    currentReaderDetail?.uid ||
    selectedThreadDetailTarget?.uid ||
    selectedDetailTarget?.uid ||
    selectedUid;
  const readerListMessage = useMemo(() => {
    const selectedListKey = lastListSelectionKeyRef.current;
    if (selectedListKey) {
      const keyedMessage = visibleMessages.find((message) => messageKey(message) === selectedListKey);
      if (keyedMessage) return keyedMessage;
    }
    const targetUid = selectedDetailTarget?.uid || selectedUid || "";
    const targetSource = selectedDetailTarget?.folder || selectedFolder;
    if (!targetUid) return undefined;
    return visibleMessages.find((message) =>
      (message.folder || folder) === targetSource &&
      (message.uid === targetUid || message.open_uid === targetUid || message.conversation_id === targetUid)
    );
  }, [folder, selectedDetailTarget?.folder, selectedDetailTarget?.uid, selectedFolder, selectedUid, visibleMessages]);
  function resolveReaderActionSource() {
    const detailFolder = (currentReaderDetail?.folder || "").trim();
    const currentFolderIsShared = Boolean(currentFolderRecord?.share_owner_email || currentFolderRecord?.share_owner_id);
    if (detailFolder && !(currentFolderIsShared && detailFolder.toUpperCase() === "INBOX")) {
      return detailFolder;
    }
    return currentFolderSource || selectedActionSource || selectedFolder;
  }
  const deleteCurrentReaderMessage = () => {
    if (selectedItems.length > 1) {
      void deleteSelection(activeSelection, messageViewMode);
      return;
    }
    // Use the same summary and view as the trash button in MessageRow. The
    // reader detail may represent one message inside a conversation and can
    // therefore have a different uid/folder shape than the list row.
    if (readerListMessage) {
      void deleteSelection(resolveDeleteTargets(readerListMessage, readerListMessage.folder || selectedFolder));
      return;
    }
    if (currentReaderDetail) {
      const source = resolveReaderActionSource();
      const deleteConversation =
        messageViewMode === "conversation" &&
        !selectedThreadDetailTarget &&
        Boolean(currentReaderDetail.conversation_count && currentReaderDetail.conversation_count > 1) &&
        Boolean(currentReaderDetail.conversation_id);
      const uid = deleteConversation
        ? currentReaderDetail.conversation_id
        : currentReaderDetail.open_uid || currentReaderDetail.uid;
      if (!uid || !currentFolderCanDeleteMessages) return;
      void deleteSelection([{ key: `${source}:${uid}`, uid, source }], deleteConversation ? "conversation" : "message");
      return;
    }
    const target =
      currentReaderSummary ||
      selectedThreadSummary ||
      selectedSummary ||
      null;
    if (!target) return;
    if (!currentFolderCanDeleteMessages) return;
    const targetFolder = currentReaderDetail ? resolveReaderActionSource() : (target.folder || selectedActionSource || currentFolderSource);
    void deleteSelection(resolveDeleteTargets(target as MessageSummary, targetFolder), "message");
  };
  const originalMessage = useQuery({
    queryKey: ["message-original", originalMessageUid || ""],
    queryFn: () => api.original(originalMessageUid as string),
    enabled: Boolean(originalOpen && originalMessageUid),
    staleTime: 0,
    refetchOnMount: "always",
    refetchOnWindowFocus: false,
  });
  const conversationMessagesForListRow = (message: MessageSummary) => {
    const messageConversationKey = message.conversation_id || message.uid;
    if (expandedConversationId !== messageConversationKey) return [];
    const threadSources = [selectedDetail, conversationFocusedMessageDetail.data?.message, detail.data?.message].filter(
      (item): item is MessageDetail => Boolean(item?.conversation_messages?.length)
    );
    const detailWithThread = threadSources.find((item) => {
      if (!item?.conversation_messages?.length) return false;
      const detailConversationKey = item.conversation_id || item.uid;
      return (
        detailConversationKey === messageConversationKey ||
        item.uid === message.uid ||
        item.open_uid === message.open_uid ||
        item.conversation_messages.some((threadMessage) => {
          const threadMeta = threadMessage as typeof threadMessage & Partial<Pick<MessageDetail, "open_uid" | "conversation_id">>;
          return (
            threadMeta.uid === message.uid ||
            threadMeta.open_uid === message.open_uid ||
            threadMeta.conversation_id === messageConversationKey
          );
        })
      );
    }) ?? (selectedDetailTarget?.view === "conversation" ? threadSources[0] : undefined);
    return (detailWithThread?.conversation_messages ?? [])
      .filter((threadMessage) => {
        const folder = (threadMessage.folder || "").trim().toLowerCase();
        return folder !== "3" && folder !== "trash" && folder !== "/trash";
      })
      .slice()
      .sort((left, right) => {
        const leftTime = Date.parse(left.date || "") || 0;
        const rightTime = Date.parse(right.date || "") || 0;
        return rightTime - leftTime;
      });
  };
  const renderConversationThreadBlock = (message: MessageSummary) => {
    const messageConversationKey = message.conversation_id || message.uid;
    const listRowConversationMessages = conversationMessagesForListRow(message);
    if (expandedConversationId !== messageConversationKey) return null;
    const threadLoading =
      !listRowConversationMessages.length && (
        conversationFocusedMessageDetail.isLoading ||
        (!conversationExpandOnly && selectedDetailTarget?.view === "conversation" && detail.isLoading)
      );
    const threadHasSettled = !threadLoading && (
      conversationFocusedMessageDetail.isSuccess ||
      conversationFocusedMessageDetail.isError ||
      detail.isSuccess ||
      detail.isError ||
      Boolean(selectedDetailTarget?.view === "conversation")
    );
    return (
      <div className="ml-3 border-l border-slate-200 bg-slate-50/70 px-2 py-2 sm:ml-6">
        <div className="mb-2 flex items-center justify-between px-2">
          <p className="text-[11px] font-black uppercase tracking-[0.12em] text-slate-400">{t("reader.threadMessages")}</p>
          <span className="text-[11px] font-semibold text-slate-400">
            {listRowConversationMessages.length ? t("reader.messagesCount", { count: listRowConversationMessages.length }) : threadHasSettled ? t("mail.noMessages") : t("reader.loadingMessage")}
          </span>
        </div>
        {listRowConversationMessages.length ? (
          <div className="grid overflow-hidden rounded-lg border border-slate-200 bg-white">
            {listRowConversationMessages.map((threadMessage, index) => (
            <ThreadRow
              t={t}
              locale={preferences.locale}
              timeZone={calendarTimeZone}
              key={threadMessage.uid || `${message.uid}-${index}`}
              message={threadMessage}
              index={index}
              active={selectedThreadDetailTarget?.uid === threadMessage.uid || selectedThreadUid === threadMessage.uid}
              onSelect={() => {
                setSelectedThreadUid(threadMessage.uid);
                setSelectedUid(threadMessage.uid);
                setSelectedFolder(threadMessage.folder || message.folder || folder);
                setConversationExpandOnly(false);
                setExpandedConversationId(messageConversationKey);
                setSelectedThreadDetailTarget({
                  folder: threadMessage.folder || message.folder || folder,
                  uid: threadMessage.uid,
                });
                setSelectedThreadSummary({
                  ...threadMessage,
                  folder: threadMessage.folder || message.folder || folder,
                } as unknown as MessageSummary);
                setSelectedDetailTarget({
                  folder: message.folder || folder,
                  uid: message.uid,
                  view: "conversation",
                });
                if (isCompactViewport) setMobileMailPane("reader");
              }}
            />
            ))}
          </div>
        ) : (
          <div className="grid gap-2 rounded-lg border border-slate-200 bg-white p-3">
            {threadLoading ? (
              <>
                <div className="h-3 w-2/3 animate-pulse rounded bg-slate-100" />
                <div className="h-3 w-5/6 animate-pulse rounded bg-slate-100" />
                <div className="h-3 w-1/2 animate-pulse rounded bg-slate-100" />
              </>
            ) : (
              <p className="text-xs font-semibold text-slate-400">{t("mail.noMessages")}</p>
            )}
          </div>
        )}
      </div>
    );
  };
  const isConversationRowSelected = (message: MessageSummary) =>
    selectedUid === message.uid &&
    selectedFolder === (message.folder || folder) &&
    !conversationThreadFocused;

  function resetWorkspaceState() {
    setFolder("INBOX");
    setSelectedUid(null);
    setSelectedDetailTarget(null);
    setSelectedThreadDetailTarget(null);
    setSelectedThreadSummary(null);
    setSelectedFolder("INBOX");
    setExpandedConversationId("");
    setSelectedKeys([]);
    setLastSelectedIndex(null);
    setSearch("");
    setGlobalSearch(false);
    setNewFolderName("");
    setFolderMenu(null);
    setFolderEditor(null);
    setConfirmDialog(null);
    setTagMenuPosition(null);
    setTagEditor(null);
    setOriginalOpen(false);
    setComposeOpen(false);
    setReplyTo(undefined);
    setSidebarOpen(false);
    setMobileMailPane("list");
    setActiveSection("email");
    setSettingsTab("preferences");
    setCalendarNotice(null);
    setDriveNotice(null);
    setDriveSearch("");
    setDriveFolderSearch("");
    setDriveNewFolderName("");
    setDriveSaveFolderId("");
    setDriveSaveFolderName("");
    setDriveBrowseFolderId("");
    setDriveDragFileId("");
    setDriveDragTargetId("");
    setDragOverTarget("");
    setSessionWarningOpen(false);
    setSessionCountdownSeconds(0);
    setMailBooted(false);
    setPostListDataReady(false);
    messagesScrollRef.current?.scrollTo({ top: 0, behavior: "auto" });
  }

  function clearSessionTimers() {
    if (sessionWarningTimer.current) {
      window.clearTimeout(sessionWarningTimer.current);
      sessionWarningTimer.current = null;
    }
    if (sessionExpiryTimer.current) {
      window.clearTimeout(sessionExpiryTimer.current);
      sessionExpiryTimer.current = null;
    }
    if (sessionCountdownTimer.current) {
      window.clearInterval(sessionCountdownTimer.current);
      sessionCountdownTimer.current = null;
    }
  }

  function performClientLogout() {
    clearSessionTimers();
    currentAccountRef.current = "";
    resetWorkspaceState();
    queryClient.clear();
    window.location.reload();
  }

  function handleSessionExpired() {
    setSessionWarningOpen(false);
    setSessionCountdownSeconds(0);
    if (!logout.isPending) logout.mutate();
  }

  function scheduleSessionTimers(expiresAt: number, ttlSeconds = me.data?.session_ttl_seconds || 0) {
    clearSessionTimers();
    if (!expiresAt) return;
    const expiryAtMs = expiresAt * 1000;
    const now = Date.now();
    const msUntilExpiry = expiryAtMs - now;
    if (msUntilExpiry <= 0) {
      handleSessionExpired();
      return;
    }
    const ttlMs = Math.max(60, ttlSeconds || 0) * 1000;
    const warningLeadMs = Math.min(60_000, Math.max(10_000, ttlMs / 4));
    const msUntilWarning = Math.max(0, msUntilExpiry - warningLeadMs);
    sessionWarningTimer.current = window.setTimeout(() => {
      setSessionWarningOpen(true);
      setSessionCountdownSeconds(Math.max(0, Math.ceil((expiryAtMs - Date.now()) / 1000)));
      sessionCountdownTimer.current = window.setInterval(() => {
        const remainingSeconds = Math.max(0, Math.ceil((expiryAtMs - Date.now()) / 1000));
        setSessionCountdownSeconds(remainingSeconds);
        if (remainingSeconds <= 0 && sessionCountdownTimer.current) {
          window.clearInterval(sessionCountdownTimer.current);
          sessionCountdownTimer.current = null;
        }
      }, 1000);
    }, msUntilWarning);
    sessionExpiryTimer.current = window.setTimeout(() => {
      handleSessionExpired();
    }, msUntilExpiry);
  }

  async function keepSessionAlive() {
    if (sessionKeepAlivePending.current) return;
    sessionKeepAlivePending.current = true;
    setSessionKeepAliveBusy(true);
    clearSessionTimers();
    setSessionWarningOpen(false);
    setSessionCountdownSeconds(0);
    try {
      const session = await api.keepAlive();
      if (!session.session_expires_at) {
        handleSessionExpired();
        return;
      }
      queryClient.setQueryData(["me"], session);
      sessionKeepAliveLastRefresh.current = Date.now();
      scheduleSessionTimers(session.session_expires_at, session.session_ttl_seconds);
    } catch {
      handleSessionExpired();
    } finally {
      sessionKeepAlivePending.current = false;
      setSessionKeepAliveBusy(false);
    }
  }

  function patchMessageRead(uid: string, source: string, seen: boolean) {
    const matchesMessage = (message: MessageSummary) =>
      (message.folder || source) === source &&
      (message.uid === uid || message.open_uid === uid || message.conversation_id === uid);
    const patch = <T extends MessageSummary>(message: T): T => ({
      ...message,
      seen,
      flags: nextFlags(message.flags, seen, undefined)
    });
    queryClient.setQueryData<InfiniteData<MessagePage>>(messageListQueryKey(source), (old) =>
      updateMessagePages(old, (message) => (matchesMessage(message) ? patch(message) : message))
    );
    queryClient.setQueriesData<{ messages: MessageSummary[] }>({ queryKey: ["mail-search"] }, (old) =>
      old ? { ...old, messages: old.messages.map((message) => matchesMessage(message) ? patch(message) : message) } : old
    );
    queryClient.setQueryData(["message", source, uid, messageViewMode], (old: { message: MessageDetail } | undefined) =>
      old ? { message: patch(old.message) } : old
    );
  }

  function markMessageRead(uid: string, source: string, backendUid: string = uid, view: "message" | "conversation" = "message") {
    patchMessageRead(uid, source, true);
    updateFlags.mutate({ uid: backendUid, source, seen: true, view });
  }

  async function moveSelection(items: MailSelectionItem[], target: string) {
    const actionable = dedupeSelection(items).filter((item) => item.source !== target);
    if (!actionable.length) return;
    const anchorKey = messageViewMode === "conversation" && lastListSelectionKeyRef.current ? lastListSelectionKeyRef.current : actionable[0].key;
    const nextSelection = resolveNextVisibleMessage(visibleMessages, anchorKey, actionable.map((item) => item.key));

    const previous = new Map<string, InfiniteData<MessagePage> | undefined>();
    const grouped = groupSelectionBySource(actionable);

    await Promise.all(Object.keys(grouped).map((source) => queryClient.cancelQueries({ queryKey: messageListQueryKey(source) })));
    for (const source of Object.keys(grouped)) {
      previous.set(source, queryClient.getQueryData<InfiniteData<MessagePage>>(messageListQueryKey(source)));
      queryClient.setQueryData<InfiniteData<MessagePage>>(messageListQueryKey(source), (old) =>
        mapMessagePages(old, (message) => (grouped[source].has(message.uid) ? null : message))
      );
    }

    if (selectedUid && actionable.some((item) => item.uid === selectedUid && item.source === selectedActionSource)) {
      setSelectedUid(null);
      setSelectedDetailTarget(null);
    }
    setSelectedKeys((current) => current.filter((key) => !actionable.some((item) => item.key === key)));

    try {
      await Promise.all(actionable.map((item) => api.moveMessage(item.source, item.uid, target, messageViewMode)));
      queryClient.invalidateQueries({ queryKey: ["messages"] });
      queryClient.invalidateQueries({ queryKey: ["folders"] });
      queryClient.invalidateQueries({ queryKey: ["mail-search"] });
      if (nextSelection) {
        pendingSelectionRef.current = nextSelection;
      }
    } catch (error) {
      for (const [source, data] of previous.entries()) {
        queryClient.setQueryData(messageListQueryKey(source), data);
      }
      throw error;
    }
  }

  function canDropMessagesIntoFolder(targetFolder: Folder | null | undefined) {
    if (!targetFolder) return false;
    const normalizedName = targetFolder.name.trim().toLowerCase();
    return targetFolder.abs_path !== "/Drafts" && normalizedName !== "drafts";
  }

  function resolveDeleteTargets(message: MessageSummary, sourceOverride?: string): MailSelectionItem[] {
    const itemKey = messageKey(message);
    const source = sourceOverride || message.folder || currentFolderSource;
    if (selectedKeys.includes(itemKey)) {
      return activeSelection.length ? activeSelection : [{ key: itemKey, uid: message.uid, source }];
    }
    return [{ key: itemKey, uid: message.uid, source }];
  }

  async function deleteSelection(items: MailSelectionItem[], viewOverride?: "conversation" | "message") {
    const actionable = dedupeSelection(items);
    if (!actionable.length) return;
    if (!currentFolderCanDeleteMessages) return;
    const uniqueActionable = actionable;
    const deleteView = viewOverride || messageViewMode;
    const anchorKey = deleteView === "conversation" && lastListSelectionKeyRef.current
      ? lastListSelectionKeyRef.current
      : selectedSummary
        ? messageKey(selectedSummary)
        : uniqueActionable[0].key;
    const nextSelection = resolveNextVisibleMessage(
      visibleMessages,
      anchorKey,
      uniqueActionable.map((item) => item.key)
    );

    const previous = new Map<string, InfiniteData<MessagePage> | undefined>();
    const grouped = groupSelectionBySource(uniqueActionable);

    setSelectedUid(null);
    setSelectedDetailTarget(null);
    setSelectedThreadDetailTarget(null);
    setSelectedThreadSummary(null);
    setConversationExpandOnly(false);
    setExpandedConversationId("");
    setSelectedKeys((current) => current.filter((key) => !uniqueActionable.some((item) => item.key === key)));
    if (nextSelection) {
      pendingSelectionRef.current = nextSelection;
    }

    await Promise.all(Object.keys(grouped).map((source) => queryClient.cancelQueries({ queryKey: messageListQueryKey(source) })));
    for (const source of Object.keys(grouped)) {
      previous.set(source, queryClient.getQueryData<InfiniteData<MessagePage>>(messageListQueryKey(source)));
      queryClient.setQueryData<InfiniteData<MessagePage>>(messageListQueryKey(source), (old) =>
        mapMessagePages(old, (message) => {
          if (deleteView === "conversation") {
            const conversationKey = message.conversation_id || message.uid;
            return grouped[source].has(message.uid) || grouped[source].has(conversationKey) ? null : message;
          }
          return grouped[source].has(message.uid) ? null : message;
        })
      );
    }

    try {
      await Promise.all(uniqueActionable.map((item) => api.deleteMessage(item.source, item.uid, deleteView)));
      queryClient.invalidateQueries({ queryKey: ["messages"] });
      queryClient.invalidateQueries({ queryKey: ["mail-search"] });
      await queryClient.refetchQueries({ queryKey: ["folders"], exact: true });
    } catch (error) {
      for (const [source, data] of previous.entries()) {
        queryClient.setQueryData(messageListQueryKey(source), data);
      }
      throw error;
    }
  }

  function openCompose(draft?: ComposeSeed) {
    setReplyTo(draft);
    setComposeOpen(true);
  }

  async function runAdvancedSearch(saveSearch = false) {
    const query = buildAdvancedMailSearchQuery(advancedSearch);
    if (!query) return;
    if (saveSearch) {
      const name = savedSearchName.trim();
      if (!name) return;
      await createSavedSearch.mutateAsync({ name, query });
    }
    setSearch(query);
    setGlobalSearch(true);
    setAdvancedSearchOpen(false);
    setSavedSearchName("");
  }

  function openSavedSearch(item: SavedSearch) {
    setSearch(item.query);
    setGlobalSearch(true);
    setActiveSection("email");
    setMobileMailPane("list");
    if (isCompactViewport) setSidebarOpen(false);
  }

  async function editDraft(message: MessageDetail) {
    const draftKey = message.open_uid || message.uid;
    const detailResult = await api.message(message.folder || folder, draftKey, "message");
    const draft = detailResult.message;
    const draftHtml = rewriteInlineImageSources(draft.html, draft.uid || draftKey, draft.attachments);
    const draftAttachments = visibleReaderAttachments(draft.attachments, draft.html);
    openCompose({
      to: draft.to,
      cc: draft.cc,
      bcc: draft.bcc,
      subject: normalizeComposeSubject(draft.subject),
      body: draft.text,
      body_html: draftHtml,
      draft_id: draftKey,
      origid: "",
      rt: undefined,
      attachments: draftAttachments.map((attachment) => ({
        filename: attachment.filename,
        content_type: attachment.content_type,
        size: attachment.size,
        kind: "existing",
        part: attachment.part,
      })),
      high_priority: draft.high_priority,
      request_read_receipt: draft.request_read_receipt,
    });
  }

  async function editDraftFromSummary(message: MessageSummary) {
    const draftKey = message.open_uid || message.uid;
    const detailResult = await api.message(message.folder || folder, message.open_uid || message.uid, "message");
    editDraft(detailResult.message);
  }

  async function replyDraft(message: MessageDetail) {
    const quotedHtml = buildQuotedMessageHtml(message);
    const inlinedHtml = await inlineMessageImages(quotedHtml);
    openCompose({
      to: message.sender_email,
      subject: replySubject(message.subject),
      body: `\n${quoteMessage(message)}`,
      body_html: `<div><br /></div>${inlinedHtml}`,
      focus_target: "body",
      origid: message.uid,
      rt: "r" as const
    });
  }

  async function replyAllDraft(message: MessageDetail) {
    const currentEmail = me.data?.email?.trim().toLowerCase() || "";
    const currentLocalPart = currentEmail.split("@")[0] || "";
    const recipients = uniqueAddresses([
      message.sender_email,
      ...extractAddressTokens(message.to),
      ...extractAddressTokens(message.cc),
    ])
      .filter((email) => {
        const token = normalizeRecipientToken(email);
        const localPart = token.includes("@") ? token.split("@")[0] : token;
        return token !== currentEmail && localPart !== currentLocalPart;
      });
    const quotedHtml = buildQuotedMessageHtml(message);
    const inlinedHtml = await inlineMessageImages(quotedHtml);
    openCompose({
      to: recipients.join(", "),
      cc: "",
      subject: replySubject(message.subject),
      body: `\n${quoteMessage(message)}`,
      body_html: `<div><br /></div>${inlinedHtml}`,
      focus_target: "body",
      origid: message.uid,
      rt: "r" as const
    });
  }

  async function forwardDraft(message: MessageDetail) {
    const forwardedHtml = buildForwardedMessageHtml(message);
    const inlinedHtml = await inlineMessageImages(forwardedHtml);
    const forwardedAttachments = visibleReaderAttachments(message.attachments, message.html)
      .filter((attachment) => attachment.part)
      .map((attachment) => ({
        filename: attachment.filename,
        content_type: attachment.content_type,
        size: attachment.size,
        kind: "existing" as const,
        part: attachment.part,
        source_uid: message.uid,
      }));
    openCompose({
      subject: forwardSubject(message.subject),
      body: forwardedMessage(message),
      body_html: inlinedHtml,
      focus_target: "to",
      origid: message.uid,
      rt: "w" as const,
      attachments: forwardedAttachments,
    });
  }

  async function refreshMailboxView(targetFolder = folder, includeDetail = true) {
    setMailboxRefreshSpin(true);
    if (mailboxRefreshTimer.current) {
      window.clearTimeout(mailboxRefreshTimer.current);
    }
    mailboxRefreshTimer.current = window.setTimeout(() => setMailboxRefreshSpin(false), 650);
    await Promise.all([
      queryClient.refetchQueries({ queryKey: messageListQueryKey(targetFolder), exact: true }),
      api.folders(true).then((data) => queryClient.setQueryData(["folders"], data)),
      queryClient.refetchQueries({ queryKey: ["tags"], exact: true }),
      searchTerm.length > 1 ? queryClient.refetchQueries({ queryKey: ["mail-search", targetFolder, globalSearch, searchTerm], exact: true }) : Promise.resolve(),
      includeDetail && selectedUid ? queryClient.refetchQueries({ queryKey: ["message", selectedFolder, selectedUid, messageViewMode], exact: true }) : Promise.resolve(),
    ]);
  }

  useEffect(() => {
    const pendingSelection = pendingSelectionRef.current;
    if (pendingSelection) {
      const pendingVisible = visibleMessages.find(
        (message) => message.uid === pendingSelection.uid && (message.folder || folder) === pendingSelection.source
      );
      if (pendingVisible) {
        pendingSelectionRef.current = null;
        setSelectedUid(pendingVisible.uid);
        setSelectedFolder(pendingSelection.source);
        setSelectedDetailTarget({ folder: pendingSelection.source, uid: pendingVisible.open_uid || pendingVisible.uid, view: "message" });
        setSelectedThreadDetailTarget(null);
        setSelectedThreadSummary(null);
        return;
      }
    }
    if (!visibleMessages.length) {
      if (selectedDetailTarget?.uid && (detail.isLoading || detail.isFetching)) return;
      if (selectedUid) {
        setSelectedUid(null);
        setSelectedDetailTarget(null);
        setSelectedThreadUid(null);
        setSelectedThreadDetailTarget(null);
        setSelectedThreadSummary(null);
        setSelectedKeys([]);
      }
      return;
    }
    const selectedExists = selectedUid
      ? visibleMessages.some((message) =>
          (message.folder || folder) === selectedFolder &&
          (message.uid === selectedUid || message.open_uid === selectedUid || message.conversation_id === selectedUid)
        )
      : false;
    if (selectedUid && !selectedExists) {
      if ((selectedThreadUid && selectedUid === selectedThreadUid) || (selectedThreadDetailTarget && selectedUid === selectedThreadDetailTarget.uid)) {
        return;
      }
      if (selectedDetailTarget?.uid && (detail.isLoading || detail.isFetching)) return;
      const currentIndex = visibleMessages.findIndex((message) => message.uid === selectedUid && (message.folder || folder) === selectedFolder);
      const nextMessage =
        (currentIndex >= 0
          ? visibleMessages.slice(currentIndex + 1).find((message) => (message.folder || folder) === selectedFolder) ||
            visibleMessages.slice(0, currentIndex).reverse().find((message) => (message.folder || folder) === selectedFolder)
          : undefined) ||
        visibleMessages.find((message) => (message.folder || folder) === selectedFolder);
      if (nextMessage) {
        setSelectedUid(nextMessage.uid);
        setSelectedFolder(nextMessage.folder || folder);
        setSelectedDetailTarget({ folder: nextMessage.folder || folder, uid: nextMessage.uid, view: "message" });
        setSelectedThreadDetailTarget(null);
        setSelectedThreadSummary(null);
      } else {
        setSelectedUid(null);
        setSelectedDetailTarget(null);
        setSelectedThreadDetailTarget(null);
        setSelectedThreadSummary(null);
        setExpandedConversationId("");
      }
    }
  }, [detail.isFetching, detail.isLoading, folder, selectedDetailTarget?.uid, selectedDetailTarget?.view, selectedFolder, selectedThreadUid, selectedUid, visibleMessages]);

  useEffect(() => {
    if (!folderMenu) return;
    const closeMenu = () => setFolderMenu(null);
    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setFolderMenu(null);
      }
    };
    window.addEventListener("click", closeMenu);
    window.addEventListener("keydown", handleKeyDown);
    return () => {
      window.removeEventListener("click", closeMenu);
      window.removeEventListener("keydown", handleKeyDown);
    };
  }, [folderMenu]);

  useEffect(() => {
    const nextAccount = me.data?.email?.toLowerCase() || "";
    if (currentAccountRef.current && currentAccountRef.current !== nextAccount) {
      resetWorkspaceState();
      setAcknowledgedLicenseWarningKey("");
      queryClient.clear();
    }
    currentAccountRef.current = nextAccount;
  }, [me.data?.email, queryClient]);

  useEffect(() => {
    const clearDragTarget = () => setDragOverTarget("");
    window.addEventListener("dragend", clearDragTarget);
    window.addEventListener("drop", clearDragTarget);
    return () => {
      window.removeEventListener("dragend", clearDragTarget);
      window.removeEventListener("drop", clearDragTarget);
    };
  }, []);

  if (me.isLoading) {
    return <div className="grid min-h-screen place-items-center font-bold text-slate-500">{t("mail.loadingWorkspace")}</div>;
  }
  if (!me.data) {
    return (
      <LoginScreen
        brandDomain={tenantDomain}
        onSignedIn={async (loginResult) => {
          currentAccountRef.current = "";
          resetWorkspaceState();
          setAcknowledgedLicenseWarningKey("");
          await queryClient.invalidateQueries({ queryKey: ["me"] });
          if (!loginResult?.two_factor_setup_required) {
            const loadedPreferences = await queryClient.fetchQuery({
              queryKey: ["workspace-preferences"],
              queryFn: api.workspacePreferences,
            });
            const nextMessageViewMode = loadedPreferences.message_view_mode === "message" ? "message" : "conversation";
            await queryClient.prefetchInfiniteQuery({
              queryKey: messageListQueryKey("INBOX", nextMessageViewMode),
              initialPageParam: 0,
              queryFn: ({ pageParam = 0 }) => api.messages("INBOX", MESSAGE_PAGE_SIZE, pageParam, nextMessageViewMode, messageSortOrder),
            });
          }
        }}
      />
    );
  }

  if (!workspacePreferences.data) {
    return (
      <div className="grid min-h-screen place-items-center bg-[#f7f9fc] px-4 text-center text-slate-500">
        <div className="grid justify-items-center gap-3">
          <div className="h-8 w-8 animate-spin rounded-full border-2 border-slate-200 border-t-slate-500" aria-hidden="true" />
          <p className="text-sm font-bold">{t("mail.loadingWorkspace")}</p>
        </div>
      </div>
    );
  }

  if (me.data.two_factor_setup_required) {
    return (
      <div className={clsx("min-h-screen overflow-auto bg-gradient-to-br px-4 py-6 text-slate-900", activeTheme.shell, fontClass)} style={{ "--accent": activeTheme.accent } as CSSProperties}>
        <div className="mx-auto grid w-full max-w-3xl gap-4">
          <div className="rounded-2xl border border-amber-200 bg-white p-5 shadow-soft">
            <p className="text-xs font-black uppercase tracking-[0.16em] text-amber-700">{t("license.twoFactorRequired")}</p>
            <h1 className="mt-2 text-2xl font-black text-slate-950">{t("license.twoFactorSetupTitle")}</h1>
            <p className="mt-3 text-sm font-semibold leading-6 text-slate-600">
              {t("license.twoFactorSetupHelp", { email: me.data.email })}
            </p>
            <div className="mt-4 flex justify-end">
              <button type="button" onClick={() => logout.mutate()} className="theme-button-soft h-10 px-4 text-sm">
                <LogOut size={16} />
                {t("mail.signOut")}
              </button>
            </div>
          </div>
          <div className="control-surface rounded-2xl p-4">
            <SecuritySettings email={me.data.email} t={t} />
          </div>
        </div>
      </div>
    );
  }

  if (licenseStatus?.hard_block) {
    return (
      <div className={clsx("grid min-h-screen place-items-center bg-gradient-to-br px-4 text-slate-900", activeTheme.shell, fontClass)} style={{ "--accent": activeTheme.accent } as CSSProperties}>
        <div className="w-full max-w-xl rounded-2xl border border-red-200 bg-white p-6 shadow-soft">
          <p className="text-xs font-black uppercase tracking-[0.16em] text-red-600">{t("license.activationRequired")}</p>
          <h1 className="mt-3 text-2xl font-black text-slate-950">{t("license.notActivated")}</h1>
          <p className="mt-3 text-sm font-semibold leading-6 text-slate-600">
            {licenseStatus.message || t("license.validRequired")}
          </p>
          {licenseStatus.activation_grace_until ? (
            <p className="mt-3 text-sm font-semibold text-slate-500">{t("license.graceUntil", { time: new Date(licenseStatus.activation_grace_until).toLocaleString() })}</p>
          ) : null}
          <div className="mt-5 flex flex-wrap gap-2">
            <a href="/admin" className="theme-button h-10 px-4 text-sm">{t("license.openAdmin")}</a>
            <button type="button" onClick={() => logout.mutate()} className="theme-button-soft h-10 px-4 text-sm">
              <LogOut size={16} />
              {t("mail.signOut")}
            </button>
          </div>
        </div>
      </div>
    );
  }

  if (licenseWarningSeverity === "user_fullscreen" && !supportOnlyWarning) {
    return (
      <div className={clsx("grid min-h-screen place-items-center bg-gradient-to-br px-4 text-slate-900", activeTheme.shell, fontClass)} style={{ "--accent": activeTheme.accent } as CSSProperties}>
        <div className="w-full max-w-2xl rounded-2xl border border-amber-300 bg-white p-6 shadow-soft">
          <div className="flex items-start gap-3">
            <div className="grid h-11 w-11 shrink-0 place-items-center rounded-xl border border-amber-200 bg-amber-50 text-amber-700">
              <AlertTriangle size={22} />
            </div>
            <div className="min-w-0">
              <p className="text-xs font-black uppercase tracking-[0.16em] text-amber-700">{t("license.attentionRequired")}</p>
              <h1 className="mt-2 text-2xl font-black text-slate-950">{t("license.contactAdministrator")}</h1>
              <p className="mt-3 text-sm font-semibold leading-6 text-slate-600">
                {licenseStatus?.message || t("license.unresolvedWarning")}
              </p>
              <p className="mt-3 text-sm font-semibold text-slate-500">{t("license.warningActiveDays", { days: licenseStatus?.days_in_warning ?? 0 })}</p>
            </div>
          </div>
          <div className="mt-6 flex flex-wrap gap-2">
            <button type="button" onClick={() => setAcknowledgedLicenseWarningKey(licenseWarningKey)} className="theme-button h-10 px-4 text-sm">{t("license.continueMailbox")}</button>
            <button type="button" onClick={() => logout.mutate()} className="theme-button-soft h-10 px-4 text-sm">
              <LogOut size={16} />
              {t("mail.signOut")}
            </button>
          </div>
        </div>
      </div>
    );
  }

  const readerIsJunkFolder = isJunkFolderPath(currentFolderRecord?.abs_path || currentFolderRecord?.path || currentFolderRecord?.name || folder);
  const readerJunkActionLabel = readerIsJunkFolder ? t("mail.notJunk") : t("mail.junk");
  const readerJunkActionTargetFolder = readerIsJunkFolder ? inboxDropTarget : (junkFolder?.path || "");
  const mobileReaderActionDetail = currentReaderDetail ? (selectedActionDetail ?? currentReaderDetail) : undefined;
  const mobileReaderActionTargetUid = mobileReaderActionDetail?.uid || "";
  const mobileReaderActionSource = mobileReaderActionDetail?.folder || selectedActionSource;

  return (
    <div className={clsx("h-[100dvh] overflow-hidden bg-gradient-to-br text-slate-900", activeTheme.shell, fontClass)} style={{ "--accent": activeTheme.accent } as CSSProperties}>
      <BrowserExitGuard />
      {sidebarOpen ? (
        <button
          type="button"
          className="fixed inset-0 z-30 bg-slate-950/35 backdrop-blur-[1px] xl:hidden"
          aria-label={t("mail.closeMenu")}
          onClick={() => setSidebarOpen(false)}
        />
      ) : null}
      <div className="grid h-full grid-cols-1 overflow-hidden xl:grid-cols-[286px_minmax(0,1fr)]">
        <aside
          className={clsx(
            "fixed inset-y-0 left-0 z-40 flex w-[286px] -translate-x-full flex-col overflow-auto border-r border-slate-200/80 bg-white/95 p-4 shadow-xl backdrop-blur-xl transition-transform duration-200 ease-out xl:static xl:z-auto xl:w-[286px] xl:flex-shrink-0 xl:translate-x-0 xl:shadow-none",
            sidebarOpen ? "translate-x-0" : "xl:translate-x-0"
          )}
        >
          <div className="mb-6 flex items-center gap-3">
            <div className="min-w-0">
              <BrandLogo size="sm" subtitle={accountProfile.data?.display_name || me.data.email} brandDomain={tenantDomain} />
            </div>
          </div>

          <button onClick={() => setComposeOpen(true)} className="theme-button mb-4 h-11 min-h-11 w-full shrink-0 whitespace-nowrap text-[15px] transition hover:-translate-y-0.5">
            <MailPlus size={18} />
            {t("mail.compose")}
          </button>

          <nav className="grid gap-1">
            <SidebarButton
              icon={inboxFolder ? folderIcon(inboxFolder) : <Inbox size={17} />}
              label={t("mail.inbox")}
              count={unreadCount}
              active={folder.toUpperCase() === "INBOX"}
              onClick={() => switchFolder("INBOX")}
              isDropTarget={dragOverTarget === "INBOX"}
              onDragTargetChange={(isTarget) => setDragOverTarget(isTarget ? "INBOX" : "")}
              onDropMessage={(items) => void moveSelection(items, inboxDropTarget)}
              onContextMenu={inboxFolder ? (event) => openFolderMenu(event, inboxFolder) : undefined}
            />
            <SidebarButton
              icon={sentFolder ? folderIcon(sentFolder) : <Send size={17} />}
              label={t("mail.sent")}
              count={sentCount}
              active={isSentFolderPath(folder)}
              onClick={() => switchFolder(sentFolder?.path || "Sent")}
              isDropTarget={dragOverTarget === (sentFolder?.path || "Sent")}
              onDragTargetChange={(isTarget) => setDragOverTarget(isTarget ? (sentFolder?.path || "Sent") : "")}
              onDropMessage={sentFolder ? (items) => void moveSelection(items, sentFolder.path) : undefined}
              onContextMenu={sentFolder ? (event) => openFolderMenu(event, sentFolder) : undefined}
            />
            <SidebarButton
              icon={<Star size={17} />}
              label={t("mail.starred")}
              count={starredCount}
              active={folder.toUpperCase() === "STARRED"}
              onClick={() => switchFolder("STARRED")}
              isDropTarget={dragOverTarget === "STARRED"}
              onDragTargetChange={(isTarget) => setDragOverTarget(isTarget ? "STARRED" : "")}
            />
            {(folders.data?.folders ?? []).filter((item) => !isInboxFolder(item) && !isSentFolderPath(item.abs_path) && !isSentFolderPath(item.name)).map((item) => (
              <FolderButton
                key={item.path}
                folder={item}
                active={item.path === folder}
                highlighted={item.path === sharedFolderHighlightPath}
                onClick={() => switchFolder(item.path)}
                count={item.abs_path === "/Drafts" ? draftsCount : item.unread_count}
                isDropTarget={dragOverTarget === item.path}
                onDragTargetChange={(isTarget) => setDragOverTarget(isTarget ? item.path : "")}
                onDropMessage={canDropMessagesIntoFolder(item) ? (items) => void moveSelection(items, item.path) : undefined}
                onContextMenu={(event) => openFolderMenu(event, item)}
              />
            ))}
          </nav>
          <div className="mt-3 flex gap-2">
            <input value={newFolderName} onChange={(event) => setNewFolderName(event.target.value)} className="field h-9 min-w-0 flex-1 text-sm" placeholder={t("mail.newFolder")} />
            <button
              onClick={() => newFolderName.trim() && createFolder.mutate(newFolderName.trim())}
              disabled={!newFolderName.trim() || createFolder.isPending}
              className="theme-button h-9 px-3 text-sm"
            >
              {createFolder.isPending ? t("mail.adding") : t("mail.add")}
            </button>
          </div>
          {createFolder.error ? <p className="mt-2 text-xs font-semibold text-red-600">{createFolder.error.message}</p> : null}

          <div className="mt-5 border-t border-slate-200 pt-4">
            <div className="mb-2 flex items-center justify-between gap-2">
              <p className="text-xs font-black uppercase tracking-[0.16em] text-slate-500">{t("mail.savedSearches")}</p>
              <button type="button" onClick={() => setAdvancedSearchOpen(true)} className="icon-button h-8 w-8" aria-label={t("mail.advancedSearch")} title={t("mail.advancedSearch")}>
                <SlidersHorizontal size={15} />
              </button>
            </div>
            <div className="grid gap-1">
              {(savedSearches.data?.searches ?? []).map((item) => (
                <div key={item.id} className="group flex min-w-0 items-center gap-1">
                  <button type="button" onClick={() => openSavedSearch(item)} className="flex h-9 min-w-0 flex-1 items-center gap-2 rounded-md px-2 text-left text-sm font-semibold text-slate-600 transition hover:bg-slate-100 hover:text-slate-900">
                    <Search size={15} className="shrink-0" />
                    <span className="truncate">{item.name}</span>
                  </button>
                  <button type="button" onClick={() => deleteSavedSearch.mutate(item.id)} className="icon-button h-8 w-8 shrink-0 opacity-0 group-hover:opacity-100 focus:opacity-100" aria-label={t("mail.deleteSavedSearch", { name: item.name })} title={t("mail.deleteSavedSearch", { name: item.name })}>
                    <Trash2 size={14} />
                  </button>
                </div>
              ))}
              {!savedSearches.isLoading && !(savedSearches.data?.searches.length ?? 0) ? <p className="px-2 py-1 text-xs font-semibold text-slate-400">{t("mail.noSavedSearches")}</p> : null}
            </div>
          </div>

          <div className="mt-5 border-t border-slate-200 pt-4">
            <div className="mb-3 flex items-center justify-between">
              <p className="text-xs font-black uppercase tracking-[0.16em] text-slate-500">{t("mail.tags")}</p>
              <span className="text-xs font-semibold text-slate-400">{tags.data?.tags.length ?? 0}</span>
            </div>
            <div className="grid gap-1">
              {(tags.data?.tags ?? []).map((tag) => (
                <SidebarButton
                  key={tag.id}
                  icon={<TagIcon size={17} style={{ color: tagColorHex(tag) }} />}
                  label={tag.name}
                  count={tag.unread_count}
                  active={folder === `TAG:${tag.id}`}
                  onClick={() => switchFolder(`TAG:${tag.id}`)}
                  onDropMessage={(items) => void applyTagToSelection(items, tag.name)}
                />
              ))}
              {!tags.data?.tags.length ? <p className="px-3 py-2 text-sm font-semibold text-slate-400">{t("mail.noTags")}</p> : null}
            </div>
          </div>

          <div className="mt-4 grid gap-2 border-t border-slate-200 pt-4">
            <QuotaCard t={t} quota={quota.data?.quota} loading={quota.isFetching} />
            <button onClick={() => logout.mutate()} className="theme-button-soft h-10">
              <LogOut size={16} />
              {t("mail.signOut")}
            </button>
          </div>
        </aside>

        <main className="grid min-h-0 min-w-0 grid-rows-[auto_1fr] overflow-hidden">
          <header className="grid gap-3 border-b border-slate-200/80 bg-white/75 px-3 py-3 backdrop-blur-xl md:px-4">
            <div className="flex flex-wrap items-center justify-between gap-3">
              <div className="flex min-w-0 items-center gap-2">
                <button
                  type="button"
                  onClick={() => setSidebarOpen((current) => !current)}
                  className="icon-button h-11 w-11 xl:hidden"
                  aria-label={t("mail.openMenu")}
                  title={t("mail.openMenu")}
                >
                  <Menu size={18} />
                </button>
                <div className="min-w-0">
                  <p className="text-xs font-black uppercase" style={{ color: activeTheme.accent }}>{t("nav.mailWorkspace")}</p>
                  <h1 className="truncate text-[clamp(1.25rem,3vw,1.5rem)] font-black">{sectionTitle(activeSection, activeFolderLabel, driveTabLabel)}</h1>
                </div>
              </div>
              <div className="flex items-center gap-2">
                {!isCompactViewport ? (
                  <nav className="flex max-w-full flex-nowrap gap-2 overflow-x-auto rounded-lg border border-slate-200 bg-white p-1">
                    <SectionTab label={t("nav.email")} active={activeSection === "email"} onClick={() => setActiveSection("email")} />
                    <SectionTab label={t("nav.contact")} active={activeSection === "contacts"} onClick={() => setActiveSection("contacts")} />
                    {showCalendarSection ? <SectionTab label={t("nav.calendar")} active={activeSection === "calendar"} disabled={!enableCalendarSection} badge={featureBadge(calendarFeature)} tooltip={calendarFeature.locked ? lockedFeatureTooltip : undefined} onClick={() => setActiveSection("calendar")} /> : null}
                    {showTasksSection ? <SectionTab label={t("nav.task")} active={activeSection === "tasks"} disabled={!enableTasksSection} badge={featureBadge(tasksFeature)} tooltip={tasksFeature.locked ? lockedFeatureTooltip : undefined} onClick={() => setActiveSection("tasks")} /> : null}
                    {showDriveSection ? <SectionTab label={driveTabLabel} active={activeSection === "drive"} disabled={!enableDriveSection} badge={featureBadge(driveFeature)} tooltip={driveFeature.locked ? lockedFeatureTooltip : undefined} onClick={() => setActiveSection("drive")} /> : null}
                    <SectionTab label={t("nav.preferences")} active={activeSection === "preferences"} onClick={() => setActiveSection("preferences")} />
                    <button
                      type="button"
                      className="icon-button h-9 w-9 shrink-0 p-0"
                      aria-label={accountProfile.data?.display_name || me.data.email}
                      title={accountProfile.data?.display_name || me.data.email}
                      onClick={() => {
                        setActiveSection("preferences");
                        setSettingsTab("account");
                      }}
                    >
                      <ContactAvatar value={accountProfile.data?.display_name || me.data.email} photoUrl={accountProfile.data?.photo_url || ""} />
                    </button>
                  </nav>
                ) : null}
              </div>
            </div>
            {licenseStatus?.user_warning && !supportOnlyWarning && acknowledgedLicenseWarningKey !== licenseWarningKey ? (
              <div
                className={clsx(
                  "flex items-start gap-3 rounded-xl border px-4 py-3 text-sm font-semibold leading-6",
                  licenseWarningSeverity === "user_strong" || licenseWarningSeverity === "user_fullscreen"
                    ? "border-red-200 bg-red-50 text-red-800"
                    : "border-amber-200 bg-amber-50 text-amber-800",
                )}
              >
                <AlertTriangle className="mt-0.5 shrink-0" size={17} />
                <div className="min-w-0">
                  <p className="font-black">{licenseWarningSeverity === "user_strong" || licenseWarningSeverity === "user_fullscreen" ? "License warning requires attention" : "License notice"}</p>
                  <p className="mt-0.5">{licenseStatus.message || "License status requires administrator attention. Please contact your administrator."}</p>
                  {licenseStatus.days_in_warning != null ? <p className="mt-1 text-xs font-black opacity-80">Warning active for {licenseStatus.days_in_warning} days.</p> : null}
                </div>
              </div>
            ) : null}
            {activeSection === "email" ? (
              <div className="flex w-full items-center gap-2">
                <label className="relative min-w-0 flex-1">
                  <Search className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400" size={17} />
                  <input value={search} onChange={(event) => setSearch(event.target.value)} className="field h-11 w-full pl-10 pr-10" placeholder={t("mail.searchMessages")} />
                  {search ? (
                    <button
                      type="button"
                      onClick={() => setSearch("")}
                      className="absolute right-2 top-1/2 inline-flex h-7 w-7 -translate-y-1/2 items-center justify-center rounded-full text-slate-400 transition hover:bg-slate-200 hover:text-slate-700"
                      aria-label={t("mail.clearSearch")}
                      title={t("mail.clearSearch")}
                    >
                      <X size={14} />
                    </button>
                  ) : null}
                </label>
                <button type="button" onClick={() => setAdvancedSearchOpen(true)} className="icon-button h-11 w-11" aria-label={t("mail.advancedSearch")} title={t("mail.advancedSearch")}>
                  <SlidersHorizontal size={17} />
                </button>
                <button
                  onClick={() => setGlobalSearch((value) => !value)}
                  className={clsx("theme-button-soft mail-toolbar-labeled h-11 px-3 text-sm", globalSearch && "border-transparent text-white")}
                  style={globalSearch ? { backgroundColor: activeTheme.accent, color: "white" } : undefined}
                  aria-label={t("mail.allFolders")}
                  title={t("mail.allFolders")}
                >
                  <FolderIcon size={16} />
                  <span className="mail-toolbar-label">{t("mail.allFolders")}</span>
                </button>
                <div className="relative flex items-center gap-2">
                  <button
                    type="button"
                    onClick={() => void refreshMailboxView()}
                    className="icon-button h-11 w-11"
                    aria-label={t("mail.checkNew")}
                    title={t("mail.checkNew")}
                  >
                    <RefreshCw size={16} className={clsx(mailboxRefreshSpin && "animate-spin")} />
                  </button>
                  <button
                    type="button"
                    onClick={(event) => {
                      event.stopPropagation();
                      const rect = event.currentTarget.getBoundingClientRect();
                      setTagMenuPosition((current) =>
                        current
                          ? null
                          : {
                              left: Math.max(12, Math.min(rect.right - 260, window.innerWidth - 272)),
                              top: Math.max(12, Math.min(rect.bottom + 8, window.innerHeight - Math.min(window.innerHeight - 24, 160 + ((tags.data?.tags.length ?? 0) * 42)))),
                            }
                      );
                    }}
                    disabled={!resolveToolbarTargets().length}
                    className="icon-button h-11 w-11 disabled:opacity-50"
                    aria-label={t("mail.tags")}
                    title={t("mail.tags")}
                  >
                    <TagIcon size={16} />
                  </button>
                  <button
                    type="button"
                    onClick={() => void deleteSelection(resolveToolbarTargets())}
                    disabled={!resolveToolbarTargets().length}
                    className="icon-button h-11 w-11 disabled:opacity-50"
                    aria-label={t("mail.deleteSelected")}
                    title={t("mail.deleteSelected")}
                  >
                    <Trash2 size={16} />
                  </button>
                  {tagMenuPosition ? (
                    <TagActionsMenu
                      t={t}
                      position={tagMenuPosition}
                      tags={tags.data?.tags ?? []}
                      activeTags={new Set(selectedActionDetail?.tags ?? [])}
                      onToggleTag={(tagName) => void handleToolbarTagToggle(tagName)}
                      onCreateTag={() => void handleCreateTagFromToolbar()}
                      onRemoveTags={() => void handleRemoveTagsFromToolbar()}
                      onRenameTag={(tag) => void handleRenameTag(tag)}
                      onDeleteTag={(tag) => void handleDeleteTag(tag)}
                    />
                  ) : null}
                </div>
                <button
                  type="button"
                  onClick={() => handlePrintMessage()}
                  disabled={!currentReaderDetail?.uid}
                  className="theme-button-soft mail-toolbar-labeled hidden h-11 px-4 text-sm disabled:opacity-50 sm:inline-flex"
                  aria-label={t("mail.print")}
                  title={t("mail.print")}
                >
                  <Printer size={16} />
                  <span className="mail-toolbar-label">{t("mail.print")}</span>
                </button>
                <button
                  type="button"
                  onClick={() => setOriginalOpen(true)}
                  disabled={!currentReaderDetail?.uid}
                  className="theme-button-soft mail-toolbar-labeled hidden h-11 px-4 text-sm disabled:opacity-50 sm:inline-flex"
                  aria-label={t("mail.showOriginal")}
                  title={t("mail.showOriginal")}
                >
                  <FileText size={16} />
                  <span className="mail-toolbar-label">{t("mail.showOriginal")}</span>
                </button>
              </div>
            ) : null}
          </header>

          {activeSection === "email" ? (
            <section
              className="grid min-h-0 gap-0 overflow-hidden p-2 lg:p-3"
              style={
                isCompactViewport
                  ? undefined
                  : ({
                      gridTemplateColumns: `minmax(360px, min(46%, ${Math.max(360, Math.min(listWidth, 620))}px)) 12px minmax(0, 1fr)`,
                    } as CSSProperties)
              }
            >
              {isCompactViewport ? (
                mobileMailPane === "reader" && selectedUid && !conversationExpandOnly ? (
                  <div className="control-surface grid h-full min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-xl">
                    <div className="flex items-center justify-between border-b border-slate-200 px-3 py-2 md:px-4">
                      <button
                        type="button"
                        onClick={() => setMobileMailPane("list")}
                        className="icon-button h-9 w-9 shrink-0 border-[color-mix(in_srgb,var(--accent)_20%,#cbd5e1)] text-[var(--accent)] hover:bg-[color-mix(in_srgb,var(--accent)_10%,white)] hover:text-[var(--accent)]"
                        aria-label={t("mail.backToList")}
                        title={t("mail.backToList")}
                      >
                        <ChevronLeft size={16} />
                      </button>
                      <div className="flex min-w-0 flex-1 items-center justify-end gap-1 overflow-x-auto pl-2 [scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden">
                        {currentReaderDetail && mobileReaderActionDetail ? (
                          <>
                            {currentReaderDetail.is_draft ? (
                              <MobileReaderActionButton label={t("mail.editDraft")} icon={<FilePenLine size={17} />} wideOnPortrait showLabelOnLandscape onClick={() => void editDraft(currentReaderDetail)} />
                            ) : (
                              <>
                                <MobileReaderActionButton label={t("mail.reply")} icon={<Reply size={17} />} showLabelOnLandscape onClick={() => void replyDraft(currentReaderDetail)} />
                                <MobileReaderActionButton label={t("mail.replyAll")} icon={<ReplyAll size={17} />} showLabelOnLandscape onClick={() => void replyAllDraft(currentReaderDetail)} />
                                <MobileReaderActionButton label={t("mail.forward")} icon={<Forward size={17} />} showLabelOnLandscape onClick={() => void forwardDraft(currentReaderDetail)} />
                              </>
                            )}
                            {!currentReaderDetail.is_draft && junkFolder && readerJunkActionTargetFolder ? (
                              <MobileReaderActionButton
                                label={readerJunkActionLabel}
                                icon={<AlertTriangle size={17} />}
                                tone="warning"
                                showLabelOnLandscape
                                onClick={() => void moveSelection([{ key: `${selectedFolder}:${selectedUid || mobileReaderActionTargetUid}`, uid: mobileReaderActionTargetUid, source: mobileReaderActionSource }], readerJunkActionTargetFolder)}
                              />
                            ) : null}
                            <MobileReaderActionButton
                              label={t("mail.delete")}
                              icon={<Trash2 size={17} />}
                              tone="danger"
                              wideOnPortrait={Boolean(currentReaderDetail.is_draft)}
                              showLabelOnLandscape
                              disabled={!currentFolderCanDeleteMessages}
                              onClick={() => deleteCurrentReaderMessage()}
                            />
                          </>
                        ) : null}
                      </div>
                    </div>
                    <Reader
                      key={readerInstanceKey}
                      detail={currentReaderDetail}
                      actionDetail={selectedActionDetail}
                      currentFolder={folder}
                      currentAccountEmail={accountScope}
                      junkActionLabel={readerJunkActionLabel}
                      junkActionTargetFolder={readerJunkActionTargetFolder}
                      loading={readerLoading}
                      errorMessage={detail.error instanceof Error ? detail.error.message : ""}
                      onRetry={() => void detail.refetch()}
                      accent={activeTheme.accent}
                      tags={tags.data?.tags ?? []}
                      onToggleSeen={() => updateFlags.mutate({ uid: readerActionUid, source: readerTargetFolder, seen: !selectedActionDetail?.seen, view: readerActionView })}
                      onToggleStar={() => updateFlags.mutate({ uid: readerActionUid, source: readerTargetFolder, starred: !selectedActionDetail?.starred, view: readerActionView })}
                      onToggleTag={(_message, tagName, enabled) =>
                        updateMessageTags.mutate({
                          uid: readerActionUid,
                          source: readerTargetFolder,
                          add: enabled ? [tagName] : [],
                          remove: enabled ? [] : [tagName],
                          view: readerActionView
                        })
                      }
                      onReply={(message) => void replyDraft(message)}
                      onReplyAll={(message) => void replyAllDraft(message)}
                      onForward={(message) => void forwardDraft(message)}
                      onJunk={junkFolder ? (message, targetFolder) => void moveSelection([{ key: `${selectedFolder}:${selectedUid || message.uid}`, uid: message.uid, source: message.folder || selectedActionSource }], targetFolder) : undefined}
                      onEditDraft={(message) => void editDraft(message)}
                      onDelete={() => deleteCurrentReaderMessage()}
                      onSaveAttachmentToDrive={(message, part) => openAttachmentSavePicker({ ...message, folder: message.folder || selectedActionSource }, [part])}
                      onSaveAllAttachmentsToDrive={(message, parts) => openAttachmentSavePicker({ ...message, folder: message.folder || selectedActionSource }, parts)}
                      onAcceptNativeShareInvite={acceptNativeShareInvite}
                      onAcceptNativeShareInviteAttachment={acceptNativeShareInviteAttachment}
                      onDeclineNativeShareInvite={declineNativeShareInvite}
                      onDeclineNativeShareInviteAttachment={declineNativeShareInviteAttachment}
                      acceptShareBusy={acceptShareNotification.isPending || acceptShareInvite.isPending || acceptMessageShareInvite.isPending || declineShareNotification.isPending || declineMessageShareInvite.isPending}
                      calendarInviteResponseBusy={respondCalendarInvite.isPending}
                      calendarInviteResponses={calendarInviteResponses}
                      onRespondCalendarInvite={async (message, invite, response) => {
                        await respondCalendarInvite.mutateAsync({ message, invite, response });
                      }}
                      readReceiptBusy={sendReadReceipt.isPending}
                      readReceiptHandled={Boolean(currentReaderDetail && handledReadReceipts[currentReaderDetail.open_uid || currentReaderDetail.uid])}
                      onSendReadReceipt={async (message) => { await sendReadReceipt.mutateAsync(message.open_uid || message.uid); }}
                      onDeclineReadReceipt={(message) => setHandledReadReceipts((current) => ({ ...current, [message.open_uid || message.uid]: true }))}
                      canDeleteMessages={currentFolderCanDeleteMessages}
                      driveConnected={driveStatus.data?.connected ?? false}
                      driveWritable={driveWritable}
                      driveSaving={saveAttachmentToDrive.isPending || saveAllAttachmentsToDrive.isPending}
                      driveServiceLabel={driveServiceLabel}
                      locale={preferences.locale}
                      timeZone={calendarTimeZone}
                      t={t}
                      compact
                    />
                  </div>
                ) : (
                  <div className="control-surface grid h-full min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-xl">
                    {renderMessageListHeader()}
                    <div
                      ref={messagesScrollRef}
                      onScroll={(event) => {
                        const target = event.currentTarget;
                        const nearBottom = target.scrollTop + target.clientHeight >= target.scrollHeight - 96;
                        if (nearBottom) maybeLoadMoreMessages();
                      }}
                      className="min-h-0 overflow-auto pb-[calc(5.75rem+env(safe-area-inset-bottom))]"
                    >
                      {visibleMessages.map((message) => {
                        const messageConversationKey = message.conversation_id || message.uid;
                        const listRowConversationMessages = conversationMessagesForListRow(message);
                        const isExpandedConversation = expandedConversationId === messageConversationKey && listRowConversationMessages.length > 1;
                        return (
                          <div key={`${message.folder}:${message.uid}`} className="grid">
                            <MessageRow
                              t={t}
                              locale={preferences.locale}
                              timeZone={calendarTimeZone}
                              message={message}
                              active={isConversationRowSelected(message)}
                              selected={selectedKeys.includes(messageKey(message)) && !isExpandedConversation && !conversationThreadSelected}
                              theme={activeTheme}
                              themeName={effectiveThemeName}
                              tagsByName={tagsByName}
                              onSelect={(event) => handleMessageSelection(event, message)}
                              onToggleConversation={() => {
                                setMobileMailPane("list");
                                const isExpanded = expandedConversationId === messageConversationKey;
                                setSelectedKeys([messageKey(message)]);
                                setLastSelectedIndex(visibleMessages.findIndex((item) => messageKey(item) === messageKey(message)));
                                setSelectedUid(message.uid);
                                setSelectedFolder(message.folder || folder);
                                setConversationExpandOnly(!isExpanded);
                                if (isExpanded) {
                                  setExpandedConversationId("");
                                  setSelectedThreadUid(null);
                                  setSelectedThreadDetailTarget(null);
                                  setSelectedThreadSummary(null);
                                } else {
                                  setExpandedConversationId(messageConversationKey);
                                }
                                if (!isExpanded) {
                                  setSelectedDetailTarget({
                                    folder: message.folder || folder,
                                    uid: message.uid,
                                    view: "conversation",
                                  });
                                } else {
                                  setSelectedThreadUid(null);
                                  setSelectedThreadDetailTarget(null);
                                  setSelectedThreadSummary(null);
                                  setSelectedDetailTarget({
                                    folder: message.folder || folder,
                                    uid: message.uid,
                                    view: "conversation",
                                  });
                                }
                              }}
                              isConversationExpanded={expandedConversationId === messageConversationKey}
                              onOpenDraft={() => void editDraftFromSummary(message)}
                              onDelete={() => void deleteSelection(resolveDeleteTargets(message))}
                              onToggleSeen={() => updateFlags.mutate({ uid: message.uid, source: message.folder || folder, seen: !message.seen, view: messageViewMode })}
                              onToggleStar={() => updateFlags.mutate({ uid: message.uid, source: message.folder || folder, starred: !message.starred, view: messageViewMode })}
                              dragItems={resolveDragSelection(message)}
                            />
                            {renderConversationThreadBlock(message)}
                          </div>
                        );
                      })}
                      {!visibleMessages.length ? <div className="p-8 text-center text-sm font-semibold text-slate-500">{t("mail.noMessages")}</div> : null}
                      {globalSearch ? null : messages.isFetchingNextPage ? (
                        <div className="flex items-center justify-center gap-2 border-t border-slate-200 bg-slate-50 px-4 py-3 text-xs font-black uppercase tracking-[0.12em] text-slate-500">
                          <RefreshCw size={12} className="animate-spin text-[var(--accent)]" />
                          {t("mail.loadingMore")}
                        </div>
                      ) : null}
                    </div>
                  </div>
                )
              ) : (
                <>
                  <div className="control-surface grid h-full min-h-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-l-xl rounded-r-none">
                    {renderMessageListHeader()}
                    <div
                      ref={messagesScrollRef}
                      onScroll={(event) => {
                        const target = event.currentTarget;
                        const nearBottom = target.scrollTop + target.clientHeight >= target.scrollHeight - 96;
                        if (nearBottom) maybeLoadMoreMessages();
                      }}
                      className="min-h-0 overflow-auto"
                    >
                      {visibleMessages.map((message) => (
                        (() => {
                          const messageConversationKey = message.conversation_id || message.uid;
                          const listRowConversationMessages = conversationMessagesForListRow(message);
                          const isExpandedConversation = expandedConversationId === messageConversationKey && listRowConversationMessages.length > 1;
                          return (
                        <div key={`${message.folder}:${message.uid}`} className="grid">
                          <MessageRow
                            t={t}
                            locale={preferences.locale}
                            timeZone={calendarTimeZone}
                            message={message}
                            active={isConversationRowSelected(message)}
                              selected={selectedKeys.includes(messageKey(message)) && !isExpandedConversation && !conversationThreadSelected}
                              theme={activeTheme}
                            themeName={effectiveThemeName}
                            tagsByName={tagsByName}
                            onSelect={(event) => handleMessageSelection(event, message)}
                            onToggleConversation={() => {
                              setMobileMailPane("list");
                              handleMessageSelection({
                                shiftKey: false,
                                ctrlKey: false,
                                metaKey: false,
                                preventDefault() {},
                                stopPropagation() {},
                              } as unknown as ReactMouseEvent<HTMLElement>, message, { openReader: false });
                              setConversationExpandOnly(true);
                              setExpandedConversationId((current) => (current === messageConversationKey ? "" : messageConversationKey));
                              setSelectedDetailTarget({
                                folder: message.folder || folder,
                                uid: message.uid,
                                view: "conversation",
                              });
                            }}
                            isConversationExpanded={expandedConversationId === messageConversationKey}
                            onOpenDraft={() => void editDraftFromSummary(message)}
                            onDelete={() => void deleteSelection(resolveDeleteTargets(message))}
                            onToggleSeen={() => updateFlags.mutate({ uid: message.uid, source: message.folder || folder, seen: !message.seen, view: messageViewMode })}
                            onToggleStar={() => updateFlags.mutate({ uid: message.uid, source: message.folder || folder, starred: !message.starred, view: messageViewMode })}
                            dragItems={resolveDragSelection(message)}
                          />
                          {renderConversationThreadBlock(message)}
                        </div>
                          );
                        })()
                      ))}
                      {!visibleMessages.length ? <div className="p-8 text-center text-sm font-semibold text-slate-500">{t("mail.noMessages")}</div> : null}
                      {globalSearch ? null : messages.isFetchingNextPage ? (
                        <div className="flex items-center justify-center gap-2 border-t border-slate-200 bg-slate-50 px-4 py-3 text-xs font-black uppercase tracking-[0.12em] text-slate-500">
                          <RefreshCw size={12} className="animate-spin text-[var(--accent)]" />
                          {t("mail.loadingMore")}
                        </div>
                      ) : null}
                    </div>
                  </div>
                  <div className="flex">
                    <ResizeHandle onDrag={(delta) => setListWidth((width) => clamp(width + delta, 280, 620))} />
                  </div>
                  {!conversationExpandOnly ? (
                  <Reader
                    key={readerInstanceKey}
                    detail={currentReaderDetail}
                    actionDetail={selectedActionDetail}
                    currentFolder={folder}
                    currentAccountEmail={accountScope}
                    junkActionLabel={isJunkFolderPath(currentFolderRecord?.abs_path || currentFolderRecord?.path || currentFolderRecord?.name || folder) ? t("mail.notJunk") : t("mail.junk")}
                    junkActionTargetFolder={isJunkFolderPath(currentFolderRecord?.abs_path || currentFolderRecord?.path || currentFolderRecord?.name || folder) ? inboxDropTarget : (junkFolder?.path || "")}
                    loading={readerLoading}
                      errorMessage={detail.error instanceof Error ? detail.error.message : ""}
                      onRetry={() => void detail.refetch()}
                      accent={activeTheme.accent}
                      tags={tags.data?.tags ?? []}
                      onToggleSeen={() => updateFlags.mutate({ uid: readerActionUid, source: readerTargetFolder, seen: !selectedActionDetail?.seen, view: readerActionView })}
                      onToggleStar={() => updateFlags.mutate({ uid: readerActionUid, source: readerTargetFolder, starred: !selectedActionDetail?.starred, view: readerActionView })}
                      onToggleTag={(_message, tagName, enabled) =>
                        updateMessageTags.mutate({
                          uid: readerActionUid,
                          source: readerTargetFolder,
                          add: enabled ? [tagName] : [],
                          remove: enabled ? [] : [tagName],
                          view: readerActionView
                        })
                      }
                    onReply={(message) => void replyDraft(message)}
                    onReplyAll={(message) => void replyAllDraft(message)}
                    onForward={(message) => void forwardDraft(message)}
                    onJunk={junkFolder ? (message, targetFolder) => void moveSelection([{ key: `${currentFolderSource}:${message.uid}`, uid: message.uid, source: currentFolderSource }], targetFolder) : undefined}
                    onEditDraft={(message) => void editDraft(message)}
                    onDelete={() => deleteCurrentReaderMessage()}
                    onSaveAttachmentToDrive={(message, part) => openAttachmentSavePicker({ ...message, folder: currentFolderSource }, [part])}
                    onSaveAllAttachmentsToDrive={(message, parts) => openAttachmentSavePicker({ ...message, folder: currentFolderSource }, parts)}
                    onAcceptNativeShareInvite={acceptNativeShareInvite}
                    onAcceptNativeShareInviteAttachment={acceptNativeShareInviteAttachment}
                    onDeclineNativeShareInvite={declineNativeShareInvite}
                    onDeclineNativeShareInviteAttachment={declineNativeShareInviteAttachment}
                    acceptShareBusy={acceptShareNotification.isPending || acceptShareInvite.isPending || acceptMessageShareInvite.isPending || declineShareNotification.isPending || declineMessageShareInvite.isPending}
                    calendarInviteResponseBusy={respondCalendarInvite.isPending}
                    calendarInviteResponses={calendarInviteResponses}
                    onRespondCalendarInvite={async (message, invite, response) => {
                      await respondCalendarInvite.mutateAsync({ message, invite, response });
                    }}
                    readReceiptBusy={sendReadReceipt.isPending}
                    readReceiptHandled={Boolean(currentReaderDetail && handledReadReceipts[currentReaderDetail.open_uid || currentReaderDetail.uid])}
                    onSendReadReceipt={async (message) => { await sendReadReceipt.mutateAsync(message.open_uid || message.uid); }}
                    onDeclineReadReceipt={(message) => setHandledReadReceipts((current) => ({ ...current, [message.open_uid || message.uid]: true }))}
                    canDeleteMessages={currentFolderCanDeleteMessages}
                    driveConnected={driveStatus.data?.connected ?? false}
                    driveWritable={driveWritable}
                    driveSaving={saveAttachmentToDrive.isPending || saveAllAttachmentsToDrive.isPending}
                    driveServiceLabel={driveServiceLabel}
                    locale={preferences.locale}
                    timeZone={calendarTimeZone}
                    t={t}
                  />
                  ) : null}
                </>
              )}
            </section>
          ) : null}
          {activeSection === "contacts" ? (
            <section className="min-h-0 overflow-auto p-2 lg:p-3">
              <ContactsManager
                t={t}
                contacts={contacts.data?.contacts ?? []}
                autocompleteContacts={composeContacts}
                folders={contactFolders.data?.folders ?? []}
                selectedFolderId={selectedContactFolderId}
                onSelectFolder={setSelectedContactFolderId}
                loading={contacts.isLoading || contacts.isFetching || contactFolders.isLoading || contactFolders.isFetching}
                canShareFolders={canShareContactFolders}
                shareBadge={featureBadge(contactFolderShareFeature)}
                shareTooltip={contactFolderShareFeature.locked ? lockedFeatureTooltip : undefined}
                onCompose={(email) => openCompose({ to: email, subject: "", body: "" })}
              />
            </section>
          ) : null}
          {activeSection === "calendar" && enableCalendarSection ? (
            <section className="grid h-full min-h-0 overflow-hidden p-0">
              {isNativeZimbraAddonEdition(activeEdition) ? (
                <NativeZimbraCalendarAddonTab
                  t={t}
                  serviceLabel={calendarServiceLabel}
                  status={calendarStatus.data}
                  statusLoading={calendarStatus.isLoading || calendarStatus.isFetching}
                  calendars={calendarSources.data?.calendars ?? []}
                  contacts={composeContacts}
                  allowColorEdit
                  allowCalendarCreation
                  allowShareManagement
                  showDisconnect={false}
                  showRecurringOptions
                  selectedCalendarId={selectedCalendarId}
                  timeZone={calendarTimeZone}
                  locale={preferences.locale}
                  onSelectCalendar={setSelectedCalendarId}
                  events={calendar.data?.events ?? []}
                  loading={calendar.isFetching}
                  loadingCalendars={calendarSources.isFetching}
                  connectPending={connectCalendar.isPending}
                  resyncPending={resyncCalendar.isPending}
                  disconnectPending={disconnectCalendar.isPending}
                  notice={calendarNotice}
                  onDismissNotice={() => setCalendarNotice(null)}
                  onConnect={() => void connectCalendar.mutate()}
                  onResync={() => void resyncCalendar.mutate()}
                  onDisconnect={() => void disconnectCalendar.mutate()}
                  focusEventId={calendarFocusEventId || null}
                  onFocusEventHandled={() => setCalendarFocusEventId("")}
                />
              ) : (
                <GoogleCalendarAddonTab
                  t={t}
                  serviceLabel={calendarServiceLabel}
                  status={calendarStatus.data}
                  statusLoading={calendarStatus.isLoading || calendarStatus.isFetching}
                  calendars={calendarSources.data?.calendars ?? []}
                  contacts={composeContacts}
                  allowColorEdit
                  allowCalendarCreation
                  showRecurringOptions
                  selectedCalendarId={selectedCalendarId}
                  timeZone={calendarTimeZone}
                  locale={preferences.locale}
                  onSelectCalendar={setSelectedCalendarId}
                  events={calendar.data?.events ?? []}
                  loading={calendar.isFetching}
                  loadingCalendars={calendarSources.isFetching}
                  connectPending={connectCalendar.isPending}
                  resyncPending={resyncCalendar.isPending}
                  disconnectPending={disconnectCalendar.isPending}
                  notice={calendarNotice}
                  onDismissNotice={() => setCalendarNotice(null)}
                  onConnect={() => void connectCalendar.mutate()}
                  onResync={() => void resyncCalendar.mutate()}
                  onDisconnect={() => void disconnectCalendar.mutate()}
                  focusEventId={calendarFocusEventId || null}
                  onFocusEventHandled={() => setCalendarFocusEventId("")}
                />
              )}
            </section>
          ) : null}
          {enableTasksSection && (activeSection === "tasks" || isNativeZimbraAddonEdition(activeEdition)) ? (
            <section className={clsx("min-h-0 overflow-auto p-0", activeSection !== "tasks" && "contents")}>
              {isNativeZimbraAddonEdition(activeEdition) ? (
                <NativeZimbraTasksAddonTab
                  serviceLabel="Task"
                  contacts={composeContacts}
                  t={t}
                  status={calendarStatus.data}
                  statusLoading={calendarStatus.isLoading || calendarStatus.isFetching}
                  connectPending={connectCalendar.isPending}
                  onConnect={() => void connectCalendar.mutate()}
                  active={activeSection === "tasks"}
                />
              ) : isGoogleAddonEdition(activeEdition) ? (
                <GoogleTasksTab
                  t={t}
                  serviceLabel="Task"
                  connectPending={connectCalendar.isPending}
                  onConnect={() => void connectCalendar.mutate()}
                />
              ) : (
                <div className="control-surface rounded-xl p-4">
                  <p className="text-sm font-semibold text-slate-600">{t("drive.taskAvailable")}</p>
                </div>
              )}
            </section>
          ) : null}
          {activeSection === "drive" && enableDriveSection ? (
            <section className="min-h-0 overflow-auto p-2 pb-[calc(5.5rem+env(safe-area-inset-bottom))] lg:p-3 lg:pb-3">
              <div className="control-surface grid gap-4 rounded-xl p-3 sm:p-4">
                <div className="flex flex-wrap items-start justify-between gap-3">
                  <div>
                    <p className="text-xs font-black uppercase tracking-[0.16em] text-slate-500">{driveServiceLabel}</p>
                    <h2 className="text-2xl font-black">{t("drive.title", { drive: driveServiceLabel })}</h2>
                  </div>
                  <div className="flex gap-2">
                    {driveStatus.data?.connected && !isNativeZimbraAddonEdition(activeEdition) ? (
                      <button
                        type="button"
                        onClick={() => void disconnectDrive.mutate()}
                        className="theme-button-soft h-10 px-4 text-sm disabled:opacity-60"
                        disabled={disconnectDrive.isPending}
                      >
                        {t("drive.disconnect")}
                      </button>
                    ) : !driveStatus.data?.connected ? (
                      <button
                        type="button"
                        onClick={() => void connectDrive.mutate()}
                        className="theme-button h-10 px-4 text-sm disabled:opacity-60"
                        disabled={connectDrive.isPending}
                      >
                        {connectDrive.isPending ? t("calendar.connecting") : t("drive.connect", { drive: driveServiceLabel })}
                      </button>
                    ) : null}
                  </div>
                </div>
                {driveNotice ? (
                  <div
                    className={clsx(
                      "rounded-lg border p-4 text-sm font-semibold",
                      driveNotice.tone === "success"
                        ? "border-[color-mix(in_srgb,var(--accent)_20%,white)] bg-[color-mix(in_srgb,var(--accent)_8%,white)] text-[var(--accent)]"
                        : driveNotice.tone === "info"
                          ? "border-[color-mix(in_srgb,var(--accent)_18%,white)] bg-[color-mix(in_srgb,var(--accent)_6%,white)] text-slate-700"
                          : "border-red-200 bg-red-50 text-red-900"
                    )}
                  >
                    {driveNotice.message}
                  </div>
                ) : null}
                {!driveStatus.data?.connected ? (
                  <div className="rounded-lg border border-slate-200 bg-slate-50 p-4 text-sm font-semibold text-slate-600">
                    {t("drive.notConnected", { drive: driveServiceLabel })}
                  </div>
                ) : (
                  <div className="grid gap-3">
                    {!driveWritable ? (
                      <div className="rounded-lg border border-amber-200 bg-amber-50 p-4 text-sm font-semibold text-amber-800">
                        {t("drive.readOnly", { drive: driveServiceLabel })}
                      </div>
                    ) : null}
                    <input
                      ref={driveUploadInputRef}
                      type="file"
                      multiple
                      className="hidden"
                      onChange={(event) => {
                        const files = Array.from(event.target.files ?? []);
                        event.target.value = "";
                        if (!files.length) return;
                        setDriveUploadPicker({ files });
                      }}
                    />
                    <div className="grid gap-3 xl:grid-cols-[minmax(0,1.72fr)_320px]">
                      <div className="grid gap-3">
                        <div className="flex flex-wrap items-center justify-between gap-2">
                          <div>
                            <p className="text-sm font-black text-slate-900">{t("drive.browse", { drive: driveServiceLabel })}</p>
                          </div>
                          <div className="flex flex-wrap items-center gap-2">
                          {browsedDriveCurrentFolderShareable ? (
                            <button
                              type="button"
                              onClick={() => setBriefcaseShareEditor({ folderId: driveBrowseFolderId, folderName: browsedDriveCurrentFolderName || t("dialog.folders") })}
                              className="theme-button-soft h-9 px-3 text-sm"
                            >
                              <Share2 size={16} />
                              {t("drive.shareThisFolder")}
                            </button>
                          ) : null}
                          <button
                            type="button"
                            onClick={() => setDriveBrowseFolderId("")}
                            className="theme-button-soft h-9 px-3 text-sm"
                            disabled={!driveBrowseFolderId}
                          >
                            {driveBrowseRootLabel}
                          </button>
                          <button
                            type="button"
                            onClick={() => {
                              setDriveBrowseFolderId(driveBrowseFolderId ? browsedDriveParentDestination : "");
                            }}
                            className="theme-button-soft h-9 px-3 text-sm"
                            disabled={!driveBrowseFolderId || browsedDriveCurrentFolder.isLoading}
                            >
                              {t("drive.upOneLevel")}
                            </button>
                          </div>
                        </div>
                        <div className="flex flex-wrap items-center gap-1 rounded-lg border border-slate-200 bg-white px-3 py-2 text-xs font-semibold text-slate-500">
                          <span className="font-black uppercase tracking-[0.12em] text-slate-400">{t("drive.breadcrumb")}</span>
                          <button
                            type="button"
                            onClick={() => setDriveBrowseFolderId("")}
                            className={clsx("rounded-full px-2 py-0.5 transition", !driveBrowseFolderId ? "bg-[color-mix(in_srgb,var(--accent)_10%,white)] text-[var(--accent)]" : "hover:bg-slate-100 text-slate-600")}
                          >
                            {driveBrowseRootLabel}
                          </button>
                          {browsedDriveDisplayBreadcrumbs.map((crumb, index) => {
                            const active = index === browsedDriveDisplayBreadcrumbs.length - 1;
                            return (
                              <div key={crumb.id} className="flex items-center gap-1">
                                <span className="text-slate-300">/</span>
                                <button
                                  type="button"
                                  onClick={() => setDriveBrowseFolderId(crumb.id)}
                                  className={clsx(
                                    "rounded-full px-2 py-0.5 transition",
                                    active
                                      ? "bg-[color-mix(in_srgb,var(--accent)_10%,white)] text-[var(--accent)]"
                                      : "text-slate-600 hover:bg-slate-100"
                                  )}
                                >
                                  {crumb.name}
                                </button>
                              </div>
                            );
                          })}
                        </div>
                      <div className="flex flex-wrap items-center gap-2">
                        <label className="relative min-w-0 flex-1">
                          <input value={driveSearch} onChange={(event) => setDriveSearch(event.target.value)} className="field h-11 min-w-0 w-full pr-10" placeholder={t("drive.searchThisFolder")} />
                          {driveSearch ? (
                            <button
                              type="button"
                              onClick={() => setDriveSearch("")}
                              className="absolute right-2 top-1/2 inline-flex h-7 w-7 -translate-y-1/2 items-center justify-center rounded-full text-slate-400 transition hover:bg-slate-200 hover:text-slate-700"
                              aria-label={t("drive.clearSearch")}
                              title={t("drive.clearSearch")}
                            >
                              <X size={14} />
                            </button>
                          ) : null}
                        </label>
                        <button
                          type="button"
                          onClick={() => driveContents.refetch()}
                          className="theme-button-soft h-11 px-4 text-sm"
                        >
                          <RefreshCw size={17} />
                          Refresh
                        </button>
                        <button
                          type="button"
                          onClick={() => driveUploadInputRef.current?.click()}
                          className="theme-button h-11 px-4 text-sm xl:hidden"
                          disabled={!driveCanWriteCurrentFolder || uploadDriveFiles.isPending}
                        >
                          <Upload size={16} />
                          {uploadDriveFiles.isPending ? t("drive.uploading") : t("drive.uploadFile")}
                        </button>
                      </div>
                      <div className="grid gap-2 rounded-lg border border-slate-200 bg-white">
                        {driveContents.isLoading ? <div className="p-5 text-sm font-semibold text-slate-500">{t("drive.loadingFolder", { drive: driveServiceLabel })}</div> : null}
                        {!driveContents.isLoading && !((driveContents.data?.folders.length ?? 0) || (driveContents.data?.files.length ?? 0)) ? (
                          <div className="grid gap-2 p-5 text-sm font-semibold text-slate-500">
                            <p>{t("drive.emptyFolder")}</p>
                            <p className="text-xs leading-6 text-slate-400">{t("drive.emptyFolderHelp")}</p>
                          </div>
                        ) : null}
                        {browsedDriveShowParentRow ? (
                          (() => {
                            const parentFolderId = browsedDriveParentDestination;
                            return (
                          <div
                            className={clsx(
                              "flex flex-wrap items-center justify-between gap-3 border-t border-slate-100 px-4 py-3 transition",
                              driveDragTargetId === parentFolderId && "bg-[color-mix(in_srgb,var(--accent)_8%,white)]"
                            )}
                            onDragOver={(event) => {
                              if (!driveCanWriteCurrentFolder || !driveDragFileId) return;
                              event.preventDefault();
                              setDriveDragTargetId(parentFolderId);
                            }}
                            onDragLeave={() => {
                              if (driveDragTargetId === parentFolderId) {
                                setDriveDragTargetId("");
                              }
                            }}
                            onDrop={(event) => {
                              event.preventDefault();
                              if (!driveCanWriteCurrentFolder || !driveDragFileId || driveDragFileId === parentFolderId) return;
                              void moveDriveFile.mutate({ fileId: driveDragFileId, parentId: parentFolderId });
                            }}
                          >
                            <button
                              type="button"
                              onClick={() => setDriveBrowseFolderId(parentFolderId)}
                              className="flex min-w-0 flex-1 items-center gap-2 text-left"
                            >
                              <FolderIcon size={16} className="text-slate-400" />
                              <div className="min-w-0">
                                <p className="truncate text-sm font-bold text-slate-900">..</p>
                                <p className="text-xs font-semibold text-slate-500">{t("drive.parentFolderOpen")}</p>
                              </div>
                            </button>
                          </div>
                            );
                          })()
                        ) : null}
                        {(driveContents.data?.folders ?? []).map((folderItem) => {
                          const isDropTarget = driveDragTargetId === folderItem.id;
                          const mountedShare = isMountedDriveFolder(folderItem);
                          const folderWritable = canWriteDriveFolder(folderItem);
                          const mobileActionMenuId = `folder:${folderItem.id}`;
                          const mobileActionMenuOpen = openDriveActionMenuId === mobileActionMenuId;
                          return (
                          <div
                            key={folderItem.id}
                            className={clsx(
                              "flex flex-wrap items-center justify-between gap-3 border-t border-slate-100 px-4 py-3 first:border-t-0 transition",
                              isDropTarget && "bg-[color-mix(in_srgb,var(--accent)_8%,white)]"
                            )}
                            onDragOver={(event) => {
                              if (!driveCanWriteCurrentFolder || !folderWritable || !driveDragFileId) return;
                              event.preventDefault();
                              setDriveDragTargetId(folderItem.id);
                            }}
                            onDragLeave={() => {
                              if (driveDragTargetId === folderItem.id) {
                                setDriveDragTargetId("");
                              }
                            }}
                            onDrop={(event) => {
                              event.preventDefault();
                              if (!driveCanWriteCurrentFolder || !folderWritable || !driveDragFileId || driveDragFileId === folderItem.id) return;
                              void moveDriveFile.mutate({ fileId: driveDragFileId, parentId: folderItem.id });
                            }}
                          >
                            <button
                              type="button"
                              onClick={() => setDriveBrowseFolderId(folderItem.id)}
                              className="flex min-w-0 flex-1 items-center gap-2 text-left"
                            >
                              {mountedShare ? (
                                <FolderSymlink size={16} className="shrink-0 text-[var(--accent)]" aria-label={t("sharing.sharedWithMe")} />
                              ) : (
                                <FolderIcon size={16} className="shrink-0 text-[var(--accent)]" />
                              )}
                              <div className="min-w-0">
                                <p className="truncate text-sm font-bold text-slate-900">{folderItem.name}</p>
                                <p className="text-xs font-semibold text-slate-500">
                                  {isDropTarget ? t("drive.dropToMove") : describeDriveFolderStats(folderItem)}
                                </p>
                              </div>
                            </button>
                            <div className="relative xl:hidden">
                              <button
                                type="button"
                                onClick={() => setOpenDriveActionMenuId(mobileActionMenuOpen ? null : mobileActionMenuId)}
                                className="grid h-9 w-9 place-items-center rounded-lg text-slate-500 transition hover:bg-slate-100 hover:text-slate-900"
                                aria-label={t("drive.folderActionsFor", { name: folderItem.name })}
                                aria-expanded={mobileActionMenuOpen}
                              >
                                <MoreHorizontal size={17} />
                              </button>
                              {mobileActionMenuOpen ? (
                                <div className="mt-2 flex flex-wrap items-center gap-2 rounded-lg border border-slate-200 bg-slate-50 p-2">
                                  {nativeZimbraDrive && folderWritable && folderItem.name.trim().toLowerCase() !== "trash" ? (
                                    <button
                                      type="button"
                                      onClick={() => {
                                        setOpenDriveActionMenuId(null);
                                        setBriefcaseShareEditor({ folderId: folderItem.id, folderName: folderItem.name });
                                      }}
                                      className="theme-button-soft h-9 px-3 text-sm"
                                    >
                                      <Share2 size={15} />
                                      {t("common.share")}
                                    </button>
                                  ) : null}
                                  <button
                                    type="button"
                                    onClick={() => {
                                      setOpenDriveActionMenuId(null);
                                      confirmDeleteDriveFolder(folderItem.id, folderItem.name);
                                    }}
                                    className="theme-button-soft h-9 px-3 text-sm text-red-700"
                                    disabled={!driveCanWriteCurrentFolder || !folderWritable || deleteDriveFile.isPending}
                                  >
                                    {t("common.delete")}
                                  </button>
                                </div>
                              ) : null}
                            </div>
                            <div className="hidden items-center gap-2 xl:flex">
                              {nativeZimbraDrive && folderWritable && folderItem.name.trim().toLowerCase() !== "trash" ? (
                                <button
                                  type="button"
                                  onClick={() => setBriefcaseShareEditor({ folderId: folderItem.id, folderName: folderItem.name })}
                                  className="theme-button-soft h-9 px-3 text-sm"
                                >
                                  <Share2 size={15} />
                                  {t("common.share")}
                                </button>
                              ) : null}
                              <button
                                type="button"
                                onClick={() => confirmDeleteDriveFolder(folderItem.id, folderItem.name)}
                                className="theme-button-soft h-9 px-3 text-sm text-red-700"
                                disabled={!driveCanWriteCurrentFolder || !folderWritable || deleteDriveFile.isPending}
                              >
                                {t("common.delete")}
                              </button>
                            </div>
                          </div>
                          );
                        })}
                        {(driveContents.data?.files ?? []).map((file) => (
                          <div
                            key={file.id}
                            draggable
                            onDragStart={(event) => {
                              if (!driveCanWriteCurrentFolder) return;
                              event.dataTransfer.effectAllowed = "move";
                              event.dataTransfer.setData("text/plain", file.id);
                              setDriveDragFileId(file.id);
                            }}
                            onDragEnd={() => {
                              setDriveDragFileId("");
                              setDriveDragTargetId("");
                            }}
                            className={clsx(
                              "scroll-mb-[calc(6rem+env(safe-area-inset-bottom))] flex flex-wrap items-center justify-between gap-3 border-t border-slate-100 px-4 py-3 first:border-t-0",
                              driveDragFileId === file.id && "opacity-60"
                            )}
                          >
                            <div className="min-w-0">
                              <p className="truncate text-sm font-bold text-slate-900">{file.name}</p>
                              <p className="text-xs font-semibold text-slate-500">
                                {formatDriveMimeLabel(file.mime_type, file.name)} · {Math.max(1, Math.round(file.size / 1024))} KB
                              </p>
                            </div>
                          <div className="flex items-center gap-2">
                              <button
                                type="button"
                                onClick={() => {
                                  setOpenDriveActionMenuId(null);
                                  window.open(driveOpenUrl(file, isNativeZimbraAddonEdition(activeEdition)), "_blank", "noopener,noreferrer");
                                }}
                                className="theme-button-soft h-9 px-3 text-sm"
                              >
                                {t("drive.open")}
                              </button>
                              <div className="relative xl:hidden">
                                <button
                                  type="button"
                                  onClick={() => setOpenDriveActionMenuId(openDriveActionMenuId === `file:${file.id}` ? null : `file:${file.id}`)}
                                  className="grid h-9 w-9 place-items-center rounded-lg text-slate-500 transition hover:bg-slate-100 hover:text-slate-900"
                                  aria-label="File actions"
                                  aria-expanded={openDriveActionMenuId === `file:${file.id}`}
                                >
                                  <MoreHorizontal size={17} />
                                </button>
                                {openDriveActionMenuId === `file:${file.id}` ? (
                                  <div className="mt-2 grid min-w-36 gap-2 rounded-lg border border-slate-200 bg-white p-2 shadow-lg">
                                    <button
                                      type="button"
                                      onClick={() => {
                                        setOpenDriveActionMenuId(null);
                                        openCompose({ attachments: [{ filename: file.name, content_type: file.mime_type, size: file.size, kind: "drive_file", drive_file_id: file.id, drive_file_name: file.name, drive_web_view_link: file.web_view_link }] });
                                      }}
                                      className="theme-button-soft h-9 justify-start px-3 text-sm"
                                    >
                                      {t("compose.attach")}
                                    </button>
                                    {allowDriveLink ? (
                                      <button
                                        type="button"
                                        onClick={() => {
                                          setOpenDriveActionMenuId(null);
                                          openCompose({ attachments: [{ filename: file.name, content_type: file.mime_type, size: file.size, kind: "drive_link", drive_file_id: file.id, drive_file_name: file.name, drive_web_view_link: file.web_view_link }] });
                                        }}
                                        className="theme-button h-9 justify-start px-3 text-sm"
                                      >
                                        {t("drive.link")}
                                      </button>
                                    ) : null}
                                    <button
                                      type="button"
                                      onClick={() => {
                                        setOpenDriveActionMenuId(null);
                                        confirmDeleteDriveFile(file.id);
                                      }}
                                      className="theme-button-soft h-9 justify-start px-3 text-sm text-red-700"
                                      disabled={!driveCanWriteCurrentFolder || deleteDriveFile.isPending}
                                    >
                                      {t("common.delete")}
                                    </button>
                                  </div>
                                ) : null}
                              </div>
                              <div className="hidden items-center gap-2 xl:flex">
                                <button
                                  type="button"
                                  onClick={() => openCompose({ attachments: [{ filename: file.name, content_type: file.mime_type, size: file.size, kind: "drive_file", drive_file_id: file.id, drive_file_name: file.name, drive_web_view_link: file.web_view_link }] })}
                                  className="theme-button-soft h-9 px-3 text-sm"
                                >
                                  {t("compose.attach")}
                                </button>
                                {allowDriveLink ? (
                                  <button
                                    type="button"
                                    onClick={() => openCompose({ attachments: [{ filename: file.name, content_type: file.mime_type, size: file.size, kind: "drive_link", drive_file_id: file.id, drive_file_name: file.name, drive_web_view_link: file.web_view_link }] })}
                                    className="theme-button h-9 px-3 text-sm"
                                  >
                                    {t("drive.link")}
                                  </button>
                                ) : null}
                                <button
                                  type="button"
                                  onClick={() => confirmDeleteDriveFile(file.id)}
                                  className="theme-button-soft h-9 px-3 text-sm text-red-700"
                                  disabled={!driveCanWriteCurrentFolder || deleteDriveFile.isPending}
                                >
                                  {t("common.delete")}
                                </button>
                              </div>
                            </div>
                          </div>
                        ))}
                      </div>
                    </div>
                    <button
                      type="button"
                      onClick={() => setDriveFolderManagementOpen((open) => !open)}
                      className="theme-button-soft h-10 px-3 text-sm xl:hidden"
                      aria-expanded={driveFolderManagementOpen}
                    >
                      <FolderIcon size={16} />
                      Manage folders
                    </button>
                    <aside className={clsx("h-fit gap-3 rounded-xl border border-slate-200 bg-white p-4", driveFolderManagementOpen ? "grid" : "hidden", "xl:grid")}>
                      <div className="flex items-start justify-between gap-3">
                        <div>
                          <p className="text-sm font-black text-slate-900">{t("drive.briefcaseFolders")}</p>
                        </div>
                        <span className="rounded-full bg-slate-100 px-2 py-0.5 text-[11px] font-black text-slate-500">{manageableBriefcaseFolders.length}</span>
                      </div>
                      <form
                        className="grid gap-2"
                        onSubmit={(event) => {
                          event.preventDefault();
                          const name = driveNewFolderName.trim();
                          if (!name || !driveCanCreateFolder) return;
                          createDriveFolder.mutate({ name, parent_id: driveBrowseFolderId || driveSaveFolderId });
                        }}
                      >
                        <input
                          value={driveNewFolderName}
                          onChange={(event) => setDriveNewFolderName(event.target.value)}
                          className="field h-11 min-w-0"
                          placeholder={t("drive.newFolderAt", { folder: browsedDriveCurrentFolderName || driveRootLabel })}
                          onKeyDown={(event) => {
                            if (event.key === "Enter") {
                              event.preventDefault();
                              const name = driveNewFolderName.trim();
                              if (!name || !driveCanCreateFolder) return;
                              createDriveFolder.mutate({ name, parent_id: driveBrowseFolderId || driveSaveFolderId });
                            }
                          }}
                        />
                        <button
                          type="submit"
                          className="theme-button h-11 px-4 text-sm disabled:opacity-60"
                          disabled={!driveCanCreateFolder || createDriveFolder.isPending || !driveNewFolderName.trim()}
                        >
                          <Plus size={16} />
                          {createDriveFolder.isPending ? t("task.creating") : t("drive.newBriefcaseFolder")}
                        </button>
                      </form>
                      <button
                        type="button"
                        onClick={() => driveUploadInputRef.current?.click()}
                        className="theme-button-soft h-10 px-3 text-sm"
                        disabled={!driveCanWriteCurrentFolder || uploadDriveFiles.isPending}
                      >
                        <Upload size={16} />
                        {uploadDriveFiles.isPending ? t("drive.uploading") : t("drive.uploadFile")}
                      </button>
                      <div className="grid gap-2">
                        {driveFolders.isLoading ? (
                          <p className="rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm font-semibold text-slate-500">{t("drive.loadingFolders")}</p>
                        ) : manageableBriefcaseFolders.length ? (
                          manageableBriefcaseFolders.map((folderItem) => {
                            const selected = driveBrowseFolderId === folderItem.id;
                            const colorHex = folderColorHex(folderItem);
                            const menuOpen = briefcaseFolderMenuId === folderItem.id;
                            const mountedShare = isMountedDriveFolder(folderItem);
                            const folderWritable = canWriteDriveFolder(folderItem);
                            return (
                              <div key={folderItem.id} className={clsx("grid gap-2 rounded-lg border p-3 transition", selected ? "border-[color-mix(in_srgb,var(--accent)_24%,white)] bg-[color-mix(in_srgb,var(--accent)_6%,white)]" : "border-slate-200 bg-slate-50")}>
                                <div className="flex items-center gap-2">
                                  <button
                                    type="button"
                                    onClick={() => setDriveBrowseFolderId(folderItem.id)}
                                    className="flex min-w-0 flex-1 items-center gap-2 text-left"
                                  >
                                    {mountedShare ? (
                                      <FolderSymlink size={16} style={colorHex ? { color: colorHex } : undefined} className={clsx("shrink-0", colorHex ? undefined : "text-[var(--accent)]")} aria-label={t("sharing.sharedWithMe")} />
                                    ) : (
                                      <FolderIcon size={16} style={colorHex ? { color: colorHex } : undefined} className={clsx("shrink-0", colorHex ? undefined : "text-[var(--accent)]")} />
                                    )}
                                    <span className="min-w-0">
                                      <span className="block truncate text-sm font-bold text-slate-900">{folderItem.name}</span>
                                      <span className="block truncate text-xs font-semibold text-slate-500">{describeDriveFolderStats(folderItem)}</span>
                                    </span>
                                  </button>
                                  <button
                                    type="button"
                                    onClick={() => setBriefcaseFolderMenuId(menuOpen ? "" : folderItem.id)}
                                    className="grid h-8 w-8 shrink-0 place-items-center rounded-lg text-slate-500 transition hover:bg-white hover:text-slate-900"
                                    aria-label={t("drive.folderActionsFor", { name: folderItem.name })}
                                    title={t("drive.folderActions")}
                                  >
                                    <MoreHorizontal size={17} />
                                  </button>
                                </div>
                                {menuOpen ? (
                                  <div className="grid gap-3 rounded-lg border border-slate-200 bg-white p-3">
                                    <div>
                                      <div className="mb-2 flex items-center gap-2 text-xs font-black uppercase tracking-[0.12em] text-slate-400">
                                        <Palette size={13} />
                                        {t("folder.color")}
                                      </div>
                                      <div className="grid grid-cols-5 gap-2">
                                        {folderColorOptions.map((option) => {
                                          const active = folderColorMatches(folderItem, option.value, option.hex);
                                          return (
                                            <button
                                              key={option.value}
                                              type="button"
                                              onClick={() => updateDriveFolderColor.mutate({ folderId: folderItem.id, color: option.value, rgb: option.hex })}
                                              className={clsx("grid h-8 w-8 place-items-center rounded-full border transition", active ? "border-slate-900" : "border-slate-200 hover:border-slate-400")}
                                              style={{ backgroundColor: option.hex }}
                                              aria-label={t("drive.setFolderColor", { folder: folderItem.name, color: option.label })}
                                              title={option.label}
                                              disabled={updateDriveFolderColor.isPending}
                                            >
                                              {active ? <Check size={14} className="text-white drop-shadow" /> : null}
                                            </button>
                                          );
                                        })}
                                      </div>
                                    </div>
                                    <button
                                      type="button"
                                      onClick={() => {
                                        setBriefcaseFolderMenuId("");
                                        if (!folderWritable) return;
                                        setBriefcaseShareEditor({ folderId: folderItem.id, folderName: folderItem.name });
                                      }}
                                      disabled={!folderWritable}
                                      className="theme-button-soft h-9 justify-start px-3 text-sm disabled:cursor-not-allowed disabled:opacity-50"
                                    >
                                      <Share2 size={15} />
                                      {t("folder.share")}
                                    </button>
                                  </div>
                                ) : null}
                              </div>
                            );
                          })
                        ) : (
                          <p className="rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm font-semibold text-slate-500">{t("drive.noBriefcaseFolders")}</p>
                        )}
                      </div>
                    </aside>
                  </div>
                  </div>
                )}
              </div>
            </section>
          ) : null}
          {activeSection === "preferences" ? (
            <section className="min-h-0 overflow-auto p-2 lg:p-3">
              <div className="control-surface rounded-xl p-3 sm:p-4">
                <InlinePreferences
                  preferences={preferences}
                  effectiveThemeName={effectiveThemeName}
                  setPreferences={setPreferences}
                  onApplyPreferences={(nextPreferences, nextMessageViewMode) => {
                    setPreferences(nextPreferences);
                    persistWorkspacePreferences(nextPreferences, nextMessageViewMode);
                  }}
                  appVersion={packageJson.version}
                  buildId={buildId}
                  buildTime={buildTime}
                  edition={productConfig?.edition || ""}
                  tier={productConfig?.tier || ""}
                  licenseStatus={licenseStatus}
                  messageViewMode={messageViewMode}
                  onMessageViewModeChange={persistMessageViewMode}
                  contacts={contacts.data?.contacts ?? []}
                  contactFolders={contactFolders.data?.folders ?? []}
                  mailFolders={folders.data?.folders ?? []}
                  selectedContactFolderId={selectedContactFolderId}
                  onSelectContactFolder={setSelectedContactFolderId}
                  messages={allMessages}
                  calendar={calendar.data?.events ?? []}
                  defaultSignature={signatures.data?.default_signature ?? null}
                  signaturesLoading={signatures.isLoading || signatures.isFetching}
                  signaturesError={signatures.error instanceof Error ? signatures.error.message : ""}
                  signaturesSaving={saveSignatures.isPending}
                  onSaveSignature={(payload) => void saveSignatures.mutate(payload)}
                  filterRules={messageFilterRules}
                  setFilterRules={setMessageFilterRules}
                  filtersLoading={workspaceFilters.isLoading || workspaceFilters.isFetching}
                  filtersError={workspaceFilters.error instanceof Error ? workspaceFilters.error.message : ""}
                  filtersSaving={saveWorkspaceFilters.isPending}
                  onSaveFilters={async (rules) => {
                    const data = await saveWorkspaceFilters.mutateAsync({ rules });
                    const nextRules = normalizeFilterRules(data.rules ?? [], folders.data?.folders ?? []);
                    setMessageFilterRules(nextRules);
                    return nextRules;
                  }}
                  email={me.data.email}
                  sharedFolders={folders.data?.folders ?? []}
                  sharedFolderHighlightPath={sharedFolderHighlightPath}
                  sharedFolderHighlightPulse={sharedFolderHighlightPulse}
                  shareNotifications={shareNotifications.data?.notifications ?? []}
                  calendarSources={calendarSources.data?.calendars ?? []}
                  taskLists={nativeZimbraTaskLists.data?.lists ?? []}
                  briefcaseFolders={mountedBriefcaseShares.data?.folders ?? []}
                  briefcaseFoldersLoading={mountedBriefcaseShares.isLoading || mountedBriefcaseShares.isFetching}
                  showCalendarSharing={enableCalendarSection}
                  showTaskSharing={enableTasksSection}
                  showBriefcaseSharing={enableDriveSection && isNativeZimbraAddonEdition(activeEdition) && (productConfig?.capabilities.drive_native_zimbra ?? false)}
                  canShareContactFolders={canShareContactFolders}
                  contactShareBadge={featureBadge(contactFolderShareFeature)}
                  contactShareTooltip={contactFolderShareFeature.locked ? lockedFeatureTooltip : undefined}
                  activeTab={settingsTab}
                  setActiveTab={setSettingsTab}
                  t={t}
                  onCompose={(email) => openCompose({ to: email, subject: "", body: "" })}
                />
              </div>
            </section>
          ) : null}
        </main>
      </div>

      {visibleCalendarReminders.length ? (
        <div className="fixed right-4 top-4 z-[120] grid w-[min(100%-2rem,24rem)] gap-3 sm:right-6 sm:top-6">
          {visibleCalendarReminders.map((reminder) => (
            <div key={reminder.id} className="pointer-events-auto rounded-2xl border border-[color-mix(in_srgb,var(--accent)_22%,white)] bg-white p-4 shadow-[0_20px_60px_-24px_rgba(15,23,42,0.45)]">
              <div className="flex items-start gap-3">
                <div className="grid h-10 w-10 shrink-0 place-items-center rounded-xl bg-[color-mix(in_srgb,var(--accent)_12%,white)] text-[var(--accent)]">
                  <CalendarDays size={18} />
                </div>
                <div className="min-w-0 flex-1">
                  <p className="text-xs font-black uppercase tracking-[0.12em] text-[var(--accent)]">{t("reminder.title")}</p>
                  <h4 className="truncate text-base font-black text-slate-900">{reminder.event.summary}</h4>
                  <p className="mt-1 text-sm font-semibold text-slate-600">{reminder.calendar_summary || t("sharing.calendar")} • {formatCalendarReminderLabel(reminder, preferences.locale)}</p>
                  <div className="mt-3 flex flex-wrap gap-2">
                    <button
                      type="button"
                      onClick={() => {
                        setActiveSection("calendar");
                        dismissCalendarReminder(reminder.id);
                      }}
                      className="theme-button h-9 px-3 text-sm"
                    >
                      Open calendar
                    </button>
                    <button
                      type="button"
                      onClick={() => dismissCalendarReminder(reminder.id)}
                      className="theme-button-soft h-9 px-3 text-sm"
                    >
                      Dismiss
                    </button>
                  </div>
                </div>
                <button
                  type="button"
                  onClick={() => dismissCalendarReminder(reminder.id)}
                  className="text-slate-400 transition hover:text-slate-700"
                  aria-label={t("reminder.dismiss")}
                >
                  <X size={16} />
                </button>
              </div>
            </div>
          ))}
        </div>
      ) : null}

      {isCompactViewport && !sidebarOpen ? (
        <>
          <nav
            className="fixed bottom-[calc(0.75rem+env(safe-area-inset-bottom))] left-1/2 z-30 flex w-[min(calc(100%-1.5rem),46rem)] -translate-x-1/2 items-center gap-1 rounded-xl border border-slate-200 bg-white/95 p-1 shadow-[0_18px_48px_-22px_rgba(15,23,42,0.55)] backdrop-blur-xl"
            aria-label={t("navigation.primary")}
          >
            <BottomNavItem
              icon={<Inbox size={18} />}
              label={t("nav.email")}
              active={activeSection === "email"}
              onClick={() => {
                setActiveSection("email");
                setMobileMailPane("list");
                setSidebarOpen(false);
              }}
            />
            <BottomNavItem
              icon={<Users size={18} />}
              label={t("nav.contact")}
              active={activeSection === "contacts"}
              onClick={() => {
                setActiveSection("contacts");
                setSidebarOpen(false);
              }}
            />
            {showCalendarSection ? (
              <BottomNavItem
                icon={<CalendarDays size={18} />}
                label={t("nav.calendar")}
                active={activeSection === "calendar"}
                disabled={!enableCalendarSection}
                badge={featureBadge(calendarFeature)}
                tooltip={calendarFeature.locked ? lockedFeatureTooltip : undefined}
                onClick={() => {
                  setActiveSection("calendar");
                  setSidebarOpen(false);
                }}
              />
            ) : null}
            {showTasksSection ? (
              <BottomNavItem
                icon={<ListTodo size={18} />}
                label={t("nav.task")}
                active={activeSection === "tasks"}
                disabled={!enableTasksSection}
                badge={featureBadge(tasksFeature)}
                tooltip={tasksFeature.locked ? lockedFeatureTooltip : undefined}
                onClick={() => {
                  setActiveSection("tasks");
                  setSidebarOpen(false);
                }}
              />
            ) : null}
            {showDriveSection ? (
              <BottomNavItem
                icon={<FolderIcon size={18} />}
                label={driveTabLabel}
                active={activeSection === "drive"}
                disabled={!enableDriveSection}
                badge={featureBadge(driveFeature)}
                tooltip={driveFeature.locked ? lockedFeatureTooltip : undefined}
                onClick={() => {
                  setActiveSection("drive");
                  setSidebarOpen(false);
                }}
              />
            ) : null}
            <BottomNavItem
              icon={<Palette size={18} />}
              label={t("nav.prefsShort")}
              active={activeSection === "preferences"}
              onClick={() => {
                setActiveSection("preferences");
                setSidebarOpen(false);
              }}
            />
          </nav>
          {activeSection === "email" ? (
            <button
              type="button"
              onClick={() => setComposeOpen(true)}
              className="theme-button fixed bottom-[calc(5.25rem+env(safe-area-inset-bottom))] right-4 z-30 h-14 w-14 rounded-xl p-0 shadow-lg"
              aria-label={t("mail.compose")}
              title={t("mail.compose")}
            >
              <MailPlus size={22} />
            </button>
          ) : null}
        </>
      ) : null}

      {folderMenu ? (
        <FolderContextMenu
          folder={folderMenu.folder}
          t={t}
          x={folderMenu.x}
          y={folderMenu.y}
          busy={renameFolder.isPending || updateFolderColor.isPending || deleteFolder.isPending || emptyFolder.isPending || shareFolder.isPending || revokeFolderShare.isPending}
          shareDisabled={!canShareMailFolders}
          shareBadge={featureBadge(mailFolderShareFeature)}
          shareTooltip={mailFolderShareFeature.locked ? lockedFeatureTooltip : undefined}
          onRename={() => void handleRenameFolder(folderMenu.folder)}
          onColorChange={(color, rgb) => void handleFolderColorChange(folderMenu.folder, color, rgb)}
          onShare={() => void handleShareFolder(folderMenu.folder)}
          onDelete={() => void handleDeleteFolder(folderMenu.folder)}
          onEmpty={() => void handleEmptyFolder(folderMenu.folder)}
        />
      ) : null}

              <ComposeDialog
                open={composeOpen}
                onClose={() => {
                  setComposeOpen(false);
                  setReplyTo(undefined);
                }}
                replyTo={replyTo}
                focusTarget={replyTo?.focus_target || (replyTo?.origid ? "body" : "to")}
                signature={(replyTo?.origid ? signatures.data?.reply_signature?.content : signatures.data?.default_signature?.content) ?? ""}
                signatureHtml={(replyTo?.origid ? signatures.data?.reply_signature?.content_html : signatures.data?.default_signature?.content_html) ?? ""}
                contacts={composeContacts}
                driveStatus={driveStatus.data}
                driveServiceLabel={driveServiceLabel}
                allowDriveLink={allowDriveLink}
                canBrowseStorageAttachments={
                  enableDriveSection &&
                  Boolean(productConfig?.capabilities.drive)
                }
                accent={activeTheme.accent}
                timeZone={calendarTimeZone}
                t={t}
              />

      {originalOpen && (currentReaderDetail || detail.data?.message) ? (
        <OriginalMessageModal
          t={t}
          message={(currentReaderDetail || detail.data?.message) as MessageDetail}
          raw={originalMessage.data ?? ""}
          loading={originalMessage.isLoading || originalMessage.isFetching}
          errorMessage={originalMessage.error instanceof Error ? originalMessage.error.message : ""}
          onRetry={() => void originalMessage.refetch()}
          onClose={() => setOriginalOpen(false)}
        />
      ) : null}

      {tagEditor ? (
        <TagEditorModal
          title={tagEditor.mode === "edit" ? t("dialog.editTag") : t("dialog.newTag")}
          t={t}
          initialName={tagEditor.tag?.name ?? ""}
          initialColor={tagEditor.tag?.color ?? 0}
          busy={createTag.isPending || renameTag.isPending}
          onClose={() => setTagEditor(null)}
          onSave={(name, color) => void handleSaveTagEditor(name, color)}
        />
      ) : null}
      {sessionWarningOpen ? (
        <SessionExpiryModal
          t={t}
          secondsRemaining={sessionCountdownSeconds}
          busy={sessionKeepAliveBusy || logout.isPending}
          onStaySignedIn={() => void keepSessionAlive()}
          onLogoutNow={() => handleSessionExpired()}
        />
      ) : null}

      {folderEditor ? (
        <NameEditorModal
          title={t("folder.renameTitle")}
          t={t}
          initialName={displayFolder(folderEditor.folder.name)}
          busy={renameFolder.isPending}
          onClose={() => setFolderEditor(null)}
          onSave={(name) => void handleSaveFolderName(name)}
        />
      ) : null}

      {folderShareEditor ? (
        <FolderShareModal
          folder={folderShareEditor.folder}
          t={t}
          contacts={composeContacts}
          busy={shareFolder.isPending || revokeFolderShare.isPending}
          onClose={() => setFolderShareEditor(null)}
          onShare={(email, permissions) => handleShareSubmit(email, permissions)}
          onRevoke={(email) => handleShareRevoke(email)}
        />
      ) : null}

      {briefcaseShareEditor ? (
        <BriefcaseShareModal
          folderId={briefcaseShareEditor.folderId}
          folderName={briefcaseShareEditor.folderName}
          t={t}
          contacts={composeContacts}
          busy={shareNativeBriefcaseFolder.isPending || revokeNativeBriefcaseShare.isPending}
          onClose={() => setBriefcaseShareEditor(null)}
          onShare={(email, permissions) =>
            shareNativeBriefcaseFolder.mutateAsync({ resourceId: briefcaseShareEditor.folderId, email, permissions }).then(() => undefined)
          }
          onRevoke={(email) =>
            revokeNativeBriefcaseShare.mutateAsync({ resourceId: briefcaseShareEditor.folderId, email }).then(() => undefined)
          }
        />
      ) : null}

      {attachmentSavePicker ? (
        <AttachmentSavePickerModal
          t={t}
          serviceLabel={driveServiceLabel}
          rootLabel={driveRootLabel}
          nodes={driveFolderTree}
          initialFolderId={driveSaveFolderId}
          initialFolderName={selectedDriveFolderName}
          busy={saveAttachmentToDrive.isPending || saveAllAttachmentsToDrive.isPending || driveFolders.isLoading || driveFolders.isFetching}
          title={t("drive.saveAttachmentToFolder")}
          description={t("drive.saveAttachmentPickerHelp")}
          actionLabelPrefix={t("drive.saveTo")}
          onClose={() => setAttachmentSavePicker(null)}
          onSave={(folderId, folderName) => {
            persistDriveSaveFolder(folderId, folderName);
            return saveAttachmentsToFolder(folderId);
          }}
        />
      ) : null}

      {driveUploadPicker ? (
        <AttachmentSavePickerModal
          t={t}
          serviceLabel={driveServiceLabel}
          rootLabel={driveRootLabel}
          nodes={driveFolderTree}
          initialFolderId={driveSaveFolderId}
          initialFolderName={selectedDriveFolderName}
          busy={uploadDriveFiles.isPending || driveFolders.isLoading || driveFolders.isFetching}
          title={t("drive.uploadFilesToFolder")}
          description={t("drive.uploadPickerHelp")}
          actionLabelPrefix={t("drive.uploadTo")}
          onClose={() => setDriveUploadPicker(null)}
          onSave={(folderId, folderName) => {
            persistDriveSaveFolder(folderId, folderName);
            return uploadFilesToFolder(driveUploadPicker.files, folderId);
          }}
        />
      ) : null}

      {advancedSearchOpen ? (
        <div className="fixed inset-0 z-50 grid place-items-end bg-slate-950/35 sm:place-items-center sm:p-4" onMouseDown={(event) => event.target === event.currentTarget && setAdvancedSearchOpen(false)}>
          <section role="dialog" aria-modal="true" aria-labelledby="advanced-search-title" className="grid max-h-[100dvh] w-full gap-4 overflow-y-auto rounded-t-lg bg-white p-4 shadow-xl sm:max-w-2xl sm:rounded-lg sm:p-5">
            <div className="flex items-center justify-between gap-3">
              <h2 id="advanced-search-title" className="text-lg font-black text-slate-950">{t("mail.advancedSearch")}</h2>
              <button type="button" onClick={() => setAdvancedSearchOpen(false)} className="icon-button h-9 w-9" aria-label={t("common.close")}><X size={18} /></button>
            </div>
            <div className="grid gap-3 sm:grid-cols-2">
              <AdvancedSearchField label={t("mail.searchKeywords")} value={advancedSearch.keywords} onChange={(value) => setAdvancedSearch((current) => ({ ...current, keywords: value }))} />
              <AdvancedSearchField label={t("mail.searchSubject")} value={advancedSearch.subject} onChange={(value) => setAdvancedSearch((current) => ({ ...current, subject: value }))} />
              <AdvancedSearchField label={t("mail.searchFrom")} value={advancedSearch.from} onChange={(value) => setAdvancedSearch((current) => ({ ...current, from: value }))} />
              <AdvancedSearchField label={t("mail.searchTo")} value={advancedSearch.to} onChange={(value) => setAdvancedSearch((current) => ({ ...current, to: value }))} />
              <AdvancedSearchField type="date" label={t("mail.searchAfter")} value={advancedSearch.after} onChange={(value) => setAdvancedSearch((current) => ({ ...current, after: value }))} />
              <AdvancedSearchField type="date" label={t("mail.searchBefore")} value={advancedSearch.before} onChange={(value) => setAdvancedSearch((current) => ({ ...current, before: value }))} />
            </div>
            <div className="flex flex-wrap gap-4">
              <label className="inline-flex items-center gap-2 text-sm font-bold text-slate-700"><input type="checkbox" checked={advancedSearch.hasAttachments} onChange={(event) => setAdvancedSearch((current) => ({ ...current, hasAttachments: event.target.checked }))} />{t("mail.searchHasAttachments")}</label>
              <label className="inline-flex items-center gap-2 text-sm font-bold text-slate-700"><input type="checkbox" checked={advancedSearch.unreadOnly} onChange={(event) => setAdvancedSearch((current) => ({ ...current, unreadOnly: event.target.checked }))} />{t("mail.searchUnreadOnly")}</label>
            </div>
            <label className="grid gap-1.5 text-sm font-bold text-slate-700">{t("mail.savedSearchName")}<input value={savedSearchName} onChange={(event) => setSavedSearchName(event.target.value)} className="field h-10" /></label>
            {(createSavedSearch.error as Error | null)?.message ? <p className="text-sm font-semibold text-red-600">{(createSavedSearch.error as Error).message}</p> : null}
            <div className="flex flex-wrap justify-end gap-2">
              <button type="button" onClick={() => { setAdvancedSearch(emptyAdvancedMailSearch); setSavedSearchName(""); }} className="theme-button-soft h-10 px-4">{t("mail.clearAdvancedSearch")}</button>
              <button type="button" onClick={() => void runAdvancedSearch(true)} disabled={!savedSearchName.trim() || !buildAdvancedMailSearchQuery(advancedSearch) || createSavedSearch.isPending} className="theme-button-soft h-10 px-4 disabled:opacity-50"><FilePenLine size={16} />{t("mail.saveAndSearch")}</button>
              <button type="button" onClick={() => void runAdvancedSearch(false)} disabled={!buildAdvancedMailSearchQuery(advancedSearch)} className="theme-button h-10 px-4 disabled:opacity-50"><Search size={16} />{t("mail.search")}</button>
            </div>
          </section>
        </div>
      ) : null}

      {confirmDialog ? (
        <ConfirmDialog
          t={t}
          title={confirmDialog.title}
          message={confirmDialog.message}
          confirmLabel={confirmDialog.confirmLabel}
          tone={confirmDialog.tone}
          busy={deleteFolder.isPending || emptyFolder.isPending || deleteTag.isPending || deleteDriveFile.isPending}
          onClose={() => setConfirmDialog(null)}
          onConfirm={async () => {
            await confirmDialog.onConfirm();
            setConfirmDialog(null);
          }}
        />
      ) : null}

    </div>
  );

  function switchFolder(nextFolder: string) {
    setFolderMenu(null);
    setActiveSection("email");
    setFolder(nextFolder);
    setSelectedFolder(nextFolder);
    setSelectedUid(null);
    setSelectedDetailTarget(null);
    setSelectedThreadUid(null);
    setSelectedThreadDetailTarget(null);
    setSelectedThreadSummary(null);
    setExpandedConversationId("");
    setConversationExpandOnly(false);
    setSelectedKeys([]);
    setLastSelectedIndex(null);
    setSearch("");
    setMobileMailPane("list");
    if (isCompactViewport) setSidebarOpen(false);
    messagesScrollRef.current?.scrollTo({ top: 0, behavior: "auto" });
    if (nextFolder.toUpperCase() === "INBOX") {
      void refreshMailboxView(nextFolder, false);
    }
  }

  function maybeLoadMoreMessages() {
    if (globalSearch || !messages.hasNextPage || messages.isFetchingNextPage || messages.isFetching) return;
    void messages.fetchNextPage();
  }

  function toggleMessageSortOrder() {
    setMessageSortOrder((current) => (current === "newest" ? "oldest" : "newest"));
    setSelectedUid(null);
    setSelectedThreadUid(null);
    setSelectedDetailTarget(null);
    setSelectedThreadDetailTarget(null);
    setSelectedThreadSummary(null);
    setSelectedKeys([]);
    setLastSelectedIndex(null);
    setExpandedConversationId("");
    setConversationExpandOnly(false);
    messagesScrollRef.current?.scrollTo({ top: 0, behavior: "auto" });
  }

  function renderMessageListHeader() {
    const sortText = messageSortOrder === "newest" ? t("mail.newestFirst") : t("mail.oldestFirst");
    const nextSortText = messageSortOrder === "newest" ? t("mail.oldestFirst") : t("mail.newestFirst");
    return (
      <div className="flex items-center justify-between gap-3 border-b border-slate-200 px-3 py-3">
        <span className="min-w-0 truncate text-sm font-black text-slate-600">{t("reader.messagesCount", { count: visibleMessages.length })}</span>
        <button
          type="button"
          onClick={toggleMessageSortOrder}
          className="group inline-flex shrink-0 items-center justify-end gap-1 rounded-lg px-1.5 py-1 text-right text-[11px] font-black text-slate-500 transition hover:bg-slate-100 hover:text-slate-950 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-offset-2"
          aria-label={t("mail.sortMessages", { sort: nextSortText })}
          title={t("mail.sortMessages", { sort: nextSortText })}
        >
          <ArrowDownUp size={12} />
          <span>{sortText}</span>
        </button>
      </div>
    );
  }

  async function applyTagToSelection(items: MailSelectionItem[], tagName: string) {
    const actionable = dedupeSelection(items);
    if (!actionable.length) return;
    await Promise.all(actionable.map((item) => api.updateMessageTags(item.source, item.uid, { add: [tagName] }, messageViewMode)));
    queryClient.invalidateQueries({ queryKey: ["messages"] });
    queryClient.refetchQueries({ queryKey: ["messages"], type: "active" });
    queryClient.invalidateQueries({ queryKey: ["message"] });
    queryClient.invalidateQueries({ queryKey: ["tags"] });
    queryClient.refetchQueries({ queryKey: ["tags"], type: "active" });
  }

  function resolveToolbarTargets() {
    if (activeSelection.length) return activeSelection;
    if (selectedActionTargetUid) {
      return [{ key: `${selectedFolder}:${selectedActionTargetUid}`, uid: selectedActionTargetUid, source: selectedFolder }];
    }
    return [];
  }

  function resolveTagsForItem(item: MailSelectionItem) {
    const detailTags = selectedActionTargetUid && item.uid === selectedActionTargetUid ? selectedActionDetail?.tags : undefined;
    if (detailTags) return detailTags;
    return visibleMessages.find((message) => message.uid === item.uid && (message.folder || item.source) === item.source)?.tags ?? [];
  }

  function resolveToolbarTagView(item: MailSelectionItem): "conversation" | "message" {
    if (!activeSelection.length && selectedActionTargetUid && item.uid === selectedActionTargetUid) {
      if (messageViewMode === "conversation" && selectedDetailTarget?.view === "conversation" && !selectedThreadDetailTarget) {
        return "conversation";
      }
      return "message";
    }
    return messageViewMode;
  }

  async function handleToolbarTagToggle(tagName: string) {
    const targets = resolveToolbarTargets();
    if (!targets.length) return;
    setTagMenuPosition(null);
    await Promise.all(targets.map((item) => {
      const enabled = resolveTagsForItem(item).includes(tagName);
      return updateMessageTags.mutateAsync({
        uid: item.uid,
        source: item.source,
        add: enabled ? [] : [tagName],
        remove: enabled ? [tagName] : [],
        view: resolveToolbarTagView(item),
      });
    }));
  }

  async function handleCreateTagFromToolbar() {
    setTagMenuPosition(null);
    setTagEditor({ mode: "create" });
  }

  async function handleRemoveTagsFromToolbar() {
    const targets = resolveToolbarTargets();
    if (!targets.length) return;
    setTagMenuPosition(null);
    await Promise.all(targets.map((item) => {
      const currentTags = resolveTagsForItem(item);
      return currentTags.length
        ? updateMessageTags.mutateAsync({
            uid: item.uid,
            source: item.source,
            remove: currentTags,
            view: resolveToolbarTagView(item),
          })
        : Promise.resolve();
    }));
  }

  async function handleRenameTag(tag: Tag) {
    setTagMenuPosition(null);
    setTagEditor({ mode: "edit", tag });
  }

  async function handleDeleteTag(tag: Tag) {
    setTagMenuPosition(null);
    setConfirmDialog({
      title: t("dialog.deleteTag"),
      message: t("dialog.deleteTagMessage", { name: tag.name }),
      confirmLabel: t("common.delete"),
      tone: "danger",
      onConfirm: async () => {
        await deleteTag.mutateAsync(tag.id);
      },
    });
  }

  async function handleSaveTagEditor(name: string, color: number) {
    if (tagEditor?.mode === "edit" && tagEditor.tag) {
      const updates: Promise<unknown>[] = [];
      if (name !== tagEditor.tag.name) {
        updates.push(renameTag.mutateAsync({ tagId: tagEditor.tag.id, name }));
      }
      if (color !== tagEditor.tag.color) {
        updates.push(renameTag.mutateAsync({ tagId: tagEditor.tag.id, color }));
      }
      if (updates.length) {
        await Promise.all(updates);
      }
      setTagEditor(null);
      return;
    }
    const result = await api.createTag({ name, color });
    queryClient.setQueryData(["tags"], result);
    queryClient.invalidateQueries({ queryKey: ["tags"] });
    const targets = resolveToolbarTargets();
    if (targets.length) {
      await Promise.all(targets.map((item) => api.updateMessageTags(item.source, item.uid, { add: [name] })));
      queryClient.invalidateQueries({ queryKey: ["messages"] });
      queryClient.refetchQueries({ queryKey: ["messages"], type: "active" });
      queryClient.invalidateQueries({ queryKey: ["message"] });
      queryClient.invalidateQueries({ queryKey: ["tags"] });
      queryClient.refetchQueries({ queryKey: ["tags"], type: "active" });
    }
    setTagEditor(null);
  }

  function handlePrintMessage() {
    const message = currentReaderDetail;
    if (!message) return;
    const frame = document.createElement("iframe");
    frame.style.position = "fixed";
    frame.style.right = "0";
    frame.style.bottom = "0";
    frame.style.width = "0";
    frame.style.height = "0";
    frame.style.border = "0";
    document.body.appendChild(frame);
    const doc = frame.contentWindow?.document;
    if (!doc) {
      frame.remove();
      return;
    }
    doc.open();
    doc.write(renderPrintableMessage(message));
    doc.close();
    frame.onload = () => {
      frame.contentWindow?.focus();
      frame.contentWindow?.print();
      window.setTimeout(() => frame.remove(), 1000);
    };
  }

  function handleMessageSelection(
    event: ReactMouseEvent<HTMLElement>,
    message: MessageSummary,
    options?: { openReader?: boolean }
  ) {
    const key = messageKey(message);
    const currentIndex = visibleMessages.findIndex((item) => messageKey(item) === key);
    const source = message.folder || folder;
    const isConversation = messageViewMode === "conversation" && (message.conversation_count || 1) > 1;
    const detailUid = isConversation ? (message.conversation_id || message.uid) : (message.open_uid || message.uid);
    const detailView = isConversation ? "conversation" : "message";
    const detailQueryKey = ["message", source, detailUid, detailView];

    if (event.shiftKey && lastSelectedIndex !== null) {
      const start = Math.min(lastSelectedIndex, currentIndex);
      const end = Math.max(lastSelectedIndex, currentIndex);
      const rangeKeys = visibleMessages.slice(start, end + 1).map(messageKey);
      setSelectedKeys(rangeKeys);
    } else if (event.ctrlKey || event.metaKey) {
      setSelectedKeys((current) => current.includes(key) ? current.filter((item) => item !== key) : [...current, key]);
      setLastSelectedIndex(currentIndex);
    } else {
      setSelectedKeys([key]);
      setLastSelectedIndex(currentIndex);
    }

    setSelectedUid(message.uid);
    setSelectedFolder(source);
    setSelectedDetailTarget({ folder: source, uid: detailUid, view: detailView });
    setSelectedThreadUid(null);
    setSelectedThreadDetailTarget(null);
    setSelectedThreadSummary(null);
    lastListSelectionKeyRef.current = key;
    setExpandedConversationId((current) => (current === (message.conversation_id || message.uid) ? current : ""));
    setConversationExpandOnly(false);
    if (isCompactViewport && (options?.openReader ?? true)) setMobileMailPane("reader");
    queryClient.removeQueries({ queryKey: detailQueryKey, exact: true });
    void queryClient.prefetchQuery({
      queryKey: detailQueryKey,
      queryFn: () => api.message(source, detailUid, detailView),
    });
    if (!message.seen) {
      markMessageRead(message.uid, source, detailUid, "message");
    }
  }

  function resolveDragSelection(message: MessageSummary) {
    const key = messageKey(message);
    if (selectedKeys.includes(key)) {
      return selectedItems.length ? selectedItems : [messageToSelection(message)];
    }
    return [messageToSelection(message)];
  }

  function openFolderMenu(event: ReactMouseEvent<HTMLElement>, nextFolder: Folder) {
    event.preventDefault();
    event.stopPropagation();
    setFolderMenu({
      folder: nextFolder,
      x: Math.min(event.clientX, window.innerWidth - 220),
      y: Math.min(event.clientY, window.innerHeight - 320),
    });
  }

  async function handleRenameFolder(targetFolder: Folder) {
    setFolderMenu(null);
    if (!canRenameOrDeleteFolder(targetFolder)) return;
    setFolderEditor({ folder: targetFolder });
  }

  async function handleSaveFolderName(name: string) {
    if (!folderEditor) return;
    const nextName = name.trim();
    if (!nextName || nextName === folderEditor.folder.name) {
      setFolderEditor(null);
      return;
    }
    await renameFolder.mutateAsync({ folderId: folderEditor.folder.path, name: nextName });
    setFolderEditor(null);
  }

  async function handleFolderColorChange(targetFolder: Folder, color: number, rgb: string) {
    setFolderMenu(null);
    if (!canChangeFolderColor(targetFolder)) return;
    await updateFolderColor.mutateAsync({ folderId: targetFolder.path, color, rgb });
  }

  async function handleDeleteFolder(targetFolder: Folder) {
    setFolderMenu(null);
    if (!canRenameOrDeleteFolder(targetFolder)) return;
    setConfirmDialog({
      title: t("folder.deleteTitle"),
      message: t("folder.deleteMessage", { name: displayFolder(targetFolder.name) }),
      confirmLabel: t("common.delete"),
      tone: "danger",
      onConfirm: async () => {
        await deleteFolder.mutateAsync(targetFolder.path);
      },
    });
  }

  async function handleEmptyFolder(targetFolder: Folder) {
    setFolderMenu(null);
    if (!canEmptyFolder(targetFolder)) return;
    setConfirmDialog({
      title: t("folder.emptyTitle"),
      message: t("folder.emptyMessage", { name: displayFolder(targetFolder.name) }),
      confirmLabel: t("folder.empty"),
      tone: "danger",
      onConfirm: async () => {
        await emptyFolder.mutateAsync(targetFolder.path);
      },
    });
  }

  function handleShareFolder(targetFolder: Folder) {
    setFolderMenu(null);
    if (!canShareMailFolders || !canRenameOrDeleteFolder(targetFolder)) return;
    setFolderShareEditor({
      folder: targetFolder,
      email: "",
      permissions: "r",
    });
  }

  async function handleShareSubmit(email: string, permissions: string) {
    if (!folderShareEditor) return;
    await shareFolder.mutateAsync({ folderId: folderShareEditor.folder.path, email, permissions });
  }

  async function handleShareRevoke(email: string) {
    if (!folderShareEditor) return;
    await revokeFolderShare.mutateAsync({ folderId: folderShareEditor.folder.path, email });
  }
}

function SidebarButton({ icon, label, count, active, onClick, onDropMessage, onContextMenu, isDropTarget, onDragTargetChange }: { icon: React.ReactNode; label: string; count?: number; active: boolean; onClick: () => void; onDropMessage?: (items: MailSelectionItem[]) => void; onContextMenu?: (event: ReactMouseEvent<HTMLElement>) => void; isDropTarget?: boolean; onDragTargetChange?: (isTarget: boolean) => void }) {
  return (
    <button
      onClick={onClick}
      onContextMenu={onContextMenu}
      onDragOver={(event) => {
        if (!onDropMessage) return;
        event.preventDefault();
        event.dataTransfer.dropEffect = "move";
        onDragTargetChange?.(true);
      }}
      onDragLeave={() => onDragTargetChange?.(false)}
      onDrop={(event) => {
        if (!onDropMessage) return;
        event.preventDefault();
        onDragTargetChange?.(false);
        const items = parseDraggedMessages(event.dataTransfer.getData("message/items"));
        if (items.length && onDropMessage) onDropMessage(items);
      }}
      className={clsx(
        "theme-list-item transition",
        active ? "theme-list-item-active" : "text-slate-600 hover:bg-slate-100",
        isDropTarget && "border-[var(--accent)] bg-[color-mix(in_srgb,var(--accent)_12%,white)] text-slate-950 shadow-sm ring-2 ring-[color-mix(in_srgb,var(--accent)_18%,white)]"
      )}
    >
      {icon}
      <span className="min-w-0 flex-1 truncate">{label}</span>
      {count ? (
        <span className="theme-chip">
          {count}
        </span>
      ) : null}
    </button>
  );
}

function TagActionsMenu({
  t,
  position,
  tags,
  activeTags,
  onToggleTag,
  onCreateTag,
  onRemoveTags,
  onRenameTag,
  onDeleteTag
}: {
  t: ReturnType<typeof createTranslator>;
  position: MenuPosition;
  tags: Tag[];
  activeTags: Set<string>;
  onToggleTag: (tagName: string) => void;
  onCreateTag: () => void;
  onRemoveTags: () => void;
  onRenameTag: (tag: Tag) => void;
  onDeleteTag: (tag: Tag) => void;
}) {
  const menu = (
    <div
      onClick={(event) => event.stopPropagation()}
      className="fixed z-[9999] max-h-[calc(100vh-24px)] min-w-[220px] overflow-auto rounded-xl border border-slate-200 bg-white p-2 shadow-2xl"
      style={{ left: position.left, top: position.top, maxWidth: "min(260px, calc(100vw - 24px))" }}
    >
      <div className="grid gap-1">
        {tags.map((tag) => (
          <div key={tag.id} className={clsx("flex items-center gap-1 rounded-md px-1 py-1", activeTags.has(tag.name) ? "bg-lime-50" : "hover:bg-slate-50")}>
            <button
              type="button"
              onClick={() => onToggleTag(tag.name)}
              className="flex min-w-0 flex-1 items-center gap-3 rounded-md px-2 py-1.5 text-left text-sm font-semibold text-slate-700"
            >
              <TagIcon size={16} style={{ color: tagColorHex(tag) }} />
              <span className="min-w-0 flex-1 truncate">{tag.name}</span>
              {activeTags.has(tag.name) ? <Check size={14} className="text-slate-500" /> : null}
            </button>
            <button type="button" onClick={() => onRenameTag(tag)} className="grid h-8 w-8 place-items-center rounded-md text-slate-400 transition hover:bg-white hover:text-[var(--accent)]" aria-label={t("dialog.renameTagLabel", { name: tag.name })} title={t("dialog.renameTagLabel", { name: tag.name })}>
              <Pencil size={14} />
            </button>
            <button type="button" onClick={() => onDeleteTag(tag)} className="grid h-8 w-8 place-items-center rounded-md text-slate-400 transition hover:bg-white hover:text-red-600" aria-label={t("dialog.deleteTagLabel", { name: tag.name })} title={t("dialog.deleteTagLabel", { name: tag.name })}>
              <Trash2 size={14} />
            </button>
          </div>
        ))}
        {tags.length ? <div className="my-1 border-t border-slate-200" /> : null}
        <button type="button" onClick={onCreateTag} className="flex items-center gap-3 rounded-md px-3 py-2 text-left text-sm font-semibold text-[var(--accent)] transition hover:bg-slate-50">
          <TagIcon size={16} className="text-amber-500" />
          {t("dialog.newTag")}
        </button>
        <button type="button" onClick={onRemoveTags} className="flex items-center gap-3 rounded-md px-3 py-2 text-left text-sm font-semibold text-slate-400 transition hover:bg-slate-50 hover:text-[var(--accent)]">
          <TagIcon size={16} className="text-slate-300" />
          {t("dialog.removeTag")}
        </button>
      </div>
    </div>
  );

  if (typeof document === "undefined") return menu;
  return createPortal(menu, document.body);
}

function OriginalMessageModal({
  t,
  message,
  raw,
  loading,
  errorMessage,
  onRetry,
  onClose
}: {
  t: ReturnType<typeof createTranslator>;
  message: MessageDetail;
  raw: string;
  loading: boolean;
  errorMessage: string;
  onRetry: () => void;
  onClose: () => void;
}) {
  const queryClient = useQueryClient();
  const originalText = looksLikeHtmlDocument(raw) ? buildOriginalMessage(message) : (raw || buildOriginalMessage(message));

  return (
    <div className="fixed inset-0 z-50 grid place-items-center bg-slate-950/35 p-4 backdrop-blur-sm">
      <section className="grid max-h-[88vh] w-full max-w-4xl grid-rows-[auto_minmax(0,1fr)] overflow-hidden rounded-xl border border-slate-700 bg-slate-800 shadow-soft">
        <header className="flex items-center justify-between border-b border-slate-700 bg-slate-800 px-5 py-4">
          <div>
            <p className="text-xs font-black uppercase text-slate-400">{t("mail.showOriginal")}</p>
            <h3 className="text-lg font-black text-slate-50">{cleanSubject(message.subject)}</h3>
          </div>
          <button onClick={onClose} className="icon-button border border-slate-600 bg-slate-700 text-slate-100 hover:bg-slate-600" aria-label={t("reader.closeOriginal")}>
            <X size={18} />
          </button>
        </header>
        <div className="min-h-0 overflow-y-auto bg-slate-850 p-5" style={{ backgroundColor: "#172033" }}>
          {loading ? <p className="font-mono text-xs leading-6 text-emerald-50">{t("reader.loadingOriginal")}</p> : null}
          {!loading && errorMessage ? (
            <div className="grid gap-3">
              <p className="font-mono text-xs leading-6 text-rose-200">{errorMessage}</p>
              <button onClick={onRetry} className="inline-flex h-10 w-fit items-center gap-2 rounded-lg border border-slate-600 bg-slate-700 px-4 text-sm font-bold text-slate-100 hover:bg-slate-600">
                <RefreshCw size={16} />
                {t("reader.retry")}
              </button>
            </div>
          ) : null}
          {!loading && !errorMessage ? <pre className="whitespace-pre-wrap break-words font-mono text-xs leading-6 text-slate-100">{originalText}</pre> : null}
        </div>
      </section>
    </div>
  );
}

function looksLikeHtmlDocument(value: string) {
  const text = (value || "").trim().toLowerCase();
  return text.startsWith("<!doctype html") || text.startsWith("<html") || text.includes("502: bad gateway") || text.includes("cloudflare");
}

function TagEditorModal({
  title,
  t,
  initialName,
  initialColor,
  busy,
  onClose,
  onSave
}: {
  title: string;
  t: ReturnType<typeof createTranslator>;
  initialName: string;
  initialColor: number;
  busy: boolean;
  onClose: () => void;
  onSave: (name: string, color: number) => void;
}) {
  const [name, setName] = useState(initialName);
  const [color, setColor] = useState(initialColor);
  const disabled = !name.trim() || busy;

  return (
    <div className="fixed inset-0 z-[10000] grid place-items-center bg-slate-950/35 p-4 backdrop-blur-sm" onClick={onClose}>
      <form
        className="w-full max-w-md rounded-xl border border-slate-200 bg-white p-5 shadow-soft"
        onClick={(event) => event.stopPropagation()}
        onSubmit={(event) => {
          event.preventDefault();
          if (!disabled) onSave(name.trim(), color);
        }}
      >
        <div className="mb-4 flex items-center justify-between">
          <div>
            <p className="text-xs font-black uppercase text-slate-500">{t("dialog.tags")}</p>
            <h3 className="text-lg font-black">{title}</h3>
          </div>
          <button onClick={onClose} className="icon-button" aria-label={t("dialog.closeTagEditor")}>
            <X size={18} />
          </button>
        </div>
        <div className="grid gap-4">
          <div className="grid gap-2">
            <label className="text-sm font-bold text-slate-600">{t("dialog.name")}</label>
            <input value={name} onChange={(event) => setName(event.target.value)} className="field h-11 w-full" placeholder={t("dialog.tagName")} />
          </div>
          <div className="grid gap-2">
            <label className="text-sm font-bold text-slate-600">{t("dialog.color")}</label>
            <div className="flex flex-wrap gap-2">
              {tagColorOptions.map((option) => (
                <button
                  key={option.value}
                  type="button"
                  onClick={() => setColor(option.value)}
                  className={clsx(
                    "flex h-10 w-10 items-center justify-center rounded-full border-2 transition",
                    color === option.value ? "border-slate-900 scale-105" : "border-slate-200 hover:border-slate-400"
                  )}
                  title={option.label}
                  aria-label={option.label}
                >
                  <span className="h-6 w-6 rounded-full" style={{ backgroundColor: option.hex }} />
                </button>
              ))}
            </div>
          </div>
          <div className="flex justify-end gap-2">
            <button type="button" onClick={onClose} className="h-10 rounded-lg border border-slate-200 bg-white px-4 font-bold text-slate-700">
              {t("common.cancel")}
            </button>
            <button type="submit" disabled={disabled} className="theme-button h-10 px-4 disabled:opacity-50">
              {busy ? t("common.saving") : t("common.save")}
            </button>
          </div>
        </div>
      </form>
    </div>
  );
}

function NameEditorModal({
  title,
  t,
  initialName,
  busy,
  onClose,
  onSave
}: {
  title: string;
  t: ReturnType<typeof createTranslator>;
  initialName: string;
  busy: boolean;
  onClose: () => void;
  onSave: (name: string) => void;
}) {
  const [name, setName] = useState(initialName);
  const disabled = !name.trim() || busy;

  return (
    <div className="fixed inset-0 z-[10000] grid place-items-center bg-slate-950/35 p-4 backdrop-blur-sm" onClick={onClose}>
      <form
        className="w-full max-w-md rounded-xl border border-slate-200 bg-white p-5 shadow-soft"
        onClick={(event) => event.stopPropagation()}
        onSubmit={(event) => {
          event.preventDefault();
          if (!disabled) onSave(name.trim());
        }}
      >
        <div className="mb-4 flex items-center justify-between">
          <div>
            <p className="text-xs font-black uppercase text-slate-500">{t("dialog.folders")}</p>
            <h3 className="text-lg font-black">{title}</h3>
          </div>
          <button onClick={onClose} type="button" className="icon-button" aria-label={t("dialog.closeFolderEditor")}>
            <X size={18} />
          </button>
        </div>
        <div className="grid gap-4">
          <div className="grid gap-2">
            <label className="text-sm font-bold text-slate-600">{t("dialog.name")}</label>
            <input value={name} onChange={(event) => setName(event.target.value)} className="field h-11 w-full" placeholder={t("dialog.folderName")} autoFocus />
          </div>
          <div className="flex justify-end gap-2">
            <button type="button" onClick={onClose} className="h-10 rounded-lg border border-slate-200 bg-white px-4 font-bold text-slate-700">
              {t("common.cancel")}
            </button>
            <button type="submit" disabled={disabled} className="theme-button h-10 px-4 disabled:opacity-50">
              {busy ? t("common.saving") : t("common.save")}
            </button>
          </div>
        </div>
      </form>
    </div>
  );
}

function FolderShareModal({
  folder,
  t,
  contacts,
  busy,
  onClose,
  onShare,
  onRevoke,
}: {
  folder: Folder;
  t: ReturnType<typeof createTranslator>;
  contacts: Contact[];
  busy: boolean;
  onClose: () => void;
  onShare: (email: string, permissions: string) => Promise<void>;
  onRevoke: (email: string) => Promise<void>;
}) {
  const [email, setEmail] = useState("");
  const [permissions, setPermissions] = useState("r");
  const [shareError, setShareError] = useState("");
  const shares = (folder.shared ?? []).filter(hasShareRecipient);
  const effectivePermissions = permissions.trim();

  return (
    <div className="fixed inset-0 z-[10000] grid place-items-center bg-slate-950/35 p-4 backdrop-blur-sm">
      <div className="w-full max-w-lg rounded-xl border border-slate-200 bg-white p-5 shadow-soft">
        <div className="mb-4 flex items-center justify-between gap-4">
          <div className="min-w-0">
            <p className="text-xs font-black uppercase text-slate-500">{t("dialog.folders")}</p>
            <h3 className="truncate text-lg font-black">{t("common.share")} {displayFolder(folder.name)}</h3>
          </div>
          <button onClick={onClose} type="button" className="icon-button" aria-label={t("dialog.closeShare")}>
            <X size={18} />
          </button>
        </div>

        <div className="grid gap-4">
          <form
            className="grid gap-3 rounded-xl border border-slate-200 bg-slate-50 p-4"
            onSubmit={(event) => {
              event.preventDefault();
              const nextEmail = email.trim();
              if (!nextEmail || busy) return;
              setShareError("");
              onShare(nextEmail, effectivePermissions || "r")
                .then(() => {
                  setEmail("");
                  setPermissions("r");
                })
                .catch((error) => {
                setShareError(error instanceof Error ? error.message : t("dialog.shareFailed"));
                });
            }}
          >
            <ShareRecipientAutocomplete value={email} onChange={setEmail} contacts={contacts} label={t("dialog.emailAddress")} autoFocus disabled={busy} />
            <div className="grid gap-2">
              <label className="text-sm font-bold text-slate-600">{t("dialog.permission")}</label>
              <select value={permissions} onChange={(event) => setPermissions(event.target.value)} className="field h-11 w-full">
                <option value="r">{t("dialog.viewer")}</option>
                <option value="rwidx">{t("dialog.manager")}</option>
              </select>
            </div>
            <div className="flex justify-end">
              <button type="submit" disabled={!email.trim() || busy || !effectivePermissions.trim()} className="theme-button h-10 px-4 disabled:opacity-50">
                {busy ? t("common.saving") : t("common.share")}
              </button>
            </div>
            {shareError ? <p className="text-sm font-semibold text-red-600">{shareError}</p> : null}
          </form>

          <div className="grid gap-2">
            <p className="text-sm font-bold text-slate-700">{t("dialog.currentShares")}</p>
            {shares.length ? (
              <div className="grid gap-2">
                {shares.map((share) => (
                  <div key={`${share.email}:${share.permissions}`} className="flex items-center justify-between gap-3 rounded-xl border border-slate-200 px-3 py-2">
                    <div className="min-w-0">
                      <p className="truncate text-sm font-bold text-slate-900">{share.email || share.display_name || t("dialog.sharedAccess")}</p>
                      <span className={clsx("mt-1 inline-flex w-fit items-center rounded-full px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em]", shareStateBadgeClass(share.status || "pending"))}>
                        {shareStatusLabel(share.status || "pending", t)}
                      </span>
                      <span className={clsx("mt-1 ml-1 inline-flex w-fit items-center rounded-full px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em]", shareRoleBadgeClass(share.permissions || "r"))}>
                        {describeSharePermissions(share.permissions || "r")}
                      </span>
                    </div>
                    <button
                      type="button"
                      disabled={busy || !share.email}
                      onClick={() => onRevoke(share.email)}
                      className="rounded-lg border border-slate-200 px-3 py-1.5 text-sm font-bold text-slate-700 transition hover:bg-slate-100 disabled:cursor-not-allowed disabled:opacity-50"
                    >
                      {t("common.revoke")}
                    </button>
                  </div>
                ))}
              </div>
            ) : (
              <p className="text-sm font-semibold text-slate-500">{t("dialog.noSharedUsers")}</p>
            )}
          </div>
        </div>
      </div>
    </div>
  );
}

function ContactFolderShareModal({
  folder,
  t,
  contacts,
  email,
  permissions,
  busy,
  shareError,
  revokeError,
  onEmailChange,
  onPermissionsChange,
  onClose,
  onShare,
  onRevoke,
}: {
  folder: ContactFolder;
  t: ReturnType<typeof createTranslator>;
  contacts: Contact[];
  email: string;
  permissions: string;
  busy: boolean;
  shareError: string;
  revokeError: string;
  onEmailChange: (value: string) => void;
  onPermissionsChange: (value: string) => void;
  onClose: () => void;
  onShare: (email: string, permissions: string) => Promise<void>;
  onRevoke: (email: string) => Promise<void>;
}) {
  const shares = (folder.shared ?? []).filter(hasShareRecipient);
  const effectivePermissions = permissions.trim() || "r";
  const mountedShare = Boolean(folder.share_owner_email || folder.share_owner_id);

  return (
    <div className="fixed inset-0 z-[10000] grid place-items-center bg-slate-950/35 p-4 backdrop-blur-sm">
      <div role="dialog" aria-modal="true" aria-label={t("folder.share")} className="w-full max-w-xl rounded-2xl border border-slate-200 bg-white p-4 shadow-2xl">
        <div className="flex items-start justify-between gap-3">
          <div className="min-w-0">
            <p className="text-xs font-black uppercase tracking-[0.12em] text-slate-400">{t("contacts.folder")}</p>
            <h3 className="mt-1 truncate text-lg font-black text-slate-900">{t("folder.share")}</h3>
            <p className="mt-1 truncate text-sm font-semibold text-slate-500">{displayFolder(folder.name)}</p>
          </div>
          <button type="button" onClick={onClose} className="theme-button-soft h-9 px-3 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-offset-2" aria-label={t("dialog.closeShare")}>
            <X size={14} />
          </button>
        </div>

        {mountedShare ? (
          <div className="mt-4 rounded-xl border border-slate-200 bg-slate-50 px-3 py-3 text-sm font-semibold text-slate-600">
            {folder.share_owner_email || folder.share_owner_id || t("folder.sharedAccess")}
          </div>
        ) : (
          <form
            className="mt-4 grid gap-3"
            onSubmit={(event) => {
              event.preventDefault();
              const nextEmail = email.trim();
              if (!nextEmail || busy) return;
              void onShare(nextEmail, effectivePermissions);
            }}
          >
            <ShareRecipientAutocomplete value={email} onChange={onEmailChange} contacts={contacts} label={t("dialog.emailAddress")} autoFocus disabled={busy} />
            <div className="flex flex-wrap gap-2">
              <select value={permissions} onChange={(event) => onPermissionsChange(event.target.value)} className="field h-11 min-w-[160px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-offset-2" disabled={busy}>
                <option value="r">{t("dialog.viewer")}</option>
                <option value="rwidx">{t("dialog.manager")}</option>
              </select>
              <span className={clsx("inline-flex h-11 items-center rounded-full px-3 text-xs font-black uppercase tracking-[0.08em]", shareRoleBadgeClass(effectivePermissions))}>
                {describeSharePermissions(effectivePermissions)}
              </span>
              <button type="submit" disabled={!email.trim() || busy} className="theme-button h-11 px-4 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-offset-2 disabled:opacity-50">
                <Share2 size={14} />
                {busy ? t("common.sharing") : t("common.share")}
              </button>
            </div>
          </form>
        )}

        <div className="mt-4 grid gap-2">
          <p className="text-sm font-black text-slate-900">{t("dialog.currentShares")}</p>
          {!shares.length ? <p className="rounded-lg bg-slate-50 p-4 text-sm font-semibold text-slate-500">{t("dialog.noSharedUsers")}</p> : null}
          {shares.map((share) => (
            <div key={`${folder.id}:${share.email}:${share.permissions}`} className="flex flex-wrap items-center justify-between gap-2 rounded-xl border border-slate-200 bg-slate-50 px-3 py-3">
              <div className="min-w-0">
                <p className="truncate text-sm font-bold text-slate-900">{share.display_name || share.email || t("dialog.sharedAccess")}</p>
                <div className="mt-1 flex flex-wrap items-center gap-2">
                  <ShareStatusRoleBadges status={share.status || "pending"} permissions={share.permissions || "r"} t={t} />
                  <span className="text-xs font-semibold text-slate-500">{share.email || t("calendar.unknownRecipient")}</span>
                </div>
              </div>
              <button
                type="button"
                className="theme-button-soft h-9 px-3 text-sm text-red-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-300 focus-visible:ring-offset-2 disabled:opacity-50"
                disabled={busy || !share.email}
                onClick={() => void onRevoke(share.email)}
              >
                <Trash2 size={14} />
                {t("common.revoke")}
              </button>
            </div>
          ))}
        </div>
        {shareError ? <p className="mt-3 text-sm font-bold text-red-600">{shareError}</p> : null}
        {revokeError ? <p className="mt-3 text-sm font-bold text-red-600">{revokeError}</p> : null}
      </div>
    </div>
  );
}

function BriefcaseShareModal({
  folderId,
  folderName,
  t,
  contacts,
  busy,
  onClose,
  onShare,
  onRevoke,
}: {
  folderId: string;
  folderName: string;
  t: ReturnType<typeof createTranslator>;
  contacts: Contact[];
  busy: boolean;
  onClose: () => void;
  onShare: (email: string, permissions: string) => Promise<void>;
  onRevoke: (email: string) => Promise<void>;
}) {
  const [email, setEmail] = useState("");
  const [permissions, setPermissions] = useState("r");
  const [shareError, setShareError] = useState("");
  const sharesQuery = useQuery({
    queryKey: ["native-zimbra-briefcase-shares", folderId],
    queryFn: () => api.nativeZimbraBriefcaseShares(folderId),
    enabled: Boolean(folderId),
    staleTime: 30_000,
    refetchOnWindowFocus: false,
  });
  const shares = (sharesQuery.data?.shares ?? []).filter(hasShareRecipient);

  return (
    <div className="fixed inset-0 z-[10000] grid place-items-end bg-slate-950/35 p-3 sm:place-items-center sm:p-4">
      <div role="dialog" aria-modal="true" aria-label={t("dialog.closeBriefcaseShare")} className="max-h-[calc(100dvh-1.5rem)] w-full overflow-y-auto rounded-2xl border border-slate-200 bg-white p-4 shadow-2xl sm:max-h-[calc(100dvh-2rem)] sm:max-w-xl">
        <div className="flex items-start justify-between gap-3">
          <div className="min-w-0">
            <p className="text-xs font-black uppercase tracking-[0.12em] text-slate-400">{t("sharing.briefcase")}</p>
            <h3 className="mt-1 break-words text-lg font-black text-slate-900">{t("common.share")} {folderName || t("dialog.folders")}</h3>
            <p className="mt-1 text-sm font-semibold text-slate-500">{t("dialog.keepBriefcaseAccess")}</p>
          </div>
          <button onClick={onClose} type="button" className="theme-button-soft h-9 px-3 text-sm" aria-label={t("dialog.closeBriefcaseShare")}>
            <X size={14} />
          </button>
        </div>

        <form
          className="mt-4 grid gap-3"
          onSubmit={(event) => {
            event.preventDefault();
            const nextEmail = email.trim();
            if (!nextEmail || busy) return;
            setShareError("");
            onShare(nextEmail, permissions.trim() || "r")
              .then(() => {
                setEmail("");
                setPermissions("r");
              })
              .catch((error) => {
                setShareError(error instanceof Error ? error.message : t("dialog.shareFailed"));
              });
          }}
        >
          <ShareRecipientAutocomplete value={email} onChange={setEmail} contacts={contacts} label={t("dialog.emailAddress")} autoFocus disabled={busy} />
          <div className="grid gap-2 sm:flex sm:flex-wrap">
            <select value={permissions} onChange={(event) => setPermissions(event.target.value)} className="field h-11 w-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-offset-2 sm:w-auto sm:min-w-[160px]">
                <option value="r">{t("dialog.viewer")}</option>
                <option value="rwidx">{t("dialog.manager")}</option>
            </select>
            <span className={clsx("inline-flex h-11 w-full items-center justify-center rounded-full px-3 text-xs font-black uppercase tracking-[0.08em] sm:w-auto", shareRoleBadgeClass(permissions || "r"))}>
              {describeSharePermissions(permissions || "r")}
            </span>
            <button type="submit" disabled={!email.trim() || busy} className="theme-button h-11 w-full px-4 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-offset-2 disabled:opacity-50 sm:w-auto">
              <Share2 size={14} />
              {busy ? t("common.sharing") : t("common.share")}
            </button>
          </div>
          {shareError ? <p className="text-sm font-semibold text-red-600">{shareError}</p> : null}
        </form>

        <div className="mt-4 grid gap-2">
          <div className="flex items-center justify-between gap-3">
            <p className="text-sm font-black text-slate-900">{t("dialog.currentShares")}</p>
            <button type="button" className="text-xs font-bold text-[var(--accent)] disabled:opacity-50" onClick={() => void sharesQuery.refetch()} disabled={sharesQuery.isFetching}>
              {sharesQuery.isFetching ? <RefreshCw size={13} className="mr-1 inline animate-spin" /> : null}
              {t("common.refresh")}
            </button>
          </div>
          {sharesQuery.isLoading ? <p className="rounded-lg bg-slate-50 p-4 text-sm font-semibold text-slate-500">{t("dialog.loadingShares")}</p> : null}
          {sharesQuery.error ? (
            <p className="rounded-lg bg-red-50 p-4 text-sm font-semibold text-red-700">
              {sharesQuery.error instanceof Error ? sharesQuery.error.message : t("dialog.unableLoadShares")}
            </p>
          ) : null}
          {!sharesQuery.isLoading && !sharesQuery.error && !shares.length ? <p className="rounded-lg bg-slate-50 p-4 text-sm font-semibold text-slate-500">{t("dialog.noSharedUsers")}</p> : null}
          {shares.map((share: NativeZimbraShareEntry) => (
            <div key={`${share.email}:${share.permissions}`} className="grid gap-3 rounded-xl border border-slate-200 bg-slate-50 px-3 py-3 sm:flex sm:flex-wrap sm:items-center sm:justify-between sm:gap-2">
              <div className="min-w-0">
                <p className="truncate text-sm font-bold text-slate-900">{share.display_name || share.email || t("dialog.sharedAccess")}</p>
                <div className="mt-1 flex flex-wrap items-center gap-2">
                  <span className={clsx("inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-black uppercase tracking-[0.08em]", shareStateBadgeClass(share.status || "pending"))}>
                    {shareStatusLabel(share.status || "pending", t)}
                  </span>
                  <span className={clsx("inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-black uppercase tracking-[0.08em]", shareRoleBadgeClass(share.permissions || "r"))}>
                    {describeSharePermissions(share.permissions || "r")}
                  </span>
                  <span className="text-xs font-semibold text-slate-500">{share.email || t("sharing.unknownRecipient")}</span>
                </div>
              </div>
              <button
                type="button"
                className="theme-button-soft h-9 w-full px-3 text-sm text-red-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-300 focus-visible:ring-offset-2 sm:w-auto"
                disabled={busy || !share.email}
                onClick={() => void onRevoke(share.email)}
              >
                <Trash2 size={14} />
                {t("common.revoke")}
              </button>
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

function AttachmentSavePickerModal({
  t,
  serviceLabel,
  rootLabel,
  nodes,
  initialFolderId,
  initialFolderName,
  busy,
  title,
  description,
  actionLabelPrefix,
  onClose,
  onSave,
}: {
  t: ReturnType<typeof createTranslator>;
  serviceLabel: string;
  rootLabel: string;
  nodes: Awaited<ReturnType<typeof buildDriveFolderTree>>;
  initialFolderId: string;
  initialFolderName: string;
  busy: boolean;
  title: string;
  description: string;
  actionLabelPrefix: string;
  onClose: () => void;
  onSave: (folderId: string, folderName: string) => void | Promise<void>;
}) {
  const [selectedFolderId, setSelectedFolderId] = useState(initialFolderId);
  const [selectedFolderName, setSelectedFolderName] = useState(initialFolderName);
  const [search, setSearch] = useState("");

  useEffect(() => {
    setSelectedFolderId(initialFolderId);
    setSelectedFolderName(initialFolderName);
  }, [initialFolderId, initialFolderName]);

  const effectiveFolderName = selectedFolderName || rootLabel;

  return (
    <div className="fixed inset-0 z-[10000] grid place-items-center bg-slate-950/35 p-4 backdrop-blur-sm" onClick={onClose}>
      <section className="w-full max-w-2xl rounded-xl border border-slate-200 bg-white p-5 shadow-soft" onClick={(event) => event.stopPropagation()}>
        <div className="mb-4 flex items-center justify-between gap-4">
          <div className="min-w-0">
            <p className="text-xs font-black uppercase text-slate-500">{serviceLabel}</p>
            <h3 className="text-lg font-black">{title}</h3>
            <p className="mt-1 text-sm font-semibold text-slate-500">{description}</p>
          </div>
          <button onClick={onClose} type="button" className="icon-button" aria-label={t("drive.closeSaveDialog")}>
            <X size={18} />
          </button>
        </div>

        <div className="grid gap-4">
          <div className="flex flex-wrap items-center gap-2">
            <button
              type="button"
              onClick={() => {
                setSelectedFolderId("");
                setSelectedFolderName(rootLabel);
              }}
              className={clsx(
                "h-10 rounded-lg border px-4 text-sm font-bold transition",
                !selectedFolderId ? "border-[var(--accent)] bg-[color-mix(in_srgb,var(--accent)_8%,white)] text-[var(--accent)]" : "border-slate-200 bg-white text-slate-700 hover:bg-slate-50"
              )}
            >
              {rootLabel}
            </button>
            <div className="min-w-0 flex-1">
              <input value={search} onChange={(event) => setSearch(event.target.value)} className="field h-10 w-full" placeholder={t("drive.searchFolders", { drive: serviceLabel })} />
            </div>
          </div>

          <div className="max-h-80 overflow-auto rounded-lg border border-slate-200 bg-white p-2">
            <DriveFolderTree
              nodes={nodes}
              selectedId={selectedFolderId}
              onSelect={(folderId, folderName) => {
                setSelectedFolderId(folderId);
                setSelectedFolderName(folderName);
              }}
              query={search.trim().toLowerCase()}
              displayName={(node) => node.name}
              emptyLabel={t("drive.noFoldersFound")}
              expandLabel={t("drive.expandFolder")}
              collapseLabel={t("drive.collapseFolder")}
              selectedLabel={t("drive.selected")}
            />
          </div>

          <p className="text-sm font-semibold text-slate-600">
            {t("drive.selectedFolder")} <span className="font-black text-slate-900">{effectiveFolderName}</span>
          </p>

          <div className="flex justify-end gap-2">
            <button type="button" onClick={onClose} className="h-10 rounded-lg border border-slate-200 bg-white px-4 font-bold text-slate-700">
              {t("common.cancel")}
            </button>
            <button
              type="button"
              disabled={busy}
              onClick={() => void onSave(selectedFolderId, effectiveFolderName)}
              className="theme-button h-10 px-4 disabled:opacity-50"
            >
              {busy ? t("common.working") : `${actionLabelPrefix} ${effectiveFolderName}`}
            </button>
          </div>
        </div>
      </section>
    </div>
  );
}

function ConfirmDialog({
  t,
  title,
  message,
  confirmLabel,
  tone = "default",
  busy,
  onClose,
  onConfirm
}: {
  t: ReturnType<typeof createTranslator>;
  title: string;
  message: string;
  confirmLabel: string;
  tone?: "default" | "danger";
  busy: boolean;
  onClose: () => void;
  onConfirm: () => void | Promise<void>;
}) {
  return (
    <div className="fixed inset-0 z-[10000] grid place-items-center bg-slate-950/35 p-4 backdrop-blur-sm" onClick={onClose}>
      <section className="w-full max-w-md rounded-xl border border-slate-200 bg-white p-5 shadow-soft" onClick={(event) => event.stopPropagation()}>
        <div className="mb-4">
          <p className="text-xs font-black uppercase text-slate-500">{t("dialog.confirm")}</p>
          <h3 className="mt-1 text-lg font-black">{title}</h3>
          <p className="mt-3 text-sm leading-6 text-slate-600">{message}</p>
        </div>
        <div className="flex justify-end gap-2">
          <button type="button" onClick={onClose} className="h-10 rounded-lg border border-slate-200 bg-white px-4 font-bold text-slate-700">
            {t("common.cancel")}
          </button>
          <button
            type="button"
            onClick={() => void onConfirm()}
            disabled={busy}
            className={clsx("h-10 rounded-lg px-4 font-bold text-white disabled:opacity-50", tone === "danger" ? "bg-red-600 hover:bg-red-700" : "theme-button")}
          >
            {busy ? t("common.working") : confirmLabel}
          </button>
        </div>
      </section>
    </div>
  );
}

function SessionExpiryModal({
  t,
  secondsRemaining,
  busy,
  onStaySignedIn,
  onLogoutNow
}: {
  t: ReturnType<typeof createTranslator>;
  secondsRemaining: number;
  busy: boolean;
  onStaySignedIn: () => void;
  onLogoutNow: () => void;
}) {
  const minutes = Math.floor(secondsRemaining / 60);
  const seconds = secondsRemaining % 60;
  const countdown = `${minutes}:${String(seconds).padStart(2, "0")}`;
  return (
    <div className="fixed inset-0 z-[10001] grid place-items-center bg-slate-950/40 p-4 backdrop-blur-sm">
      <section className="w-full max-w-md rounded-xl border border-amber-200 bg-white p-5 shadow-soft">
        <div className="mb-4">
          <p className="text-xs font-black uppercase text-amber-600">{t("session.title")}</p>
          <h3 className="mt-1 text-lg font-black text-slate-950">{t("session.expiringTitle")}</h3>
          <p className="mt-3 text-sm leading-6 text-slate-600">
            {t("session.expiringHelp", { countdown })}
          </p>
        </div>
        <div className="flex justify-end gap-2">
          <button type="button" onClick={onLogoutNow} className="h-10 rounded-lg border border-slate-200 bg-white px-4 font-bold text-slate-700">
            {t("session.logoutNow")}
          </button>
          <button type="button" onClick={onStaySignedIn} disabled={busy} className="theme-button h-10 px-4 disabled:opacity-50">
            {busy ? t("session.refreshing") : t("session.staySignedIn")}
          </button>
        </div>
      </section>
    </div>
  );
}

function ToolbarButton({ icon, label, disabled, onClick }: { icon: React.ReactNode; label: string; disabled?: boolean; onClick?: () => void }) {
  return (
    <button onClick={onClick} disabled={disabled} className="icon-button h-11 w-11" aria-label={label} title={label}>
      {icon}
    </button>
  );
}

function MobileReaderActionButton({
  icon,
  label,
  disabled,
  tone = "default",
  wideOnPortrait = false,
  showLabelOnLandscape = false,
  onClick,
}: {
  icon: ReactNode;
  label: string;
  disabled?: boolean;
  tone?: "default" | "warning" | "danger";
  wideOnPortrait?: boolean;
  showLabelOnLandscape?: boolean;
  onClick?: () => void;
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      disabled={disabled}
      className={clsx(
        "icon-button h-10 shrink-0 disabled:cursor-not-allowed",
        !wideOnPortrait && !showLabelOnLandscape && "w-10",
        wideOnPortrait && "mobile-reader-action-wide-on-portrait",
        showLabelOnLandscape && "mobile-reader-action-labeled-on-landscape",
        tone === "warning" && "border-amber-200 text-amber-700 hover:bg-amber-50",
        tone === "danger" && "border-red-200 text-red-700 hover:bg-red-50"
      )}
      aria-label={label}
      title={label}
    >
      {icon}
      {wideOnPortrait || showLabelOnLandscape ? <span className="mobile-reader-action-label">{label}</span> : null}
    </button>
  );
}

function featureBadge(feature: { locked: boolean; requiredTier?: string }) {
  return feature.locked ? feature.requiredTier || "Pro" : undefined;
}

function FeatureLockBadge({ label, tooltip, compact = false }: { label: string; tooltip?: string; compact?: boolean }) {
  return (
    <span
      title={tooltip}
      className={clsx(
        "inline-flex origin-left scale-[0.58] shrink-0 items-center rounded-full border border-amber-200/40 bg-amber-50/35 px-1 py-[1px] text-[9px] font-extrabold uppercase leading-none text-amber-700/55",
        compact ? "-mr-3" : "-mr-2"
      )}
    >
      {label}
    </span>
  );
}

function SectionTab({ label, active, onClick, disabled = false, badge, tooltip }: { label: string; active: boolean; onClick: () => void; disabled?: boolean; badge?: string; tooltip?: string }) {
  return (
    <button
      type="button"
      onClick={disabled ? undefined : onClick}
      aria-disabled={disabled || undefined}
      title={tooltip}
      aria-label={tooltip ? `${label}. ${tooltip}` : label}
      className={clsx(
        "theme-tab shrink-0 whitespace-nowrap",
        active ? "theme-tab-active" : "theme-tab-inactive",
        disabled && "cursor-not-allowed opacity-65"
      )}
    >
      <span>{label}</span>
      {badge ? <FeatureLockBadge label={badge} tooltip={tooltip} /> : null}
    </button>
  );
}

function BottomNavItem({ icon, label, active, onClick, disabled = false, badge, tooltip }: { icon: ReactNode; label: string; active: boolean; onClick: () => void; disabled?: boolean; badge?: string; tooltip?: string }) {
  return (
    <button
      type="button"
      onClick={disabled ? undefined : onClick}
      aria-disabled={disabled || undefined}
      title={tooltip}
      aria-label={tooltip ? `${label}. ${tooltip}` : label}
      className={clsx(
        "grid min-h-12 min-w-0 flex-1 place-items-center gap-0.5 rounded-lg px-1 py-1.5 text-[11px] font-black transition",
        disabled
          ? "cursor-not-allowed text-slate-300"
          : active
          ? "bg-[color-mix(in_srgb,var(--accent)_10%,white)] text-[var(--accent)]"
          : "text-slate-500 active:bg-slate-100"
      )}
      aria-current={active ? "page" : undefined}
    >
      {icon}
      <span className="flex max-w-full items-center gap-1 truncate">
        <span className="truncate">{label}</span>
        {badge ? <FeatureLockBadge label={badge} tooltip={tooltip} compact /> : null}
      </span>
    </button>
  );
}

function InlinePreferences({
  preferences,
  effectiveThemeName,
  setPreferences,
  onApplyPreferences,
  appVersion,
  buildId,
  buildTime,
  edition,
  tier,
  licenseStatus,
  messageViewMode,
  onMessageViewModeChange,
  contacts,
  contactFolders,
  mailFolders,
  selectedContactFolderId,
  onSelectContactFolder,
  messages,
  calendar,
  defaultSignature,
  signaturesLoading,
  signaturesError,
  signaturesSaving,
  onSaveSignature,
  filterRules,
  setFilterRules,
  filtersLoading,
  filtersError,
  filtersSaving,
  onSaveFilters,
  email,
  sharedFolders,
  sharedFolderHighlightPath,
  sharedFolderHighlightPulse,
  shareNotifications,
  calendarSources,
  taskLists,
  briefcaseFolders,
  briefcaseFoldersLoading,
  showCalendarSharing,
  showTaskSharing,
  showBriefcaseSharing,
  canShareContactFolders,
  contactShareBadge,
  contactShareTooltip,
  activeTab,
  setActiveTab,
  t,
  onCompose
}: {
  preferences: Preferences;
  effectiveThemeName: ThemeName;
  setPreferences: (value: Preferences | ((current: Preferences) => Preferences)) => void;
  onApplyPreferences: (nextPreferences: Preferences, nextMessageViewMode?: "conversation" | "message") => void;
  appVersion: string;
  buildId: string;
  buildTime: string;
  edition: string;
  tier: string;
  licenseStatus?: {
    required: boolean;
    status: string;
    support_upgrade_active: boolean;
    message: string;
  };
  messageViewMode: "conversation" | "message";
  onMessageViewModeChange: (mode: "conversation" | "message") => void;
  contacts: Contact[];
  contactFolders: ContactFolder[];
  mailFolders: Folder[];
  selectedContactFolderId: string;
  onSelectContactFolder: (folderId: string) => void;
  messages: MessageSummary[];
  calendar: CalendarEvent[];
  defaultSignature: MailSignature | null;
  signaturesLoading: boolean;
  signaturesError: string;
  signaturesSaving: boolean;
  onSaveSignature: (payload: { content: string; content_html: string; content_type: string }) => void;
  filterRules: MailFilterRule[];
  setFilterRules: (value: MailFilterRule[] | ((current: MailFilterRule[]) => MailFilterRule[])) => void;
  filtersLoading: boolean;
  filtersError: string;
  filtersSaving: boolean;
  onSaveFilters: (rules: MailFilterRule[]) => Promise<MailFilterRule[]>;
  email: string;
  sharedFolders: Folder[];
  sharedFolderHighlightPath: string;
  sharedFolderHighlightPulse: boolean;
  shareNotifications: ShareNotification[];
  calendarSources: CalendarSource[];
  taskLists: NativeZimbraTaskList[];
  briefcaseFolders: DriveFile[];
  briefcaseFoldersLoading: boolean;
  showCalendarSharing: boolean;
  showTaskSharing: boolean;
  showBriefcaseSharing: boolean;
  canShareContactFolders: boolean;
  contactShareBadge?: string;
  contactShareTooltip?: string;
  activeTab: "preferences" | "information" | "sharing" | "account" | "security" | "signature" | "filters" | "import" | "migration" | "ooo";
  setActiveTab: (tab: "preferences" | "information" | "sharing" | "account" | "security" | "signature" | "filters" | "import" | "migration" | "ooo") => void;
  t: ReturnType<typeof createTranslator>;
  onCompose: (email: string, fullName: string) => void;
}) {
  const queryClient = useQueryClient();
  const accountProfile = useQuery({
    queryKey: ["account-profile", email.trim().toLowerCase()],
    queryFn: api.accountProfile,
    enabled: Boolean(email),
    staleTime: 30_000,
  });
  const [profileDraft, setProfileDraft] = useState({ display_name: "", first_name: "", surname: "" });
  const [profilePhotoFile, setProfilePhotoFile] = useState<File | null>(null);
  const [profilePhotoPreview, setProfilePhotoPreview] = useState("");
  const [removeProfilePhoto, setRemoveProfilePhoto] = useState(false);
  const updateProfile = useMutation({
    mutationFn: api.updateAccountProfile,
  });
  const [profilePhotoBusy, setProfilePhotoBusy] = useState(false);
  const [profileError, setProfileError] = useState("");
  const [password, setPassword] = useState("");
  const outOfOffice = useQuery({
    queryKey: ["out-of-office", email.trim().toLowerCase()],
    queryFn: api.outOfOfficePreferences,
    staleTime: 30_000,
  });
  const [oooEnabled, setOooEnabled] = useState(false);
  const [oooReplyMode, setOooReplyMode] = useState<"off" | "reply">("off");
  const [oooUseTimePeriod, setOooUseTimePeriod] = useState(false);
  const [oooStartDate, setOooStartDate] = useState("");
  const [oooEndDate, setOooEndDate] = useState("");
  const [oooSubject, setOooSubject] = useState("");
  const [oooMessage, setOooMessage] = useState("");
  const oooTimePeriodError =
    oooReplyMode === "reply" && oooUseTimePeriod && (!oooStartDate || !oooEndDate || oooStartDate > oooEndDate)
      ? "Select valid start and end dates."
      : "";
  const saveOutOfOffice = useMutation({
    mutationFn: api.updateOutOfOfficePreferences,
    onSuccess: (data) => {
      setOooEnabled(data.enabled);
      setOooReplyMode(data.reply_mode === "reply" ? "reply" : "off");
      setOooUseTimePeriod(Boolean(data.use_time_period || data.start_date || data.end_date));
      setOooStartDate(data.start_date || "");
      setOooEndDate(data.end_date || "");
      setOooSubject(data.subject || "");
      setOooMessage(data.message || "");
    }
  });
  const [confirmPassword, setConfirmPassword] = useState("");
  const changePassword = useMutation({
    mutationFn: api.changePassword,
    onSuccess: () => {
      setPassword("");
      setConfirmPassword("");
    }
  });
  const passwordError = password ? validatePassword(password, t) : "";
  const passwordMismatch = confirmPassword && password !== confirmPassword ? t("password.mismatch") : "";
  const canSavePassword = Boolean(password && confirmPassword && !passwordError && !passwordMismatch && !changePassword.isPending);

  useEffect(() => {
    if (!accountProfile.data) return;
    setProfileDraft({
      display_name: accountProfile.data.display_name || "",
      first_name: accountProfile.data.first_name || "",
      surname: accountProfile.data.surname || "",
    });
    setProfilePhotoPreview(accountProfile.data.photo_url || "");
    setProfilePhotoFile(null);
    setRemoveProfilePhoto(false);
  }, [accountProfile.data]);

  useEffect(() => {
    if (activeTab !== "account") return;
    void accountProfile.refetch();
  }, [activeTab, email]);

  async function saveProfile() {
    setProfilePhotoBusy(true);
    setProfileError("");
    try {
      const fallbackSurname = email.split("@", 1)[0].trim();
      await updateProfile.mutateAsync({
        ...profileDraft,
        surname: profileDraft.surname.trim() || fallbackSurname,
      });
      if (profilePhotoFile) {
        await api.uploadAccountProfilePhoto(profilePhotoFile);
      } else if (removeProfilePhoto) {
        await api.deleteAccountProfilePhoto();
      }
      await queryClient.invalidateQueries({ queryKey: ["account-profile", email.trim().toLowerCase()] });
      setProfilePhotoFile(null);
      setRemoveProfilePhoto(false);
    } catch (error) {
      setProfileError(error instanceof Error ? error.message : t("profile.saveFailed"));
    } finally {
      setProfilePhotoBusy(false);
    }
  }

  useEffect(() => {
    if (!outOfOffice.data) return;
    setOooEnabled(outOfOffice.data.enabled);
    setOooReplyMode(outOfOffice.data.reply_mode === "reply" ? "reply" : "off");
    setOooUseTimePeriod(Boolean(outOfOffice.data.use_time_period || outOfOffice.data.start_date || outOfOffice.data.end_date));
    setOooStartDate(outOfOffice.data.start_date || "");
    setOooEndDate(outOfOffice.data.end_date || "");
    setOooSubject(outOfOffice.data.subject || "");
    setOooMessage(outOfOffice.data.message || "");
  }, [outOfOffice.data]);
  const acceptedShares = useMemo(
    () => sharedFolders.filter((folder) => Boolean(folder.share_owner_email || folder.share_owner_id)).sort((a, b) => displayFolder(a.name).localeCompare(displayFolder(b.name))),
    [sharedFolders]
  );
  const acceptedContactShares = useMemo(
    () => contactFolders.filter((folder) => Boolean(folder.share_owner_email || folder.share_owner_id)).sort((a, b) => displayFolder(a.name).localeCompare(displayFolder(b.name))),
    [contactFolders]
  );
  const sharedByMeFolders = useMemo(
    () => mailFolders
      .map((folder) => ({
        folder,
        shares: (folder.shared ?? []).filter(hasShareRecipient),
      }))
      .filter((item) => item.shares.length)
      .sort((a, b) => displayFolder(a.folder.name).localeCompare(displayFolder(b.folder.name))),
    [mailFolders]
  );
  const sharedByMeContactFolders = useMemo(
    () => contactFolders
      .map((folder) => ({
        folder,
        shares: (folder.shared ?? []).filter(hasShareRecipient),
      }))
      .filter((item) => item.shares.length && !item.folder.share_owner_email && !item.folder.share_owner_id)
      .sort((a, b) => displayFolder(a.folder.name).localeCompare(displayFolder(b.folder.name))),
    [contactFolders]
  );
  const outgoingCalendarShareResourceIds = useMemo(
    () => showCalendarSharing ? calendarSources.map((calendar) => calendar.id).filter(Boolean).sort() : [],
    [calendarSources, showCalendarSharing]
  );
  const outgoingCalendarShares = useQuery({
    queryKey: ["native-zimbra-calendar-shares", "preferences-outgoing", outgoingCalendarShareResourceIds.join("|")],
    queryFn: async () => {
      const responses = await Promise.all(outgoingCalendarShareResourceIds.map((resourceId) => api.nativeZimbraCalendarShares(resourceId)));
      return responses.flatMap((response) => response.shares ?? []).filter(hasShareRecipient);
    },
    enabled: showCalendarSharing && outgoingCalendarShareResourceIds.length > 0,
    staleTime: 30_000,
    refetchOnWindowFocus: false,
  });
  const sharedByMeCalendarGroups = useMemo(() => {
    const groups = new Map<string, { resource: NativeZimbraShareEntry; shares: NativeZimbraShareEntry[] }>();
    for (const share of outgoingCalendarShares.data ?? []) {
      const key = share.resource_id || share.resource_path || share.resource_name || share.email;
      const current = groups.get(key);
      if (current) {
        current.shares.push(share);
      } else {
        groups.set(key, { resource: share, shares: [share] });
      }
    }
    return Array.from(groups.values()).sort((a, b) => (a.resource.resource_name || t("sharing.calendar")).localeCompare(b.resource.resource_name || t("sharing.calendar")));
  }, [outgoingCalendarShares.data, t]);
  const outgoingTaskShareResourceIds = useMemo(
    () => showTaskSharing ? taskLists.map((list) => list.id).filter(Boolean).sort() : [],
    [showTaskSharing, taskLists]
  );
  const outgoingTaskShares = useQuery({
    queryKey: ["native-zimbra-task-shares", "preferences-outgoing", outgoingTaskShareResourceIds.join("|")],
    queryFn: async () => {
      const responses = await Promise.all(outgoingTaskShareResourceIds.map((resourceId) => api.nativeZimbraTaskShares(resourceId)));
      return responses.flatMap((response) => response.shares ?? []).filter(hasShareRecipient);
    },
    enabled: showTaskSharing && outgoingTaskShareResourceIds.length > 0,
    staleTime: 30_000,
    refetchOnWindowFocus: false,
  });
  const sharedByMeTaskGroups = useMemo(() => {
    const groups = new Map<string, { resource: NativeZimbraShareEntry; shares: NativeZimbraShareEntry[] }>();
    for (const share of outgoingTaskShares.data ?? []) {
      const key = share.resource_id || share.resource_path || share.resource_name || share.email;
      const current = groups.get(key);
      if (current) {
        current.shares.push(share);
      } else {
        groups.set(key, { resource: share, shares: [share] });
      }
    }
    return Array.from(groups.values()).sort((a, b) => (a.resource.resource_name || t("sharing.task")).localeCompare(b.resource.resource_name || t("sharing.task")));
  }, [outgoingTaskShares.data, t]);
  const outgoingBriefcaseShares = useQuery({
    queryKey: ["native-zimbra-briefcase-shares", "preferences-outgoing"],
    queryFn: api.nativeZimbraOutgoingBriefcaseShares,
    enabled: showBriefcaseSharing,
    staleTime: 30_000,
    refetchOnWindowFocus: false,
  });
  const sharedByMeBriefcaseGroups = useMemo(() => {
    const groups = new Map<string, { resource: NativeZimbraShareEntry; shares: NativeZimbraShareEntry[] }>();
    for (const share of outgoingBriefcaseShares.data?.shares ?? []) {
      const key = share.resource_id || share.resource_path || share.resource_name || share.email;
      const current = groups.get(key);
      if (current) {
        current.shares.push(share);
      } else {
        groups.set(key, { resource: share, shares: [share] });
      }
    }
    return Array.from(groups.values()).sort((a, b) => (a.resource.resource_name || t("sharing.briefcase")).localeCompare(b.resource.resource_name || t("sharing.briefcase")));
  }, [outgoingBriefcaseShares.data?.shares, t]);
  const sharedByMeCount = useMemo(
    () =>
      sharedByMeFolders.reduce((total, item) => total + item.shares.length, 0) +
      sharedByMeContactFolders.reduce((total, item) => total + item.shares.length, 0) +
      sharedByMeCalendarGroups.reduce((total, item) => total + item.shares.length, 0) +
      sharedByMeTaskGroups.reduce((total, item) => total + item.shares.length, 0) +
      sharedByMeBriefcaseGroups.reduce((total, item) => total + item.shares.length, 0),
    [sharedByMeBriefcaseGroups, sharedByMeCalendarGroups, sharedByMeContactFolders, sharedByMeFolders, sharedByMeTaskGroups]
  );
  const activeShareNotifications = useMemo(
    () => shareNotifications.filter((item) => (item.status || "").trim().toLowerCase() !== "revoked"),
    [shareNotifications]
  );
  const emailShareNotifications = useMemo(
    () => activeShareNotifications.filter((item) => isEmailShareNotification(item)),
    [activeShareNotifications]
  );
  const contactShareNotifications = useMemo(
    () => activeShareNotifications.filter((item) => isContactShareNotification(item)),
    [activeShareNotifications]
  );
  const calendarShareNotifications = useMemo(
    () => activeShareNotifications.filter((item) => isCalendarShareNotification(item)),
    [activeShareNotifications]
  );
  const taskShareNotifications = useMemo(
    () => activeShareNotifications.filter((item) => isTaskShareNotification(item)),
    [activeShareNotifications]
  );
  const briefcaseShareNotifications = useMemo(
    () => activeShareNotifications.filter((item) => isBriefcaseShareNotification(item)),
    [activeShareNotifications]
  );
  const visibleShareNotifications = useMemo(
    () => shareNotifications.filter((item) => (
      isEmailShareNotification(item) ||
      isContactShareNotification(item) ||
      (showCalendarSharing && isCalendarShareNotification(item)) ||
      (showTaskSharing && isTaskShareNotification(item)) ||
      (showBriefcaseSharing && isBriefcaseShareNotification(item))
    )),
    [shareNotifications, showCalendarSharing, showTaskSharing, showBriefcaseSharing]
  );
  const pendingShareNotifications = useMemo(
    () => visibleShareNotifications.filter((item) =>
      isPendingShareNotification(item) &&
      !isMountedShareNotification(item, acceptedShares, acceptedContactShares, calendarSources, taskLists, briefcaseFolders)
    ),
    [visibleShareNotifications, acceptedContactShares, acceptedShares, calendarSources, taskLists, briefcaseFolders]
  );
  const pendingEmailShareNotifications = useMemo(
    () => emailShareNotifications.filter((item) =>
      isPendingShareNotification(item) &&
      !findSharedFolderForNotification(acceptedShares, item)
    ),
    [emailShareNotifications, acceptedShares]
  );
  const pendingContactShareNotifications = useMemo(
    () => contactShareNotifications.filter((item) =>
      isPendingShareNotification(item) &&
      !findContactFolderForShareNotification(acceptedContactShares, item)
    ),
    [contactShareNotifications, acceptedContactShares]
  );
  const pendingBriefcaseShareNotifications = useMemo(
    () => briefcaseShareNotifications.filter((item) =>
      isPendingShareNotification(item) &&
      !findDriveFolderForShareNotification(briefcaseFolders, item)
    ),
    [briefcaseShareNotifications, briefcaseFolders]
  );
  const mountedCalendarShares = useMemo(
    () => calendarSources.filter(isMountedCalendarSource),
    [calendarSources]
  );
  const pendingCalendarShareNotifications = useMemo(
    () => calendarShareNotifications.filter((item) =>
      isPendingShareNotification(item) &&
      !findCalendarForShareNotification(calendarSources, item)
    ),
    [calendarShareNotifications, calendarSources]
  );
  const mountedTaskShares = useMemo(
    () => taskLists.filter(isMountedTaskList),
    [taskLists]
  );
  const pendingTaskShareNotifications = useMemo(
    () => taskShareNotifications.filter((item) =>
      isPendingShareNotification(item) &&
      !findTaskListForShareNotification(taskLists, item)
    ),
    [taskShareNotifications, taskLists]
  );
  const acceptedReceivedShares = useMemo(
    () => [
      ...acceptedShares.map((folder) => ({
        key: `mail:${folder.path}:${folder.share_owner_email || folder.share_owner_id}`,
        kind: "mail" as const,
        type: t("sharing.email"),
        name: displayFolder(folder.name),
        path: folder.abs_path || folder.path,
        owner: folder.share_owner_email || folder.share_owner_id || t("sharing.unknown"),
        permissions: folder.permissions || "r",
        highlightPath: folder.path,
        description: folder.flags.includes("f") ? t("sharing.mountedShare") : t("sharing.sharedFolderType"),
      })),
      ...acceptedContactShares.map((folder) => ({
        key: `contact:${folder.id}:${folder.share_owner_email || folder.share_owner_id}`,
        kind: "contact" as const,
        type: t("settings.contact"),
        name: displayFolder(folder.name),
        path: folder.abs_path || folder.id,
        owner: folder.share_owner_email || folder.share_owner_id || t("sharing.unknown"),
        permissions: folder.permissions || "r",
        highlightPath: "",
        description: t("sharing.mountedShare"),
      })),
      ...mountedCalendarShares.map((calendar) => ({
        key: `calendar:${calendar.id}:${calendar.share_owner_email || calendar.share_owner_id || calendar.remote_id}`,
        kind: "calendar" as const,
        type: t("sharing.calendar"),
        name: calendar.summary || t("sharing.calendar"),
        path: t("sharing.calendar"),
        owner: calendar.share_owner_email || calendar.share_owner_id || t("sharing.unknown"),
        permissions: calendar.permissions || "r",
        highlightPath: "",
        description: t("sharing.mountedShare"),
      })),
      ...mountedTaskShares.map((list) => ({
        key: `task:${list.id}:${list.share_owner_email || list.share_owner_id || list.remote_id}`,
        kind: "task" as const,
        type: t("sharing.task"),
        name: list.name || t("sharing.task"),
        path: displayMountedTaskSharePath(list),
        owner: list.share_owner_email || list.share_owner_id || t("sharing.unknown"),
        permissions: list.permissions || "r",
        highlightPath: "",
        description: t("sharing.mountedShare"),
      })),
      ...briefcaseFolders.map((folder) => ({
        key: `briefcase:${folder.id}:${folder.share_owner_email || folder.share_owner_id}`,
        kind: "briefcase" as const,
        type: t("sharing.briefcase"),
        name: folder.name || t("sharing.briefcase"),
        path: t("sharing.briefcase"),
        owner: folder.share_owner_email || folder.share_owner_id || t("sharing.unknown"),
        permissions: folder.permissions || "r",
        highlightPath: "",
        description: t("sharing.mountedShare"),
      })),
    ],
    [acceptedContactShares, acceptedShares, mountedCalendarShares, mountedTaskShares, briefcaseFolders, t]
  );
  const revokedShareNotifications = useMemo(
    () => visibleShareNotifications.filter((item) => (item.status || "").trim().toLowerCase() === "revoked"),
    [visibleShareNotifications]
  );

  return (
    <div className="grid gap-4 lg:grid-cols-[220px_1fr] lg:items-start lg:gap-5">
      <nav className="flex gap-2 overflow-x-auto rounded-lg border border-slate-200 bg-slate-50 p-2 lg:sticky lg:top-5 lg:grid lg:max-h-[calc(100vh-2.5rem)] lg:self-start lg:gap-0 lg:overflow-y-auto lg:p-3">
        <SettingsTab active={activeTab === "preferences"} icon={<Palette size={17} />} label={t("settings.appearance")} onClick={() => setActiveTab("preferences")} />
        <SettingsTab active={activeTab === "account"} icon={<UserRound size={17} />} label={t("settings.account")} onClick={() => setActiveTab("account")} />
        <SettingsTab active={activeTab === "security"} icon={<ShieldCheck size={17} />} label={t("settings.security")} onClick={() => setActiveTab("security")} />
        <SettingsTab active={activeTab === "signature"} icon={<FilePenLine size={17} />} label={t("settings.signature")} onClick={() => setActiveTab("signature")} />
        <SettingsTab active={activeTab === "ooo"} icon={<Clock3 size={17} />} label={t("settings.outOfOffice")} onClick={() => setActiveTab("ooo")} />
        <SettingsTab active={activeTab === "filters"} icon={<SlidersHorizontal size={17} />} label={t("settings.filters")} onClick={() => setActiveTab("filters")} />
        <SettingsTab active={activeTab === "sharing"} icon={<Share2 size={17} />} label={t("settings.sharing")} onClick={() => setActiveTab("sharing")} />
        <SettingsTab active={activeTab === "import"} icon={<Upload size={17} />} label={t("settings.importExport")} onClick={() => setActiveTab("import")} />
        <SettingsTab active={activeTab === "migration"} icon={<RefreshCw size={17} />} label={t("settings.migration")} onClick={() => setActiveTab("migration")} />
        <SettingsTab active={activeTab === "information"} icon={<FileText size={17} />} label={t("settings.information")} onClick={() => setActiveTab("information")} />
      </nav>

      <div className="min-w-0">
        {activeTab === "preferences" ? (
          <div className="grid gap-6">
            <section className="grid gap-3">
              <h3 className="font-black">{t("preferences.language")}</h3>
              <div className="grid gap-2 rounded-lg border border-slate-200 p-4">
                <label className="flex items-center gap-2 text-sm font-bold text-slate-500">
                  <Languages size={16} />
                  {t("preferences.languageLabel")}
                </label>
                <select
                  value={normalizeLocale(preferences.locale)}
                  onChange={(event) => onApplyPreferences({ ...preferences, locale: normalizeLocale(event.target.value) })}
                  className="field h-11 w-full"
                >
                  {localeOptions.map((option) => (
                    <option key={option.value} value={option.value}>
                      {option.nativeLabel} - {option.label}
                    </option>
                  ))}
                </select>
                <p className="text-xs font-semibold text-slate-500">{t("preferences.languageHelp")}</p>
              </div>
            </section>

            <section className="grid gap-3">
              <h3 className="font-black">{t("preferences.theme")}</h3>
              <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
                {themeOrder.map((name) => (
                  <button
                    key={name}
                    onClick={() => onApplyPreferences({ ...preferences, theme: name })}
                    className={clsx(
                      "grid gap-3 rounded-xl border p-3 text-left transition",
                      effectiveThemeName === name
                        ? "border-[var(--accent)] bg-[color-mix(in_srgb,var(--accent)_8%,white)] text-slate-950 shadow-sm"
                        : "border-slate-200 bg-white hover:border-[var(--accent)] hover:bg-[color-mix(in_srgb,var(--accent)_4%,white)]"
                    )}
                  >
                    <span className={clsx("block h-9 rounded-lg", themes[name].preview)} />
                    <span className="grid gap-1">
                      <span className="font-black">{themes[name].name}</span>
                      <span className="text-xs font-medium leading-5 text-slate-500">{themes[name].description}</span>
                    </span>
                  </button>
                ))}
              </div>
            </section>

            <section className="grid gap-3">
              <h3 className="font-black">{t("preferences.messageView")}</h3>
              <div className="grid gap-2 rounded-lg border border-slate-200 bg-slate-50 p-4">
                <label className="text-sm font-bold text-slate-500">{t("preferences.defaultMessageListMode")}</label>
                <div className="inline-flex w-fit rounded-lg border border-slate-200 bg-white p-1">
                  {(["conversation", "message"] as const).map((mode) => (
                    <button
                      key={mode}
                      type="button"
                      onClick={() => onMessageViewModeChange(mode)}
                      className={clsx(
                        "h-9 rounded-md px-4 text-sm font-bold capitalize transition",
                        messageViewMode === mode ? "bg-[var(--accent)] text-white shadow-sm" : "text-slate-500 hover:bg-slate-100 hover:text-slate-900"
                      )}
                    >
                      {mode === "conversation" ? t("messageMode.conversation") : t("messageMode.message")}
                    </button>
                  ))}
                </div>
                <p className="text-xs font-semibold text-slate-500">{t("preferences.messageViewHelp")}</p>
              </div>
            </section>

            <section className="grid gap-3">
              <h3 className="font-black">{t("preferences.fontSize")}</h3>
              <div className="grid grid-cols-3 rounded-lg border border-slate-200 bg-slate-50 p-1 sm:inline-flex sm:w-fit">
                {(["compact", "comfortable", "large"] as FontScale[]).map((scale) => (
                  <button key={scale} onClick={() => onApplyPreferences({ ...preferences, fontScale: scale })} className={clsx("h-9 rounded-md px-4 font-bold", preferences.fontScale === scale ? "bg-white shadow-sm" : "text-slate-500")}>{t(`fontScale.${scale}`)}</button>
                ))}
              </div>
            </section>

            <section className="grid gap-3">
              <h3 className="font-black">{t("preferences.timeZone")}</h3>
              <div className="grid gap-2 rounded-lg border border-slate-200 p-4">
                <label className="text-sm font-bold text-slate-500">{t("preferences.calendarTimeZone")}</label>
                <select
                  value={normalizeTimeZone(preferences.timeZone)}
                  onChange={(event) => onApplyPreferences({ ...preferences, timeZone: normalizeTimeZone(event.target.value) })}
                  className="field h-11 w-full"
                >
                  {timeZoneOptions.map((option) => (
                    <option key={option.value} value={option.value}>
                      {option.label}
                    </option>
                  ))}
                </select>
                <p className="text-xs font-semibold text-slate-500">{t("preferences.timeZoneHelp")}</p>
              </div>
            </section>

          </div>
        ) : null}
        {activeTab === "information" ? (
          <div className="grid gap-6">
            {licenseStatus?.required && licenseStatus.status === "active" && licenseStatus.support_upgrade_active === false ? (
              <section className="grid gap-3">
                <h3 className="font-black">{t("license.productStatus")}</h3>
                <div className="flex items-start gap-3 rounded-xl border border-amber-200 bg-amber-50 px-4 py-3 text-sm font-semibold leading-6 text-amber-800">
                  <AlertTriangle className="mt-0.5 shrink-0" size={17} />
                  <div className="min-w-0">
                    <p className="font-black">{t("license.supportPlan")}</p>
                    <p className="mt-0.5">{licenseStatus.message || t("license.supportExpired")}</p>
                  </div>
                </div>
              </section>
            ) : null}
            <section className="grid gap-3">
              <h3 className="font-black">{t("info.software")}</h3>
              <div className="grid gap-1 rounded-lg border border-slate-200 bg-slate-50 p-4">
                <p className="text-sm font-semibold text-slate-700">{t("info.appVersion", { version: appVersion })}</p>
                <p className="text-sm font-semibold text-slate-700">{t("info.buildId", { buildId: buildId || t("info.unknown") })}</p>
                <p className="text-sm font-semibold text-slate-700">{t("info.deployedAt", { time: formatBuildTime(buildTime) })}</p>
                <p className="text-sm font-semibold text-slate-700">{t("info.edition", { edition: formatProductTierLabel(tier, edition, t) })}</p>
                <p className="text-xs font-semibold text-slate-500">{t("info.deployHelp")}</p>
              </div>
            </section>
          </div>
        ) : null}
        {activeTab === "sharing" ? (
          <div className="grid gap-4">
            <section className="grid gap-3">
              <h3 className="font-black">{t("sharing.sharedWithMe")}</h3>
              <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-5">
                <SharingSummaryCard
                  title={t("sharing.email")}
                  icon={<MailOpen size={17} />}
                  count={acceptedShares.length + pendingEmailShareNotifications.length}
                  detail={t("sharing.mountedInvites", { mounted: acceptedShares.length, invites: pendingEmailShareNotifications.length })}
                />
                <SharingSummaryCard
                  title={t("settings.contact")}
                  icon={<UserPlus size={17} />}
                  count={acceptedContactShares.length + pendingContactShareNotifications.length}
                  detail={t("sharing.mountedInvites", { mounted: acceptedContactShares.length, invites: pendingContactShareNotifications.length })}
                />
                {showCalendarSharing ? (
                  <SharingSummaryCard
                    title={t("sharing.calendar")}
                    icon={<CalendarDays size={17} />}
                    count={mountedCalendarShares.length + pendingCalendarShareNotifications.length}
                    detail={shareNotificationSummary(mountedCalendarShares.length, pendingCalendarShareNotifications.length)}
                  />
                ) : null}
                {showTaskSharing ? (
                  <SharingSummaryCard
                    title={t("sharing.task")}
                    icon={<ListTodo size={17} />}
                    count={mountedTaskShares.length + pendingTaskShareNotifications.length}
                    detail={shareNotificationSummary(mountedTaskShares.length, pendingTaskShareNotifications.length)}
                  />
                ) : null}
                {showBriefcaseSharing ? (
                  <SharingSummaryCard
                    title={t("sharing.briefcase")}
                    icon={<FolderIcon size={17} />}
                    count={briefcaseFolders.length + pendingBriefcaseShareNotifications.length}
                    detail={briefcaseFoldersLoading ? t("drive.loadingFolders") : t("sharing.mountedInvites", { mounted: briefcaseFolders.length, invites: pendingBriefcaseShareNotifications.length })}
                  />
                ) : null}
              </div>
            </section>
            <section className="grid gap-3">
              <h3 className="font-black">{t("sharing.sharedByMe")}</h3>
              <div className="rounded-lg border border-slate-200 bg-slate-50 p-4">
                <p className="text-sm font-semibold text-slate-600">
                  {t("sharing.sharedByMeHelp", { count: sharedByMeCount })}
                </p>
                <div className="mt-4 grid gap-2">
                  {sharedByMeFolders.length || sharedByMeContactFolders.length || sharedByMeCalendarGroups.length || sharedByMeTaskGroups.length || sharedByMeBriefcaseGroups.length ? (
                    <>
                    {sharedByMeFolders.map(({ folder, shares }) => (
                      <div key={folder.path || folder.name} className="grid gap-2 rounded-xl border border-slate-200 bg-white px-3 py-2">
                        <div className="flex items-start justify-between gap-3">
                          <div className="flex min-w-0 items-start gap-2">
                            <ShareResourceIcon kind="mail" />
                            <div className="min-w-0">
                              <p className="truncate text-sm font-bold text-slate-900">{displayFolder(folder.name)}</p>
                              <p className="truncate text-xs font-semibold text-slate-500">{folder.abs_path || folder.path || t("sharing.sharedFolder")}</p>
                            </div>
                          </div>
                          <span className="inline-flex shrink-0 items-center rounded-full border border-slate-200 bg-slate-50 px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em] text-slate-600">
                            {t("sharing.recipientCount", { count: shares.length })}
                          </span>
                        </div>
                        <div className="grid gap-1">
                          {shares.map((share) => (
                            <div key={`${folder.path}:${share.email}:${share.permissions}`} className="flex items-center justify-between gap-3 rounded-lg bg-slate-50 px-2.5 py-2">
                              <p className="min-w-0 truncate text-sm font-semibold text-slate-700">{share.display_name || share.email}</p>
                              <ShareStatusRoleBadges status={share.status || "pending"} permissions={share.permissions || "r"} t={t} />
                            </div>
                          ))}
                        </div>
                      </div>
                    ))}
                    {sharedByMeContactFolders.map(({ folder, shares }) => (
                      <div key={`contact:${folder.id || folder.name}`} className="grid gap-2 rounded-xl border border-slate-200 bg-white px-3 py-2">
                        <div className="flex items-start justify-between gap-3">
                          <div className="flex min-w-0 items-start gap-2">
                            <ShareResourceIcon kind="contact" />
                            <div className="min-w-0">
                              <p className="truncate text-sm font-bold text-slate-900">{displayFolder(folder.name)}</p>
                              <p className="truncate text-xs font-semibold text-slate-500">{folder.abs_path || folder.id || t("settings.contact")}</p>
                            </div>
                          </div>
                          <span className="inline-flex shrink-0 items-center rounded-full border border-slate-200 bg-slate-50 px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em] text-slate-600">
                            {t("sharing.recipientCount", { count: shares.length })}
                          </span>
                        </div>
                        <div className="grid gap-1">
                          {shares.map((share) => (
                            <div key={`${folder.id}:${share.email}:${share.permissions}`} className="flex items-center justify-between gap-3 rounded-lg bg-slate-50 px-2.5 py-2">
                              <p className="min-w-0 truncate text-sm font-semibold text-slate-700">{share.display_name || share.email}</p>
                              <ShareStatusRoleBadges status={share.status || "pending"} permissions={share.permissions || "r"} t={t} />
                            </div>
                          ))}
                        </div>
                      </div>
                    ))}
                    {sharedByMeCalendarGroups.map(({ resource, shares }) => (
                      <div key={`calendar:${resource.resource_id || resource.resource_name}`} className="grid gap-2 rounded-xl border border-slate-200 bg-white px-3 py-2">
                        <div className="flex items-start justify-between gap-3">
                          <div className="flex min-w-0 items-start gap-2">
                            <ShareResourceIcon kind="calendar" />
                            <div className="min-w-0">
                              <p className="truncate text-sm font-bold text-slate-900">{resource.resource_name || t("sharing.calendar")}</p>
                              <p className="truncate text-xs font-semibold text-slate-500">{resource.resource_path || t("sharing.calendar")}</p>
                            </div>
                          </div>
                          <span className="inline-flex shrink-0 items-center rounded-full border border-slate-200 bg-slate-50 px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em] text-slate-600">
                            {t("sharing.recipientCount", { count: shares.length })}
                          </span>
                        </div>
                        <div className="grid gap-1">
                          {shares.map((share) => (
                            <div key={`${resource.resource_id}:${share.email}:${share.permissions}`} className="flex items-center justify-between gap-3 rounded-lg bg-slate-50 px-2.5 py-2">
                              <p className="min-w-0 truncate text-sm font-semibold text-slate-700">{share.display_name || share.email}</p>
                              <ShareStatusRoleBadges status={share.status || "pending"} permissions={share.permissions || "r"} t={t} />
                            </div>
                          ))}
                        </div>
                      </div>
                    ))}
                    {sharedByMeTaskGroups.map(({ resource, shares }) => (
                      <div key={`task:${resource.resource_id || resource.resource_name}`} className="grid gap-2 rounded-xl border border-slate-200 bg-white px-3 py-2">
                        <div className="flex items-start justify-between gap-3">
                          <div className="flex min-w-0 items-start gap-2">
                            <ShareResourceIcon kind="task" />
                            <div className="min-w-0">
                              <p className="truncate text-sm font-bold text-slate-900">{resource.resource_name || t("sharing.task")}</p>
                              <p className="truncate text-xs font-semibold text-slate-500">{resource.resource_path || t("sharing.task")}</p>
                            </div>
                          </div>
                          <span className="inline-flex shrink-0 items-center rounded-full border border-slate-200 bg-slate-50 px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em] text-slate-600">
                            {t("sharing.recipientCount", { count: shares.length })}
                          </span>
                        </div>
                        <div className="grid gap-1">
                          {shares.map((share) => (
                            <div key={`${resource.resource_id}:${share.email}:${share.permissions}`} className="flex items-center justify-between gap-3 rounded-lg bg-slate-50 px-2.5 py-2">
                              <p className="min-w-0 truncate text-sm font-semibold text-slate-700">{share.display_name || share.email}</p>
                              <ShareStatusRoleBadges status={share.status || "pending"} permissions={share.permissions || "r"} t={t} />
                            </div>
                          ))}
                        </div>
                      </div>
                    ))}
                    {sharedByMeBriefcaseGroups.map(({ resource, shares }) => (
                      <div key={`briefcase:${resource.resource_id || resource.resource_name}`} className="grid gap-2 rounded-xl border border-slate-200 bg-white px-3 py-2">
                        <div className="flex items-start justify-between gap-3">
                          <div className="flex min-w-0 items-start gap-2">
                            <ShareResourceIcon kind="briefcase" />
                            <div className="min-w-0">
                              <p className="truncate text-sm font-bold text-slate-900">{resource.resource_name || t("sharing.briefcase")}</p>
                              <p className="truncate text-xs font-semibold text-slate-500">{resource.resource_path || t("sharing.briefcase")}</p>
                            </div>
                          </div>
                          <span className="inline-flex shrink-0 items-center rounded-full border border-slate-200 bg-slate-50 px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em] text-slate-600">
                            {t("sharing.recipientCount", { count: shares.length })}
                          </span>
                        </div>
                        <div className="grid gap-1">
                          {shares.map((share) => (
                            <div key={`${resource.resource_id}:${share.email}:${share.permissions}`} className="flex items-center justify-between gap-3 rounded-lg bg-slate-50 px-2.5 py-2">
                              <p className="min-w-0 truncate text-sm font-semibold text-slate-700">{share.display_name || share.email}</p>
                              <ShareStatusRoleBadges status={share.status || "pending"} permissions={share.permissions || "r"} t={t} />
                            </div>
                          ))}
                        </div>
                      </div>
                    ))}
                    </>
                  ) : (
                    <p className="text-sm font-semibold text-slate-400">{outgoingCalendarShares.isLoading || outgoingTaskShares.isLoading || outgoingBriefcaseShares.isLoading ? t("dialog.loadingShares") : t("sharing.noSharedByMe")}</p>
                  )}
                </div>
              </div>
            </section>
            <section className="grid gap-3">
              <h3 className="font-black">{t("sharing.pendingInvitations")}</h3>
              <div className="rounded-lg border border-slate-200 bg-slate-50 p-4">
                <p className="text-sm font-semibold text-slate-600">
                  {t("sharing.pendingHelp")}
                </p>
                <div className="mt-4 grid gap-2">
                  {pendingShareNotifications.length ? (
                    pendingShareNotifications.map((item) => {
                      const kind = shareNotificationKind(item);
                      return (
                      <div key={item.id} className="grid gap-1 rounded-xl border border-slate-200 bg-white px-3 py-2 transition-all duration-700 ease-out">
                        <div className="flex items-start justify-between gap-3">
                          <div className="flex min-w-0 items-start gap-2">
                            <ShareResourceIcon kind={kind} />
                            <div className="min-w-0">
                              <p className="truncate text-sm font-bold text-slate-900">{item.item_name || t("sharing.sharedFolder")}</p>
                              <p className="truncate text-xs font-semibold text-slate-500">
                                {shareResourceLabel(kind, t)} - {t("sharing.from", { sender: item.grantor_email || item.grantor_name || item.grantor_id || t("sharing.unknown") })}
                              </p>
                            </div>
                          </div>
                          <div className="flex items-center gap-1.5">
                            <span className={clsx("inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em]", shareStateBadgeClass(item.status || "pending"))}>
                              {item.status || "pending"}
                            </span>
                            <span className={clsx("inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em]", shareRoleBadgeClass(item.item_perm || "r"))}>
                              {describeSharePermissions(item.item_perm || "r")}
                            </span>
                          </div>
                        </div>
                        <p className="text-xs font-semibold text-slate-500">{t("sharing.openInvite")}</p>
                      </div>
                      );
                    })
                  ) : (
                    <p className="text-sm font-semibold text-slate-400">{t("sharing.noPending")}</p>
                  )}
                </div>
              </div>
            </section>
            {revokedShareNotifications.length ? (
              <section className="grid gap-3">
                <h3 className="font-black">{t("sharing.history")}</h3>
                <div className="rounded-lg border border-slate-200 bg-slate-50 p-4">
                  <p className="text-sm font-semibold text-slate-600">{t("sharing.historyHelp")}</p>
                  <div className="mt-4 grid gap-2">
                    {revokedShareNotifications.map((item) => {
                      const kind = shareNotificationKind(item);
                      return (
                      <div key={item.id} className="grid gap-1 rounded-xl border border-rose-200 bg-rose-50 px-3 py-2">
                        <div className="flex items-start justify-between gap-3">
                          <div className="flex min-w-0 items-start gap-2">
                            <ShareResourceIcon kind={kind} tone="danger" />
                            <div className="min-w-0">
                              <p className="truncate text-sm font-bold text-rose-950">{item.item_name || t("sharing.sharedFolder")}</p>
                              <p className="truncate text-xs font-semibold text-rose-800">
                                {shareResourceLabel(kind, t)} - {t("sharing.from", { sender: item.grantor_email || item.grantor_name || item.grantor_id || t("sharing.unknown") })}
                              </p>
                            </div>
                          </div>
                          <div className="flex items-center gap-1.5">
                            <span className={clsx("inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em]", shareStateBadgeClass("revoked"))}>
                              revoked
                            </span>
                            <span className={clsx("inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em]", shareRoleBadgeClass(item.item_perm || "r"))}>
                              {describeSharePermissions(item.item_perm || "r")}
                            </span>
                          </div>
                        </div>
                        <p className="text-xs font-semibold text-rose-700">{t("sharing.revokedByOwner")}</p>
                      </div>
                      );
                    })}
                  </div>
                </div>
              </section>
            ) : null}
            <section className="grid gap-3">
              <h3 className="font-black">{t("sharing.acceptedShares")}</h3>
              <div className="rounded-lg border border-slate-200 bg-slate-50 p-4">
                <p className="text-sm font-semibold text-slate-600">
                  {t("sharing.acceptedHelp")}
                </p>
                <div className="mt-4 grid gap-2">
                  {acceptedReceivedShares.length ? (
                    acceptedReceivedShares.map((share) => (
                      <div
                        key={share.key}
                        className={clsx(
                          "grid gap-1 rounded-xl border px-3 py-2 transition-all duration-700 ease-out",
                          share.highlightPath && sharedFolderHighlightPath === share.highlightPath && sharedFolderHighlightPulse
                            ? "animate-pulse border-[color-mix(in_srgb,var(--accent)_35%,white)] bg-[color-mix(in_srgb,var(--accent)_7%,white)]"
                            : share.highlightPath && sharedFolderHighlightPath === share.highlightPath
                              ? "border-[color-mix(in_srgb,var(--accent)_35%,white)] bg-[color-mix(in_srgb,var(--accent)_7%,white)]"
                              : "border-slate-200 bg-white"
                        )}
                      >
                        <div className="flex items-start justify-between gap-3">
                          <div className="flex min-w-0 items-start gap-2">
                            <ShareResourceIcon kind={share.kind} />
                            <div className="min-w-0">
                              <p className="truncate text-sm font-bold text-slate-900">{share.name}</p>
                              <p className="truncate text-xs font-semibold text-slate-500">
                                {share.type} - {t("sharing.from", { sender: share.owner })}
                              </p>
                            </div>
                          </div>
                          <div className="flex items-center gap-1.5">
                            <span className={clsx("inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em]", shareStateBadgeClass("accepted"))}>
                              {t("calendar.accepted")}
                            </span>
                            <span className={clsx("inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em]", shareRoleBadgeClass(share.permissions || "r"))}>
                              {describeSharePermissions(share.permissions || "r")}
                            </span>
                          </div>
                        </div>
                        <p className="text-xs font-semibold text-slate-500">
                          {share.path} - {share.description}
                        </p>
                      </div>
                    ))
                  ) : (
                    <p className="text-sm font-semibold text-slate-400">{t("sharing.noAccepted")}</p>
                  )}
                </div>
              </div>
            </section>
          </div>
        ) : null}
        {activeTab === "ooo" ? (
          <OutOfOfficeForm
            t={t}
            loading={outOfOffice.isLoading}
            enabled={oooEnabled}
            replyMode={oooReplyMode}
            useTimePeriod={oooUseTimePeriod}
            startDate={oooStartDate}
            endDate={oooEndDate}
            subject={oooSubject}
            message={oooMessage}
            onEnabledChange={setOooEnabled}
            onReplyModeChange={(value) => {
              setOooReplyMode(value);
              setOooEnabled(value === "reply");
            }}
            onUseTimePeriodChange={setOooUseTimePeriod}
            onStartDateChange={(value) => {
              setOooStartDate(value);
              if (value) setOooUseTimePeriod(true);
            }}
            onEndDateChange={(value) => {
              setOooEndDate(value);
              if (value) setOooUseTimePeriod(true);
            }}
            onSubjectChange={setOooSubject}
            onMessageChange={setOooMessage}
            error={(oooTimePeriodError ? t("ooo.invalidTimePeriod") : "") || (saveOutOfOffice.error instanceof Error ? saveOutOfOffice.error.message : "")}
            saving={saveOutOfOffice.isPending}
            saved={saveOutOfOffice.isSuccess}
            onSave={() => {
              if (oooTimePeriodError) {
                return;
              }
              saveOutOfOffice.mutate({
                enabled: oooReplyMode === "reply",
                reply_mode: oooReplyMode,
                use_time_period: oooUseTimePeriod,
                start_date: oooUseTimePeriod ? oooStartDate : "",
                end_date: oooUseTimePeriod ? oooEndDate : "",
                subject: oooSubject,
                message: oooMessage
              });
            }}
          />
        ) : null}
        {activeTab === "account" ? (
          <div className="grid gap-6">
            <section className="grid gap-3">
              <h3 className="font-black">{t("profile.title")}</h3>
              <form
                className="grid gap-3 rounded-lg border border-slate-200 p-4"
                onSubmit={(event) => {
                  event.preventDefault();
                  void saveProfile();
                }}
              >
                <div className="flex flex-wrap items-center gap-3">
                  <ContactAvatar value={profileDraft.display_name || profileDraft.first_name || email} photoUrl={profilePhotoPreview} size="lg" />
                  <div className="grid gap-2">
                    <strong className="text-sm text-slate-700">{t("profile.photo")}</strong>
                    <div className="flex flex-wrap items-center gap-2">
                      <label className="theme-button-soft h-9 cursor-pointer px-3 text-sm">
                        <Upload size={14} />
                        {t("profile.choosePhoto")}
                        <input type="file" accept="image/jpeg,image/png,image/webp,image/gif" className="sr-only" onChange={(event) => {
                          const file = event.target.files?.[0];
                          if (!file) return;
                          setProfilePhotoFile(file);
                          setProfilePhotoPreview(URL.createObjectURL(file));
                          setRemoveProfilePhoto(false);
                        }} />
                      </label>
                      {profilePhotoPreview ? <button type="button" className="icon-button h-9 w-9" onClick={() => { setProfilePhotoFile(null); setProfilePhotoPreview(""); setRemoveProfilePhoto(true); }} aria-label={t("profile.removePhoto")} title={t("profile.removePhoto")}><Trash2 size={15} /></button> : null}
                    </div>
                  </div>
                </div>
                <div className="grid gap-3 sm:grid-cols-3">
                  <label className="grid gap-1.5 text-sm font-bold text-slate-600">{t("profile.displayName")}<input value={profileDraft.display_name} onChange={(event) => setProfileDraft({ ...profileDraft, display_name: event.target.value })} className="field h-10" /></label>
                  <label className="grid gap-1.5 text-sm font-bold text-slate-600">{t("profile.firstName")}<input value={profileDraft.first_name} onChange={(event) => setProfileDraft({ ...profileDraft, first_name: event.target.value })} className="field h-10" /></label>
                  <label className="grid gap-1.5 text-sm font-bold text-slate-600">{t("profile.surname")}<input value={profileDraft.surname} onChange={(event) => setProfileDraft({ ...profileDraft, surname: event.target.value })} className="field h-10" /></label>
                </div>
                <div className="flex flex-wrap items-center gap-3">
                  <button type="submit" className="theme-button h-10 px-4" disabled={profilePhotoBusy || updateProfile.isPending}><UserRound size={16} />{profilePhotoBusy ? t("common.saving") : t("common.save")}</button>
                  {updateProfile.isSuccess ? <span className="text-sm font-bold text-emerald-700">{t("profile.updated")}</span> : null}
                  {profileError ? <span className="text-sm font-bold text-red-600">{profileError}</span> : null}
                </div>
              </form>
            </section>
            <section className="grid gap-3">
              <h3 className="font-black">{t("password.change")}</h3>
              <form
                className="grid gap-3 rounded-lg border border-slate-200 p-4"
                onSubmit={(event) => {
                  event.preventDefault();
                  if (canSavePassword) changePassword.mutate({ current_password: "", password });
                }}
              >
                <span className="text-sm font-bold text-slate-500">{email}</span>
                <div className="grid gap-3 sm:grid-cols-2">
                  <input value={password} onChange={(event) => setPassword(event.target.value)} type="password" className="field h-10 min-w-0" placeholder={t("password.new")} />
                  <input value={confirmPassword} onChange={(event) => setConfirmPassword(event.target.value)} type="password" className="field h-10 min-w-0" placeholder={t("password.confirm")} />
                </div>
                <div className="flex flex-wrap items-center gap-3">
                  <button
                    type="submit"
                    className="theme-button h-10 px-4 disabled:opacity-50"
                    disabled={!canSavePassword}
                  >
                    {t("common.save")}
                  </button>
                  <p className="text-xs font-semibold text-slate-500">{t("password.rule")}</p>
                </div>
                {passwordError ? <span className="text-sm font-bold text-red-600">{passwordError}</span> : null}
                {!passwordError && passwordMismatch ? <span className="text-sm font-bold text-red-600">{passwordMismatch}</span> : null}
                {changePassword.isSuccess ? <span className="inline-flex items-center gap-2 text-sm font-bold text-emerald-700"><Check size={16} /> {t("password.updated")}</span> : null}
                {changePassword.error ? <span className="text-sm font-bold text-red-600">{changePassword.error.message}</span> : null}
              </form>
            </section>
          </div>
        ) : null}
        {activeTab === "security" ? <SecuritySettings email={email} t={t} /> : null}
        {activeTab === "signature" ? (
          <SignatureSettings
            t={t}
            defaultSignature={defaultSignature}
            loading={signaturesLoading}
            errorMessage={signaturesError}
            saving={signaturesSaving}
            onSave={onSaveSignature}
          />
        ) : null}
        {activeTab === "filters" ? (
          <FilterSettings
            t={t}
            syncedEmail={email}
            rules={filterRules}
            setRules={setFilterRules}
            folders={mailFolders}
            loading={filtersLoading}
            errorMessage={filtersError}
            saving={filtersSaving}
            onSave={onSaveFilters}
          />
        ) : null}
        {activeTab === "import" ? <ImportExportPanel t={t} contacts={contacts} selectedFolderId={selectedContactFolderId} messages={messages} /> : null}
        {activeTab === "migration" ? <MigrationCenter t={t} email={email} /> : null}
      </div>
    </div>
  );
}

function ResizeHandle({ onDrag }: { onDrag: (delta: number) => void }) {
  const lastXRef = useRef(0);

  return (
    <div
      onPointerDown={(event) => {
        event.preventDefault();
        lastXRef.current = event.clientX;
        event.currentTarget.setPointerCapture(event.pointerId);
      }}
      onPointerMove={(event) => {
        if (!event.currentTarget.hasPointerCapture(event.pointerId)) return;
        onDrag(event.clientX - lastXRef.current);
        lastXRef.current = event.clientX;
      }}
      onPointerUp={(event) => {
        if (event.currentTarget.hasPointerCapture(event.pointerId)) {
          event.currentTarget.releasePointerCapture(event.pointerId);
        }
      }}
      onPointerCancel={(event) => {
        if (event.currentTarget.hasPointerCapture(event.pointerId)) {
          event.currentTarget.releasePointerCapture(event.pointerId);
        }
      }}
      className="h-full w-3 touch-none cursor-col-resize rounded-lg transition hover:bg-[color-mix(in_srgb,var(--accent)_12%,white)]"
      role="separator"
      aria-orientation="vertical"
    />
  );
}

function QuotaCard({ t, quota, loading }: { t: ReturnType<typeof createTranslator>; quota?: MailQuota; loading?: boolean }) {
  if (loading && !quota) {
    return <div className="rounded-lg bg-slate-50 px-3 py-3 text-xs font-bold text-slate-500">{t("quota.checking")}</div>;
  }
  if (!quota?.available) {
    return (
      <div className="rounded-lg bg-slate-50 px-3 py-3">
        <div className="flex items-center justify-between text-xs font-black uppercase text-slate-400">
          <span>{t("quota.storage")}</span>
          <span>{t("quota.insufficientData")}</span>
        </div>
        <p className="mt-2 text-xs font-semibold text-slate-500">{t("quota.insufficientHelp")}</p>
      </div>
    );
  }
  return (
    <div className="rounded-lg bg-slate-50 px-3 py-3">
      <div className="flex items-center justify-between text-xs font-black uppercase text-slate-400">
        <span>{t("quota.storage")}</span>
        <span>{quota.percent}%</span>
      </div>
      <div className="mt-2 h-2 overflow-hidden rounded-full bg-slate-200">
        <div className="h-full rounded-full bg-[var(--accent)]" style={{ width: `${Math.min(quota.percent, 100)}%` }} />
      </div>
      <p className="mt-2 text-xs font-semibold text-slate-600">{t("quota.usedOf", { used: formatStorage(quota.used_kb), limit: formatStorage(quota.limit_kb) })}</p>
    </div>
  );
}

function FolderButton({ folder, active, highlighted, count, onClick, onDropMessage, onContextMenu, isDropTarget, onDragTargetChange }: { folder: Folder; active: boolean; highlighted?: boolean; count?: number; onClick: () => void; onDropMessage?: (items: MailSelectionItem[]) => void; onContextMenu: (event: ReactMouseEvent<HTMLElement>) => void; isDropTarget?: boolean; onDragTargetChange?: (isTarget: boolean) => void }) {
  return (
    <button
      onClick={onClick}
      onContextMenu={onContextMenu}
      onDragOver={(event) => {
        if (!onDropMessage) return;
        event.preventDefault();
        event.dataTransfer.dropEffect = "move";
        onDragTargetChange?.(true);
      }}
      onDragLeave={() => onDragTargetChange?.(false)}
      onDrop={(event) => {
        if (!onDropMessage) return;
        event.preventDefault();
        onDragTargetChange?.(false);
        const items = parseDraggedMessages(event.dataTransfer.getData("message/items"));
        if (items.length) onDropMessage(items);
      }}
      className={clsx(
        "theme-list-item transition-all duration-700 ease-out",
        active ? "theme-list-item-active" : "text-slate-600 hover:bg-slate-100",
        highlighted && !active && "border-[color-mix(in_srgb,var(--accent)_45%,white)] bg-[color-mix(in_srgb,var(--accent)_8%,white)] text-slate-950 ring-2 ring-[color-mix(in_srgb,var(--accent)_16%,white)]",
        !onDropMessage && "opacity-90",
        isDropTarget && "border-[var(--accent)] bg-[color-mix(in_srgb,var(--accent)_12%,white)] text-slate-950 shadow-sm ring-2 ring-[color-mix(in_srgb,var(--accent)_18%,white)]"
      )}
    >
      {folderIcon(folder)}
      <span className="min-w-0 flex-1 truncate">{displayFolder(folder.name)}</span>
      {count ? (
        <span className="theme-chip">
          {count}
        </span>
      ) : null}
    </button>
  );
}

function FolderContextMenu({
  folder,
  t,
  x,
  y,
  busy,
  shareDisabled,
  shareBadge,
  shareTooltip,
  onRename,
  onColorChange,
  onShare,
  onDelete,
  onEmpty,
}: {
  folder: Folder;
  t: ReturnType<typeof createTranslator>;
  x: number;
  y: number;
  busy: boolean;
  shareDisabled?: boolean;
  shareBadge?: string;
  shareTooltip?: string;
  onRename: () => void;
  onColorChange: (color: number, rgb: string) => void;
  onShare: () => void;
  onDelete: () => void;
  onEmpty: () => void;
}) {
  const renameDeleteDisabled = busy || !canRenameOrDeleteFolder(folder);
  const colorDisabled = busy || !canChangeFolderColor(folder);
  const emptyDisabled = busy || !canEmptyFolder(folder);

  return (
    <div
      className="fixed z-50 min-w-[200px] rounded-xl border border-slate-200 bg-white p-1 shadow-xl"
      style={{ left: x, top: y }}
      onClick={(event) => event.stopPropagation()}
    >
      <div className="border-b border-slate-100 px-3 py-2 text-xs font-black uppercase text-slate-400">
        {displayFolder(folder.name)}
      </div>
      <FolderMenuItem label={t("folder.rename")} disabled={renameDeleteDisabled} onClick={onRename} />
      <div className="px-3 py-2">
        <div className="mb-2 flex items-center justify-between gap-2">
          <p className="text-xs font-black uppercase text-slate-400">{t("folder.color")}</p>
          {!colorDisabled ? <span className="text-[11px] font-semibold text-slate-400">{t("folder.rightClickChoose")}</span> : null}
        </div>
        <div className="flex flex-wrap gap-1.5">
          {folderColorOptions.map((option) => {
            const selected = folderColorMatches(folder, option.value, option.hex);
            return (
              <button
                key={option.value}
                type="button"
                disabled={colorDisabled}
                onClick={() => onColorChange(option.value, option.hex)}
                className={clsx(
                  "grid h-7 w-7 place-items-center rounded-full border transition",
                  colorDisabled ? "cursor-not-allowed border-slate-100 opacity-40" : selected ? "border-slate-900 scale-105" : "border-slate-200 hover:border-slate-400"
                )}
                style={{ backgroundColor: option.hex }}
                aria-label={t("folder.setColor", { color: option.label })}
                title={option.label}
              >
                {selected ? <Check size={13} className="text-slate-950" /> : null}
              </button>
            );
          })}
        </div>
      </div>
      <FolderMenuItem label={t("folder.share")} disabled={renameDeleteDisabled || shareDisabled} badge={shareBadge} tooltip={shareTooltip} onClick={onShare} />
      <FolderMenuItem label={t("folder.empty")} disabled={emptyDisabled} onClick={onEmpty} />
      <FolderMenuItem label={t("common.delete")} disabled={renameDeleteDisabled} tone="danger" onClick={onDelete} />
      {folder.shared.length && !folder.share_owner_email && !folder.share_owner_id ? (
        <div className="mt-1 border-t border-slate-100 px-3 py-2">
          <p className="mb-2 text-xs font-black uppercase text-slate-400">{t("folder.sharedWith")}</p>
          <div className="grid gap-1.5">
            {folder.shared.map((share) => (
              <div key={`${share.email}:${share.permissions}`} className="rounded-lg bg-slate-50 px-2 py-1.5">
                <p className="truncate text-xs font-bold text-slate-700">{share.email || share.display_name || t("folder.sharedAccess")}</p>
                <p className="text-[11px] font-semibold text-slate-500">{describeSharePermissions(share.permissions || "r")}</p>
              </div>
            ))}
          </div>
        </div>
      ) : null}
      {folder.is_system ? <p className="px-3 py-2 text-xs font-semibold text-slate-400">{t("folder.systemFolderHelp")}</p> : null}
      {!canChangeFolderColor(folder) ? <p className="px-3 pb-2 text-xs font-semibold text-slate-400">{t("folder.colorLockedHelp")}</p> : null}
    </div>
  );
}

function FolderMenuItem({ label, disabled, badge, tooltip, tone = "default", onClick }: { label: string; disabled?: boolean; badge?: string; tooltip?: string; tone?: "default" | "danger"; onClick: () => void }) {
  return (
    <button
      type="button"
      onClick={() => {
        if (disabled) return;
        onClick();
      }}
      aria-disabled={disabled || undefined}
      title={tooltip}
      aria-label={tooltip ? `${label}. ${tooltip}` : label}
      className={clsx(
        "flex h-9 w-full items-center gap-2 rounded-md px-3 text-sm font-semibold transition",
        disabled ? "cursor-not-allowed text-slate-300" : tone === "danger" ? "text-red-600 hover:bg-red-50" : "text-slate-700 hover:bg-slate-100"
      )}
    >
      <span className="min-w-0 flex-1 truncate text-left">{label}</span>
      {badge ? <FeatureLockBadge label={badge} tooltip={tooltip} /> : null}
    </button>
  );
}

function messageHasCalendarInvite(message: { subject: string; preview: string; has_calendar_invite?: boolean }) {
  if (message.has_calendar_invite) return true;
  const subject = normalizeReaderText(message.subject).toLowerCase();
  const preview = normalizeReaderText(message.preview).toLowerCase();
  if (subject.startsWith("accept:") || subject.startsWith("accepted:") || subject.startsWith("tentative:") || subject.startsWith("declined:") || subject.startsWith("decline:") || subject.startsWith("ยอมรับ:") || subject.startsWith("ตอบรับ:") || subject.startsWith("ไม่แน่นอน:") || subject.startsWith("ไม่เข้าร่วม:") || subject.startsWith("ปฏิเสธ:")) {
    return true;
  }
  return (
    preview.includes("meeting request") ||
    preview.includes("calendar invitation") ||
    preview.includes("calendar invite") ||
    preview.includes("has accepted the invitation") ||
    preview.includes("has tentatively accepted the invitation") ||
    preview.includes("has declined the invitation") ||
    preview.includes("yes, i will attend") ||
    preview.includes("no, i will not attend")
  );
}

function CalendarResponseMarker({ state }: { state: string }) {
  if (!state) return null;
  const accepted = state === "accepted";
  const tentative = state === "tentative";
  return (
    <span className={clsx(
      "absolute -right-1 -top-1 inline-flex h-3.5 w-3.5 items-center justify-center rounded-full text-white shadow-[0_0_0_1px_white]",
      accepted ? "bg-emerald-500" : tentative ? "bg-amber-500" : "bg-rose-500"
    )}>
      {accepted ? <Check size={9} /> : tentative ? <Clock3 size={9} /> : <X size={9} />}
    </span>
  );
}

function MessageRow({
  t,
  locale,
  timeZone,
  message,
  active,
  selected,
  theme,
  themeName,
  tagsByName,
  onSelect,
  onToggleConversation,
  onOpenDraft,
  onDelete,
  onToggleSeen,
  onToggleStar,
  isConversationExpanded = false,
  dragItems
}: {
  t: ReturnType<typeof createTranslator>;
  locale: AppLocale;
  timeZone: string;
  message: MessageSummary;
  active: boolean;
  selected: boolean;
  theme: { accent: string; active: string };
  themeName: ThemeName;
  tagsByName: Map<string, Tag>;
  onSelect: (event: ReactMouseEvent<HTMLElement>) => void;
  onToggleConversation?: () => void;
  onOpenDraft: () => void;
  onDelete: () => void;
  onToggleSeen: () => void;
  onToggleStar: () => void;
  isConversationExpanded?: boolean;
  dragItems: MailSelectionItem[];
}) {
  const isConversation = message.conversation_count > 1;
  const hasCalendarInvite = messageHasCalendarInvite(message);
  const calendarResponseState = calendarInviteReplyStateFromSubject(message.subject);
  const deleteLabel = selected ? t("mail.deleteSelected") : t("mail.deleteMessage");
  const senderLabel = message.is_draft
    ? (message.to || t("reader.draft"))
    : (message.sender_name || message.sender_email || (message.conversation_id ? t("reader.conversation") : t("reader.unknownSender")));
  const rowAccent = theme.accent;
  const scheduledSendLabel = message.scheduled_send_at_ms > 0
    ? t("mail.waitingToSend", {
        date: new Intl.DateTimeFormat(locale, {
          dateStyle: "medium",
          timeStyle: "short",
          timeZone
        }).format(new Date(message.scheduled_send_at_ms))
      })
    : "";
  const activeRowClass = themeName === "graphite"
    ? "bg-[color-mix(in_srgb,#1e3a8a_7%,white)] text-slate-700 border-[color-mix(in_srgb,#1e3a8a_22%,white)] shadow-sm"
    : theme.active;
  const selectedRowClass = themeName === "graphite"
    ? "bg-[color-mix(in_srgb,#1e3a8a_5%,white)]"
    : "bg-[color-mix(in_srgb,var(--accent)_6%,white)]";
  return (
    <article
      draggable
      onDragStart={(event) => {
        event.dataTransfer.setData("message/items", JSON.stringify(dragItems));
        event.dataTransfer.effectAllowed = "move";
      }}
      onClick={(event) => {
        if ((event.target as HTMLElement | null)?.closest?.("[data-conversation-toggle='true']")) {
          return;
        }
        onSelect(event);
      }}
      onDoubleClick={() => {
        if (message.is_draft) onOpenDraft();
      }}
      className={clsx("group grid cursor-pointer gap-1 border-b border-slate-200/80 px-3 py-2.5 transition", active ? activeRowClass : selected ? selectedRowClass : "bg-white hover:bg-slate-50")}
    >
      <div className="grid min-w-0 grid-cols-[minmax(0,1fr)_auto] items-start gap-x-2">
        <div className="grid min-w-0 gap-0.5">
          <div className="flex min-w-0 items-center gap-1.5">
            {isConversation ? (
              <button
                type="button"
                data-conversation-toggle="true"
                onClick={(event) => {
                  event.stopPropagation();
                  onToggleConversation?.();
                }}
                className={clsx("grid h-4 w-4 shrink-0 place-items-center rounded-sm border transition", active ? "border-[color-mix(in_srgb,var(--accent)_30%,white)] bg-white/80 text-[var(--accent)] hover:bg-white" : "border-slate-200 bg-white text-slate-400 hover:border-[color-mix(in_srgb,var(--accent)_30%,white)] hover:text-[var(--accent)]")}
                aria-label={t("mail.toggleConversation")}
                title={t("mail.toggleConversation")}
              >
                <ChevronRight size={11} className={clsx("-ml-0.5 transition", isConversationExpanded && "rotate-90")} />
              </button>
            ) : null}
            {!message.seen ? <span className="h-1.5 w-1.5 shrink-0 rounded-full" style={{ backgroundColor: rowAccent }} /> : null}
            {message.high_priority ? <CircleAlert size={16} className="shrink-0 text-red-600" aria-label={t("mail.highPriority")} /> : null}
            {scheduledSendLabel ? (
              <span
                className={clsx("relative inline-flex h-5 w-5 shrink-0 items-center justify-center", active ? "text-[var(--accent)]" : "text-sky-600")}
                aria-label={scheduledSendLabel}
                title={scheduledSendLabel}
              >
                <Mail size={17} />
                <span className="absolute -bottom-0.5 -right-1 grid h-3 w-3 place-items-center rounded-full bg-white shadow-[0_0_0_1px_white]">
                  <Clock3 size={10} strokeWidth={2.5} />
                </span>
              </span>
            ) : null}
            <strong
              className={clsx(
                "min-w-0 truncate text-sm leading-5",
                active
                  ? "font-medium text-[color-mix(in_srgb,var(--accent)_82%,black)]"
                  : selected
                    ? "font-medium text-[color-mix(in_srgb,var(--accent)_72%,black)]"
                    : message.seen
                      ? "font-medium text-slate-500"
                      : "font-bold text-slate-900"
              )}
            >
              {senderLabel}
            </strong>
          </div>
          <p
            title={cleanSubject(message.subject)}
            className={clsx(
              "line-clamp-1 min-w-0 break-words text-sm leading-5",
              active
                ? "font-medium text-[color-mix(in_srgb,var(--accent)_82%,black)]"
                : selected
                  ? "font-medium text-[color-mix(in_srgb,var(--accent)_68%,black)]"
                  : message.seen
                    ? "font-semibold text-slate-500"
                    : "font-black text-slate-950"
            )}
          >
            {cleanSubject(message.subject)}
          </p>
          {message.preview ? (
            <p className={clsx("flex min-w-0 items-start gap-1.5 text-xs leading-4", active ? "text-slate-600" : "text-slate-500")}>
              {hasCalendarInvite ? (
                <span className="relative mt-0.5 shrink-0">
                  <CalendarDays size={13} className={clsx(active ? "text-[var(--accent)]" : "text-sky-600")} />
                  <CalendarResponseMarker state={calendarResponseState} />
                </span>
              ) : null}
              <span className="line-clamp-1 min-w-0 break-words">{message.preview}</span>
            </p>
          ) : hasCalendarInvite ? (
            <p className={clsx("flex min-w-0 items-center gap-1.5 text-xs leading-4", active ? "text-slate-600" : "text-slate-500")}>
              <span className="relative shrink-0">
                <CalendarDays size={13} className={clsx(active ? "text-[var(--accent)]" : "text-sky-600")} />
                <CalendarResponseMarker state={calendarResponseState} />
              </span>
              <span className="min-w-0 break-words">{t("calendar.invitation")}</span>
            </p>
          ) : null}
        </div>
        <div className="flex flex-col items-end gap-1 text-right">
          <div className="flex flex-wrap items-center justify-end gap-1.5">
            {isConversation ? (
              <span className={clsx("rounded-full px-2 py-0.5 text-[10px] font-black uppercase tracking-[0.08em]", active ? "bg-[color-mix(in_srgb,var(--accent)_10%,white)] text-[var(--accent)]" : "bg-slate-100 text-slate-500")}>
                {t("reader.messagesCount", { count: message.conversation_count })}
              </span>
            ) : null}
            <time
              className={clsx("text-[11px] font-semibold leading-4", active ? "text-[color-mix(in_srgb,var(--accent)_70%,black)]" : selected ? "text-[color-mix(in_srgb,var(--accent)_60%,black)]" : "text-slate-400")}
              dateTime={message.date}
            >
              {formatMessageDate(message.date, locale, timeZone)}
            </time>
          </div>
          <div className="flex items-center justify-end gap-1">
            {message.has_attachments ? <Paperclip size={13} className={clsx("shrink-0", active ? "text-[color-mix(in_srgb,var(--accent)_70%,black)]" : selected ? "text-[color-mix(in_srgb,var(--accent)_55%,black)]" : "text-slate-400")} aria-label={t("reader.hasAttachments")} /> : null}
            <button onClick={(event) => {
              event.stopPropagation();
              onToggleStar();
            }} className={clsx("grid h-7 w-7 shrink-0 place-items-center rounded-md transition sm:opacity-0 sm:group-hover:opacity-100", message.starred ? "text-amber-500 sm:opacity-100" : active ? "text-[color-mix(in_srgb,var(--accent)_70%,black)] hover:bg-[color-mix(in_srgb,var(--accent)_8%,white)]" : selected ? "text-[color-mix(in_srgb,var(--accent)_60%,black)] hover:bg-[color-mix(in_srgb,var(--accent)_8%,white)]" : "text-slate-400 hover:bg-amber-50")} aria-label={t("reader.star")}>
              <Star size={14} fill={message.starred ? "currentColor" : "none"} />
            </button>
            <button onClick={(event) => {
              event.stopPropagation();
              onToggleSeen();
            }} className={clsx("grid h-7 w-7 shrink-0 place-items-center rounded-md transition sm:opacity-0 sm:group-hover:opacity-100", active ? "text-[color-mix(in_srgb,var(--accent)_70%,black)] hover:bg-[color-mix(in_srgb,var(--accent)_8%,white)]" : selected ? "text-[color-mix(in_srgb,var(--accent)_60%,black)] hover:bg-[color-mix(in_srgb,var(--accent)_8%,white)] hover:text-[var(--accent)]" : "text-slate-400 hover:bg-[color-mix(in_srgb,var(--accent)_8%,white)] hover:text-[var(--accent)]")} aria-label={t("reader.readState")}>
              <MailOpen size={14} />
            </button>
            <button onClick={(event) => {
              event.stopPropagation();
              onDelete();
            }} className={clsx("grid h-7 w-7 shrink-0 place-items-center rounded-md transition sm:opacity-0 sm:group-hover:opacity-100", active ? "text-[color-mix(in_srgb,var(--accent)_70%,black)] hover:bg-slate-100 hover:text-slate-900" : selected ? "text-[color-mix(in_srgb,var(--accent)_55%,black)] hover:bg-red-50 hover:text-red-600" : "text-slate-400 hover:bg-red-50 hover:text-red-600")} aria-label={deleteLabel} title={deleteLabel}>
              <Trash2 size={14} />
            </button>
          </div>
        </div>
      </div>
      {message.tags.length ? <div className="flex flex-wrap items-center gap-1.5 pt-0.5">
        {message.tags.slice(0, 4).map((tagName) => (
          <span
            key={tagName}
            className="rounded-full px-1.5 py-px text-[9px] font-bold uppercase tracking-[0.06em]"
            style={{
              backgroundColor: `${tagColorHex(tagsByName.get(tagName))}20`,
              color: active ? "color-mix(in srgb, #0f172a 82%, white)" : tagColorHex(tagsByName.get(tagName))
            }}
          >
            {tagName}
          </span>
        ))}
      </div> : null}
    </article>
  );
}

function ThreadRow({
  t,
  locale,
  timeZone,
  message,
  index,
  active,
  onSelect,
}: {
  t: ReturnType<typeof createTranslator>;
  locale: AppLocale;
  timeZone: string;
  message: MessageDetail["conversation_messages"][number];
  index: number;
  active: boolean;
  onSelect: () => void;
}) {
  const senderLabel = message.sender_name || message.sender_email || t("reader.unknownSender");
  const hasCalendarInvite = messageHasCalendarInvite(message);
  const calendarResponseState = calendarInviteReplyStateFromSubject(message.subject);
  return (
    <button
      type="button"
      onClick={(event) => {
        event.stopPropagation();
        onSelect();
      }}
      className={clsx(
        "grid w-full gap-1 border-b border-slate-100 px-3 py-2 text-left transition last:border-b-0",
        active ? "bg-[color-mix(in_srgb,var(--accent)_8%,white)]" : "hover:bg-slate-50"
      )}
    >
      <div className="flex items-center justify-between gap-2">
        <div className="flex min-w-0 items-center gap-2">
          <span className={clsx("grid h-5 w-5 shrink-0 place-items-center rounded-full border text-[10px] font-black", active ? "border-transparent bg-[var(--accent)] text-white" : "border-slate-200 bg-white text-slate-500")}>
            {index + 1}
          </span>
          <strong className={clsx("truncate text-sm text-slate-900", active ? "font-medium" : "font-bold")}>{senderLabel}</strong>
        </div>
        <time className="shrink-0 text-[11px] font-semibold text-slate-400">{formatMessageDate(message.date, locale, timeZone)}</time>
      </div>
      <div className="min-w-0 text-xs font-semibold text-slate-500">
        <span className="truncate">{cleanSubject(message.subject)}</span>
        {message.preview ? (
          <span className="ml-2 inline-flex max-w-full items-start gap-1.5 align-top text-slate-400">
            {hasCalendarInvite ? (
              <span className="relative mt-0.5 shrink-0">
                <CalendarDays size={13} className="text-sky-600" />
                <CalendarResponseMarker state={calendarResponseState} />
              </span>
            ) : null}
            <span className="line-clamp-1 min-w-0">- {message.preview}</span>
          </span>
        ) : hasCalendarInvite ? (
          <span className="ml-2 inline-flex items-center gap-1.5 align-top text-slate-400">
            <span className="relative shrink-0">
              <CalendarDays size={13} className="text-sky-600" />
              <CalendarResponseMarker state={calendarResponseState} />
            </span>
            <span className="min-w-0">{t("calendar.invitation")}</span>
          </span>
        ) : null}
      </div>
    </button>
  );
}

function Reader({
  detail,
  actionDetail,
  currentFolder,
  currentAccountEmail,
  junkActionLabel,
  junkActionTargetFolder,
  loading,
  errorMessage,
  onRetry,
  accent,
  tags,
  onToggleTag,
  onReply,
  onReplyAll,
  onForward,
  onJunk,
  onEditDraft,
  onDelete,
  onToggleSeen,
  onToggleStar,
  onSaveAttachmentToDrive,
  onSaveAllAttachmentsToDrive,
  onAcceptNativeShareInvite,
  onAcceptNativeShareInviteAttachment,
  onDeclineNativeShareInvite,
  onDeclineNativeShareInviteAttachment,
  acceptShareBusy = false,
  calendarInviteResponseBusy,
  calendarInviteResponses,
  onRespondCalendarInvite,
  readReceiptBusy,
  readReceiptHandled,
  onSendReadReceipt,
  onDeclineReadReceipt,
  canDeleteMessages,
  driveConnected,
  driveWritable,
  driveSaving,
  driveServiceLabel,
  locale,
  timeZone,
  t,
  compact = false,
}: {
  detail?: MessageDetail;
  actionDetail?: MessageDetail;
  currentFolder: string;
  currentAccountEmail: string;
  junkActionLabel: string;
  junkActionTargetFolder: string;
  loading: boolean;
  errorMessage: string;
  onRetry: () => void;
  accent: string;
  tags: Tag[];
  onToggleTag: (message: MessageDetail, tagName: string, enabled: boolean) => void;
  onReply: (message: MessageDetail) => void;
  onReplyAll: (message: MessageDetail) => void;
  onForward: (message: MessageDetail) => void;
  onJunk?: (message: MessageDetail, targetFolder: string) => void;
  onEditDraft: (message: MessageDetail) => void;
  onDelete: (message: MessageDetail) => void;
  onToggleSeen: (message: MessageDetail) => void;
  onToggleStar: (message: MessageDetail) => void;
  onSaveAttachmentToDrive: (message: MessageDetail, part: string) => void;
  onSaveAllAttachmentsToDrive: (message: MessageDetail, parts: string[]) => void;
  onAcceptNativeShareInvite: (invite: NonNullable<ReturnType<typeof parseZimbraShareXml>>, message: MessageDetail) => void | Promise<void>;
  onAcceptNativeShareInviteAttachment: (message: MessageDetail, attachment: MessageDetail["attachments"][number]) => void | Promise<void>;
  onDeclineNativeShareInvite: (invite: NonNullable<ReturnType<typeof parseZimbraShareXml>>, message: MessageDetail) => void | Promise<void>;
  onDeclineNativeShareInviteAttachment: (message: MessageDetail, attachment?: MessageDetail["attachments"][number]) => void | Promise<void>;
  acceptShareBusy?: boolean;
  calendarInviteResponseBusy?: boolean;
  calendarInviteResponses: Record<string, "accepted" | "tentative" | "declined">;
  onRespondCalendarInvite: (message: MessageDetail, invite: NonNullable<MessageDetail["calendar_invite"]>, response: "accepted" | "tentative" | "declined") => void | Promise<void>;
  readReceiptBusy: boolean;
  readReceiptHandled: boolean;
  onSendReadReceipt: (message: MessageDetail) => void | Promise<void>;
  onDeclineReadReceipt: (message: MessageDetail) => void;
  canDeleteMessages: boolean;
  driveConnected: boolean;
  driveWritable: boolean;
  driveSaving: boolean;
  driveServiceLabel: string;
  locale: AppLocale;
  timeZone: string;
  t: ReturnType<typeof createTranslator>;
  compact?: boolean;
}) {
  const [compactHeaderCollapsed, setCompactHeaderCollapsed] = useState(false);

  useEffect(() => {
    setCompactHeaderCollapsed(false);
  }, [detail?.uid, compact]);

  if (loading && !detail) {
    return (
      <section className="control-surface grid min-h-[420px] grid-rows-[auto_auto_minmax(0,1fr)] overflow-hidden rounded-r-xl rounded-l-none">
        <header className="border-b border-slate-200 p-4">
          <div className="flex items-start justify-between gap-4">
            <div className="min-w-0 flex-1">
              <div className="h-8 w-4/5 rounded-lg bg-slate-200 animate-pulse" />
              <div className="mt-3 flex flex-wrap gap-2">
                <div className="h-4 w-28 rounded bg-slate-200 animate-pulse" />
                <div className="h-4 w-36 rounded bg-slate-200 animate-pulse" />
              </div>
            </div>
            <div className="flex shrink-0 flex-wrap gap-2">
              <div className="h-10 w-20 rounded-lg bg-slate-200 animate-pulse" />
              <div className="h-10 w-20 rounded-lg bg-slate-200 animate-pulse" />
              <div className="h-10 w-24 rounded-lg bg-slate-200 animate-pulse" />
              <div className="h-10 w-24 rounded-lg bg-slate-200 animate-pulse" />
            </div>
          </div>
          <div className="mt-4 flex flex-wrap gap-2">
            <div className="h-8 w-24 rounded-full bg-slate-200 animate-pulse" />
            <div className="h-8 w-20 rounded-full bg-slate-200 animate-pulse" />
            <div className="h-8 w-28 rounded-full bg-slate-200 animate-pulse" />
            <div className="h-8 w-18 rounded-full bg-slate-200 animate-pulse" />
          </div>
          <div className="mt-4 rounded-lg border border-slate-200 bg-slate-50 p-3">
            <div className="flex items-center gap-2 text-sm font-black text-slate-700">
              <div className="h-4 w-4 rounded bg-slate-200 animate-pulse" />
              <span>{t("reader.attachments")}</span>
            </div>
            <div className="mt-3 grid gap-2 sm:grid-cols-2">
              <div className="h-14 rounded-lg bg-white animate-pulse" />
              <div className="h-14 rounded-lg bg-white animate-pulse" />
            </div>
          </div>
        </header>
        <div className="border-b border-slate-200 bg-slate-50 px-4 py-2 transition-opacity duration-200 ease-out">
          <div className="flex items-center gap-2 text-xs font-black uppercase tracking-[0.12em] text-slate-400">
            <RefreshCw size={12} className="animate-spin text-[var(--accent)]" />
            {t("reader.loadingMessage")}
          </div>
        </div>
        <div className="bg-white p-6 transition-opacity duration-200 ease-out">
          <div className="mx-auto max-w-3xl transition-all duration-200 ease-out">
            <div className="grid gap-3">
              <div className="h-4 w-2/5 rounded bg-slate-200 animate-pulse" />
              <div className="h-4 w-5/6 rounded bg-slate-200 animate-pulse" />
              <div className="h-4 w-4/6 rounded bg-slate-200 animate-pulse" />
              <div className="h-4 w-11/12 rounded bg-slate-200 animate-pulse" />
              <div className="h-4 w-3/5 rounded bg-slate-200 animate-pulse" />
              <div className="mt-4 grid gap-2">
                <div className="h-3 w-full rounded bg-slate-100 animate-pulse" />
                <div className="h-3 w-11/12 rounded bg-slate-100 animate-pulse" />
                <div className="h-3 w-10/12 rounded bg-slate-100 animate-pulse" />
                <div className="h-3 w-9/12 rounded bg-slate-100 animate-pulse" />
                <div className="h-3 w-8/12 rounded bg-slate-100 animate-pulse" />
                <div className="h-3 w-11/12 rounded bg-slate-100 animate-pulse" />
                <div className="h-3 w-7/12 rounded bg-slate-100 animate-pulse" />
              </div>
            </div>
          </div>
        </div>
      </section>
    );
  }

  if (errorMessage && !detail) {
    return (
      <section className="control-surface grid min-h-[420px] place-items-center rounded-xl p-8 text-center">
        <div className="max-w-md">
          <strong className="block text-lg text-red-700">{t("reader.unableOpen")}</strong>
          <span className="mt-2 block text-sm font-semibold text-slate-500">{errorMessage}</span>
          <button onClick={onRetry} className="mt-4 inline-flex h-10 items-center gap-2 rounded-lg border border-slate-200 bg-white px-4 font-bold transition hover:bg-slate-50">
            <RefreshCw size={16} />
            {t("reader.retry")}
          </button>
        </div>
      </section>
    );
  }

  if (!detail) {
    if (loading) {
      return (
        <section className={clsx("control-surface grid h-full min-h-[420px] animate-pulse gap-4 overflow-hidden p-4", compact ? "rounded-xl" : "rounded-r-xl rounded-l-none")}>
          <div className="h-8 w-2/3 rounded bg-slate-100" />
          <div className="h-4 w-1/3 rounded bg-slate-100" />
          <div className="mt-2 h-6 w-40 rounded bg-slate-100" />
          <div className="grid gap-2">
            <div className="h-3 w-full rounded bg-slate-100" />
            <div className="h-3 w-11/12 rounded bg-slate-100" />
            <div className="h-3 w-10/12 rounded bg-slate-100" />
            <div className="h-3 w-9/12 rounded bg-slate-100" />
          </div>
        </section>
      );
    }
    return (
      <section className="control-surface grid min-h-[420px] place-items-center rounded-xl p-8 text-center">
        <div>
          <strong className="block text-lg">{t("reader.selectEmail")}</strong>
          <span className="mt-2 block text-sm font-semibold text-slate-500">{t("reader.emptyHelp")}</span>
        </div>
      </section>
    );
  }

  const scopedDetail = actionDetail ?? detail;

  const isConversation = detail.conversation_count > 1;
  const cachedReader = getCachedReaderRender(detail);
  const displayAttachments = cachedReader.visibleAttachments;
  const showEditDraft = detail.is_draft;
  const detailActionTargetUid = scopedDetail.uid;
  const senderLabel = formatMailboxLabel(detail.sender_name, detail.sender_email);
  const recipientLabel = formatRecipientLabel(detail.to);
  const ccLabel = formatRecipientLabel(detail.cc || messageHeaderValue(detail.headers, "cc"));
  const canRenderHtml = cachedReader.canRenderHtml;
  const readerPlainText = cachedReader.plainTextBody || detail.subject || t("reader.noContent");
  const calendarInvite = detail.calendar_invite || null;
  const calendarInviteMethod = calendarInvite?.method.trim().toUpperCase() || "";
  const calendarInviteIsRequest = calendarInviteMethod === "REQUEST";
  const isSentMailboxFolder = isSentFolderPath(currentFolder) || isSentFolderPath(detail.folder);
  const isOutgoingCalendarInvite = Boolean(
    calendarInviteIsRequest &&
      currentAccountEmail &&
      detail.sender_email.trim().toLowerCase() === currentAccountEmail.trim().toLowerCase()
  );
  const calendarInviteReplyState = calendarInvite ? calendarInviteReplyStateFromSubject(detail.subject) : "";
  const calendarInviteResponseKey = calendarInvite ? `${detail.open_uid || detail.uid}:${calendarInvite.uid || calendarInvite.summary}`.toLowerCase() : "";
  const recordedCalendarInviteResponse = calendarInviteResponseKey ? calendarInviteResponses[calendarInviteResponseKey] || "" : "";
  const effectiveCalendarInviteReplyState = recordedCalendarInviteResponse || calendarInviteReplyState;
  const calendarInviteResponseLabel = calendarInvite
    ? (recordedCalendarInviteResponse === "accepted"
      ? t("calendar.accepted")
      : recordedCalendarInviteResponse === "tentative"
        ? t("calendar.tentative")
        : recordedCalendarInviteResponse === "declined"
          ? t("calendar.declined")
          : calendarInviteIsRequest ? t("calendar.invitation") : calendarInviteReplyLabel(detail.subject, t))
    : "";
  const calendarInviteReplyMessage = calendarInvite ? calendarInviteReplyMessageForDetail(detail, calendarInvite, senderLabel, t) : "";
  const calendarInviteReplyExcerpt = calendarInvite ? calendarInviteReplyExcerptFromDetail(detail) : "";
  const shareInvite = parseZimbraShareXml(detail.share_xml || "");
  const shareInviteAttachment = !shareInvite ? displayAttachments.find(isShareInviteAttachment) : undefined;
  // Never promote an arbitrary non-inline attachment to a share invite. A normal
  // sent message with an inline image (or any regular attachment) can contain
  // words such as "share" or "calendar" in its body. The old heuristic then
  // rendered Accept/Decline buttons for the first attachment, e.g. a PNG logo.
  const effectiveShareInviteAttachment = shareInviteAttachment;
  const headerMetadataVisible = !compact || !compactHeaderCollapsed;

  return (
    <section className={clsx("control-surface grid h-full min-h-0 grid-rows-[auto_auto_minmax(0,1fr)] overflow-hidden", compact ? "rounded-xl" : "rounded-r-xl rounded-l-none")}>
      <header className={clsx("border-b border-slate-200", compact ? "bg-white/95 p-2 backdrop-blur-xl md:p-3" : "p-4")}>
        {compact ? (
          <div className="mb-1 flex items-center justify-between gap-2">
            <div className="flex min-w-0 flex-1 items-center gap-2 text-xs font-semibold text-slate-500">
              {isConversation ? (
                <span className="inline-flex min-w-0 shrink items-center gap-1.5 rounded-full border border-slate-200 bg-slate-50 px-2.5 py-1 font-black text-slate-600">
                  <ChevronRight size={12} className="shrink-0 rotate-90 text-[var(--accent)]" />
                  <span className="truncate">{t("reader.messagesCount", { count: detail.conversation_count })}</span>
                </span>
              ) : null}
              {detail.date ? <time className="min-w-0 truncate" dateTime={detail.date}>{formatDate(detail.date, locale, timeZone)}</time> : null}
            </div>
            <button
              type="button"
              onClick={() => setCompactHeaderCollapsed((collapsed) => !collapsed)}
              className="icon-button h-6 w-6 shrink-0 rounded-md border-[color-mix(in_srgb,var(--accent)_20%,#cbd5e1)] text-[var(--accent)] hover:bg-[color-mix(in_srgb,var(--accent)_10%,white)] hover:text-[var(--accent)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-offset-1"
              aria-label={compactHeaderCollapsed ? t("reader.showHeader") : t("reader.hideHeader")}
              aria-expanded={!compactHeaderCollapsed}
              title={compactHeaderCollapsed ? t("reader.showHeader") : t("reader.hideHeader")}
            >
              {compactHeaderCollapsed ? <ChevronDown size={13} /> : <ChevronUp size={13} />}
            </button>
          </div>
        ) : null}
        <div
          className={clsx(
            "overflow-hidden transition-[max-height,opacity,margin] duration-200 ease-out motion-reduce:transition-none",
            headerMetadataVisible ? "mb-3 max-h-[70vh] opacity-100" : "mb-0 max-h-0 opacity-0 pointer-events-none"
          )}
        >
        <div className="mb-3 grid gap-3">
          <div className="min-w-0">
            {compact ? (
              <p className="mb-2 text-xs font-black uppercase tracking-[0.12em] text-slate-400">{t("reader.message")}</p>
            ) : null}
            <h2 className="min-w-0 break-words text-xl font-black leading-tight text-slate-950">{detail.subject}</h2>
            <div className="mt-2 grid gap-1 text-xs font-semibold text-slate-500">
              <div className="grid min-w-0 grid-cols-[42px_minmax(0,1fr)] gap-2">
                <span className="font-black uppercase tracking-[0.08em] text-slate-400">{t("reader.fromLabel")}</span>
                <span className="min-w-0 break-words">{showEditDraft ? t("reader.draft") : senderLabel || t("reader.unknownSender")}</span>
              </div>
              {(recipientLabel || ccLabel) ? (
                <>
                {recipientLabel ? (
                  <div className="grid min-w-0 grid-cols-[42px_minmax(0,1fr)] gap-2">
                    <span className="font-black uppercase tracking-[0.08em] text-slate-400">To</span>
                    <span className="min-w-0 break-words">{recipientLabel}</span>
                  </div>
                ) : null}
                {ccLabel ? (
                  <div className="grid min-w-0 grid-cols-[42px_minmax(0,1fr)] gap-2">
                    <span className="font-black uppercase tracking-[0.08em] text-slate-400">Cc</span>
                    <span className="min-w-0 break-words">{ccLabel}</span>
                  </div>
                ) : null}
                </>
              ) : null}
            </div>
          </div>
          <div className="min-w-0">
            <div className={clsx("mb-2 flex flex-wrap items-center justify-start gap-2 text-xs font-semibold text-slate-500", compact ? "hidden" : "flex")}>
              {isConversation ? (
                <span className="inline-flex items-center gap-1.5 rounded-full border border-slate-200 bg-slate-50 px-2.5 py-1 font-black text-slate-600">
                  <ChevronRight size={12} className="rotate-90 text-[var(--accent)]" />
                  {t("reader.messagesCount", { count: detail.conversation_count })}
                </span>
              ) : null}
              {detail.date ? <time dateTime={detail.date}>{formatDate(detail.date, locale, timeZone)}</time> : null}
            </div>
            <div className={clsx("min-w-0 flex-wrap gap-2", compact ? "hidden" : "flex")}>
            <ToolbarButton label={t("reader.star")} icon={<Star size={17} fill={scopedDetail.starred ? "currentColor" : "none"} />} onClick={() => onToggleStar({ ...scopedDetail, uid: detailActionTargetUid })} />
            <ToolbarButton label={t("reader.readState")} icon={<MailOpen size={17} />} onClick={() => onToggleSeen({ ...scopedDetail, uid: detailActionTargetUid })} />
            {showEditDraft ? <button onClick={() => onEditDraft(detail)} className="theme-button-soft h-10 px-4"><FilePenLine size={16} /> {t("mail.editDraft")}</button> : <button onClick={() => onReply(detail)} className="theme-button-soft h-10 px-4"><Reply size={16} /> {t("mail.reply")}</button>}
            {!showEditDraft ? <button onClick={() => onReplyAll(detail)} className="theme-button-soft h-10 px-4"><ReplyAll size={16} /> {t("mail.replyAll")}</button> : null}
            {!showEditDraft ? <button onClick={() => onForward(detail)} className="theme-button-soft h-10 px-4"><Forward size={16} /> {t("mail.forward")}</button> : null}
            {!showEditDraft && onJunk && junkActionTargetFolder ? (
              <button onClick={() => onJunk({ ...scopedDetail, uid: detailActionTargetUid }, junkActionTargetFolder)} className="theme-button-soft h-10 border-amber-200 px-4 text-amber-700 hover:bg-amber-50">
                <AlertTriangle size={16} />
                {junkActionLabel}
              </button>
            ) : null}
            <button
              onClick={() => onDelete({ ...scopedDetail, uid: detailActionTargetUid })}
              className="theme-button-soft h-10 border-red-200 px-4 text-red-700 hover:bg-red-50 disabled:cursor-not-allowed disabled:opacity-40"
              disabled={!canDeleteMessages}
              title={!canDeleteMessages ? t("reader.deleteBlocked") : undefined}
            >
              <Trash2 size={16} /> {t("mail.delete")}
            </button>
            </div>
          </div>
        </div>
        {detail.request_read_receipt && !showEditDraft && !readReceiptHandled && detail.sender_email.trim().toLowerCase() !== currentAccountEmail.trim().toLowerCase() ? (
          <div className="mb-3 flex flex-wrap items-center gap-3 rounded-md border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm font-semibold text-emerald-900">
            <CheckCheck size={17} className="shrink-0" />
            <span className="min-w-0 flex-1">{t("reader.readReceiptRequested")}</span>
            <button type="button" onClick={() => void onSendReadReceipt(detail)} disabled={readReceiptBusy} className="theme-button h-9 px-3 disabled:opacity-50">{readReceiptBusy ? t("common.saving") : t("reader.sendReadReceipt")}</button>
            <button type="button" onClick={() => onDeclineReadReceipt(detail)} disabled={readReceiptBusy} className="theme-button-soft h-9 px-3 disabled:opacity-50">{t("reader.declineReadReceipt")}</button>
          </div>
        ) : null}
        {loading ? (
          <div className="mb-3 inline-flex items-center gap-2 rounded-full border border-slate-200 bg-slate-50 px-3 py-1 text-[11px] font-black uppercase tracking-[0.12em] text-slate-500">
            <RefreshCw size={12} className="animate-spin text-[var(--accent)]" />
            {isConversation ? t("reader.refreshingConversation") : t("reader.refreshingMessage")}
          </div>
        ) : null}
        {displayAttachments.length ? (
          <div className="mt-4 rounded-md border border-slate-200 bg-slate-50 px-2.5 py-2">
            <div className="mb-1.5 flex flex-wrap items-center gap-2 text-xs font-black uppercase tracking-[0.08em] text-slate-600">
              <Paperclip size={14} />
              {t("reader.attachments")}
              {driveConnected && driveWritable && displayAttachments.some((attachment) => attachment.part) ? (
                <button
                  type="button"
                  onClick={() => onSaveAllAttachmentsToDrive(detail, displayAttachments.filter((attachment) => attachment.part).map((attachment) => attachment.part))}
                  className="theme-button-soft h-6 rounded-full px-2.5 text-[10px] uppercase tracking-[0.12em]"
                  disabled={driveSaving}
                >
                  {driveSaving ? t("compose.saving") : t("reader.saveAllToDrive", { drive: driveServiceLabel })}
                </button>
              ) : null}
            </div>
            <div className="flex flex-wrap gap-1.5">
              {displayAttachments.map((attachment, index) => (
                <div
                  key={`${attachment.filename}-${index}`}
                  className={clsx(
                    "flex min-w-[180px] max-w-[300px] items-center gap-2 rounded-md border border-slate-200 bg-white px-2 py-1.5 text-xs shadow-sm",
                    attachment.part ? "transition hover:bg-slate-50" : "cursor-default"
                  )}
                >
                  <a
                    href={
                      attachment.part
                        ? `/api/mail/messages/${encodeURIComponent(detail.uid)}/attachments?part=${encodeURIComponent(attachment.part)}${canPreviewAttachment(attachment.content_type, attachment.filename) ? "&preview=1" : ""}`
                        : undefined
                    }
                    target="_blank"
                    rel="noreferrer"
                    className="flex min-w-0 flex-1 items-center gap-2"
                  >
                    {attachmentTypeIcon(attachment.content_type, attachment.filename)}
                    <div className="min-w-0 flex-1">
                      <p className="truncate font-semibold text-slate-800">
                        {cleanAttachmentDisplayName(attachment.filename)}
                        <span className="ml-1.5 text-[11px] font-semibold text-slate-500">{formatAttachmentSize(attachment.size)}</span>
                      </p>
                      <p className="truncate text-[11px] font-semibold text-slate-400">{formatAttachmentTypeLabel(attachment.content_type, attachment.filename)}</p>
                    </div>
                  </a>
                  {driveConnected && driveWritable && attachment.part ? (
                    <button
                      type="button"
                      onClick={() => onSaveAttachmentToDrive(detail, attachment.part)}
                      className="theme-button-soft h-6 px-2 text-[10px]"
                      disabled={driveSaving}
                    >
                      {driveSaving ? t("compose.saving") : t("reader.saveToDrive", { drive: driveServiceLabel })}
                    </button>
                  ) : null}
                </div>
              ))}
            </div>
          </div>
        ) : null}
        </div>
        {calendarInvite ? (
          <div className="mt-4 rounded-xl border border-sky-200 bg-gradient-to-br from-sky-50 via-white to-cyan-50 px-4 py-4 shadow-sm">
            <div className="flex flex-wrap items-start justify-between gap-4">
              <div className="min-w-0 flex-1">
                <p className="text-xs font-black uppercase tracking-[0.12em] text-sky-700">
                  {calendarInviteIsRequest ? t("calendar.invitation") : t("calendar.response")}
                </p>
                <h3 className="mt-1 break-words text-base font-black text-slate-950">
                  {calendarInvite.summary || detail.subject || t("calendar.invitation")}
                </h3>
                <p className="mt-1 text-sm font-semibold text-slate-700">{formatCalendarInviteRange(calendarInvite, locale)}</p>
                {calendarInvite.location ? (
                  <p className="mt-1 flex items-start gap-1.5 text-sm font-semibold text-slate-600">
                    <MapPin size={15} className="mt-0.5 shrink-0 text-sky-600" />
                    <span className="min-w-0 break-words">{calendarInvite.location}</span>
                  </p>
                ) : null}
                {calendarInvite.organizer ? (
                  <p className="mt-1 flex items-start gap-1.5 text-sm font-semibold text-slate-600">
                    <Users size={15} className="mt-0.5 shrink-0 text-sky-600" />
                    <span className="min-w-0 break-words">
                      {t("calendar.organizer")} {formatCalendarInviteParticipant(calendarInvite.organizer) || calendarInvite.organizer}
                    </span>
                  </p>
                ) : null}
                {calendarInvite.attendees.length ? (
                  <div className="mt-3">
                    <p className="text-xs font-black uppercase tracking-[0.08em] text-slate-500">{t("calendar.invitees")}</p>
                    <div className="mt-2 flex flex-wrap gap-1.5">
                      {calendarInvite.attendees.map((attendee) => (
                        <span
                          key={attendee}
                          className="inline-flex max-w-full items-center rounded-full border border-sky-200 bg-white px-2.5 py-1 text-xs font-semibold text-slate-700 shadow-sm"
                        >
                          <span className="truncate">{formatCalendarInviteParticipant(attendee) || attendee}</span>
                        </span>
                      ))}
                    </div>
                  </div>
                ) : null}
              </div>
              <div className="flex shrink-0 flex-col items-start gap-2">
                <span className="inline-flex items-center rounded-full border border-sky-200 bg-white px-2.5 py-1 text-[10px] font-black uppercase tracking-[0.12em] text-sky-700 shadow-sm">
                  {calendarInviteResponseLabel}
                </span>
                {calendarInvite.all_day ? (
                  <span className="inline-flex items-center rounded-full border border-slate-200 bg-slate-50 px-2.5 py-1 text-[10px] font-black uppercase tracking-[0.12em] text-slate-500">
                    {t("calendar.allDay")}
                  </span>
                ) : null}
              </div>
            </div>
            {calendarInviteIsRequest && !effectiveCalendarInviteReplyState && !isOutgoingCalendarInvite && !isSentMailboxFolder ? (
              <div className="mt-4 flex flex-wrap gap-2">
                <button
                  type="button"
                  className="theme-button h-9 px-4 text-sm disabled:opacity-60"
                  onClick={() => onRespondCalendarInvite(detail, calendarInvite, "accepted")}
                  disabled={calendarInviteResponseBusy}
                >
                  <Check size={15} className={clsx(calendarInviteResponseBusy && "animate-pulse")} />
                  {calendarInviteResponseBusy ? t("calendar.sending") : t("calendar.accept")}
                </button>
                <button
                  type="button"
                  className="theme-button-soft h-9 px-4 text-sm disabled:opacity-60"
                  onClick={() => onRespondCalendarInvite(detail, calendarInvite, "tentative")}
                  disabled={calendarInviteResponseBusy}
                >
                  <Clock3 size={15} className={clsx(calendarInviteResponseBusy && "animate-pulse")} />
                  {calendarInviteResponseBusy ? t("calendar.sending") : t("calendar.tentative")}
                </button>
                <button
                  type="button"
                  className="theme-button-soft h-9 px-4 text-sm disabled:opacity-60"
                  onClick={() => onRespondCalendarInvite(detail, calendarInvite, "declined")}
                  disabled={calendarInviteResponseBusy}
                >
                  <X size={15} className={clsx(calendarInviteResponseBusy && "animate-pulse")} />
                  {calendarInviteResponseBusy ? t("calendar.sending") : t("calendar.decline")}
                </button>
              </div>
            ) : calendarInviteIsRequest && (isOutgoingCalendarInvite || isSentMailboxFolder) ? (
              <p className="mt-4 rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-semibold text-slate-700">
                {t("calendar.sentReadOnly")}
              </p>
            ) : (
              <div
                className={clsx(
                  "mt-4 rounded-lg border px-3 py-3 text-sm font-semibold",
                  effectiveCalendarInviteReplyState === "accepted"
                    ? "border-emerald-200 bg-emerald-100 text-emerald-950"
                    : effectiveCalendarInviteReplyState === "tentative"
                      ? "border-amber-200 bg-amber-50 text-amber-950"
                      : "border-rose-200 bg-rose-50 text-rose-950"
                )}
              >
                <div className="flex items-start gap-2">
                  <span
                    className={clsx(
                      "mt-0.5 inline-flex h-5 w-5 flex-none items-center justify-center rounded-full",
                      effectiveCalendarInviteReplyState === "accepted"
                        ? "bg-emerald-200 text-emerald-800"
                        : effectiveCalendarInviteReplyState === "tentative"
                          ? "bg-amber-200 text-amber-800"
                          : "bg-rose-200 text-rose-800"
                    )}
                  >
                    {effectiveCalendarInviteReplyState === "declined" ? <X size={12} /> : effectiveCalendarInviteReplyState === "tentative" ? <Clock3 size={12} /> : <Check size={12} />}
                  </span>
                  <div className="min-w-0">
                    <p>{calendarInviteReplyMessage || t("calendar.responseRecorded")}</p>
                    {calendarInviteReplyExcerpt ? <p className="mt-1 text-xs font-medium opacity-80">{calendarInviteReplyExcerpt}</p> : null}
                  </div>
                </div>
              </div>
            )}
          </div>
        ) : null}
        {shareInvite || effectiveShareInviteAttachment ? (
          <div className="mt-4 rounded-md border border-sky-200 bg-sky-50 px-4 py-3">
            <div className="flex flex-wrap items-start justify-between gap-3">
              <div className="min-w-0">
                <p className="text-xs font-black uppercase tracking-[0.12em] text-sky-700">{t("sharing.folderInvite")}</p>
                <p className="mt-1 text-sm font-semibold text-slate-700">
                  {shareInvite ? t("sharing.folderInviteFrom", { sender: shareInvite.grantor_email || shareInvite.grantor_name || t("reader.unknownSender"), name: shareInvite.item_name || t("sharing.sharedFolder") }) : t("sharing.calendarInviteAttached")}
                </p>
                {shareInvite ? (
                  <p className="mt-1 text-xs font-semibold text-slate-500">
                    {t("sharing.role")}{" "}
                    <span className={clsx("inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em]", shareRoleBadgeClass(shareInvite.perm || "r"))}>
                      {describeSharePermissions(shareInvite.perm || "r")}
                    </span>{" "}
                    {shareInvite.view ? t("sharing.type", { type: shareInvite.view }) : ""}
                  </p>
                ) : effectiveShareInviteAttachment ? (
                  <p className="mt-1 text-xs font-semibold text-slate-500">{cleanAttachmentDisplayName(effectiveShareInviteAttachment.filename) || t("sharing.inviteAttachment")}</p>
                ) : null}
              </div>
              <div className="flex items-center gap-2">
                <button
                  type="button"
                  className="theme-button h-9 px-4 text-sm disabled:opacity-60"
                  onClick={() => shareInvite ? onAcceptNativeShareInvite(shareInvite, detail) : effectiveShareInviteAttachment ? onAcceptNativeShareInviteAttachment(detail, effectiveShareInviteAttachment) : undefined}
                  disabled={acceptShareBusy}
                >
                  {acceptShareBusy ? t("sharing.accepting") : t("calendar.accept")}
                </button>
                <button
                  type="button"
                  className="theme-button-soft h-9 px-4 text-sm disabled:opacity-60"
                  onClick={() => shareInvite ? onDeclineNativeShareInvite(shareInvite, detail) : onDeclineNativeShareInviteAttachment(detail, effectiveShareInviteAttachment)}
                  disabled={acceptShareBusy}
                >
                  {t("calendar.decline")}
                </button>
              </div>
            </div>
          </div>
        ) : null}
      </header>
      {canRenderHtml ? (
        <div className="min-h-0 overflow-auto bg-white">
          <div
            className={clsx("mail-reader-html p-6 text-[15px] leading-7 text-slate-800", (shareInvite || effectiveShareInviteAttachment) && "mail-reader-share-invite")}
            style={{ "--mail-reader-link": accent } as CSSProperties}
            onClick={handleReaderHtmlClick}
            dangerouslySetInnerHTML={{ __html: cachedReader.renderedReaderHtml }}
          />
        </div>
      ) : (
        <div className="min-h-0 overflow-auto bg-white p-6">
          <pre className="whitespace-pre-wrap break-words font-sans text-[15px] leading-7 text-slate-800">{readerPlainText}</pre>
        </div>
      )}
    </section>
  );
}

function OutOfOfficeForm({
  t,
  loading,
  enabled,
  replyMode,
  useTimePeriod,
  startDate,
  endDate,
  subject,
  message,
  error,
  saving,
  saved,
  onEnabledChange,
  onReplyModeChange,
  onUseTimePeriodChange,
  onStartDateChange,
  onEndDateChange,
  onSubjectChange,
  onMessageChange,
  onSave,
}: {
  t: ReturnType<typeof createTranslator>;
  loading: boolean;
  enabled: boolean;
  replyMode: "off" | "reply";
  useTimePeriod: boolean;
  startDate: string;
  endDate: string;
  subject: string;
  message: string;
  error: string;
  saving: boolean;
  saved: boolean;
  onEnabledChange: (value: boolean) => void;
  onReplyModeChange: (value: "off" | "reply") => void;
  onUseTimePeriodChange: (value: boolean) => void;
  onStartDateChange: (value: string) => void;
  onEndDateChange: (value: string) => void;
  onSubjectChange: (value: string) => void;
  onMessageChange: (value: string) => void;
  onSave: () => void;
}) {
  const invalidTimePeriod = replyMode === "reply" && useTimePeriod && (!startDate || !endDate || startDate > endDate);
  const surfaceStyle = {
    "--ooo-accent": "var(--accent)",
    "--ooo-accent-soft": "color-mix(in srgb, var(--accent) 8%, white)",
    "--ooo-accent-softer": "color-mix(in srgb, var(--accent) 4%, white)",
    "--ooo-accent-border": "color-mix(in srgb, var(--accent) 22%, #cbd5e1)",
    "--ooo-accent-ink": "color-mix(in srgb, var(--accent) 76%, black)",
  } as CSSProperties;

  return (
    <section className="grid gap-3 rounded-xl border border-slate-200 bg-white p-4" style={surfaceStyle}>
      <div className="border-b border-slate-200 pb-3">
        <h3 className="font-black text-slate-950">{t("ooo.title")}</h3>
        <p className="text-xs font-semibold text-slate-500">{t("ooo.help")}</p>
      </div>
      <div className="grid gap-4 text-[13px]" style={{ color: "color-mix(in srgb, var(--ooo-accent-ink) 82%, black)" }}>
        <div className="grid grid-cols-[180px_1fr] items-start gap-3">
          <div className="pt-1 text-right font-bold">{t("ooo.statusLabel")}</div>
          <div className="grid gap-2">
            <label className="flex items-center gap-2"><input type="radio" checked={replyMode === "off"} onChange={() => onReplyModeChange("off")} className="accent-[var(--ooo-accent)]" /> {t("ooo.doNotSend")}</label>
            <label className="flex items-center gap-2"><input type="radio" checked={replyMode === "reply"} onChange={() => onReplyModeChange("reply")} className="accent-[var(--ooo-accent)]" /> {t("ooo.sendReply")}</label>
          </div>
        </div>
        <div className="grid grid-cols-[180px_1fr] items-start gap-3">
          <label className="pt-2 text-right font-bold">{t("ooo.messageLabel")}</label>
          <textarea
            value={message}
            onChange={(event) => onMessageChange(event.target.value)}
            disabled={replyMode === "off"}
            className="min-h-[126px] w-[520px] max-w-full border bg-white p-2 text-[13px] disabled:cursor-not-allowed disabled:bg-slate-100"
            style={{ borderColor: "var(--ooo-accent-border)" }}
          />
        </div>
        <div className="grid grid-cols-[180px_1fr] items-start gap-3">
          <div className="pt-1 text-right font-bold">{t("ooo.timePeriod")}</div>
          <div className="grid gap-2">
            <label className={clsx("flex items-center gap-2", replyMode === "off" && "opacity-50")}>
              <input type="checkbox" checked={useTimePeriod} onChange={(event) => onUseTimePeriodChange(event.target.checked)} className="accent-[var(--ooo-accent)]" disabled={replyMode === "off"} />
              {t("ooo.timePeriodHelp")}
            </label>
            <div className={clsx("grid gap-2 pl-6", (!useTimePeriod || replyMode === "off") && "opacity-40")}>
              <div className="flex flex-wrap items-center gap-2">
                <span className="w-12 text-right">{t("ooo.start")}</span>
                <input
                  type="date"
                  value={startDate}
                  onChange={(event) => onStartDateChange(event.target.value)}
                  disabled={replyMode === "off"}
                  className="w-[160px] border bg-white px-2 py-1 disabled:cursor-not-allowed disabled:bg-slate-100"
                  style={{ borderColor: "var(--ooo-accent-border)" }}
                />
              </div>
              <div className="flex flex-wrap items-center gap-2">
                <span className="w-12 text-right">{t("ooo.end")}</span>
                <input
                  type="date"
                  value={endDate}
                  onChange={(event) => onEndDateChange(event.target.value)}
                  disabled={replyMode === "off"}
                  className="w-[160px] border bg-white px-2 py-1 disabled:cursor-not-allowed disabled:bg-slate-100"
                  style={{ borderColor: "var(--ooo-accent-border)" }}
                />
              </div>
            </div>
          </div>
        </div>
        <div className="grid grid-cols-[180px_1fr] items-center gap-3">
          <div />
          <div className="flex flex-wrap items-center gap-3">
            <button type="button" onClick={onSave} className="rounded-md border px-4 py-2 font-bold text-white disabled:opacity-50" style={{ borderColor: "var(--ooo-accent)", backgroundColor: "var(--ooo-accent)" }} disabled={saving || invalidTimePeriod}>
              {saving ? t("common.saving") : t("ooo.saveChanges")}
            </button>
            {loading ? <span className="text-slate-500">{t("common.loading")}</span> : null}
            {error ? <span className="font-semibold text-red-700">{error}</span> : null}
          </div>
        </div>
      </div>
    </section>
  );
}


function SecuritySettings({ email, t }: { email: string; t: ReturnType<typeof createTranslator> }) {
  const branding = useBranding();
  const queryClient = useQueryClient();
  const [code, setCode] = useState("");
  const [recoveryCodes, setRecoveryCodes] = useState<string[]>([]);
  const [qrCodeDataUrl, setQrCodeDataUrl] = useState("");
  const security = useQuery({
    queryKey: ["two-factor-status"],
    queryFn: api.twoFactorStatus,
    staleTime: 30_000,
    retry: false,
  });
  const setup = useMutation({
    mutationFn: api.twoFactorSetup,
    onSuccess: async () => {
      setCode("");
      await queryClient.invalidateQueries({ queryKey: ["two-factor-status"] });
    }
  });
  const enable = useMutation({
    mutationFn: api.twoFactorEnable,
    onSuccess: async () => {
      setCode("");
      await queryClient.invalidateQueries({ queryKey: ["me"] });
      await queryClient.invalidateQueries({ queryKey: ["two-factor-status"] });
    }
  });
  const disable = useMutation({
    mutationFn: api.twoFactorDisable,
    onSuccess: async () => {
      setCode("");
      setRecoveryCodes([]);
      await queryClient.invalidateQueries({ queryKey: ["two-factor-status"] });
    }
  });
  const generateRecoveryCodes = useMutation({
    mutationFn: api.twoFactorRecoveryCodes,
    onSuccess: async (data) => {
      setRecoveryCodes(data.recovery_codes);
      await queryClient.invalidateQueries({ queryKey: ["two-factor-status"] });
    }
  });

  const status = security.data;
  const enabled = Boolean(status?.enabled);
  const required = Boolean(status?.required);
  const configured = Boolean(status?.configured);
  const setupSecret = configured && !enabled ? status?.secret ?? "" : "";
  const setupUri = configured && !enabled ? status?.provisioning_uri ?? "" : "";
  const actionPending = setup.isPending || enable.isPending || disable.isPending || generateRecoveryCodes.isPending;
  const statusMessage = enable.isSuccess
    ? t("security.enabledMailbox")
    : disable.isSuccess
      ? t("security.disabledMailbox")
      : generateRecoveryCodes.isSuccess
        ? t("security.recoveryRegenerated")
        : setup.isSuccess
          ? t("security.setupReady")
          : "";

  useEffect(() => {
    let cancelled = false;
    async function buildQrCode() {
      if (!configured || enabled || !setupUri) {
        setQrCodeDataUrl("");
        return;
      }
      try {
        const dataUrl = await QRCode.toDataURL(setupUri, {
          width: 220,
          margin: 1,
          errorCorrectionLevel: "M",
          color: {
            dark: "#172033",
            light: "#ffffff",
          },
        });
        if (!cancelled) setQrCodeDataUrl(dataUrl);
      } catch {
        if (!cancelled) setQrCodeDataUrl("");
      }
    }
    void buildQrCode();
    return () => {
      cancelled = true;
    };
  }, [configured, enabled, setupUri]);

  async function copyText(text: string) {
    if (!text) return;
    if (navigator.clipboard?.writeText) {
      await navigator.clipboard.writeText(text);
      return;
    }
    const field = document.createElement("textarea");
    field.value = text;
    field.style.position = "fixed";
    field.style.opacity = "0";
    document.body.appendChild(field);
    field.select();
    document.execCommand("copy");
    document.body.removeChild(field);
  }

  function downloadText(filename: string, content: string) {
    const blob = new Blob([content], { type: "text/plain;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = filename;
    document.body.appendChild(link);
    link.click();
    link.remove();
    URL.revokeObjectURL(url);
  }

  function submitTwoFactorCode() {
    if (code.length >= 6 && !actionPending) {
      enable.mutate({ code });
    }
  }

  function buildRecoverySheetHtml(codes: string[]) {
    const escapeHtml = (value: string) =>
      value.replace(/[&<>"']/g, (char) => {
        switch (char) {
          case "&":
            return "&amp;";
          case "<":
            return "&lt;";
          case ">":
            return "&gt;";
          case '"':
            return "&quot;";
          case "'":
            return "&#39;";
          default:
            return char;
        }
      });
    const codeBlocks = codes.map((item) => `<span class="code">${escapeHtml(item)}</span>`).join("");
    return `<!doctype html>
<html>
<head>
  <meta charset="utf-8" />
  <title>${branding.name} recovery codes</title>
  <style>
    @page { size: A4; margin: 18mm; }
    body {
      margin: 0;
      font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      color: #152033;
      background: #fff;
    }
    .sheet {
      display: grid;
      gap: 16px;
      padding: 0;
    }
    .hero {
      border: 1px solid #d7e0ea;
      border-radius: 12px;
      padding: 20px;
      background: #f7f9fc;
    }
    .title {
      margin: 0;
      font-size: 22px;
      font-weight: 900;
      letter-spacing: -0.03em;
    }
    .meta {
      margin: 8px 0 0;
      font-size: 13px;
      line-height: 1.6;
      color: #475569;
    }
    .warning {
      border: 1px solid #fcd34d;
      background: #fffbeb;
      border-radius: 12px;
      padding: 14px 16px;
      font-size: 13px;
      line-height: 1.6;
      color: #7c2d12;
      font-weight: 600;
    }
    .grid {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: 10px;
    }
    .code {
      display: block;
      border: 1px solid #d7e0ea;
      border-radius: 10px;
      padding: 12px 14px;
      font-size: 14px;
      font-weight: 800;
      letter-spacing: 0.18em;
      text-align: center;
      background: #fff;
    }
    .footer {
      margin-top: 4px;
      font-size: 12px;
      color: #64748b;
      line-height: 1.6;
    }
    @media print {
      .warning { break-inside: avoid; }
      .code { break-inside: avoid; }
    }
  </style>
</head>
<body>
  <div class="sheet">
    <section class="hero">
      <h1 class="title">${branding.name} Recovery Codes</h1>
      <p class="meta">${escapeHtml(email)}</p>
      <p class="footer">Store this page offline. Each code works once when your authenticator app is unavailable.</p>
    </section>
    <section class="warning">
      These recovery codes are only shown once. Print or save this sheet now. Regenerating codes will invalidate the old set.
    </section>
    <section class="grid">
      ${codeBlocks}
    </section>
  </div>
</body>
</html>`;
  }

  function printRecoverySheet(codes: string[]) {
    const html = buildRecoverySheetHtml(codes);
    const frame = window.open("", "_blank", "noopener,noreferrer,width=960,height=720");
    if (!frame) return;
    frame.document.open();
    frame.document.write(html);
    frame.document.close();
    frame.focus();
    frame.onload = () => {
      frame.print();
    };
  }

  return (
    <div className="grid gap-6">
      <section className="grid gap-3">
        <h3 className="font-black">{t("security.title")}</h3>
        <div className="grid gap-3 rounded-xl border border-slate-200 bg-white p-4">
          <div className="flex flex-wrap items-center justify-between gap-3">
            <div>
              <p className="text-sm font-black text-slate-900">{enabled ? t("security.enabled") : t("security.disabled")}</p>
              <p className="text-xs font-semibold text-slate-500">
                {required ? "Your administrator requires 2FA for this mailbox." : t("security.help")}
              </p>
            </div>
            <span className={clsx("rounded-full px-3 py-1 text-xs font-black uppercase tracking-[0.12em]", enabled ? "bg-emerald-100 text-emerald-700" : "bg-slate-100 text-slate-500")}>
              {required && !enabled ? "Required" : enabled ? t("security.protected") : t("security.offByDefault")}
            </span>
          </div>

          {security.isLoading && !status ? <p className="text-sm font-semibold text-slate-500">{t("security.loading")}</p> : null}
          {security.error instanceof Error ? <p className="text-sm font-semibold text-red-600">{security.error.message}</p> : null}

          <div className="rounded-lg border border-slate-200 bg-slate-50 p-4">
            <div className="flex items-start gap-3">
              <div className="rounded-full bg-white p-2 text-[var(--accent)] shadow-sm">
                <ShieldCheck size={16} />
              </div>
              <div className="min-w-0">
                <p className="text-sm font-black text-slate-900">{email}</p>
                <p className="mt-1 text-xs font-semibold leading-6 text-slate-500">
                  {t("security.appHelp")}
                </p>
              </div>
            </div>
          </div>

          {!enabled && !configured ? (
            <div className="rounded-lg border border-dashed border-slate-200 bg-slate-50 p-4 text-sm font-semibold text-slate-600">
              {t("security.noSecret")}
            </div>
          ) : null}

          {!enabled && configured ? (
            <div className="grid gap-3 rounded-lg border border-slate-200 bg-white p-4">
              <div className="rounded-lg border border-amber-200 bg-amber-50 p-4 text-sm font-semibold leading-6 text-amber-950">
                {t("security.recoveryOnce")}
              </div>
              <div className="grid gap-3 lg:grid-cols-[220px_1fr]">
                <div className="grid place-items-center rounded-xl border border-slate-200 bg-slate-50 p-4">
                  {qrCodeDataUrl ? (
                    <img
                      src={qrCodeDataUrl}
                      alt={t("security.qrAlt")}
                      className="h-[220px] w-[220px] rounded-lg bg-white p-2"
                    />
                  ) : (
                    <div className="grid h-[220px] w-[220px] place-items-center rounded-lg border border-dashed border-slate-200 bg-white text-center text-sm font-semibold text-slate-500">
                      {t("security.generatingQr")}
                    </div>
                  )}
                </div>
                <div className="grid gap-3">
                  <div className="grid gap-2">
                    <label className="text-xs font-black uppercase tracking-[0.12em] text-slate-500">{t("security.manualKey")}</label>
                    <div className="flex flex-wrap items-center gap-2 rounded-lg border border-slate-200 bg-slate-50 px-3 py-2">
                      <code className="min-w-0 flex-1 break-all text-sm font-bold text-slate-900">{setupSecret}</code>
                    <button
                      type="button"
                      onClick={() => void copyText(setupSecret)}
                      className="theme-button-soft h-8 px-3 text-xs"
                      disabled={!setupSecret}
                    >
                      {t("common.copy")}
                    </button>
                  </div>
                </div>
                  <form
                    className="grid gap-2 sm:grid-cols-[minmax(0,1fr)_auto]"
                    onSubmit={(event) => {
                      event.preventDefault();
                      submitTwoFactorCode();
                    }}
                  >
                    <input
                      value={code}
                      onChange={(event) => setCode(event.target.value.replace(/\D/g, "").slice(0, 6))}
                      onKeyDown={(event) => {
                        if (event.key === "Enter") {
                          event.preventDefault();
                          submitTwoFactorCode();
                        }
                      }}
                      className="field h-11 min-w-0 tracking-[0.3em]"
                      inputMode="numeric"
                      enterKeyHint="done"
                      autoComplete="one-time-code"
                      placeholder={t("security.enterCode")}
                    />
                    <button
                      type="submit"
                      className="theme-button h-11 px-4"
                      disabled={actionPending || code.length < 6}
                    >
                      {t("security.enable")}
                    </button>
                  </form>
                </div>
              </div>
            </div>
          ) : null}

          <div className="flex flex-wrap items-center gap-2">
            {!enabled && !configured ? (
              <button
                type="button"
                onClick={() => setup.mutate()}
                className="theme-button h-10 px-4"
                disabled={actionPending}
              >
                {t("security.startSetup")}
              </button>
            ) : null}
            {enabled ? (
              <button
                type="button"
                onClick={() => disable.mutate()}
                className="theme-button-soft h-10 border-red-200 px-4 text-red-700 hover:bg-red-50"
                disabled={actionPending || required}
                title={required ? "2FA is required by your administrator." : undefined}
              >
                {t("security.disable")}
              </button>
            ) : null}
            {(enabled || configured) ? (
              <button
                type="button"
                onClick={() => generateRecoveryCodes.mutate()}
                className="theme-button-soft h-10 px-4"
                disabled={actionPending}
              >
                {t("security.recoveryCodes")}
              </button>
            ) : null}
          </div>

          {statusMessage ? (
            <div className="rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm font-semibold leading-6 text-emerald-900">
              {statusMessage}
            </div>
          ) : null}
          {setup.error instanceof Error ? <p className="text-sm font-semibold text-red-600">{setup.error.message}</p> : null}
          {enable.error instanceof Error ? <p className="text-sm font-semibold text-red-600">{enable.error.message}</p> : null}
          {disable.error instanceof Error ? <p className="text-sm font-semibold text-red-600">{disable.error.message}</p> : null}
          {generateRecoveryCodes.error instanceof Error ? <p className="text-sm font-semibold text-red-600">{generateRecoveryCodes.error.message}</p> : null}
          {recoveryCodes.length ? (
            <div className="grid gap-3 rounded-xl border border-amber-200 bg-amber-50 p-4">
              <div>
                <p className="text-sm font-black text-amber-950">{t("security.recoveryCodes")}</p>
                <p className="mt-1 text-xs font-semibold leading-6 text-amber-900/80">
                  {t("security.recoveryHelp")}
                </p>
              </div>
              <div className="flex flex-wrap gap-2">
                <button
                  type="button"
                  onClick={() => void copyText(recoveryCodes.join("\n"))}
                  className="theme-button-soft h-9 px-3 text-sm"
                >
                  {t("security.copyCodes")}
                </button>
                <button
                  type="button"
                  onClick={() => downloadText(`recovery-codes-${email}.txt`, recoveryCodes.join("\n"))}
                  className="theme-button-soft h-9 px-3 text-sm"
                >
                  {t("security.downloadCodes")}
                </button>
                <button
                  type="button"
                  onClick={() => printRecoverySheet(recoveryCodes)}
                  className="theme-button-soft h-9 px-3 text-sm"
                >
                  {t("security.printSheet")}
                </button>
                <button
                  type="button"
                  onClick={() => downloadText(`recovery-sheet-${email}.html`, buildRecoverySheetHtml(recoveryCodes))}
                  className="theme-button-soft h-9 px-3 text-sm"
                >
                  {t("security.downloadSheet")}
                </button>
              </div>
              <div className="grid gap-2 sm:grid-cols-2">
                {recoveryCodes.map((item) => (
                  <code key={item} className="rounded-lg border border-amber-200 bg-white px-3 py-2 text-sm font-bold tracking-[0.18em] text-amber-950">
                    {item}
                  </code>
                ))}
              </div>
            </div>
          ) : null}
          {status && status.recovery_codes_remaining > 0 ? (
            <p className="text-xs font-semibold text-slate-500">
              {t("security.remaining", { count: status.recovery_codes_remaining, suffix: status.recovery_codes_remaining === 1 ? "" : "s" })}
            </p>
          ) : null}
        </div>
      </section>
    </div>
  );
}

function SignatureSettings({
  t,
  defaultSignature,
  loading,
  errorMessage,
  saving,
  onSave
}: {
  t: ReturnType<typeof createTranslator>;
  defaultSignature: MailSignature | null;
  loading: boolean;
  errorMessage: string;
  saving: boolean;
  onSave: (payload: { content: string; content_html: string; content_type: string }) => void;
}) {
  const [contentHtml, setContentHtml] = useState(defaultSignature?.content_html || "");
  const editorRef = useRef<HTMLDivElement | null>(null);
  const selectionRef = useRef<Range | null>(null);

  useEffect(() => {
    setContentHtml(defaultSignature?.content_html || "");
  }, [defaultSignature?.content, defaultSignature?.content_html, defaultSignature?.name]);

  useEffect(() => {
    if (!editorRef.current) return;
    if ((editorRef.current.innerHTML || "").trim() !== contentHtml.trim()) {
      editorRef.current.innerHTML = contentHtml || "";
    }
  }, [contentHtml]);

  function saveSelection() {
    const editor = editorRef.current;
    const selection = window.getSelection();
    if (!editor || !selection?.rangeCount) return;
    const range = selection.getRangeAt(0);
    if (editor.contains(range.commonAncestorContainer)) {
      selectionRef.current = range.cloneRange();
    }
  }

  function restoreSelection() {
    const editor = editorRef.current;
    const range = selectionRef.current;
    editor?.focus();
    if (!range) return;
    const selection = window.getSelection();
    selection?.removeAllRanges();
    selection?.addRange(range);
  }

  function syncEditor() {
    const editor = editorRef.current;
    if (!editor) return;
    setContentHtml(editor.innerHTML);
    saveSelection();
  }

  function format(command: string, value?: string) {
    restoreSelection();
    document.execCommand(command, false, value);
    syncEditor();
  }

  function insertLink() {
    const href = window.prompt(t("compose.linkUrl"));
    if (!href) return;
    format("createLink", href);
  }

  function applyColor() {
    const color = window.prompt(t("compose.textColor"), "#0891b2");
    if (!color) return;
    format("foreColor", color);
  }

  return (
    <div className="grid gap-6">
      <section className="grid gap-3">
        <div className="flex flex-wrap items-center justify-between gap-3">
          <h3 className="font-black">{t("signature.title")}</h3>
        </div>
        {errorMessage ? <p className="text-sm font-bold text-red-600">{errorMessage}</p> : null}
        <div className="grid gap-2">
          <span className="text-sm font-bold text-slate-500">{t("signature.html")}</span>
          <div className="overflow-hidden rounded-xl border border-slate-200 bg-white shadow-sm">
            <div className="flex flex-wrap items-center gap-1 border-b border-slate-200 bg-slate-50 px-2 py-2">
              <FormatButton label={t("compose.bold")} onClick={() => format("bold")} icon={<Bold size={16} />} />
              <FormatButton label={t("compose.italic")} onClick={() => format("italic")} icon={<Italic size={16} />} />
              <FormatButton label={t("compose.underline")} onClick={() => format("underline")} icon={<Underline size={16} />} />
              <FormatButton label={t("compose.bulletedList")} onClick={() => format("insertUnorderedList")} icon={<List size={16} />} />
              <FormatButton label={t("compose.insertLink")} onClick={insertLink} icon={<Link size={16} />} />
              <ColorButton label={t("compose.textColor")} onChange={(color) => format("foreColor", color)} />
            </div>
            <div
              ref={editorRef}
              contentEditable
              suppressContentEditableWarning
              onInput={syncEditor}
              onMouseUp={saveSelection}
              onKeyUp={saveSelection}
              className="min-h-36 max-h-[340px] overflow-auto p-3 text-sm leading-6 outline-none empty:before:text-slate-400 empty:before:content-[attr(data-placeholder)] [&_a]:text-[var(--accent)] [&_a]:underline [&_li]:ml-5 [&_ul]:list-disc"
              data-placeholder={t("signature.placeholder")}
              role="textbox"
              aria-label={t("signature.html")}
              aria-multiline="true"
            />
          </div>
        </div>
        <p className="text-xs font-semibold text-slate-500">{t("signature.help")}</p>
        <div className="flex flex-wrap items-center justify-between gap-3">
          <button
            type="button"
            onClick={() => onSave({ content: "", content_html: contentHtml, content_type: "text/html" })}
            disabled={saving}
            className="theme-button h-10 px-4 disabled:opacity-60"
          >
            {saving ? t("common.saving") : t("signature.save")}
          </button>
          <div className="text-xs font-semibold text-slate-500">
            {loading && !defaultSignature ? t("signature.loading") : contentHtml.trim() ? t("signature.ready") : t("signature.none")}
          </div>
        </div>
      </section>
    </div>
  );
}

function FilterSettings({
  t,
  syncedEmail,
  rules,
  setRules,
  folders,
  loading,
  errorMessage,
  saving,
  onSave,
}: {
  t: ReturnType<typeof createTranslator>;
  syncedEmail: string;
  rules: MailFilterRule[];
  setRules: (value: MailFilterRule[] | ((current: MailFilterRule[]) => MailFilterRule[])) => void;
  folders: Folder[];
  loading: boolean;
  errorMessage: string;
  saving: boolean;
  onSave: (rules: MailFilterRule[]) => Promise<MailFilterRule[]>;
}) {
  const [draftRules, setDraftRules] = useState<MailFilterRule[]>(rules);
  const [editingRule, setEditingRule] = useState<MailFilterRule | null>(null);
  const [editingOriginId, setEditingOriginId] = useState("");
  const [notice, setNotice] = useState("");
  const editingRuleRef = useRef<MailFilterRule | null>(null);
  const editorNameRef = useRef<HTMLInputElement | null>(null);
  const editorFieldRef = useRef<HTMLSelectElement | null>(null);
  const editorOperatorRef = useRef<HTMLSelectElement | null>(null);
  const editorValueRef = useRef<HTMLInputElement | null>(null);
  const editorFolderRef = useRef<HTMLSelectElement | null>(null);
  const editorStopRef = useRef<HTMLInputElement | null>(null);
  const editorPanelRef = useRef<HTMLDivElement | null>(null);
  const rulesListRef = useRef<HTMLDivElement | null>(null);
  const folderOptions = useMemo(() => folders.map((folder) => ({ folder, label: displayFolder(folder.name) })), [folders]);
  const hasSavedRules = draftRules.some((rule) => rule.value.trim() && rule.target_folder_id.trim());
  const editingReady = Boolean(editingRule?.value.trim() && editingRule?.target_folder_id.trim());
  const canSave = Boolean(!saving && (editingRule ? editingReady : hasSavedRules));
  const filterFieldLabels: Record<MailFilterRule["field"], TranslationKey> = {
    from: "filters.fieldFrom",
    to: "filters.fieldTo",
    subject: "filters.fieldSubject",
    body: "filters.fieldBody",
  };
  const filterOperatorLabels: Record<MailFilterRule["operator"], TranslationKey> = {
    contains: "filters.operatorContains",
    equals: "filters.operatorEquals",
    starts_with: "filters.operatorStartsWith",
    ends_with: "filters.operatorEndsWith",
  };
  const translatedRuleName = (rule: MailFilterRule | null | undefined, index?: number) => rule?.name || t("filters.ruleNumber", { number: typeof index === "number" ? index + 1 : 1 });
  const translatedField = (field: MailFilterRule["field"]) => t(filterFieldLabels[field] || "filters.fieldFrom");
  const translatedOperator = (operator: MailFilterRule["operator"]) => t(filterOperatorLabels[operator] || "filters.operatorContains");

  useEffect(() => {
    setDraftRules(rules);
  }, [rules]);

  useEffect(() => {
    if (!editingRule) return;
    editorPanelRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
    window.setTimeout(() => editorNameRef.current?.focus(), 50);
  }, [editingRule?.id]);

  useEffect(() => {
    editingRuleRef.current = editingRule;
  }, [editingRule]);

  function syncEditingRule(patch: Partial<MailFilterRule>) {
    setEditingRule((current) => {
      const next = current ? { ...current, ...patch } : current;
      editingRuleRef.current = next;
      return next;
    });
  }

  function readEditingRuleSnapshot() {
    const current = editingRuleRef.current || editingRule;
    if (!current) return null;
    const folderValue = editorFolderRef.current?.value ?? current.target_folder_id;
    const folder = folders.find((item) => item.path === folderValue || item.abs_path === folderValue);
    return {
      ...current,
      name: editorNameRef.current?.value ?? current.name,
      field: (editorFieldRef.current?.value ?? current.field) as MailFilterRule["field"],
      operator: (editorOperatorRef.current?.value ?? current.operator) as MailFilterRule["operator"],
      value: editorValueRef.current?.value ?? current.value,
      target_folder_id: folderValue,
      target_folder_name: folder ? displayFolder(folder.name) : current.target_folder_name,
      stop_processing: editorStopRef.current ? editorStopRef.current.checked : current.stop_processing,
    } as MailFilterRule;
  }

  function addRule() {
    const nextRule = createFilterRuleDraft(draftRules.length, folders[0]);
    editingRuleRef.current = nextRule;
    setEditingRule(nextRule);
    setEditingOriginId("");
    setNotice(t("filters.noticeEditorOpened"));
  }

  function duplicateRule(index: number) {
    setDraftRules((current) => {
      const source = current[index];
      if (!source) return current;
      const clone = {
        ...source,
        id: `filter-${Date.now()}-${current.length}-${Math.random().toString(36).slice(2, 8)}`,
        name: t("filters.copyName", { name: source.name || t("filters.ruleNumber", { number: index + 1 }) }),
        order: current.length,
      };
      return [...current, clone];
    });
  }

  async function persistRules(
    nextRules: MailFilterRule[],
    options: { emptyMessage?: string; successMessage?: string; allowEmpty?: boolean } = {}
  ) {
    const normalized = dedupeRules(normalizeFilterRules(nextRules, folders));
    if (!normalized.length && !options.allowEmpty) {
      setNotice(options.emptyMessage || t("filters.noRulesToSave"));
      return [];
    }
    try {
      setNotice(options.successMessage || t("common.saving"));
      const savedRules = await onSave(normalized);
      setDraftRules(savedRules);
      setRules(savedRules);
      setNotice(
        savedRules.length
          ? t("filters.savedRules", { count: savedRules.length, names: savedRules
              .slice(0, 3)
              .map((rule) => rule.name || t("filters.untitledRule"))
              .join(", "), more: savedRules.length > 3 ? "..." : "" })
          : t("filters.savedNoRules")
      );
      window.setTimeout(() => rulesListRef.current?.scrollIntoView({ behavior: "smooth", block: "start" }), 0);
      return savedRules;
    } catch (error) {
      setNotice(error instanceof Error ? error.message : t("filters.failedSave"));
      throw error;
    }
  }

  async function removeRule(index: number) {
    const currentRule = draftRules[index];
    const next = draftRules
      .filter((_, currentIndex) => currentIndex !== index)
      .map((rule, currentIndex) => ({ ...rule, order: currentIndex }));
    setDraftRules(next);
    if (currentRule?.id === editingOriginId) {
      editingRuleRef.current = null;
      setEditingRule(null);
      setEditingOriginId("");
    }
    await persistRules(next, {
      allowEmpty: true,
      emptyMessage: t("filters.deletingRule"),
      successMessage: t("filters.deletingRule"),
    });
  }

  function moveRule(index: number, direction: -1 | 1) {
    setDraftRules((current) => {
      const target = index + direction;
      if (target < 0 || target >= current.length) return current;
      const next = [...current];
      const [item] = next.splice(index, 1);
      next.splice(target, 0, item);
      return next.map((rule, currentIndex) => ({ ...rule, order: currentIndex }));
    });
  }

  function ruleSignature(rule: MailFilterRule) {
    return [
      rule.name.trim().toLowerCase(),
      rule.field.trim().toLowerCase(),
      rule.operator.trim().toLowerCase(),
      rule.value.trim().toLowerCase(),
      rule.target_folder_id.trim(),
    ].join("|");
  }

  function upsertRule(current: MailFilterRule[], incoming: MailFilterRule, preferExistingId = true) {
    const next = [...current];
    const normalizedIncoming = normalizeFilterRules([incoming], folders)[0];
    if (!normalizedIncoming) return current;
    const existingIndexById = next.findIndex((rule) => rule.id === normalizedIncoming.id);
    if (existingIndexById >= 0) {
      next[existingIndexById] = { ...normalizedIncoming, id: next[existingIndexById].id, order: existingIndexById };
      return next.map((rule, index) => ({ ...rule, order: index }));
    }
    const existingIndexBySignature = next.findIndex((rule) => ruleSignature(rule) === ruleSignature(normalizedIncoming));
    if (existingIndexBySignature >= 0) {
      const preservedId = preferExistingId ? next[existingIndexBySignature].id : normalizedIncoming.id;
      next[existingIndexBySignature] = { ...normalizedIncoming, id: preservedId, order: existingIndexBySignature };
      return next.map((rule, index) => ({ ...rule, order: index }));
    }
    next.unshift(normalizedIncoming);
    return next.map((rule, index) => ({ ...rule, order: index }));
  }

  function dedupeRules(rules: MailFilterRule[]) {
    const seen = new Set<string>();
    const deduped: MailFilterRule[] = [];
    for (const rule of rules) {
      const signature = ruleSignature(rule);
      if (seen.has(signature)) continue;
      seen.add(signature);
      deduped.push(rule);
    }
    return deduped.map((rule, index) => ({ ...rule, order: index }));
  }

  function commitEditingRule() {
    const snapshot = readEditingRuleSnapshot();
    if (!snapshot) return false;
    const normalizedEditing = normalizeFilterRules([snapshot], folders)[0];
    if (!normalizedEditing) {
      setNotice(t("filters.fillRuleBeforeAdding"));
      return false;
    }
    setDraftRules((current) => upsertRule(current, { ...normalizedEditing, id: editingOriginId || normalizedEditing.id }, true));
    setNotice(editingOriginId ? t("filters.ruleUpdated") : t("filters.ruleAdded"));
    setEditingRule(normalizedEditing);
    editingRuleRef.current = normalizedEditing;
    setEditingOriginId(editingOriginId || normalizedEditing.id);
    return true;
  }

  async function saveRules() {
    const liveEditingRule = readEditingRuleSnapshot();
    let nextRules = [...draftRules];
    if (liveEditingRule) {
      const normalizedEditing = normalizeFilterRules([liveEditingRule], folders)[0];
      if (!normalizedEditing) {
        setNotice(
          t("filters.finishOpenRule", { value: liveEditingRule.value || "", folder: liveEditingRule.target_folder_id || "" })
        );
        return;
      }
      nextRules = upsertRule(nextRules, { ...normalizedEditing, id: editingOriginId || normalizedEditing.id }, true);
    }
    const savedRules = await persistRules(nextRules, {
      emptyMessage: liveEditingRule ? t("filters.noRulesToSaveWithDetail", { value: liveEditingRule.value || "", folder: liveEditingRule.target_folder_id || "" }) : t("filters.noRulesToSave"),
    });
    if (savedRules.length && liveEditingRule) {
      const savedRule = normalizeFilterRules([liveEditingRule], folders)[0];
      if (savedRule) {
        setEditingRule(savedRule);
        editingRuleRef.current = savedRule;
        setEditingOriginId(editingOriginId || savedRule.id);
      }
    }
  }

  async function clearAllRules() {
    try {
      const savedRules = await persistRules([], {
        allowEmpty: true,
        emptyMessage: t("filters.clearingRules"),
        successMessage: t("filters.clearingRules"),
      });
      editingRuleRef.current = null;
      setEditingRule(null);
      setEditingOriginId("");
      setDraftRules(savedRules);
      setRules(savedRules);
      setNotice(t("filters.allRemoved"));
      window.setTimeout(() => rulesListRef.current?.scrollIntoView({ behavior: "smooth", block: "start" }), 0);
    } catch (error) {
      setNotice(error instanceof Error ? error.message : t("filters.failedClear"));
    }
  }

  const editorTitle = editingOriginId ? t("filters.editingRule") : t("filters.newRule");

  return (
    <div className="grid gap-5">
      <section className="grid gap-4 rounded-xl border border-slate-200 p-4">
        <div className="flex flex-wrap items-center justify-between gap-3">
          <div className="grid gap-1">
            <h3 className="font-black">{t("filters.title")}</h3>
            <p className="max-w-2xl text-sm leading-6 text-slate-500">
              {t("filters.help")}
            </p>
            <p className="text-xs font-bold uppercase tracking-[0.14em] text-slate-400">
              {t("filters.configuredCount", { count: draftRules.length })}
            </p>
          </div>
          <div className="flex flex-wrap gap-2">
            <button type="button" onClick={addRule} className="theme-button-soft h-10 px-4">
              <Plus size={16} />
              {t("filters.addRule")}
            </button>
          </div>
        </div>
        {notice ? <div className="rounded-lg border border-[color-mix(in_srgb,var(--accent)_18%,white)] bg-[color-mix(in_srgb,var(--accent)_7%,white)] px-4 py-3 text-sm font-semibold text-[var(--accent)]">{notice}</div> : null}
        {errorMessage ? <p className="text-sm font-bold text-red-600">{errorMessage}</p> : null}
        {loading ? <p className="text-sm font-semibold text-slate-500">{t("common.loading")}</p> : null}

        <div ref={editorPanelRef} className={clsx("grid gap-4 rounded-xl border p-4 transition", editingRule ? "border-[var(--accent)] bg-[color-mix(in_srgb,var(--accent)_6%,white)] shadow-sm" : "border-dashed border-slate-200 bg-slate-50")}>
          {editingRule ? (
            <>
              <div className="flex flex-wrap items-center justify-between gap-3">
                <div className="grid gap-1">
                  <p className="text-xs font-black uppercase tracking-[0.14em] text-[var(--accent)]">{editorTitle}</p>
                  <p className="text-sm font-semibold text-slate-700">{editingRule.name || t("filters.untitledRule")}</p>
                </div>
                <div className="flex flex-wrap gap-2">
                  <button type="button" onClick={saveRules} className="theme-button h-9 px-3 text-xs disabled:opacity-50" disabled={!editingReady && !hasSavedRules}>
                    <Check size={14} />
                    {t("common.save")}
                  </button>
                  <button
                    type="button"
                    onClick={() => {
                      editingRuleRef.current = null;
                      setEditingRule(null);
                      setEditingOriginId("");
                      setNotice(t("filters.editorClosed"));
                    }}
                    className="theme-button-soft h-9 px-3 text-xs"
                  >
                    <X size={14} />
                    {t("common.cancel")}
                  </button>
                </div>
              </div>
                <input
                  ref={editorNameRef}
                  value={editingRule.name}
                  onChange={(event) => syncEditingRule({ name: event.target.value })}
                  className="field h-10"
                  placeholder={t("filters.ruleName")}
                />
              <div className="grid gap-3 lg:grid-cols-[160px_160px_1fr]">
                <label className="grid gap-2 text-sm font-bold text-slate-500">
                  {t("filters.field")}
                  <select
                    ref={editorFieldRef}
                    value={editingRule.field}
                    onChange={(event) => syncEditingRule({ field: event.target.value as MailFilterRule["field"] })}
                    className="field h-10"
                  >
                    <option value="from">{t("filters.fieldFrom")}</option>
                    <option value="to">{t("filters.fieldTo")}</option>
                    <option value="subject">{t("filters.fieldSubject")}</option>
                    <option value="body">{t("filters.fieldBody")}</option>
                  </select>
                </label>
                <label className="grid gap-2 text-sm font-bold text-slate-500">
                  {t("filters.match")}
                  <select
                    ref={editorOperatorRef}
                    value={editingRule.operator}
                    onChange={(event) => syncEditingRule({ operator: event.target.value as MailFilterRule["operator"] })}
                    className="field h-10"
                  >
                    <option value="contains">{t("filters.operatorContains")}</option>
                    <option value="equals">{t("filters.operatorEquals")}</option>
                    <option value="starts_with">{t("filters.operatorStartsWith")}</option>
                    <option value="ends_with">{t("filters.operatorEndsWith")}</option>
                  </select>
                </label>
                <label className="grid gap-2 text-sm font-bold text-slate-500">
                  {t("filters.value")}
                  <input
                    ref={editorValueRef}
                    value={editingRule.value}
                    onChange={(event) => syncEditingRule({ value: event.target.value })}
                    className="field h-10"
                    placeholder={t("filters.valuePlaceholder")}
                  />
                </label>
              </div>
              <div className="rounded-lg border border-slate-200 bg-white px-3 py-2 text-xs font-semibold leading-5 text-slate-500">
                {t("filters.previewPrefix")}{" "}
                <span className="font-black text-slate-700">{translatedField(editingRule.field)}</span> {translatedOperator(editingRule.operator)}{" "}
                <span className="font-black text-slate-700">"{editingRule.value || "..." }"</span>, {t("filters.moveTo")}{" "}
                <span className="font-black text-slate-700">{editingRule.target_folder_name || displayFolder(editingRule.target_folder_id) || "..."}</span>
                {editingRule.target_folder_id ? <span className="ml-2 text-slate-400">({editingRule.target_folder_id})</span> : null}
              </div>
              <div className="grid gap-3 lg:grid-cols-[1fr_180px]">
                <label className="grid gap-2 text-sm font-bold text-slate-500">
                  {t("filters.moveToFolder")}
                  <select
                    ref={editorFolderRef}
                    value={editingRule.target_folder_id}
                    onChange={(event) => {
                      const folder = folders.find((item) => item.path === event.target.value || item.abs_path === event.target.value);
                      syncEditingRule({
                        target_folder_id: event.target.value,
                        target_folder_name: folder ? displayFolder(folder.name) : "",
                      });
                    }}
                    className="field h-10"
                    disabled={!folders.length}
                  >
                    <option value="">{t("filters.selectFolder")}</option>
                    {folderOptions.map(({ folder, label }) => (
                      <option key={folder.abs_path || folder.path} value={folder.abs_path || folder.path}>
                        {label}
                      </option>
                    ))}
                  </select>
                </label>
                <label className="flex items-center justify-between rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-bold text-slate-700">
                  {t("filters.stopAfterMatch")}
                  <input
                    ref={editorStopRef}
                    type="checkbox"
                    checked={editingRule.stop_processing}
                    onChange={(event) => syncEditingRule({ stop_processing: event.target.checked })}
                    className="h-4 w-4 rounded border-slate-300 text-[var(--accent)]"
                  />
                </label>
              </div>
            </>
          ) : (
            <div className="flex flex-wrap items-center justify-between gap-3">
              <div className="grid gap-1">
                <p className="text-xs font-black uppercase tracking-[0.14em] text-slate-400">{t("filters.ruleEditor")}</p>
              <p className="text-sm font-semibold text-slate-500">{t("filters.editorHelp")}</p>
              </div>
            </div>
          )}
        </div>

        {!loading && !draftRules.length && !editingRule ? (
          <div className="rounded-lg border border-dashed border-slate-200 bg-slate-50 p-4 text-sm font-semibold text-slate-500">
            {t("filters.noMessageRules")}
          </div>
        ) : null}

        <div ref={rulesListRef} className="grid gap-3">
          <div className="flex flex-wrap items-center justify-between gap-3">
            <div className="grid gap-1">
              <p className="text-xs font-black uppercase tracking-[0.14em] text-slate-400">{t("filters.savedRulesTitle")}</p>
              <p className="text-sm font-semibold text-slate-500">
                {draftRules.length ? t("filters.readyToRun", { count: draftRules.length }) : t("filters.noSavedRules")}
              </p>
            </div>
            {draftRules.length ? (
              <div className="flex flex-wrap gap-2">
                {draftRules.slice(0, 4).map((rule) => (
                  <span key={rule.id} className="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold text-slate-600">
                    {rule.name || t("filters.untitledRule")}
                  </span>
                ))}
                {draftRules.length > 4 ? (
                  <span className="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold text-slate-600">
                    +{draftRules.length - 4}
                  </span>
                ) : null}
              </div>
            ) : null}
          </div>
          {draftRules.length ? null : (
            <div className="rounded-lg border border-dashed border-slate-200 bg-slate-50 p-4 text-sm font-semibold text-slate-500">
              {t("filters.noSavedRulesHelp")} <span className="text-slate-700">{t("common.save")}</span>.
            </div>
          )}
          {draftRules.map((rule, index) => {
            const isEditingSource = editingOriginId === rule.id;
            return (
              <div
                key={rule.id}
                className={clsx(
                  "grid gap-4 rounded-xl border p-4 transition",
                  isEditingSource ? "border-[var(--accent)] bg-[color-mix(in_srgb,var(--accent)_6%,white)] shadow-sm" : rule.enabled ? "border-slate-200 bg-white" : "border-slate-200 bg-slate-50 opacity-80"
                )}
              >
                <div className="flex flex-wrap items-start justify-between gap-3">
                  <label className="inline-flex items-center gap-3 text-sm font-bold text-slate-700">
                    <input
                      type="checkbox"
                      checked={rule.enabled}
                      onChange={(event) => {
                        setDraftRules((current) => current.map((item, currentIndex) => (currentIndex === index ? { ...item, enabled: event.target.checked } : item)));
                      }}
                      className="h-4 w-4 rounded border-slate-300 text-[var(--accent)]"
                    />
                    <span className="uppercase tracking-[0.12em] text-slate-400">{t("filters.ruleNumber", { number: index + 1 })}</span>
                  </label>
                  <div className="flex flex-wrap gap-2">
                    <button
                      type="button"
                      onClick={() => {
                        setEditingRule({ ...rule });
                        setEditingOriginId(rule.id);
                        setNotice(t("filters.editingNotice", { name: rule.name || t("filters.ruleNumber", { number: index + 1 }) }));
                      }}
                      className="theme-button-soft h-9 px-3 text-xs"
                    >
                      {t("common.edit")}
                    </button>
                    <button type="button" onClick={() => duplicateRule(index)} className="theme-button-soft h-9 px-3 text-xs">
                      {t("filters.duplicate")}
                    </button>
                    <button type="button" onClick={() => moveRule(index, -1)} disabled={index === 0} className="theme-button-soft h-9 px-3 text-xs disabled:opacity-50">
                      {t("filters.up")}
                    </button>
                    <button type="button" onClick={() => moveRule(index, 1)} disabled={index === draftRules.length - 1} className="theme-button-soft h-9 px-3 text-xs disabled:opacity-50">
                      {t("filters.down")}
                    </button>
                    <button type="button" onClick={() => void removeRule(index)} className="theme-button-soft h-9 px-3 text-xs text-red-700 hover:bg-red-50">
                      {t("common.delete")}
                    </button>
                  </div>
                </div>
                <div className="grid gap-2">
                  <p className="text-base font-semibold text-slate-900">{rule.name || t("filters.ruleNumber", { number: index + 1 })}</p>
                  <p className="text-sm leading-6 text-slate-600">
                    {t("filters.previewPrefix")} <span className="font-semibold text-slate-900">{translatedField(rule.field)}</span> {translatedOperator(rule.operator)}{" "}
                    <span className="font-semibold text-slate-900">"{rule.value}"</span>, {t("filters.moveTo")}{" "}
                    <span className="font-semibold text-slate-900">{rule.target_folder_name || displayFolder(rule.target_folder_id)}</span>.
                  </p>
                  <p className="text-xs font-semibold text-slate-400">
                    {t("filters.folderId")} <span className="text-slate-600">{rule.target_folder_id || t("filters.notSet")}</span>
                  </p>
                  <div className="flex flex-wrap gap-2 text-xs font-semibold text-slate-500">
                    <span className="rounded-full bg-slate-100 px-2.5 py-1">{rule.enabled ? t("filters.enabled") : t("filters.disabled")}</span>
                    <span className="rounded-full bg-slate-100 px-2.5 py-1">{rule.stop_processing ? t("filters.stopAfterMatch") : t("filters.continueMatching")}</span>
                  </div>
                </div>
              </div>
            );
          })}
        </div>

        <div className="flex flex-wrap items-center justify-between gap-3">
          <p className="text-xs font-semibold leading-5 text-slate-500">
            {t("filters.supportedConditions")}
          </p>
          <div className="flex flex-wrap gap-2">
            <button type="button" onClick={clearAllRules} className="theme-button-soft h-10 px-4">
              {t("filters.clearAll")}
            </button>
            <button type="button" onClick={saveRules} disabled={!canSave} className="theme-button h-10 px-4 disabled:opacity-50">
              {saving ? t("common.saving") : t("filters.saveRules")}
            </button>
          </div>
        </div>
      </section>
    </div>
  );
}

function SettingsTab({ icon, label, active, onClick }: { icon: React.ReactNode; label: string; active: boolean; onClick: () => void }) {
  return (
    <button onClick={onClick} className={clsx("flex h-11 shrink-0 items-center gap-2 rounded-lg px-3 text-left text-sm font-bold transition lg:mb-1 lg:h-10 lg:w-full lg:gap-3", active ? "bg-[color-mix(in_srgb,var(--accent)_8%,white)] text-slate-950 shadow-sm" : "text-slate-500 hover:bg-white")}>
      {icon}
      <span className="whitespace-nowrap">{label}</span>
    </button>
  );
}

type ShareResourceKind = "mail" | "contact" | "calendar" | "task" | "briefcase";

function ShareResourceIcon({ kind, tone = "default" }: { kind: ShareResourceKind; tone?: "default" | "danger" }) {
  const className = clsx(
    "grid h-8 w-8 shrink-0 place-items-center rounded-lg",
    tone === "danger" ? "bg-white/70 text-rose-700" : "bg-slate-100 text-slate-600"
  );
  return (
    <span className={className} aria-hidden="true">
      {kind === "calendar" ? (
        <span className="relative grid h-5 w-5 place-items-center">
          <CalendarDays size={16} />
          <span className={clsx("absolute -bottom-0.5 -right-0.5 grid h-3 w-3 place-items-center rounded-full shadow-sm", tone === "danger" ? "bg-rose-50 text-rose-700" : "bg-white text-slate-600")}>
            <Share2 size={8} />
          </span>
        </span>
      ) : kind === "contact" ? <UserPlus size={16} /> : kind === "task" ? <ListTodo size={16} /> : kind === "briefcase" ? <FolderIcon size={16} /> : <MailOpen size={16} />}
    </span>
  );
}

function SharingSummaryCard({ title, icon, count, detail }: { title: string; icon: React.ReactNode; count: number; detail: string }) {
  return (
    <div className="grid gap-3 rounded-lg border border-slate-200 bg-white p-4">
      <div className="flex items-center justify-between gap-3">
        <div className="grid h-9 w-9 place-items-center rounded-lg bg-slate-100 text-slate-600">
          {icon}
        </div>
        <span className="rounded-full bg-[color-mix(in_srgb,var(--accent)_10%,white)] px-2.5 py-1 text-xs font-black text-[var(--accent)]">{count}</span>
      </div>
      <div>
        <p className="text-sm font-black text-slate-900">{title}</p>
        <p className="mt-1 text-xs font-semibold text-slate-500">{detail}</p>
      </div>
    </div>
  );
}

function ContactsManager({
  t,
  contacts,
  autocompleteContacts,
  folders,
  selectedFolderId,
  onSelectFolder,
  loading = false,
  canShareFolders = true,
  shareBadge,
  shareTooltip,
  onCompose
}: {
  t: ReturnType<typeof createTranslator>;
  contacts: Contact[];
  autocompleteContacts: Contact[];
  folders: ContactFolder[];
  selectedFolderId: string;
  onSelectFolder: (folderId: string) => void;
  loading?: boolean;
  canShareFolders?: boolean;
  shareBadge?: string;
  shareTooltip?: string;
  onCompose: (email: string, fullName: string) => void;
}) {
  const queryClient = useQueryClient();
  const emptyDraft = { full_name: "", email: "", company: "", phone: "", notes: "" };
  const [draft, setDraft] = useState(emptyDraft);
  const [photoFile, setPhotoFile] = useState<File | null>(null);
  const [photoPreview, setPhotoPreview] = useState("");
  const [removePhoto, setRemovePhoto] = useState(false);
  const [photoBusy, setPhotoBusy] = useState(false);
  const [editingId, setEditingId] = useState("");
  const [contactFormOpen, setContactFormOpen] = useState(false);
  const contactFormRef = useRef<HTMLElement | null>(null);
  const [searchTerm, setSearchTerm] = useState("");
  const [formError, setFormError] = useState("");
  const [contactToDelete, setContactToDelete] = useState<Contact | null>(null);
  const [folderEditor, setFolderEditor] = useState<{ mode: "create" | "rename"; folder?: ContactFolder } | null>(null);
  const [folderToDelete, setFolderToDelete] = useState<ContactFolder | null>(null);
  const [newContactFolderName, setNewContactFolderName] = useState("");
  const [actionMenuContactFolderId, setActionMenuContactFolderId] = useState("");
  const [colorContactFolderId, setColorContactFolderId] = useState("");
  const [shareContactFolderId, setShareContactFolderId] = useState("");
  const [shareEmail, setShareEmail] = useState("");
  const [sharePermissions, setSharePermissions] = useState("r");
  const [mergeSummary, setMergeSummary] = useState("");
  const [mergeSummaryTone, setMergeSummaryTone] = useState<"success" | "error">("success");
  const [mergePending, setMergePending] = useState(false);
  const createContact = useMutation({
    mutationFn: api.createContact,
    onSuccess: async () => {
      setDraft(emptyDraft);
      setFormError("");
      await queryClient.invalidateQueries({ queryKey: ["contacts"] });
    }
  });
  const updateContact = useMutation({
    mutationFn: ({ contactId, payload }: { contactId: string; payload: typeof emptyDraft }) => api.updateContact(contactId, payload),
    onSuccess: async () => {
      setDraft(emptyDraft);
      setEditingId("");
      setFormError("");
      await queryClient.invalidateQueries({ queryKey: ["contacts"] });
    }
  });
  const deleteContact = useMutation({
    mutationFn: api.deleteContact,
    onSuccess: async (_data, contactId) => {
      setContactToDelete(null);
      if (contactId === editingId) resetDraft();
      await queryClient.invalidateQueries({ queryKey: ["contacts"] });
    }
  });
  const createFolder = useMutation({
    mutationFn: api.createContactFolder,
    onSuccess: async (data, name) => {
      setFolderEditor(null);
      setNewContactFolderName("");
      await queryClient.invalidateQueries({ queryKey: ["contact-folders"] });
      const created = data.folders.find((folder) => folder.name.trim().toLowerCase() === name.trim().toLowerCase());
      if (created?.id) onSelectFolder(created.id);
    }
  });
  const renameFolder = useMutation({
    mutationFn: ({ folderId, name }: { folderId: string; name: string }) => api.renameContactFolder(folderId, name),
    onSuccess: async () => {
      setFolderEditor(null);
      await queryClient.invalidateQueries({ queryKey: ["contact-folders"] });
    }
  });
  const deleteFolder = useMutation({
    mutationFn: api.deleteContactFolder,
    onSuccess: async (data, folderId) => {
      setFolderToDelete(null);
      await queryClient.invalidateQueries({ queryKey: ["contact-folders"] });
      await queryClient.invalidateQueries({ queryKey: ["contacts"] });
      if (folderId === selectedFolderId) {
        const fallback = data.folders.find((folder) => folder.abs_path === "/Contacts")?.id ?? data.folders[0]?.id ?? "";
        if (fallback) onSelectFolder(fallback);
      }
    }
  });
  const updateFolderColor = useMutation({
    mutationFn: ({ folderId, color, rgb }: { folderId: string; color: number; rgb: string }) => api.updateContactFolderColor(folderId, { color, rgb }),
    onSuccess: async () => {
      await queryClient.invalidateQueries({ queryKey: ["contact-folders"] });
    }
  });
  const shareFolder = useMutation({
    mutationFn: ({ folderId, email, permissions }: { folderId: string; email: string; permissions: string }) => api.shareContactFolder(folderId, { email, permissions }),
    onSuccess: async () => {
      setShareEmail("");
      await queryClient.invalidateQueries({ queryKey: ["contact-folders"] });
    }
  });
  const revokeFolderShare = useMutation({
    mutationFn: ({ folderId, email }: { folderId: string; email: string }) => api.revokeContactFolderShare(folderId, { email }),
    onSuccess: async () => {
      await queryClient.invalidateQueries({ queryKey: ["contact-folders"] });
    }
  });

  function resetDraft() {
    setDraft(emptyDraft);
    setPhotoFile(null);
    setPhotoPreview("");
    setRemovePhoto(false);
    setEditingId("");
    setContactFormOpen(false);
    setFormError("");
  }

  function showContactForm() {
    setContactFormOpen(true);
    window.requestAnimationFrame(() => {
      contactFormRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
    });
  }

  function startNewContact() {
    setDraft(emptyDraft);
    setPhotoFile(null);
    setPhotoPreview("");
    setRemovePhoto(false);
    setEditingId("");
    setFormError("");
    showContactForm();
  }

  function choosePhoto(file: File | undefined) {
    if (!file) return;
    if (!file.type.startsWith("image/")) {
      setFormError(t("contacts.photoImageError"));
      return;
    }
    setPhotoFile(file);
    setPhotoPreview(URL.createObjectURL(file));
    setRemovePhoto(false);
    setFormError("");
  }

  async function saveContact() {
    const email = safeText(draft.email).trim();
    if (!email) return;
    const normalizedEmail = email.toLowerCase();
    const duplicate = contacts.find((contact) => safeText(contact.email).trim().toLowerCase() === normalizedEmail && contact.id !== editingId);
    if (duplicate) {
      setFormError(t("contacts.duplicate", { email }));
      return;
    }
    const contactId = editingId;
    setPhotoBusy(true);
    try {
      const result = contactId
        ? await updateContact.mutateAsync({ contactId, payload: draft })
        : await createContact.mutateAsync({ ...draft, folder_id: selectedFolderId });
      if (photoFile) {
        await api.uploadContactPhoto(result.contact.id, photoFile);
      } else if (removePhoto && contactId) {
        await api.deleteContactPhoto(contactId);
      }
      await queryClient.invalidateQueries({ queryKey: ["contacts"] });
      resetDraft();
    } catch (error) {
      setFormError(error instanceof Error ? error.message : "Unable to save contact photo");
    } finally {
      setPhotoBusy(false);
    }
  }

  const busy = createContact.isPending || updateContact.isPending || photoBusy;
  const normalizedSearch = searchTerm.trim().toLowerCase();
  const duplicateGroups = groupContactsByEmail(contacts).filter((group) => group.length > 1);
  const filteredContacts = normalizedSearch
    ? contacts.filter((contact) =>
        [contact.full_name, contact.email, contact.company, contact.phone, contact.notes]
          .map(safeText)
          .join(" ")
          .toLowerCase()
          .includes(normalizedSearch)
      )
    : contacts;
  const selectedFolder = folders.find((item) => item.id === selectedFolderId) ?? folders[0] ?? null;
  const shareContactFolder = folders.find((item) => item.id === shareContactFolderId) ?? null;
  const folderActionBusy = createFolder.isPending || renameFolder.isPending || deleteFolder.isPending || updateFolderColor.isPending || shareFolder.isPending || revokeFolderShare.isPending;

  async function mergeDuplicates() {
    if (!duplicateGroups.length || mergePending) return;
    setMergePending(true);
    setMergeSummary("");
    setMergeSummaryTone("success");
    try {
      let removed = 0;
      for (const group of duplicateGroups) {
        const primary = [...group].sort((left, right) => contactCompleteness(right) - contactCompleteness(left))[0];
        const merged = mergeContacts(primary, group);
        await api.updateContact(primary.id, {
          full_name: merged.full_name,
          email: merged.email,
          company: merged.company,
          notes: merged.notes,
          phone: merged.phone,
        });
        const duplicates = group.filter((item) => item.id !== primary.id);
        for (const duplicate of duplicates) {
          await api.deleteContact(duplicate.id);
          removed += 1;
        }
      }
      setMergeSummary(t("contacts.mergeSummary", {
        groups: duplicateGroups.length,
        groupSuffix: duplicateGroups.length === 1 ? "" : "s",
        removed,
        contactSuffix: removed === 1 ? "" : "s",
      }));
      setMergeSummaryTone("success");
      await queryClient.invalidateQueries({ queryKey: ["contacts"] });
    } catch (error) {
      setMergeSummaryTone("error");
      setMergeSummary(error instanceof Error ? error.message : t("contacts.mergeFailed"));
    } finally {
      setMergePending(false);
    }
  }

  return (
    <div className="control-surface grid gap-3 rounded-xl p-3 sm:p-3 xl:grid-cols-[minmax(0,1fr)_320px]">
      <div className="grid min-w-0 gap-3">
      <section className="grid gap-3 rounded-xl border border-slate-200 p-3">
        {folders.length ? (
          <label className="grid gap-1.5 xl:hidden">
            <span className="text-xs font-black uppercase tracking-[0.12em] text-slate-500">{t("contacts.folder")}</span>
            <select
              value={selectedFolderId}
              onChange={(event) => onSelectFolder(event.target.value)}
              className="field h-11 w-full bg-white"
            >
              {folders.map((folder) => (
                <option key={folder.id} value={folder.id}>
                  {displayFolder(folder.name)}
                </option>
              ))}
            </select>
          </label>
        ) : null}
        <div className="flex flex-wrap items-center justify-between gap-3">
          <h3 className="font-black">{t("contacts.listTitle")}</h3>
          <div className="flex flex-wrap items-center gap-3">
            <span className="text-sm font-semibold text-slate-500">{t("contacts.shown", { count: filteredContacts.length })}</span>
            <button
              type="button"
              onClick={startNewContact}
              className="theme-button h-10 px-3 text-sm sm:h-9"
            >
              <UserPlus size={14} />
              {t("contacts.new")}
            </button>
            <button
              type="button"
              onClick={() => void mergeDuplicates()}
              disabled={!duplicateGroups.length || mergePending}
              className={clsx(
                "theme-button-soft h-10 px-3 text-sm disabled:opacity-50 sm:h-9 xl:inline-flex",
                duplicateGroups.length || mergePending ? "inline-flex" : "hidden"
              )}
            >
              <Users size={14} />
              {mergePending ? t("contacts.merging") : `${t("contacts.mergeDuplicates")}${duplicateGroups.length ? ` (${duplicateGroups.length})` : ""}`}
            </button>
          </div>
        </div>
        <div className="relative">
            <input
              value={searchTerm}
              onChange={(event) => setSearchTerm(event.target.value)}
              className="field h-10 w-full pr-10"
              placeholder="Search contacts"
            />
          {searchTerm ? (
            <button
              type="button"
              onClick={() => setSearchTerm("")}
              className="absolute right-2 top-1/2 inline-flex h-7 w-7 -translate-y-1/2 items-center justify-center rounded-full text-slate-400 transition hover:bg-slate-200 hover:text-slate-700"
              aria-label={t("contacts.clearSearch")}
              title={t("contacts.clearSearch")}
            >
              <X size={14} />
            </button>
          ) : null}
        </div>
        {mergeSummary ? <p className={`text-sm font-semibold ${mergeSummaryTone === "success" ? "text-emerald-700" : "text-red-600"}`}>{mergeSummary}</p> : null}
        {loading && !contacts.length ? <div className="rounded-lg border border-slate-200 p-4 text-sm font-semibold text-slate-500">{t("contacts.loading")}</div> : null}
        {!loading && !contacts.length ? <div className="rounded-lg border border-slate-200 p-4 text-sm font-semibold text-slate-500">{t("contacts.empty")}</div> : null}
        {!loading && contacts.length > 0 && !filteredContacts.length ? <div className="rounded-lg border border-slate-200 p-4 text-sm font-semibold text-slate-500">{t("contacts.noMatch")}</div> : null}
        <div className="grid gap-2">
        {filteredContacts.map((contact) => (
          <div key={contact.id} className="grid gap-3 rounded-xl border border-slate-200 p-3 sm:grid-cols-[auto_1fr_auto] sm:items-center sm:p-4">
                <ContactAvatar value={safeText(contact.full_name) || safeText(contact.email)} photoUrl={safeText(contact.photo_url)} />
            <div className="min-w-0">
              <strong className="block truncate">{safeText(contact.full_name) || safeText(contact.email)}</strong>
              <span className="block truncate text-sm text-slate-500">
                {safeText(contact.email)}
                {safeText(contact.company) ? ` - ${safeText(contact.company)}` : ""}
                {safeText(contact.phone) ? ` - ${safeText(contact.phone)}` : ""}
              </span>
              {safeText(contact.notes) ? <span className="mt-1 block truncate text-sm text-slate-400">{safeText(contact.notes)}</span> : null}
            </div>
            <div className="grid grid-cols-[1fr_auto_auto] items-center gap-2 sm:flex">
              <button
                onClick={() => onCompose(safeText(contact.email), safeText(contact.full_name))}
                className="theme-button-soft h-10 px-3 text-sm sm:h-9"
                aria-label={t("contacts.composeTo", { email: safeText(contact.email) })}
              >
                <Send size={14} />
                {t("contacts.mail")}
              </button>
              <button
                onClick={() => {
                  setEditingId(contact.id);
                  setDraft({
                    full_name: safeText(contact.full_name),
                    email: safeText(contact.email),
                    company: safeText(contact.company),
                    phone: safeText(contact.phone),
                    notes: safeText(contact.notes),
                  });
                  setPhotoFile(null);
                  setPhotoPreview(safeText(contact.photo_url));
                  setRemovePhoto(false);
                  setFormError("");
                  showContactForm();
                }}
                className="grid h-10 w-10 place-items-center rounded-lg border border-slate-200 text-slate-500 sm:h-9 sm:w-9"
                aria-label={t("contacts.edit")}
              >
                <Pencil size={16} />
              </button>
              <button onClick={() => setContactToDelete(contact)} className="grid h-10 w-10 place-items-center rounded-lg border border-slate-200 text-slate-500 sm:h-9 sm:w-9" aria-label={t("common.delete")}>
                <Trash2 size={16} />
              </button>
            </div>
          </div>
        ))}
        </div>
      </section>
      {contactFormOpen ? (
      <section ref={contactFormRef} className="grid scroll-mt-3 gap-3 rounded-xl border border-slate-200 p-3">
        <div className="flex items-center justify-between gap-3">
          <h3 className="font-black">{editingId ? t("contacts.edit") : t("contacts.new")}</h3>
          <button type="button" onClick={resetDraft} className="h-9 rounded-lg border border-slate-200 px-3 text-sm font-bold text-slate-600">{t("common.cancel")}</button>
        </div>
        <div className="flex flex-wrap items-center gap-3 rounded-lg border border-slate-200 bg-slate-50 p-3">
          <ContactAvatar value={draft.full_name || draft.email} photoUrl={photoPreview} size="lg" />
          <div className="grid min-w-0 flex-1 gap-2">
            <strong className="text-sm text-slate-700">{t("contacts.photo")}</strong>
            <div className="flex flex-wrap items-center gap-2">
              <label className="theme-button-soft h-9 cursor-pointer px-3 text-sm">
                <Upload size={14} />
                {t("contacts.choosePhoto")}
                <input type="file" accept="image/jpeg,image/png,image/webp,image/gif" className="sr-only" onChange={(event) => choosePhoto(event.target.files?.[0])} />
              </label>
              {photoPreview ? (
                <button type="button" onClick={() => { setPhotoFile(null); setPhotoPreview(""); setRemovePhoto(Boolean(editingId)); }} className="icon-button h-9 w-9" aria-label={t("contacts.removePhoto")} title={t("contacts.removePhoto")}>
                  <Trash2 size={15} />
                </button>
              ) : null}
            </div>
          </div>
        </div>
        <div className="grid gap-3 sm:grid-cols-2">
          <input value={draft.full_name} onChange={(event) => setDraft({ ...draft, full_name: event.target.value })} className="field h-11 sm:h-10" placeholder={t("contacts.name")} />
          <input value={draft.email} onChange={(event) => {
            setFormError("");
            setDraft({ ...draft, email: event.target.value });
          }} className="field h-11 sm:h-10" placeholder={t("contacts.email")} />
          <input value={draft.company} onChange={(event) => setDraft({ ...draft, company: event.target.value })} className="field h-11 sm:h-10" placeholder={t("contacts.company")} />
          <input value={draft.phone} onChange={(event) => setDraft({ ...draft, phone: event.target.value })} className="field h-11 sm:h-10" placeholder={t("contacts.phone")} />
        </div>
        <textarea value={draft.notes} onChange={(event) => setDraft({ ...draft, notes: event.target.value })} className="field min-h-24 p-3" placeholder={t("contacts.notes")} />
        <div className="flex flex-wrap items-center gap-3">
          <button onClick={() => void saveContact()} disabled={!draft.email.trim() || busy} className="theme-button h-11 w-full px-4 disabled:opacity-50 sm:h-10 sm:w-fit">
            {editingId ? <Pencil size={17} /> : <UserPlus size={17} />}
            {busy ? t("common.saving") : editingId ? t("common.save") : t("contacts.add")}
          </button>
          {formError ? <span className="text-sm font-bold text-red-600">{formError}</span> : null}
          {createContact.error instanceof Error ? <span className="text-sm font-bold text-red-600">{createContact.error.message}</span> : null}
          {updateContact.error instanceof Error ? <span className="text-sm font-bold text-red-600">{updateContact.error.message}</span> : null}
        </div>
      </section>

      ) : null}
      </div>

      <aside className="hidden h-fit content-start gap-3 rounded-xl border border-slate-200 bg-white p-3 xl:sticky xl:top-4 xl:grid">
        <div className="mb-1 flex items-center gap-2">
          <FolderIcon size={18} className="text-[var(--accent)]" />
          <div className="min-w-0">
            <p className="text-xs font-black uppercase tracking-[0.12em] text-slate-400">{t("contacts.listTitle")}</p>
            <h3 className="truncate text-lg font-black text-slate-900">{t("contacts.folder")}</h3>
          </div>
        </div>
        <form
          className="flex flex-wrap gap-2"
          onSubmit={(event) => {
            event.preventDefault();
            const name = newContactFolderName.trim();
            if (!name || createFolder.isPending) return;
            void createFolder.mutate(name);
          }}
        >
          <input
            value={newContactFolderName}
            onChange={(event) => setNewContactFolderName(event.target.value)}
            className="field h-10 min-w-0 flex-1 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-offset-2"
            placeholder={t("contacts.newFolder")}
          />
          <button type="submit" className="theme-button h-10 px-4 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-offset-2" disabled={!newContactFolderName.trim() || createFolder.isPending}>
            <Plus size={16} />
            {createFolder.isPending ? t("common.saving") : t("contacts.newFolder")}
          </button>
        </form>
        <div className="grid gap-3">
          {folders.map((folder) => {
            const selected = selectedFolderId === folder.id;
            const folderColor = folderColorHex(folder);
            const mountedShare = Boolean(folder.share_owner_email || folder.share_owner_id);
            const folderShares = (folder.shared ?? []).filter(hasShareRecipient);
            const canManageFolder = !folder.is_system && !mountedShare;
            const canShareFolder = !mountedShare;
            const shareDisabled = !canShareFolders;
            const colorOpen = colorContactFolderId === folder.id;
            return (
              <div
                key={folder.id}
                className={clsx(
                  "rounded-xl border px-3 py-3 transition",
                  selected || actionMenuContactFolderId === folder.id || colorOpen || shareContactFolderId === folder.id
                    ? "border-[color-mix(in_srgb,var(--accent)_22%,white)] bg-[color-mix(in_srgb,var(--accent)_6%,white)]"
                    : "border-slate-200 bg-slate-50"
                )}
              >
                <div className="flex items-start justify-between gap-3">
                  <button
                    type="button"
                    onClick={() => {
                      onSelectFolder(folder.id);
                      setActionMenuContactFolderId("");
                      setColorContactFolderId("");
                    }}
                    className="min-w-0 flex-1 rounded-md text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-offset-2"
                  >
                    <div className="flex min-w-0 items-center gap-2">
                      <span className="h-3 w-3 shrink-0 rounded-full border border-black/5" style={{ backgroundColor: folderColor }} />
                      {mountedShare ? <FolderSymlink size={15} className="shrink-0 text-[var(--accent)]" aria-label={t("folder.sharedAccess")} /> : null}
                      <p className="truncate text-sm font-black text-slate-900">{displayFolder(folder.name)}</p>
                      {folder.is_system ? <span className="rounded-full bg-white px-2 py-0.5 text-[10px] font-black uppercase tracking-[0.08em] text-slate-500">{t("calendar.primary")}</span> : null}
                    </div>
                    <p className="mt-1 text-xs font-semibold text-slate-500">
                      {mountedShare ? t("folder.sharedAccess") : folder.is_system ? t("contacts.systemFolder") : t("contacts.customFolder")} · {t("contacts.shown", { count: folder.total_count })}
                      {!mountedShare && folderShares.length ? ` · ${t("sharing.recipientCount", { count: folderShares.length })}` : ""}
                    </p>
                  </button>
                  <button
                    type="button"
                    onClick={() => {
                      setActionMenuContactFolderId((current) => (current === folder.id ? "" : folder.id));
                      setColorContactFolderId("");
                      setShareContactFolderId("");
                    }}
                    className="theme-button-soft h-8 px-2.5 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-offset-2"
                    aria-label={`${t("contacts.folder")} ${displayFolder(folder.name)}`}
                    aria-haspopup="menu"
                    aria-expanded={actionMenuContactFolderId === folder.id}
                  >
                    <MoreHorizontal size={15} />
                  </button>
                </div>
                {actionMenuContactFolderId === folder.id ? (
                  <div role="menu" className="mt-3 rounded-lg border border-slate-200 bg-white p-1.5">
                    <div className="px-3 py-2 text-[11px] font-black uppercase tracking-[0.08em] text-slate-400">{t("calendar.manage")}</div>
                    {canManageFolder ? (
                      <button
                        type="button"
                        role="menuitem"
                        onClick={() => {
                          setActionMenuContactFolderId("");
                          setColorContactFolderId("");
                          setShareContactFolderId("");
                          setFolderEditor({ mode: "rename", folder });
                        }}
                        className="flex h-9 w-full items-center gap-2 rounded-md px-3 text-sm font-semibold text-slate-700 transition hover:bg-slate-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-inset"
                      >
                        <Pencil size={14} />
                        {t("contacts.rename")}
                      </button>
                    ) : null}
                    <button
                      type="button"
                      role="menuitem"
                      onClick={() => {
                        setActionMenuContactFolderId("");
                        setShareContactFolderId("");
                        setColorContactFolderId((current) => (current === folder.id ? "" : folder.id));
                      }}
                      className="flex h-9 w-full items-center gap-2 rounded-md px-3 text-sm font-semibold text-slate-700 transition hover:bg-slate-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-inset"
                    >
                      <span className="h-3 w-3 rounded-full border border-black/5" style={{ backgroundColor: folderColor }} />
                      {t("calendar.changeColor")}
                    </button>
                    {canShareFolder ? (
                      <>
                        <div className="px-3 py-2 text-[11px] font-black uppercase tracking-[0.08em] text-slate-400">{t("folder.share")}</div>
                        <button
                          type="button"
                          role="menuitem"
                          onClick={() => {
                            if (shareDisabled) return;
                            setActionMenuContactFolderId("");
                            setColorContactFolderId("");
                            setShareContactFolderId(folder.id);
                            setShareEmail("");
                          }}
                          aria-disabled={shareDisabled || undefined}
                          title={shareTooltip}
                          aria-label={shareTooltip ? `${t("folder.share")}. ${shareTooltip}` : t("folder.share")}
                          className={clsx(
                            "flex h-9 w-full items-center gap-2 rounded-md px-3 text-sm font-semibold transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-inset",
                            shareDisabled ? "cursor-not-allowed text-slate-300" : "text-slate-700 hover:bg-slate-100"
                          )}
                        >
                          <Share2 size={14} />
                          <span className="min-w-0 flex-1 text-left">{t("folder.share")}</span>
                          {shareBadge ? <FeatureLockBadge label={shareBadge} tooltip={shareTooltip} /> : null}
                        </button>
                      </>
                    ) : null}
                    {canManageFolder ? (
                      <>
                        <div className="my-1 border-t border-slate-100" />
                        <div className="px-3 py-2 text-[11px] font-black uppercase tracking-[0.08em] text-slate-400">{t("calendar.danger")}</div>
                        <button
                          type="button"
                          role="menuitem"
                          onClick={() => {
                            setActionMenuContactFolderId("");
                            setFolderToDelete(folder);
                          }}
                          className="flex h-9 w-full items-center gap-2 rounded-md px-3 text-sm font-semibold text-red-600 transition hover:bg-red-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-300 focus-visible:ring-inset"
                        >
                          <Trash2 size={14} />
                          {t("common.delete")}
                        </button>
                      </>
                    ) : null}
                  </div>
                ) : null}
                {colorOpen ? (
                  <div className="mt-3 flex flex-wrap gap-1.5">
                    {folderColorOptions.map((option) => {
                      const colorSelected = folderColorMatches(folder, option.value, option.hex);
                      return (
                        <button
                          key={`${folder.id}:${option.value}`}
                          type="button"
                          onClick={() => updateFolderColor.mutate({ folderId: folder.id, color: option.value, rgb: option.hex })}
                          disabled={updateFolderColor.isPending}
                          className={clsx(
                            "grid h-7 w-7 place-items-center rounded-full border transition focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--accent)] focus-visible:ring-offset-2",
                            updateFolderColor.isPending ? "cursor-not-allowed border-slate-100 opacity-50" : colorSelected ? "scale-105 border-slate-900" : "border-slate-200 hover:border-slate-400"
                          )}
                          style={{ backgroundColor: option.hex }}
                          aria-label={t("folder.setColor", { color: option.label })}
                          title={option.label}
                        >
                          {colorSelected ? <Check size={13} className="text-slate-950" /> : null}
                        </button>
                      );
                    })}
                  </div>
                ) : null}
                {mountedShare ? (
                  <div className="mt-3 rounded-lg border border-slate-200 bg-white px-3 py-2 text-sm font-semibold text-slate-500">
                    {folder.share_owner_email || folder.share_owner_id || t("folder.sharedAccess")}
                  </div>
                ) : null}
              </div>
            );
          })}
          {!folders.length ? <p className="rounded-lg bg-slate-50 p-4 text-sm font-semibold text-slate-500">{t("contacts.empty")}</p> : null}
        </div>
        {shareFolder.error instanceof Error ? <p className="text-sm font-bold text-red-600">{shareFolder.error.message}</p> : null}
        {revokeFolderShare.error instanceof Error ? <p className="text-sm font-bold text-red-600">{revokeFolderShare.error.message}</p> : null}
      </aside>
      {shareContactFolder && canShareFolders ? (
        <ContactFolderShareModal
          folder={shareContactFolder}
          t={t}
          contacts={autocompleteContacts}
          email={shareEmail}
          permissions={sharePermissions}
          busy={shareFolder.isPending || revokeFolderShare.isPending}
          shareError={shareFolder.error instanceof Error ? shareFolder.error.message : ""}
          revokeError={revokeFolderShare.error instanceof Error ? revokeFolderShare.error.message : ""}
          onEmailChange={setShareEmail}
          onPermissionsChange={setSharePermissions}
          onClose={() => {
            setShareContactFolderId("");
            setShareEmail("");
          }}
          onShare={async (email, permissions) => {
            if (!email.trim() || shareFolder.isPending) return;
            await shareFolder.mutateAsync({ folderId: shareContactFolder.id, email: email.trim(), permissions: permissions.trim() || "r" });
            setShareContactFolderId("");
            setShareEmail("");
          }}
          onRevoke={async (email) => {
            if (!email.trim() || revokeFolderShare.isPending) return;
            await revokeFolderShare.mutateAsync({ folderId: shareContactFolder.id, email: email.trim() });
            setShareContactFolderId("");
            setShareEmail("");
          }}
        />
      ) : null}
      {folderEditor ? (
        <NameEditorModal
          title={folderEditor.mode === "create" ? t("contacts.newFolderTitle") : t("contacts.renameFolderTitle")}
          t={t}
          initialName={folderEditor.folder ? displayFolder(folderEditor.folder.name) : ""}
          busy={createFolder.isPending || renameFolder.isPending}
          onClose={() => setFolderEditor(null)}
          onSave={(name) => {
            if (folderEditor.mode === "create") {
              void createFolder.mutate(name);
              return;
            }
            if (folderEditor.folder) {
              void renameFolder.mutate({ folderId: folderEditor.folder.id, name });
            }
          }}
        />
      ) : null}
      {folderToDelete ? (
        <ConfirmDialog
          t={t}
          title={t("contacts.deleteFolder")}
          message={t("contacts.deleteFolderMessage", { name: displayFolder(folderToDelete.name) })}
          confirmLabel={t("common.delete")}
          tone="danger"
          busy={deleteFolder.isPending}
          onClose={() => setFolderToDelete(null)}
          onConfirm={async () => {
            await deleteFolder.mutateAsync(folderToDelete.id);
          }}
        />
      ) : null}
      {contactToDelete ? (
        <ConfirmDialog
          t={t}
          title="Delete contact?"
          message="This removes the contact from this address book."
          confirmLabel="Delete"
          tone="danger"
          busy={deleteContact.isPending}
          onClose={() => setContactToDelete(null)}
          onConfirm={async () => {
            await deleteContact.mutateAsync(contactToDelete.id);
          }}
        />
      ) : null}
    </div>
  );
}

function ImportExportPanel({ t, contacts, selectedFolderId, messages }: { t: ReturnType<typeof createTranslator>; contacts: Contact[]; selectedFolderId: string; messages: MessageSummary[] }) {
  const queryClient = useQueryClient();
  const [importSummary, setImportSummary] = useState("");
  const [mailExportSummary, setMailExportSummary] = useState("");
  const [mailExportPhase, setMailExportPhase] = useState("");
  const [mailExportProgress, setMailExportProgress] = useState(0);
  const [mailArchiveExporting, setMailArchiveExporting] = useState(false);
  const [mailImportSummary, setMailImportSummary] = useState("");
  const [mailImportPhase, setMailImportPhase] = useState("");
  const [mailImportProgress, setMailImportProgress] = useState(0);
  const [mailImportRunning, setMailImportRunning] = useState(false);
  const [mailImportElapsedSeconds, setMailImportElapsedSeconds] = useState(0);
  const [mailImportStage, setMailImportStage] = useState<"uploading" | "queued" | "processing" | "downloading" | "completed" | "idle">("idle");
  const importContactsMutation = useMutation({
    mutationFn: async (items: Partial<Contact>[]) => {
      const existingEmails = new Set(contacts.map((contact) => safeText(contact.email).trim().toLowerCase()).filter(Boolean));
      let created = 0;
      let skipped = 0;
      for (const item of items) {
        const legacy = item as Partial<Contact> & { name?: string };
        const email = safeText(item.email).trim();
        if (!email) {
          skipped += 1;
          continue;
        }
        const normalizedEmail = email.toLowerCase();
        if (existingEmails.has(normalizedEmail)) {
          skipped += 1;
          continue;
        }
        await api.createContact({
          folder_id: selectedFolderId,
          full_name: safeText(item.full_name || legacy.name).trim(),
          first_name: safeText(item.first_name).trim(),
          last_name: safeText(item.last_name).trim(),
          email,
          company: safeText(item.company).trim(),
          notes: safeText(item.notes).trim(),
          phone: safeText(item.phone).trim(),
        });
        existingEmails.add(normalizedEmail);
        created += 1;
      }
      return { created, skipped };
    },
    onSuccess: async ({ created, skipped }) => {
      setImportSummary(t("importExport.contactImported", {
        created,
        contactSuffix: created === 1 ? "" : "s",
        skippedText: skipped ? t("importExport.skippedContacts", { skipped, entrySuffix: skipped === 1 ? "y" : "ies" }) : "",
      }));
      await queryClient.invalidateQueries({ queryKey: ["contacts"] });
    }
  });

  useEffect(() => {
    if (!mailImportRunning) {
      setMailImportElapsedSeconds(0);
      return;
    }
    const startedAt = Date.now();
    setMailImportElapsedSeconds(0);
    const timer = window.setInterval(() => {
      setMailImportElapsedSeconds(Math.max(0, Math.floor((Date.now() - startedAt) / 1000)));
    }, 1000);
    return () => window.clearInterval(timer);
  }, [mailImportRunning]);
  async function importContacts(event: ChangeEvent<HTMLInputElement>) {
    const file = event.target.files?.[0];
    if (!file) return;
    setImportSummary("");
    const text = await file.text();
    const imported = file.name.endsWith(".csv") ? parseContactsCsv(text) : JSON.parse(text);
    await importContactsMutation.mutateAsync(Array.isArray(imported) ? imported : []);
    event.target.value = "";
  }

  async function exportAllMailArchive() {
    if (mailArchiveExporting) return;
    setMailArchiveExporting(true);
    setMailExportSummary("");
    setMailExportPhase("");
    setMailExportProgress(0);
    try {
      const { job } = await api.startMailExportArchiveJob();
      setMailExportSummary(t("importExport.preparingExport"));
      setMailExportPhase(job.phase || job.status);
      let current = job;
      for (let attempt = 0; attempt < 120; attempt += 1) {
        setMailExportProgress(Math.min(92, Math.round((attempt / 120) * 92)));
        if (current.status === "success") break;
        if (current.status === "failed" || current.status === "cancelled") {
          throw new Error(t("importExport.exportJobFailed"));
        }
        await new Promise((resolve) => setTimeout(resolve, 2000));
        current = (await api.getMailExportArchiveJob(job.id)).job;
        setMailExportSummary(`${t("importExport.preparingExport")} ${current.phase || current.status}`);
        setMailExportPhase(current.phase || current.status);
      }
      if (current.status !== "success") {
        throw new Error(t("importExport.exportTimedOut"));
      }
      setMailExportPhase(t("importExport.downloading"));
      setMailExportProgress(95);
      const blob = await api.downloadMailExportArchiveJob(job.id);
      downloadBlob(`mail-archive-${new Date().toISOString().slice(0, 10)}.tgz`, blob);
      setMailExportSummary(t("importExport.exportSuccess"));
      setMailExportPhase(t("importExport.completed"));
      setMailExportProgress(100);
    } catch (error) {
      setMailExportSummary(error instanceof Error ? error.message : t("importExport.exportFailed"));
      setMailExportProgress(0);
    } finally {
      setMailArchiveExporting(false);
    }
  }

  async function importMailArchive(event: ChangeEvent<HTMLInputElement>) {
    const file = event.target.files?.[0];
    if (!file) return;
      setMailImportSummary("");
      setMailImportPhase("");
      setMailImportProgress(0);
      setMailImportElapsedSeconds(0);
      setMailImportStage("uploading");
      setMailImportRunning(true);
    try {
      const chunkSize = 8 * 1024 * 1024;
      const { upload_id } = await api.startMailImportUpload({ filename: file.name, folder: "INBOX" });
      for (let offset = 0; offset < file.size; offset += chunkSize) {
        const chunk = file.slice(offset, Math.min(offset + chunkSize, file.size));
        const sent = await api.uploadMailImportChunk(upload_id, chunk);
        const pct = file.size > 0 ? Math.round((sent.bytes / file.size) * 100) : 0;
        setMailImportStage("uploading");
        setMailImportProgress(Math.min(90, Math.max(1, pct)));
        setMailImportSummary(t("importExport.uploadingArchive", { percent: pct }));
      }
      setMailImportStage("queued");
      const { job } = await api.finishMailImportUpload(upload_id);
      let current = job;
      let processingProgress = 20;
      while (true) {
        setMailImportStage(current.status === "success" ? "downloading" : current.status === "running" ? "processing" : "queued");
        if (current.status === "success") break;
        if (current.status === "failed" || current.status === "cancelled") {
          throw new Error(t("importExport.importJobFailed"));
        }
        if (current.status === "running") {
          processingProgress = Math.min(90, processingProgress + 3);
          setMailImportProgress(processingProgress);
        } else {
          setMailImportProgress(Math.min(18, mailImportProgress || 18));
        }
        await new Promise((resolve) => setTimeout(resolve, 2000));
        current = (await api.getMailImportArchiveJob(job.id)).job;
        setMailImportPhase(current.phase || current.status);
        setMailImportSummary(t("importExport.importingArchive", { phase: current.phase || current.status }));
      }
      setMailImportStage("completed");
      setMailImportPhase(t("importExport.completed"));
      setMailImportProgress(100);
      setMailImportSummary(t("importExport.importSuccess"));
      await queryClient.invalidateQueries({ queryKey: ["messages"] });
      await queryClient.invalidateQueries({ queryKey: ["folders"] });
    } catch (error) {
      setMailImportSummary(error instanceof Error ? error.message : t("importExport.importFailed"));
      setMailImportProgress(0);
      setMailImportStage("idle");
    } finally {
      setMailImportRunning(false);
      setMailImportStage("idle");
      event.target.value = "";
    }
  }

  return (
    <div className="grid gap-5">
      <section className="grid gap-3 rounded-xl border border-slate-200 p-4">
        <h3 className="font-black">{t("importExport.contact")}</h3>
        <div className="flex flex-wrap gap-2">
          <label className="theme-button-soft h-10 cursor-pointer px-4"><Upload size={17} /> {t("importExport.import")}<input type="file" accept=".json,.csv" onChange={importContacts} className="sr-only" /></label>
          <button onClick={() => downloadFile("contacts.json", JSON.stringify(contacts, null, 2), "application/json")} className="theme-button-soft h-10 px-4"><Download size={17} /> JSON</button>
          <button onClick={() => downloadFile("contacts.csv", contactsToCsv(contacts), "text/csv")} className="theme-button-soft h-10 px-4"><Download size={17} /> CSV</button>
        </div>
        {importSummary ? <p className="text-sm font-semibold text-emerald-700">{importSummary}</p> : null}
        {importContactsMutation.isPending ? <p className="text-sm font-semibold text-slate-500">{t("importExport.importingContact")}</p> : null}
        {importContactsMutation.error instanceof Error ? <p className="text-sm font-bold text-red-600">{importContactsMutation.error.message}</p> : null}
      </section>

      <section className="grid gap-3 rounded-xl border border-slate-200 p-4">
        <h3 className="font-black">{t("importExport.mail")}</h3>
        <div className="flex flex-wrap gap-2">
          <label className="theme-button h-10 cursor-pointer px-4">
            <Upload size={17} />
            {mailImportRunning ? t("importExport.importing") : t("importExport.importArchive")}
            <input type="file" accept=".tgz,.tar.gz" onChange={importMailArchive} className="sr-only" />
          </label>
          <button
            type="button"
            onClick={() => void exportAllMailArchive()}
            disabled={mailArchiveExporting}
            className="theme-button h-10 px-4 disabled:opacity-50"
          >
            <Download size={17} />
            {mailArchiveExporting ? t("importExport.exporting") : t("importExport.exportAllMail")}
          </button>
        </div>
        {mailImportSummary ? <p className={clsx("text-sm font-semibold", isFailureSummary(mailImportSummary) ? "text-red-600" : "text-emerald-700")}>{mailImportSummary}</p> : null}
        {mailImportRunning ? (
          <div className="grid gap-2">
            <div className="relative h-2 overflow-hidden rounded-full bg-slate-100">
              <div
                className={clsx(
                  "h-full rounded-full bg-[linear-gradient(90deg,var(--accent),color-mix(in_srgb,var(--accent)_70%,white),var(--accent))] bg-[length:200%_100%] transition-all duration-500",
                  mailImportStage === "uploading" && mailImportProgress === 0 ? "animate-pulse" : "animate-mail-import-stripes"
                )}
                style={{ width: mailImportStage === "uploading" && mailImportProgress === 0 ? "40%" : `${mailImportProgress}%` }}
              />
              <div className="mail-import-shimmer pointer-events-none absolute inset-0 rounded-full" />
            </div>
            <div className="flex items-center justify-between text-xs font-semibold uppercase tracking-[0.12em] text-slate-500">
              <span>{mailImportStage === "uploading" ? t("importExport.uploading") : mailImportPhase || t("importExport.queued")}</span>
              <span>{t("importExport.importingStage")}</span>
            </div>
            <p className="text-[11px] font-semibold uppercase tracking-[0.12em] text-slate-400">
              {t("importExport.elapsed", { duration: formatDurationShort(mailImportElapsedSeconds) })}
            </p>
          </div>
        ) : null}
        {mailExportSummary ? <p className={clsx("text-sm font-semibold", isFailureSummary(mailExportSummary) ? "text-red-600" : "text-emerald-700")}>{mailExportSummary}</p> : null}
        {mailArchiveExporting ? (
          <div className="grid gap-2">
            <div className="h-2 overflow-hidden rounded-full bg-slate-100">
              <div
                className="h-full rounded-full bg-[linear-gradient(90deg,var(--accent),color-mix(in_srgb,var(--accent)_70%,white))] transition-all duration-500"
                style={{ width: `${mailExportProgress}%` }}
              />
            </div>
            <div className="flex items-center justify-between text-xs font-semibold uppercase tracking-[0.12em] text-slate-500">
              <span>{mailExportPhase || t("importExport.queued")}</span>
              <span>{mailExportProgress}%</span>
            </div>
          </div>
        ) : null}
      </section>

      <section className="grid gap-3 rounded-xl border border-slate-200 p-4">
        <h3 className="font-black">{t("calendar.calendar")}</h3>
        <div className="rounded-lg border border-[color-mix(in_srgb,var(--accent)_18%,white)] bg-[color-mix(in_srgb,var(--accent)_7%,white)] px-4 py-3 text-sm font-semibold leading-6 text-slate-700">
          {t("importExport.calendarNote")}
        </div>
      </section>
    </div>
  );
}

function MigrationCenter({ t, email }: { t: ReturnType<typeof createTranslator>; email: string }) {
  const [form, setForm] = useState({
    label: "",
    source_host: "",
    source_port: "993",
    source_security: "ssl" as "ssl" | "starttls" | "plain",
    source_skip_ssl_verify: true,
    source_username: email,
    source_password: "",
    dry_run: false,
    include_folders: "",
    exclude_folders: "Trash,Junk,Spam",
  });
  const [connectionResult, setConnectionResult] = useState<MailMigrationConnectionResult | null>(null);
  const [notice, setNotice] = useState<{ tone: "success" | "error" | "info"; message: string } | null>(null);
  const [expandedJobId, setExpandedJobId] = useState("");
  const jobs = useQuery({
    queryKey: ["mail-migrations", email],
    queryFn: api.mailMigrations,
    refetchInterval: 5_000,
    enabled: Boolean(email),
  });
  const testConnection = useMutation({
    mutationFn: api.testMailMigrationConnection,
    onSuccess: (result) => {
      setConnectionResult(result);
      setNotice({ tone: "success", message: result.message });
    },
    onError: (error) => {
      setConnectionResult(null);
      setNotice({ tone: "error", message: error instanceof Error ? error.message : t("migration.connectFailed") });
    }
  });
  const startMigration = useMutation({
    mutationFn: api.startMailMigration,
    onSuccess: async ({ job }) => {
      setNotice({ tone: "success", message: t("migration.startedNotice", { id: job.id, username: job.source_username }) });
      await jobs.refetch();
    },
    onError: (error) => {
      setNotice({ tone: "error", message: error instanceof Error ? error.message : t("migration.startFailed") });
    }
  });
  const cancelMigration = useMutation({
    mutationFn: api.cancelMailMigration,
    onSuccess: async ({ job }) => {
      setNotice({ tone: "info", message: t("migration.cancelledNotice", { id: job.id }) });
      await jobs.refetch();
    },
    onError: (error) => {
      setNotice({ tone: "error", message: error instanceof Error ? error.message : t("migration.cancelFailed") });
    }
  });
  const clearHistory = useMutation({
    mutationFn: api.clearMailMigrations,
    onSuccess: async () => {
      setNotice({ tone: "info", message: t("migration.historyCleared") });
      setExpandedJobId("");
      await jobs.refetch();
    },
    onError: (error) => {
      setNotice({ tone: "error", message: error instanceof Error ? error.message : t("migration.clearFailed") });
    }
  });

  const isGmailSource = useMemo(() => {
    const host = form.source_host.trim().toLowerCase();
    const username = form.source_username.trim().toLowerCase();
    return host.includes("gmail") || host.includes("googlemail") || username.endsWith("@gmail.com") || username.endsWith("@googlemail.com");
  }, [form.source_host, form.source_username]);
  const looksLikeAppPassword = useMemo(() => {
    const value = form.source_password.trim().replace(/\s+/g, "");
    return value.length === 16 && /^[a-z0-9]+$/i.test(value);
  }, [form.source_password]);

  useEffect(() => {
    setConnectionResult(null);
    setNotice(null);
    setExpandedJobId("");
    setForm({
      label: "",
      source_host: "",
      source_port: "993",
      source_security: "ssl",
      source_skip_ssl_verify: true,
      source_username: email,
      source_password: "",
      dry_run: false,
      include_folders: "",
      exclude_folders: "Trash,Junk,Spam",
    });
  }, [email]);

  function payload() {
    return {
      label: form.label.trim(),
      source_host: form.source_host.trim(),
      source_port: Number(form.source_port) || 993,
      source_security: form.source_security,
      source_skip_ssl_verify: form.source_skip_ssl_verify,
      source_username: form.source_username.trim(),
      source_password: form.source_password,
      dry_run: form.dry_run,
      include_folders: csvToList(form.include_folders),
      exclude_folders: csvToList(form.exclude_folders),
    };
  }

  const canSubmit = Boolean(form.source_host.trim() && form.source_username.trim() && form.source_password);

  return (
    <div className="grid gap-4">
      <section className="grid gap-3 rounded-xl border border-slate-200 p-4">
        <div className="grid gap-1">
          <h3 className="font-black">{t("migration.title")}</h3>
          <p className="max-w-3xl text-sm leading-6 text-slate-500">
            {t("migration.help", { email })}
          </p>
          {isGmailSource ? (
            <p className="max-w-3xl text-sm leading-6 text-amber-700">
              {t("migration.gmailHelp")}
            </p>
          ) : null}
        </div>
        <div className="grid gap-3 sm:grid-cols-2">
          <label className="grid gap-2 text-sm font-bold text-slate-600">
            {t("migration.sourceHost")}
            <input value={form.source_host} onChange={(event) => setForm((current) => ({ ...current, source_host: event.target.value }))} className="field h-11" placeholder="imap.example.com" />
          </label>
          <label className="grid gap-2 text-sm font-bold text-slate-600">
            {t("migration.sourcePort")}
            <input value={form.source_port} onChange={(event) => setForm((current) => ({ ...current, source_port: event.target.value }))} className="field h-11" inputMode="numeric" placeholder="993" />
          </label>
          <label className="grid gap-2 text-sm font-bold text-slate-600">
            {t("migration.security")}
            <select value={form.source_security} onChange={(event) => setForm((current) => ({ ...current, source_security: event.target.value as "ssl" | "starttls" | "plain" }))} className="field h-11">
              <option value="ssl">SSL/TLS</option>
              <option value="starttls">STARTTLS</option>
              <option value="plain">{t("migration.plain")}</option>
            </select>
          </label>
          <label className="grid gap-2 text-sm font-bold text-slate-600">
            {t("migration.sourceUsername")}
            <input value={form.source_username} onChange={(event) => setForm((current) => ({ ...current, source_username: event.target.value }))} className="field h-11" placeholder="user@example.com" />
          </label>
          <label className="grid gap-2 text-sm font-bold text-slate-600 sm:col-span-2">
            {t("migration.sourcePassword")}
            <input value={form.source_password} onChange={(event) => setForm((current) => ({ ...current, source_password: event.target.value }))} className="field h-11" type="password" placeholder={t("migration.sourcePasswordPlaceholder")} />
            {isGmailSource ? (
              <span className="text-xs font-semibold leading-5 text-amber-700">
                {t("migration.gmailPasswordHelp")}
              </span>
            ) : null}
          </label>
          <label className="grid gap-2 text-sm font-bold text-slate-600">
            {t("migration.includeFolders")}
            <input value={form.include_folders} onChange={(event) => setForm((current) => ({ ...current, include_folders: event.target.value }))} className="field h-11" placeholder="Inbox,Sent" />
          </label>
          <label className="grid gap-2 text-sm font-bold text-slate-600">
            {t("migration.excludeFolders")}
            <input value={form.exclude_folders} onChange={(event) => setForm((current) => ({ ...current, exclude_folders: event.target.value }))} className="field h-11" placeholder="Trash,Junk,Spam" />
          </label>
          <label className="grid gap-2 text-sm font-bold text-slate-600 sm:col-span-2">
            {t("migration.jobLabel")}
            <input value={form.label} onChange={(event) => setForm((current) => ({ ...current, label: event.target.value }))} className="field h-11" placeholder="Cutover batch 1" />
          </label>
        </div>
        <label className="inline-flex items-center gap-3 text-sm font-bold text-slate-600">
          <input type="checkbox" checked={form.dry_run} onChange={(event) => setForm((current) => ({ ...current, dry_run: event.target.checked }))} className="h-4 w-4 rounded border-slate-300 text-[var(--accent)]" />
          {t("migration.dryRunOnly")}
        </label>
        <label className="inline-flex items-center gap-3 text-sm font-bold text-slate-600">
          <input type="checkbox" checked={form.source_skip_ssl_verify} onChange={(event) => setForm((current) => ({ ...current, source_skip_ssl_verify: event.target.checked }))} className="h-4 w-4 rounded border-slate-300 text-[var(--accent)]" />
          {t("migration.skipSslVerify")}
        </label>
        {isGmailSource ? (
          <div className="rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm font-semibold leading-6 text-amber-800">
            {t("migration.gmailDetected")}
          </div>
        ) : null}
        <div className="flex flex-wrap gap-2">
          <button type="button" onClick={() => void testConnection.mutate(payload())} disabled={!canSubmit || testConnection.isPending} className="theme-button-soft h-11 px-4 disabled:opacity-50">
            <RefreshCw size={16} className={clsx(testConnection.isPending && "animate-spin")} />
            {t("migration.testConnection")}
          </button>
          <button
            type="button"
            onClick={() => void startMigration.mutate(payload())}
            disabled={!canSubmit || startMigration.isPending || (isGmailSource && !looksLikeAppPassword)}
            className="theme-button h-11 px-4 disabled:opacity-50"
            title={isGmailSource && !looksLikeAppPassword ? t("migration.appPasswordRequiredTitle") : ""}
          >
            {startMigration.isPending ? t("migration.starting") : form.dry_run ? t("migration.startDryRun") : t("migration.startMigration")}
          </button>
          <button
            type="button"
            onClick={() => void clearHistory.mutate()}
            disabled={clearHistory.isPending}
            className="theme-button-soft h-11 border-slate-200 px-4 text-slate-700 hover:bg-slate-50 disabled:opacity-50"
          >
            {clearHistory.isPending ? t("migration.clearing") : t("migration.clearHistory")}
          </button>
        </div>
        {isGmailSource && !looksLikeAppPassword ? (
          <p className="text-xs font-semibold text-amber-700">{t("migration.appPasswordRequired")}</p>
        ) : null}
        {notice ? (
          <div className={clsx(
            "rounded-lg border px-4 py-3 text-sm font-semibold",
            notice.tone === "success"
              ? "border-[color-mix(in_srgb,var(--accent)_20%,white)] bg-[color-mix(in_srgb,var(--accent)_8%,white)] text-[var(--accent)]"
              : notice.tone === "info"
                ? "border-slate-200 bg-slate-50 text-slate-700"
                : "border-red-200 bg-red-50 text-red-700"
          )}>
            {notice.message}
          </div>
        ) : null}
        {connectionResult?.folders?.length ? (
          <div className="rounded-lg border border-slate-200 bg-slate-50 px-4 py-3 text-sm text-slate-700">
            <strong className="font-black text-slate-900">{t("migration.foldersFound")}</strong> {connectionResult.folders.slice(0, 12).join(", ")}{connectionResult.folders.length > 12 ? ` ${t("migration.moreFolders", { count: connectionResult.folders.length - 12 })}` : ""}.
          </div>
        ) : null}
      </section>

      <section className="grid gap-3 rounded-xl border border-slate-200 p-4">
        <div className="flex flex-wrap items-center justify-between gap-3">
          <div>
            <h3 className="font-black">{t("migration.jobs")}</h3>
            <p className="text-sm text-slate-500">{t("migration.jobsHelp")}</p>
          </div>
          <button type="button" onClick={() => void jobs.refetch()} className="theme-button-soft h-10 px-4">
            <RefreshCw size={16} className={clsx(jobs.isFetching && "animate-spin")} />
            {t("common.refresh")}
          </button>
        </div>
        {!jobs.data?.jobs.length ? <div className="rounded-lg border border-dashed border-slate-200 bg-slate-50 p-5 text-sm font-semibold text-slate-500">{t("migration.noJobs")}</div> : null}
        <div className="grid gap-3">
          {(jobs.data?.jobs ?? []).map((job) => {
            const running = job.status === "queued" || job.status === "running";
            const expanded = expandedJobId === job.id;
            const startedAt = job.started_at ? new Date(job.started_at).getTime() : 0;
            const elapsedSeconds = running && startedAt ? Math.max(0, Math.floor((Date.now() - startedAt) / 1000)) : 0;
            return (
              <article key={job.id} className="grid gap-3 rounded-xl border border-slate-200 bg-white p-4">
                <div className="flex flex-wrap items-start justify-between gap-3">
                  <div className="min-w-0">
                    <div className="flex flex-wrap items-center gap-2">
                      <span className="rounded-full bg-[color-mix(in_srgb,var(--accent)_10%,white)] px-2.5 py-1 text-[11px] font-black uppercase tracking-[0.12em] text-[var(--accent)]">{job.status}</span>
                      {running ? <span className="rounded-full bg-amber-50 px-2.5 py-1 text-[11px] font-black uppercase tracking-[0.12em] text-amber-700">{t("migration.working")}</span> : null}
                      <span className="text-xs font-semibold text-slate-400">{job.id}</span>
                    </div>
                    <p className="mt-2 text-sm font-bold text-slate-900">{job.source_username} via {job.source_host}:{job.source_port}</p>
                    <p className="mt-1 text-xs font-semibold text-slate-500">{t("migration.phaseSummary", { phase: job.phase, processed: job.processed_messages, copied: job.copied_messages, failed: job.failed_messages })}</p>
                    {running && elapsedSeconds ? <p className="mt-1 text-xs font-semibold text-slate-400">{t("importExport.elapsed", { duration: formatDurationShort(elapsedSeconds) })}</p> : null}
                  </div>
                  {running ? (
                    <button
                      type="button"
                      onClick={() => void cancelMigration.mutate(job.id)}
                      disabled={cancelMigration.isPending}
                      className="theme-button-soft h-10 border-red-200 px-4 text-red-700 hover:bg-red-50"
                    >
                      {job.dry_run ? t("migration.stopDryRun") : t("migration.cancel")}
                    </button>
                  ) : null}
                </div>
                {job.last_error ? <p className="text-sm font-semibold text-red-700">{job.last_error}</p> : null}
                <div className="flex flex-wrap gap-2">
                  {job.log_excerpt ? (
                    <button
                      type="button"
                      onClick={() => setExpandedJobId(expanded ? "" : job.id)}
                      className="theme-button-soft h-9 px-3 text-xs"
                    >
                      {expanded ? t("migration.hideDetails") : t("migration.showDetails")}
                    </button>
                  ) : null}
                </div>
                {expanded && job.log_excerpt ? (
                  <pre className="min-h-[18rem] max-h-[34rem] overflow-auto whitespace-pre-wrap rounded-lg border border-slate-200 bg-slate-950 p-4 font-mono text-xs leading-6 text-slate-100">{job.log_excerpt}</pre>
                ) : null}
              </article>
            );
          })}
        </div>
      </section>
    </div>
  );
}

function AdvancedSearchField({ label, value, onChange, type = "text" }: { label: string; value: string; onChange: (value: string) => void; type?: "text" | "date" }) {
  return <label className="grid gap-1.5 text-sm font-bold text-slate-700">{label}<input type={type} value={value} onChange={(event) => onChange(event.target.value)} className="field h-10" /></label>;
}

function zimbraSearchPhrase(value: string) {
  return `"${value.trim().replace(/([\\"])/g, "\\$1")}"`;
}

function zimbraSearchDate(value: string) {
  const match = value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
  return match ? `${match[2]}/${match[3]}/${match[1]}` : "";
}

function buildAdvancedMailSearchQuery(value: AdvancedMailSearch) {
  const clauses: string[] = [];
  if (value.keywords.trim()) clauses.push(zimbraSearchPhrase(value.keywords));
  if (value.from.trim()) clauses.push(`from:${zimbraSearchPhrase(value.from)}`);
  if (value.to.trim()) clauses.push(`to:${zimbraSearchPhrase(value.to)}`);
  if (value.subject.trim()) clauses.push(`subject:${zimbraSearchPhrase(value.subject)}`);
  if (value.after) clauses.push(`after:${zimbraSearchDate(value.after)}`);
  if (value.before) clauses.push(`before:${zimbraSearchDate(value.before)}`);
  if (value.hasAttachments) clauses.push("has:attachment");
  if (value.unreadOnly) clauses.push("is:unread");
  return clauses.filter(Boolean).join(" ");
}

function displayFolder(value: string) {
  return value.replace("[Gmail]/", "");
}

function isInboxFolder(folder: Folder) {
  return folder.abs_path === "/Inbox" || (folder.is_system && folder.name.trim().toLowerCase() === "inbox");
}

function isJunkFolderPath(folderPath: string) {
  const normalized = folderPath.replace(/\s+/g, "").trim().toLowerCase();
  return normalized.includes("junk") || normalized.includes("spam");
}

function isSentFolderPath(folderPath: string) {
  const normalized = folderPath.replace(/\s+/g, "").trim().toLowerCase();
  return normalized === "/sent" || normalized === "sent" || normalized.endsWith("/sent");
}

function folderColorHex(folder: Pick<Folder, "color" | "rgb">) {
  if (folder.rgb) return folder.rgb;
  return folderColorOptions.find((option) => option.value === folder.color)?.hex ?? "";
}

function folderColorMatches(folder: Pick<Folder, "color" | "rgb">, color: number, rgb: string) {
  const currentRgb = (folder.rgb || "").trim().toLowerCase();
  const nextRgb = rgb.trim().toLowerCase();
  if (currentRgb && nextRgb) return currentRgb === nextRgb;
  return folder.color === color;
}

function isFolderColorRestricted(folder: Pick<Folder, "name" | "abs_path">) {
  const normalizedName = folder.name.trim().toLowerCase();
  return normalizedName === "starred" || ["/Drafts", "/Trash", "/Junk", "/Spam"].includes(folder.abs_path);
}

function folderIcon(folder: Folder) {
  const color = folderColorHex(folder);
  const iconProps = color ? { size: 17, style: { color } } : { size: 17 };
  if (Boolean(folder.share_owner_email || folder.share_owner_id) && !(folder.shared?.length ?? 0)) {
    return <FolderSymlink {...iconProps} />;
  }
  switch (folder.abs_path) {
    case "/Inbox":
      return <Inbox {...iconProps} />;
    case "/Sent":
      return <Send {...iconProps} />;
    case "/Drafts":
      return <FilePenLine {...iconProps} />;
    case "/Trash":
      return <Trash2 {...iconProps} />;
    case "/Junk":
    case "/Spam":
      return <ShieldAlert {...iconProps} />;
    case "/Archive":
      return <Archive {...iconProps} />;
    default:
      if (folder.name.trim().toLowerCase().includes("star")) {
        return <Star {...iconProps} />;
      }
      return <FolderIcon {...iconProps} />;
  }
}

function canRenameOrDeleteFolder(folder: Folder) {
  return !folder.is_system && !isMountedMailFolder(folder);
}

function canChangeFolderColor(folder: Folder) {
  return !isFolderColorRestricted(folder);
}

function canEmptyFolder(folder: Folder) {
  if (isMountedMailFolder(folder)) return false;
  return !folder.is_system || ["/Sent", "/Trash", "/Junk", "/Spam"].includes(folder.abs_path);
}

function canDeleteMessagesInFolder(folder: Folder | null | undefined) {
  if (!folder) return true;
  if (!folder.share_owner_email && !folder.share_owner_id) return true;
  return nativeSharePermissionAllowsWrite(folder.permissions || "", "d");
}

function isMountedMailFolder(folder: Folder | null | undefined) {
  return Boolean((folder?.share_owner_email || folder?.share_owner_id || "").trim());
}

function messageKey(message: Pick<MessageSummary, "folder" | "uid">) {
  return `${message.folder}:${message.uid}`;
}

function messageToSelection(message: Pick<MessageSummary, "folder" | "uid">): MailSelectionItem {
  return { key: messageKey(message), uid: message.uid, source: message.folder };
}

function groupContactsByEmail(contacts: Contact[]) {
  const groups = new Map<string, Contact[]>();
  for (const contact of contacts) {
    const email = safeText(contact.email).trim().toLowerCase();
    if (!email) continue;
    if (!groups.has(email)) groups.set(email, []);
    groups.get(email)!.push(contact);
  }
  return Array.from(groups.values());
}

function contactCompleteness(contact: Contact) {
  return [contact.full_name, contact.company, contact.phone, contact.notes].map(safeText).filter((value) => value.trim()).length;
}

function mergeContacts(primary: Contact, group: Contact[]): Contact {
  const firstNonEmpty = (...values: string[]) => values.find((value) => value.trim())?.trim() || "";
  const notes = Array.from(new Set(group.map((contact) => safeText(contact.notes).trim()).filter(Boolean))).join("\n\n");
  return {
    ...primary,
    full_name: firstNonEmpty(...group.map((contact) => safeText(contact.full_name))),
    company: firstNonEmpty(...group.map((contact) => safeText(contact.company))),
    phone: firstNonEmpty(...group.map((contact) => safeText(contact.phone))),
    notes,
  };
}

function dedupeSelection(items: MailSelectionItem[]) {
  const seen = new Set<string>();
  return items.filter((item) => {
    if (!item.uid || !item.source || seen.has(item.key)) return false;
    seen.add(item.key);
    return true;
  });
}

function groupSelectionBySource(items: MailSelectionItem[]) {
  return items.reduce<Record<string, Set<string>>>((groups, item) => {
    if (!groups[item.source]) groups[item.source] = new Set<string>();
    groups[item.source].add(item.uid);
    return groups;
  }, {});
}

function parseDraggedMessages(raw: string) {
  if (!raw) return [];
  try {
    const parsed = JSON.parse(raw);
    if (!Array.isArray(parsed)) return [];
    return dedupeSelection(parsed.filter((item): item is MailSelectionItem => (
      typeof item?.key === "string" &&
      typeof item?.uid === "string" &&
      typeof item?.source === "string"
    )));
  } catch {
    return [];
  }
}

function csvToList(value: string) {
  return value.split(",").map((item) => item.trim()).filter(Boolean);
}

function isFailureSummary(value: string) {
  const normalized = value.toLowerCase();
  return normalized.includes("unable") || normalized.includes("failed") || normalized.includes("fail") || normalized.includes("ไม่สามารถ") || normalized.includes("ล้มเหลว") || normalized.includes("无法") || normalized.includes("失败");
}

function createFilterRuleDraft(index: number, folder?: Folder): MailFilterRule {
  return {
    id: `filter-${Date.now()}-${index}-${Math.random().toString(36).slice(2, 8)}`,
    name: `Rule ${index + 1}`,
    enabled: true,
    field: "from",
    operator: "contains",
    value: "",
    target_folder_id: folder?.abs_path || folder?.path || "",
    target_folder_name: folder ? displayFolder(folder.name) : "",
    stop_processing: true,
    order: index,
  };
}

function normalizeFilterRules(rules: MailFilterRule[], folders: Folder[]) {
  const folderById = new Map(folders.flatMap((folder) => [[folder.path, folder], [folder.abs_path, folder]] as const));
  return rules
    .map((rule, index) => {
      const field = (rule.field || "from").toLowerCase() as MailFilterRule["field"];
      const operator = (rule.operator || "contains").toLowerCase() as MailFilterRule["operator"];
      const targetFolderId = rule.target_folder_id.trim();
      const folder = folderById.get(targetFolderId);
      return {
        ...rule,
        id: rule.id.trim() || `filter-${index + 1}`,
        name: rule.name.trim() || `Rule ${index + 1}`,
        enabled: Boolean(rule.enabled),
        field: ["from", "to", "subject", "body"].includes(field) ? field : "from",
        operator: ["contains", "equals", "starts_with", "ends_with"].includes(operator) ? operator : "contains",
        value: rule.value.trim(),
        target_folder_id: targetFolderId,
        target_folder_name: rule.target_folder_name.trim() || folder?.name || "",
        stop_processing: rule.stop_processing !== false,
        order: index,
      };
    })
    .filter((rule) => rule.value && rule.target_folder_id);
}

function safeText(value: unknown) {
  return typeof value === "string" ? value : value == null ? "" : String(value);
}

function messageTimestamp(message: Pick<MessageSummary, "date">) {
  const timestamp = new Date(message.date || "").getTime();
  return Number.isFinite(timestamp) ? timestamp : 0;
}

function sortMessageSummaries(messages: MessageSummary[], sortOrder: MessageSortOrder) {
  return [...messages].sort((left, right) => {
    const diff = messageTimestamp(left) - messageTimestamp(right);
    return sortOrder === "oldest" ? diff : -diff;
  });
}

function formatMailboxLabel(name: string, email: string) {
  const cleanEmail = safeText(email).trim();
  const cleanName = safeText(name).trim();
  if (cleanEmail) return cleanEmail;
  return cleanName;
}

function messageHeaderValue(headers: MessageDetail["headers"], name: string) {
  const normalized = name.trim().toLowerCase();
  return headers.find((header) => header.name.trim().toLowerCase() === normalized)?.value || "";
}

function formatRecipientLabel(value: string) {
  const clean = safeText(value).trim();
  if (!clean) return "";
  return displayAddressTokens(clean).join(", ");
}

function sectionTitle(section: "email" | "contacts" | "calendar" | "tasks" | "drive" | "preferences", folder: string, driveLabel = "Drive") {
  if (section === "email") return displayFolder(folder);
  if (section === "contacts") return "Contact";
  if (section === "calendar") return "Calendar";
  if (section === "tasks") return "Task";
  if (section === "drive") return driveLabel;
  return "Preferences";
}

function tagColorHex(tag?: Pick<Tag, "color" | "rgb"> | null) {
  if (tag?.rgb) return tag.rgb;
  return tagColorOptions.find((option) => option.value === (tag?.color ?? 0))?.hex ?? tagColorOptions[0].hex;
}

function validatePassword(password: string, t: ReturnType<typeof createTranslator>) {
  if (!password) return "";
  if (!/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,16}$/.test(password)) {
    return t("password.invalid");
  }
  return "";
}

function buildOriginalMessage(message: MessageDetail) {
  const headers = (message.headers.length
    ? message.headers
        .filter((header) => header.name.trim().toLowerCase() !== "bcc")
        .map((header) => `${header.name}: ${header.value}`)
    : [
        `From: ${message.sender_email}`,
        `To: ${displayAddressTokens(message.to).join(", ")}`,
        message.cc ? `Cc: ${displayAddressTokens(message.cc).join(", ")}` : "",
        `Date: ${message.date}`,
        `Subject: ${cleanSubject(message.subject)}`,
        message.tags.length ? `X-Webmail-Tags: ${message.tags.join(", ")}` : "",
        "MIME-Version: 1.0",
        `Content-Type: ${message.html ? "text/html; charset=utf-8" : "text/plain; charset=utf-8"}`
      ]).filter(Boolean);
  const body = message.text || message.preview || stripHtml(message.html);
  return `${headers.join("\n")}\n\n${body}`;
}

function handleReaderHtmlClick(event: ReactMouseEvent<HTMLElement>) {
  const target = event.target;
  if (!(target instanceof Element)) return;
  const anchor = target.closest<HTMLAnchorElement>("a[href]");
  if (!anchor) return;

  const safeUrl = resolveSafeReaderLinkUrl(anchor.getAttribute("href"));
  if (!safeUrl) {
    event.preventDefault();
    event.stopPropagation();
    return;
  }

  event.preventDefault();
  event.stopPropagation();
  const openedWindow = window.open(safeUrl, "_blank", "noopener,noreferrer");
  if (openedWindow) openedWindow.opener = null;
}

function resolveSafeReaderLinkUrl(href: string | null) {
  const raw = (href || "").trim();
  if (!raw || typeof window === "undefined") return "";
  try {
    const url = new URL(raw, window.location.origin);
    if (url.protocol === "http:" || url.protocol === "https:" || url.protocol === "mailto:" || url.protocol === "tel:") {
      return url.href;
    }
  } catch {
    return "";
  }
  return "";
}

function renderPrintableMessage(message: MessageDetail) {
  const rendered = getCachedReaderRender(message);
  const body = rendered.canRenderHtml ? rendered.htmlBody : `<pre>${escapeHtml(rendered.plainTextBody || "No message content.")}</pre>`;
  const attachments = rendered.visibleAttachments.length
    ? `<div class="attachments">${rendered.visibleAttachments.map((attachment) => `<span>${escapeHtml(cleanAttachmentDisplayName(attachment.filename))}</span>`).join("")}</div>`
    : "";
  return `<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>${escapeHtml(cleanSubject(message.subject))}</title>
    <style>
      body { font-family: Arial, sans-serif; margin: 32px; color: #0f172a; }
      h1 { font-size: 28px; margin: 0 0 16px; }
      .meta { margin-bottom: 24px; color: #475569; font-size: 14px; line-height: 1.7; }
      .meta strong { color: #0f172a; }
      .attachments{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 20px;padding:0}
      .attachments span{border:1px solid #dbe3ee;border-radius:999px;padding:3px 10px;font-size:12px;font-weight:700;color:#475569;background:#f8fafc}
      .content { font-size: 15px; line-height: 1.7; }
      pre { white-space: pre-wrap; word-break: break-word; }
      img { max-width: 100%; }
    </style>
  </head>
  <body>
    <h1>${escapeHtml(cleanSubject(message.subject))}</h1>
    <div class="meta">
      <div><strong>From:</strong> ${escapeHtml(message.sender_email)}</div>
      <div><strong>To:</strong> ${escapeHtml(displayAddressTokens(message.to).join(", "))}</div>
      ${message.cc ? `<div><strong>Cc:</strong> ${escapeHtml(displayAddressTokens(message.cc).join(", "))}</div>` : ""}
      <div><strong>Date:</strong> ${escapeHtml(formatDate(message.date))}</div>
    </div>
    ${attachments}
    <div class="content">${body}</div>
  </body>
</html>`;
}

function buildReaderDocument(html: string, text: string, title = "Message") {
  const baseHref = typeof window !== "undefined" ? window.location.origin + "/" : "/";
  const baseTag = `<base href="${escapeHtml(baseHref)}" />`;
  if (html.trim()) {
    if (/<html[\s>]/i.test(html) && typeof window !== "undefined" && typeof DOMParser !== "undefined") {
      const parser = new DOMParser();
      const document = parser.parseFromString(html, "text/html");
      const safeStyles = sanitizeReaderDocument(document);
      const safeHead = document.head || document.createElement("head");
      for (const style of safeStyles) {
        const styleNode = document.createElement("style");
        styleNode.textContent = style;
        safeHead.appendChild(styleNode);
      }
      safeHead.insertAdjacentHTML("afterbegin", baseTag);
      if (!safeHead.querySelector("meta[charset]")) {
        safeHead.insertAdjacentHTML("afterbegin", '<meta charset="utf-8" />');
      }
      if (!safeHead.querySelector("title")) {
        const titleNode = document.createElement("title");
        titleNode.textContent = title;
        safeHead.appendChild(titleNode);
      }
      return `<!doctype html>${document.documentElement.outerHTML}`;
    }
    const safeHtml = extractReaderBodyHtml(html);
    return `<!doctype html><html><head><meta charset="utf-8" />${baseTag}<title>${escapeHtml(title)}</title><meta name="viewport" content="width=device-width, initial-scale=1" /><style>html,body{margin:0;padding:0;background:#fff;color:#0f172a}body{padding:24px;font-family:Arial,sans-serif;line-height:1.65;overflow-wrap:anywhere}img{max-width:100%;height:auto}table{max-width:100%;border-collapse:collapse}a{color:var(--mail-reader-link,#0f766e)}</style></head><body>${safeHtml || escapeHtml(text || "No message content.")}</body></html>`;
  }
  return `<!doctype html><html><head><meta charset="utf-8" />${baseTag}<title>${escapeHtml(title)}</title><meta name="viewport" content="width=device-width, initial-scale=1" /><style>html,body{margin:0;padding:0;background:#fff;color:#0f172a}body{padding:24px;font-family:Arial,sans-serif;line-height:1.7;white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere}</style></head><body>${escapeHtml(text || "No message content.")}</body></html>`;
}

function buildInlineReaderMarkup(html: string, text: string) {
  const content = html.trim() ? extractReaderBodyHtml(html) : `<pre>${escapeHtml(text || "No message content.")}</pre>`;
  return `<style>
    .mail-reader-root{font-family:Arial,sans-serif;line-height:1.65;overflow-wrap:anywhere;word-break:break-word;color:#0f172a}
    .mail-reader-root img{max-width:100%;height:auto}
    .mail-reader-root table{max-width:100%;border-collapse:collapse}
    .mail-reader-root pre{white-space:pre-wrap;word-break:break-word}
    .mail-reader-root blockquote{margin:0 0 0 12px;padding-left:12px;border-left:3px solid #cbd5e1;color:#475569}
    .mail-reader-root a{color:var(--mail-reader-link,#0f766e)}
  </style><div class="mail-reader-root">${content}</div>`;
}

function isMeaningfulReaderMarkup(html: string) {
  if (!html.trim()) return false;
  if (typeof window === "undefined" || typeof DOMParser === "undefined") {
    return /[A-Za-z0-9\u0E00-\u0E7F]/.test(html);
  }
  const parser = new DOMParser();
  const document = parser.parseFromString(html, "text/html");
  const text = (document.body?.textContent || "").replace(/\s+/g, " ").trim();
  if (text.length >= 12) return true;
  return Boolean(document.body?.querySelector("img,table,pre,blockquote,ul,ol,li,p,br,a"));
}

function extractReaderBodyHtml(html: string) {
  if (!html.trim()) return "";
  if (typeof window === "undefined" || typeof DOMParser === "undefined") {
    const bodyMatch = html.match(/<body[^>]*>([\s\S]*)<\/body>/i);
    return bodyMatch?.[1] || html;
  }
  const parser = new DOMParser();
  const document = parser.parseFromString(html, "text/html");
  const safeStyles = sanitizeReaderDocument(document);
  const bodyHtml = document.body?.innerHTML?.trim() || "";
  const bodyText = (document.body?.textContent || "").replace(/\s+/g, " ").trim();
  const hasParserError = Boolean(document.querySelector("parsererror"));
  if (hasParserError && !bodyText) return "";
  if (!bodyHtml && !bodyText) return "";
  const styleMarkup = safeStyles.map((style) => `<style>${style}</style>`).join("");
  return `${styleMarkup}${bodyHtml || html}`;
}

function sanitizeReaderDocument(document: Document) {
  const safeStyles: string[] = [];
  for (const node of Array.from(document.querySelectorAll("script,style,link,meta,base,noscript,iframe,object,embed,form,input,button,select,textarea"))) {
    if (node.tagName.toLowerCase() === "style") {
      const safeStyle = sanitizeReaderStylesheet(node.textContent || "");
      if (safeStyle) safeStyles.push(safeStyle);
    }
    node.remove();
  }
  for (const element of Array.from(document.body.querySelectorAll("*"))) {
    for (const attribute of Array.from(element.attributes)) {
      const name = attribute.name.toLowerCase();
      if (name.startsWith("on")) {
        element.removeAttribute(attribute.name);
        continue;
      }
      if (name === "style") {
        const safeStyle = sanitizeReaderStyle(attribute.value);
        if (safeStyle) {
          element.setAttribute("style", safeStyle);
        } else {
          element.removeAttribute(attribute.name);
        }
        continue;
      }
      if (!isReaderSafeAttribute(element.tagName.toLowerCase(), name)) {
        element.removeAttribute(attribute.name);
        continue;
      }
      if (name === "background" && !isReaderSafeUrl(attribute.value, false)) {
        element.removeAttribute(attribute.name);
        continue;
      }
      if ((name === "href" || name === "src") && !isReaderSafeUrl(attribute.value, name === "src")) {
        element.removeAttribute(attribute.name);
      }
    }
    if (element.tagName.toLowerCase() === "a") {
      if (element.getAttribute("href")) {
        element.setAttribute("target", "_blank");
        element.setAttribute("rel", "noopener noreferrer");
      } else {
        element.removeAttribute("target");
        element.removeAttribute("rel");
      }
    }
  }
  return safeStyles;
}

function sanitizeReaderStyle(value: string) {
  const raw = (value || "").trim();
  if (!raw) return "";
  if (/expression\s*\(|javascript:|data:|@import|-moz-binding/i.test(raw)) return "";
  for (const match of raw.matchAll(/url\s*\(\s*["']?([^"')]+)["']?\s*\)/gi)) {
    if (!/^https?:\/\//i.test(match[1].trim())) return "";
  }
  const allowedProperties = [
    "background",
    "background-color",
    "background-image",
    "background-position",
    "background-repeat",
    "background-size",
    "border",
    "border-bottom",
    "border-color",
    "border-left",
    "border-right",
    "border-top",
    "border-width",
    "color",
    "box-sizing",
    "border-collapse",
    "border-radius",
    "display",
    "direction",
    "font",
    "font-family",
    "font-size",
    "font-style",
    "font-weight",
    "height",
    "line-height",
    "list-style",
    "list-style-position",
    "list-style-type",
    "margin",
    "margin-bottom",
    "margin-left",
    "margin-right",
    "margin-top",
    "max-width",
    "max-height",
    "min-height",
    "min-width",
    "object-fit",
    "overflow",
    "overflow-wrap",
    "padding",
    "padding-bottom",
    "padding-left",
    "padding-right",
    "padding-top",
    "text-align",
    "text-decoration",
    "text-indent",
    "text-transform",
    "letter-spacing",
    "table-layout",
    "vertical-align",
    "white-space",
    "width",
    "word-break",
  ];
  if (typeof document === "undefined") {
    return raw
      .split(";")
      .map((part) => part.trim())
      .filter((part) => {
        const [name = "", ...valueParts] = part.split(":");
        const property = name.trim().toLowerCase();
        const propertyValue = valueParts.join(":").trim();
        return allowedProperties.includes(property) && propertyValue && !/expression\s*\(|javascript:|data:|@import|-moz-binding/i.test(propertyValue) && [...propertyValue.matchAll(/url\s*\(\s*["']?([^"')]+)["']?\s*\)/gi)].every((match) => /^https?:\/\//i.test(match[1].trim()));
      })
      .join("; ");
  }
  const probe = document.createElement("span");
  probe.setAttribute("style", raw);
  return allowedProperties
    .map((property) => {
      const propertyValue = probe.style.getPropertyValue(property).trim();
      if (!propertyValue || /expression\s*\(|javascript:|data:|@import|-moz-binding/i.test(propertyValue)) return "";
      for (const match of propertyValue.matchAll(/url\s*\(\s*["']?([^"')]+)["']?\s*\)/gi)) {
        if (!/^https?:\/\//i.test(match[1].trim())) return "";
      }
      return `${property}: ${propertyValue}`;
    })
    .filter(Boolean)
    .join("; ");
}

function sanitizeReaderStylesheet(value: string) {
  const css = (value || "")
    .replace(/\/\*[\s\S]*?\*\//g, "")
    .replace(/<\/?style[^>]*>/gi, "")
    .trim();
  if (!css) return "";

  function sanitizeRules(source: string): string {
    const rules: string[] = [];
    let cursor = 0;
    while (cursor < source.length) {
      const open = source.indexOf("{", cursor);
      if (open < 0) break;
      const selectorText = source.slice(cursor, open).trim();
      let depth = 1;
      let close = open + 1;
      while (close < source.length && depth > 0) {
        if (source[close] === "{") depth += 1;
        if (source[close] === "}") depth -= 1;
        close += 1;
      }
      if (depth !== 0) break;
      const body = source.slice(open + 1, close - 1);
      cursor = close;
      if (!selectorText || /@(?:import|font-face|namespace|keyframes|-webkit-keyframes)/i.test(selectorText)) continue;
      if (/^@media\b/i.test(selectorText)) {
        const nested = sanitizeRules(body);
        if (nested) rules.push(`${selectorText} { ${nested} }`);
        continue;
      }
      const declarations = sanitizeReaderStyle(body);
      if (!declarations) continue;
      const selectors = selectorText
        .split(",")
        .map((selector) => selector.trim())
        .filter(Boolean)
        .map((selector) => {
          const normalized = selector
            .replace(/\b(?:html|body)\b/gi, ".mail-reader-root")
            .replace(/:root\b/gi, ".mail-reader-root");
          return normalized.startsWith(".mail-reader-root")
            ? normalized
            : `.mail-reader-root ${normalized}`;
        });
      if (selectors.length) rules.push(`${selectors.join(", ")} { ${declarations} }`);
    }
    return rules.join("\n");
  }

  return sanitizeRules(css);
}

function parseZimbraShareXml(xml: string) {
  const text = (xml || "").trim();
  if (!text) return null;
  const read = (pattern: RegExp) => {
    const match = text.match(pattern);
    return match?.[1] || "";
  };
  return {
    share_id: read(/<share[^>]*\bid="([^"]+)"/i),
    item_id: read(/<link[^>]*\bid="([^"]+)"/i),
    item_name: read(/<link[^>]*\bname="([^"]+)"/i),
    view: read(/<link[^>]*\bview="([^"]+)"/i),
    perm: read(/<link[^>]*\bperm="([^"]+)"/i),
    grantee_email: read(/<grantee[^>]*\bemail="([^"]+)"/i),
    grantee_name: read(/<grantee[^>]*\bname="([^"]+)"/i),
    grantor_id: read(/<grantor[^>]*\bid="([^"]+)"/i),
    grantor_email: read(/<grantor[^>]*\bemail="([^"]+)"/i),
    grantor_name: read(/<grantor[^>]*\bname="([^"]+)"/i),
  };
}

function isShareInviteAttachment(attachment: MessageDetail["attachments"][number]) {
  const contentType = (attachment.content_type || "").trim().toLowerCase();
  const filename = (attachment.filename || "").trim().toLowerCase();
  if (contentType.includes("zimbra-share")) return true;
  if (filename.includes("zimbra") && filename.includes("share") && filename.endsWith(".xml")) return true;
  if (filename.includes("share") && filename.endsWith(".xml")) return true;
  return false;
}

function isReaderSafeAttribute(tagName: string, attributeName: string) {
  if (attributeName === "class" || attributeName.startsWith("aria-")) return true;
  if (["colspan", "rowspan", "align", "valign", "width", "height", "bgcolor"].includes(attributeName)) return true;
  if (attributeName === "background") return ["body", "table", "td", "th"].includes(tagName);
  if (tagName === "a") return ["href", "title", "name", "target", "rel"].includes(attributeName);
  if (tagName === "img") return ["src", "alt", "title", "width", "height"].includes(attributeName);
  if (["td", "th", "table", "tr", "tbody", "thead", "tfoot", "div", "span", "p", "pre"].includes(tagName)) {
    return ["colspan", "rowspan", "align", "valign", "width", "height", "bgcolor", "background", "class"].includes(attributeName);
  }
  return attributeName === "class";
}

function isReaderSafeUrl(value: string, allowDataImage: boolean) {
  const text = (value || "").trim();
  if (!text) return false;
  if (text.startsWith("/") || text.startsWith("#")) return true;
  if (/^https?:/i.test(text)) return true;
  if (!allowDataImage && /^mailto:/i.test(text)) return true;
  if (allowDataImage && /^cid:/i.test(text)) return true;
  if (allowDataImage && /^data:image\/(?:png|jpe?g|gif|webp);base64,/i.test(text)) return true;
  return false;
}

function buildConversationReaderDocument(messages: NonNullable<MessageDetail["conversation_messages"]>, title = "Conversation") {
  const baseHref = typeof window !== "undefined" ? window.location.origin + "/" : "/";
  const baseTag = `<base href="${escapeHtml(baseHref)}" />`;
  const blocks = messages.map((message, index) => {
    const rendered = getCachedReaderRender(message);
    const attachments = rendered.visibleAttachments.length
      ? `<div class="attachments">${rendered.visibleAttachments.map((attachment) => `<span>${escapeHtml(cleanAttachmentDisplayName(attachment.filename))}</span>`).join("")}</div>`
      : "";
    const body = rendered.canRenderHtml
      ? `<div class="body">${rendered.htmlBody}</div>`
      : `<pre class="body text">${escapeHtml(rendered.plainTextBody || "No message content.")}</pre>`;
    return `
      <section class="thread-message">
        <header class="thread-head">
          <div class="thread-index">Message ${index + 1}</div>
          <div class="thread-from">${escapeHtml(message.sender_email || "Unknown sender")}</div>
          ${message.to ? `<div class="thread-to">To: ${escapeHtml(displayAddressTokens(message.to).join(", "))}</div>` : ""}
          ${message.cc ? `<div class="thread-cc">Cc: ${escapeHtml(displayAddressTokens(message.cc).join(", "))}</div>` : ""}
          <div class="thread-date">${escapeHtml(formatDate(message.date))}</div>
          <div class="thread-subject">${escapeHtml(cleanSubject(message.subject))}</div>
        </header>
        ${attachments}
        ${body}
      </section>
    `;
  }).join("");
  return `<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    ${baseTag}
    <title>${escapeHtml(title)}</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      html,body{margin:0;padding:0;background:#f8fafc;color:#0f172a}
      body{padding:20px;font-family:Arial,sans-serif;line-height:1.65;overflow-wrap:anywhere}
      .thread{display:grid;gap:14px;max-width:980px;margin:0 auto}
      .summary{border:1px solid #dbe3ee;border-radius:14px;background:#fff;padding:16px 18px}
      .summary h1{margin:0;font-size:22px;line-height:1.25;letter-spacing:-0.02em}
      .summary p{margin:8px 0 0;color:#64748b;font-size:13px}
      .thread-message{border:1px solid #dbe3ee;border-radius:14px;background:#fff;overflow:hidden;box-shadow:0 1px 2px rgba(15,23,42,.04)}
      .thread-head{display:grid;gap:6px;border-bottom:1px solid #e5edf5;background:#fbfdff;padding:14px 16px}
      .thread-index{text-transform:uppercase;letter-spacing:.12em;font-size:11px;font-weight:800;color:#94a3b8}
      .thread-from,.thread-to,.thread-cc,.thread-date{font-size:13px;color:#334155;font-weight:700;word-break:break-word}
      .thread-subject{font-size:16px;font-weight:800;color:#0f172a;word-break:break-word}
      .attachments{display:flex;flex-wrap:wrap;gap:6px;border-bottom:1px solid #eef2f7;padding:10px 16px;background:#fff}
      .attachments span{border:1px solid #dbe3ee;border-radius:999px;padding:3px 10px;font-size:12px;font-weight:700;color:#475569;background:#f8fafc}
      .body{padding:18px 16px}
      .body.text{white-space:pre-wrap;word-break:break-word;font-family:Arial,sans-serif;font-size:14px}
      .body img{max-width:100%;height:auto}
      .body table{max-width:100%;border-collapse:collapse}
      .body a{color:#0f766e}
    </style>
  </head>
  <body>
    <div class="thread">
      <section class="summary">
        <h1>${escapeHtml(title)}</h1>
        <p>${messages.length} message${messages.length === 1 ? "" : "s"}</p>
      </section>
      ${blocks}
    </div>
  </body>
</html>`;
}

function rewriteInlineImageSources(html: string, uid: string, attachments: MessageDetail["attachments"]) {
  if (!html || !attachments.length) return html;
  const inlineMap = new Map<string, string>();
  for (const attachment of attachments) {
    const key = normalizeInlineContentId(attachment.content_id);
    if (key) {
      inlineMap.set(key, attachment.part || attachment.content_id || "");
    }
  }
  if (!inlineMap.size) return html;
  if (typeof document === "undefined" || typeof DOMParser === "undefined") {
    return html.replace(/\b(?:src|data-mce-src|dfsrc)=(["'])cid:([^"']+)\1/gi, (match, quote, cid) => {
      const part = inlineMap.get(normalizeInlineContentId(String(cid)));
      if (!part) return match;
      return `src=${quote}/api/mail/messages/${encodeURIComponent(uid)}/attachments?part=${encodeURIComponent(part)}&preview=1${quote}`;
    });
  }
  const parser = new DOMParser();
  const doc = parser.parseFromString(html, "text/html");
  const images = Array.from(doc.querySelectorAll("img"));
  for (const img of images) {
    const src = img.getAttribute("src") || img.getAttribute("data-mce-src") || img.getAttribute("dfsrc") || "";
    if (!src.toLowerCase().startsWith("cid:")) continue;
    const contentId = normalizeInlineContentId(src.slice(4));
    const part = inlineMap.get(contentId);
    if (!part) continue;
    img.setAttribute("src", `/api/mail/messages/${encodeURIComponent(uid)}/attachments?part=${encodeURIComponent(part)}&preview=1`);
    img.removeAttribute("data-mce-src");
    img.removeAttribute("dfsrc");
  }
  const sources = Array.from(doc.querySelectorAll("source"));
  for (const source of sources) {
    const srcset = source.getAttribute("srcset") || source.getAttribute("data-mce-srcset") || "";
    if (!srcset.toLowerCase().includes("cid:")) continue;
    const rewritten = srcset.replace(/cid:([^,\s]+)/gi, (match, cid) => {
      const part = inlineMap.get(normalizeInlineContentId(String(cid)));
      return part ? `/api/mail/messages/${encodeURIComponent(uid)}/attachments?part=${encodeURIComponent(part)}&preview=1` : match;
    });
    source.setAttribute("srcset", rewritten);
    source.removeAttribute("data-mce-srcset");
  }
  return serializeParsedHtml(doc);
}

function inlineContentIdsFromHtml(html: string) {
  const ids = new Set<string>();
  const text = (html || "").trim();
  if (!text) return ids;
  const regex = /cid:([^"')\s>]+)/gi;
  for (const match of text.matchAll(regex)) {
    const id = normalizeInlineContentId(match[1]);
    if (id) ids.add(id);
  }
  return ids;
}

function visibleReaderAttachments(attachments: MessageDetail["attachments"], html = "") {
  const inlineContentIds = inlineContentIdsFromHtml(html);
  return attachments.filter((attachment) => {
    if (attachment.inline) return false;
    if (attachment.content_type?.toLowerCase().startsWith("text/calendar")) return false;
    const contentId = normalizeInlineContentId(attachment.content_id);
    return !(contentId && inlineContentIds.has(contentId));
  });
}

function formatCalendarInviteRange(invite: NonNullable<MessageDetail["calendar_invite"]>, locale: AppLocale = DEFAULT_LOCALE) {
  const timeZone = DEFAULT_TIME_ZONE;
  const displayLocale = calendarDisplayLocale(locale);
  if (invite.all_day) {
    const start = new Date(`${invite.start.slice(0, 10)}T00:00:00`);
    if (Number.isNaN(start.getTime())) return invite.summary || "All day";
    const end = invite.end ? new Date(`${invite.end.slice(0, 10)}T00:00:00`) : null;
    const startLabel = new Intl.DateTimeFormat(displayLocale, { dateStyle: "full" }).format(start);
    const endLabel = end && !Number.isNaN(end.getTime()) ? new Intl.DateTimeFormat(displayLocale, { dateStyle: "full" }).format(end) : "";
    return endLabel && endLabel !== startLabel ? `${startLabel} - ${endLabel}` : startLabel;
  }
  const start = new Date(invite.start);
  if (Number.isNaN(start.getTime())) return invite.start || "Calendar invitation";
  const end = invite.end ? new Date(invite.end) : null;
  const formatter = new Intl.DateTimeFormat(displayLocale, {
    dateStyle: "medium",
    timeStyle: "short",
    timeZone,
  });
  const startLabel = formatter.format(start);
  const endLabel = end && !Number.isNaN(end.getTime()) ? formatter.format(end) : "";
  return endLabel && endLabel !== startLabel ? `${startLabel} - ${endLabel}` : startLabel;
}

function calendarInviteBodyText(invite: NonNullable<MessageDetail["calendar_invite"]>) {
  const lines: string[] = [];
  if (invite.summary) lines.push(`Subject: ${invite.summary}`);
  if (invite.organizer) lines.push(`Organiser: ${invite.organizer}`);
  if (invite.start || invite.end) lines.push(`Time: ${formatCalendarInviteRange(invite)}`);
  if (invite.location) lines.push(`Location: ${invite.location}`);
  if (invite.attendees.length) lines.push(`Invitees: ${invite.attendees.join(", ")}`);
  if (invite.description) {
    lines.push("");
    lines.push(invite.description);
  }
  return lines.join("\n").trim();
}

function calendarInviteReplyLabel(subject: string, t: ReturnType<typeof createTranslator>) {
  const clean = (subject || "").trim().toLowerCase();
  if (clean.startsWith("accepted:") || clean.startsWith("accept:") || clean.startsWith("ยอมรับ:") || clean.startsWith("ตอบรับ:")) return t("calendar.accepted");
  if (clean.startsWith("tentative:") || clean.startsWith("ไม่แน่นอน:")) return t("calendar.tentative");
  if (clean.startsWith("declined:") || clean.startsWith("decline:") || clean.startsWith("ไม่เข้าร่วม:") || clean.startsWith("ปฏิเสธ:")) return t("calendar.declined");
  return t("calendar.response");
}

function calendarInviteReplyStateFromSubject(subject: string) {
  const clean = (subject || "").trim().toLowerCase();
  if (clean.startsWith("accepted:") || clean.startsWith("accept:") || clean.startsWith("ยอมรับ:") || clean.startsWith("ตอบรับ:")) return "accepted";
  if (clean.startsWith("tentative:") || clean.startsWith("ไม่แน่นอน:")) return "tentative";
  if (clean.startsWith("declined:") || clean.startsWith("decline:") || clean.startsWith("ไม่เข้าร่วม:") || clean.startsWith("ปฏิเสธ:")) return "declined";
  return "";
}

function calendarInviteReplyMessageForDetail(
  detail: Pick<MessageDetail, "sender_email" | "sender_name" | "subject">,
  invite: NonNullable<MessageDetail["calendar_invite"]>,
  senderLabel: string,
  t: ReturnType<typeof createTranslator>
) {
  const respondent = formatCalendarInviteParticipant(detail.sender_email) || formatCalendarInviteParticipant(detail.sender_name) || senderLabel || t("calendar.attendee");
  const state = calendarInviteReplyStateFromSubject(detail.subject);
  if (state === "accepted") return t("calendar.acceptedBy", { attendee: respondent });
  if (state === "tentative") return t("calendar.tentativeBy", { attendee: respondent });
  if (state === "declined") return t("calendar.declinedBy", { attendee: respondent });
  const method = (invite.method || "").trim().toUpperCase();
  if (method === "REPLY") return t("calendar.respondedBy", { attendee: respondent });
  return "";
}

function calendarInviteReplyExcerptFromDetail(detail: Pick<MessageDetail, "text" | "html">) {
  const source = normalizeReaderText(detail.text) || stripHtml(detail.html);
  if (!source) return "";
  const lines = source
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter(Boolean)
    .filter((line) => !/^(subject|organiser|organizer|time|invitees|from|to|cc|bcc):/i.test(line))
    .filter((line) => line !== "*~*~*~*~*~*~*~*~*~*");
  return lines.find((line) => /[A-Za-z\u0E00-\u0E7F]/.test(line)) || "";
}

function formatCalendarInviteParticipant(value: string) {
  const clean = safeText(value).trim();
  if (!clean) return "";
  return clean.replace(/^mailto:/i, "").trim();
}

function buildCachedReaderRender(
  message: Pick<MessageDetail, "uid" | "html" | "text" | "preview" | "attachments" | "calendar_invite">
): ReaderRenderCache {
  const attachmentKey = message.attachments
    .map((attachment) => `${attachment.part || ""}:${attachment.content_id || ""}:${attachment.filename || ""}:${attachment.content_type || ""}:${attachment.inline ? "1" : "0"}`)
    .join("|");
  const visibleAttachments = visibleReaderAttachments(message.attachments, message.html);
  const htmlWithInlineImages = rewriteInlineImageSources(message.html, message.uid, message.attachments);
  const restoredHtml = restoreImageSources(htmlWithInlineImages).trim();
  const htmlBody = extractReaderBodyHtml(restoredHtml);
  const plainTextFromHtml = stripHtml(htmlBody || restoredHtml || message.html);
  const inviteBody = message.calendar_invite ? calendarInviteBodyText(message.calendar_invite) : "";
  const normalizedText = normalizeReaderText(message.text);
  const normalizedHtmlText = normalizeReaderText(plainTextFromHtml);
  const fallbackText = normalizedText === "The message has no text content." ? "" : message.text;
  const fallbackPreview = normalizeReaderText(message.preview) === "The message has no text content." ? "" : message.preview;
  const plainTextBody = chooseReaderPlainText(
    fallbackText || inviteBody,
    plainTextFromHtml || inviteBody,
    fallbackPreview || inviteBody
  );
  const htmlShouldUseInviteBody =
    Boolean(inviteBody) &&
    (!htmlBody || normalizedHtmlText === "The message has no text content.");
  const renderedHtmlSource = htmlShouldUseInviteBody
    ? inviteBody.split(/\r?\n/).map((line) => escapeHtml(line)).join("<br>")
    : htmlBody;
  const renderedReaderHtml = buildInlineReaderMarkup(renderedHtmlSource, plainTextBody);
  const htmlLooksUseful = Boolean(renderedHtmlSource && isMeaningfulReaderMarkup(renderedReaderHtml));
  const plainTextLooksUseful = Boolean(plainTextBody && plainTextBody.trim().length >= 3);
  return {
    html: message.html,
    text: message.text,
    preview: message.preview,
    attachments: attachmentKey,
    htmlBody,
    visibleAttachmentKey: visibleAttachments.map((attachment) => `${attachment.part || ""}:${attachment.filename || ""}:${attachment.content_type || ""}`).join("|"),
    visibleAttachments,
    plainTextBody,
    renderedReaderHtml,
    canRenderHtml: htmlLooksUseful && (htmlLooksUseful || plainTextLooksUseful),
  };
}

function getCachedReaderRender(
  message: Pick<MessageDetail, "uid" | "html" | "text" | "preview" | "attachments" | "calendar_invite">
) {
  const attachmentKey = message.attachments
    .map((attachment) => `${attachment.part || ""}:${attachment.content_id || ""}:${attachment.filename || ""}:${attachment.content_type || ""}:${attachment.inline ? "1" : "0"}`)
    .join("|");
  const inviteKey = message.calendar_invite
    ? [
        message.calendar_invite.uid || "",
        message.calendar_invite.summary || "",
        message.calendar_invite.start || "",
        message.calendar_invite.end || "",
        message.calendar_invite.method || "",
        message.calendar_invite.organizer || "",
        message.calendar_invite.attendees.join("|"),
      ].join("::")
    : "";
  const cacheKey = `${message.uid}::${message.html}::${message.text}::${message.preview}::${attachmentKey}::${inviteKey}`;
  const cached = readerRenderCache.get(cacheKey);
  if (cached) return cached;
  const next = buildCachedReaderRender(message);
  readerRenderCache.set(cacheKey, next);
  return next;
}

function restoreImageSources(html: string) {
  if (!html.trim()) return html;
  const deferredImageAttrs = [
    "data-mce-src",
    "dfsrc",
    "data-src",
    "data-originalsrc",
    "data-orig-src",
    "originalsrc",
    "data-lazy-src",
  ];
  const deferredSrcsetAttrs = [
    "data-mce-srcset",
    "data-srcset",
    "data-originalsrcset",
    "originalsrcset",
  ];
  if (typeof document === "undefined" || typeof DOMParser === "undefined") {
    let restored = html;
    for (const attr of deferredImageAttrs) {
      const imagePattern = new RegExp(`<img\\b([^>]*?)\\s${attr}=(["'])(https?:\\/\\/[^"']+)\\2([^>]*)>`, "gi");
      restored = restored.replace(imagePattern, (tag, before, quote, src, after) => {
        return /\ssrc=/i.test(tag) ? tag : `<img${before} src=${quote}${src}${quote}${after}>`;
      });
      const cleanupPattern = new RegExp(`\\s${attr}=(["'])https?:\\/\\/[^"']+\\1`, "gi");
      restored = restored.replace(cleanupPattern, "");
    }
    for (const attr of deferredSrcsetAttrs) {
      const sourcePattern = new RegExp(`<source\\b([^>]*?)\\s${attr}=(["'])([^"']+)\\2([^>]*)>`, "gi");
      restored = restored.replace(sourcePattern, (tag, before, quote, srcset, after) => {
        return /\ssrcset=/i.test(tag) ? tag : `<source${before} srcset=${quote}${srcset}${quote}${after}>`;
      });
      const cleanupPattern = new RegExp(`\\s${attr}=(["'])[^"']+\\1`, "gi");
      restored = restored.replace(cleanupPattern, "");
    }
    return restored;
  }
  const parser = new DOMParser();
  const doc = parser.parseFromString(html, "text/html");
  for (const img of Array.from(doc.querySelectorAll("img"))) {
    const currentSrc = (img.getAttribute("src") || "").trim();
    const deferredSrc = deferredImageAttrs
      .map((attr) => (img.getAttribute(attr) || "").trim())
      .find((value) => /^https?:\/\//i.test(value)) || "";
    const looksLikePlaceholder = !currentSrc || currentSrc === "#" || currentSrc.startsWith("data:image/gif") || currentSrc.startsWith("cid:");
    if (looksLikePlaceholder && deferredSrc) {
      img.setAttribute("src", deferredSrc);
    }
    for (const attr of deferredImageAttrs) {
      img.removeAttribute(attr);
    }
  }
  for (const source of Array.from(doc.querySelectorAll("source"))) {
    const currentSrcset = (source.getAttribute("srcset") || "").trim();
    const deferredSrcset = deferredSrcsetAttrs
      .map((attr) => (source.getAttribute(attr) || "").trim())
      .find((value) => Boolean(value)) || "";
    if (!currentSrcset && deferredSrcset) {
      source.setAttribute("srcset", deferredSrcset);
    }
    for (const attr of deferredSrcsetAttrs) {
      source.removeAttribute(attr);
    }
  }
  return serializeParsedHtml(doc);
}

function normalizeInlineContentId(value: string | undefined | null) {
  let text = (value || "").trim();
  if (!text) return "";
  if (text.toLowerCase().startsWith("cid:")) text = text.slice(4);
  try {
    text = decodeURIComponent(text);
  } catch {
    // Keep the original content-id when it is not valid URI encoding.
  }
  return text.trim().replace(/^<|>$/g, "").toLowerCase();
}

function cleanSubject(value: string) {
  return (value || "(no subject)").replace(/\s+/g, " ").trim();
}

function normalizeComposeSubject(value: string) {
  const subject = cleanSubject(value);
  return subject.toLowerCase() === "(no subject)" ? "" : subject;
}

function formatDate(value?: string, locale: AppLocale = DEFAULT_LOCALE, timeZone: string = DEFAULT_TIME_ZONE) {
  if (!value) return "";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return value;
  return new Intl.DateTimeFormat(calendarDisplayLocale(locale), { dateStyle: "short", timeStyle: "short", timeZone }).format(date);
}

function formatMessageDate(value?: string, locale: AppLocale = DEFAULT_LOCALE, timeZone: string = DEFAULT_TIME_ZONE) {
  if (!value) return "-";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "-";
  const displayLocale = calendarDisplayLocale(locale);
  const parts = new Intl.DateTimeFormat(displayLocale, { timeZone, year: "numeric", month: "2-digit", day: "2-digit" }).formatToParts(date);
  const todayParts = new Intl.DateTimeFormat(displayLocale, { timeZone, year: "numeric", month: "2-digit", day: "2-digit" }).formatToParts(new Date());
  const partValue = (items: Intl.DateTimeFormatPart[], type: string) => items.find((item) => item.type === type)?.value || "";
  const sameDay = ["year", "month", "day"].every((type) => partValue(parts, type) === partValue(todayParts, type));
  if (sameDay) {
    return new Intl.DateTimeFormat(displayLocale, { hour: "2-digit", minute: "2-digit", timeZone }).format(date);
  }
  return new Intl.DateTimeFormat(displayLocale, { day: "2-digit", month: "short", year: "numeric", timeZone }).format(date);
}

function formatDurationShort(totalSeconds: number) {
  const seconds = Math.max(0, Math.floor(totalSeconds));
  const hours = Math.floor(seconds / 3600);
  const minutes = Math.floor((seconds % 3600) / 60);
  const remainingSeconds = seconds % 60;
  if (hours > 0) return `${hours}h ${minutes}m`;
  if (minutes > 0) return `${minutes}m ${remainingSeconds.toString().padStart(2, "0")}s`;
  return `${remainingSeconds}s`;
}

function formatAttachmentSize(bytes?: number) {
  const value = bytes ?? 0;
  if (value >= 1024 * 1024) return `${(value / (1024 * 1024)).toFixed(1)} MB`;
  if (value >= 1024) return `${Math.round(value / 1024)} KB`;
  return `${value} B`;
}

function fileExtension(value: string) {
  const clean = value.trim().toLowerCase().split("?")[0].split("#")[0];
  const fileName = clean.split("/").pop() || clean;
  const match = fileName.match(/\.([a-z0-9]{1,8})$/i);
  return match ? match[1].toLowerCase() : "";
}

function classifyAttachment(mimeType: string, filename = "") {
  const value = mimeType.trim().toLowerCase();
  const ext = fileExtension(filename);
  if (value === "application/pdf" || ext === "pdf") return "PDF";
  if (value.startsWith("image/") || ["jpg", "jpeg", "png", "gif", "webp", "bmp", "heic", "heif", "avif", "tif", "tiff"].includes(ext)) return "Image";
  if (value.startsWith("video/")) return "Video";
  if (value.startsWith("audio/")) return "Audio";
  if (value === "application/zip" || ["zip", "rar", "7z", "tar", "gz", "tgz"].includes(ext)) return "ZIP";
  if (value === "text/plain") return "Text";
  if (value === "application/octet-stream" && ext) {
    if (["pdf"].includes(ext)) return "PDF";
    if (["zip", "rar", "7z", "tar", "gz", "tgz"].includes(ext)) return "ZIP";
    if (["jpg", "jpeg", "png", "gif", "webp", "bmp", "heic", "heif", "avif", "tif", "tiff"].includes(ext)) return "Image";
  }
  if (isGoogleDriveMimeType(value)) return googleDriveAttachmentLabel(value);
  return "File";
}

function formatAttachmentTypeLabel(mimeType: string, filename = "") {
  const value = mimeType.trim().toLowerCase();
  if (!value) return "File";
  return classifyAttachment(value, filename);
}

function cleanAttachmentDisplayName(value: string) {
  const text = safeText(value).trim();
  if (!text) return "Attachment";
  const lower = text.toLowerCase();
  if (lower.startsWith("inline;") || lower.startsWith("attachment;")) {
    const match = text.match(/filename\s*=\s*(?:"([^"]+)"|([^;]+))/i);
    if (match) {
      return (match[1] || match[2] || "").trim().replace(/^"|"$/g, "") || "Attachment";
    }
  }
  return text.replace(/^inline;\s*filename\s*=\s*/i, "").replace(/^attachment;\s*filename\s*=\s*/i, "").replace(/^["']|["']$/g, "") || "Attachment";
}

function attachmentTypeIcon(mimeType: string, filename = "") {
  const value = mimeType.trim().toLowerCase();
  const label = classifyAttachment(value, filename);
  if (!value) return <Paperclip size={13} className="shrink-0 text-slate-400" />;
  if (label === "PDF") return <FileText size={13} className="shrink-0 text-[var(--accent)]" />;
  if (label === "Image") return <FileImage size={13} className="shrink-0 text-[var(--accent)]" />;
  if (value.startsWith("video/")) return <Video size={13} className="shrink-0 text-[var(--accent)]" />;
  if (value.startsWith("audio/")) return <Music2 size={13} className="shrink-0 text-[var(--accent)]" />;
  if (label === "ZIP") return <FileArchive size={13} className="shrink-0 text-[var(--accent)]" />;
  if (value === "application/vnd.google-apps.spreadsheet") return <FileSpreadsheet size={13} className="shrink-0 text-[var(--accent)]" />;
  if (value === "application/vnd.google-apps.document") return <FileText size={13} className="shrink-0 text-[var(--accent)]" />;
  if (value === "application/vnd.google-apps.presentation") return <FileText size={13} className="shrink-0 text-[var(--accent)]" />;
  return <Paperclip size={13} className="shrink-0 text-slate-400" />;
}

function canPreviewAttachment(mimeType: string, filename = "") {
  const value = mimeType.trim().toLowerCase();
  const label = classifyAttachment(value, filename);
  return value.startsWith("image/") || value.startsWith("text/") || label === "PDF" || label === "Image";
}

function formatDriveMimeLabel(mimeType: string, filename = "") {
  const value = mimeType.trim().toLowerCase();
  if (!value) return "";
  return classifyAttachment(value, filename);
}

function formatDriveBytes(value: number) {
  const size = Math.max(0, Number(value || 0));
  if (size >= 1024 * 1024 * 1024) return `${(size / 1024 / 1024 / 1024).toFixed(2)} GB`;
  if (size >= 1024 * 1024) return `${(size / 1024 / 1024).toFixed(1)} MB`;
  if (size >= 1024) return `${Math.max(1, Math.round(size / 1024))} KB`;
  return `${size} B`;
}

function describeDriveFolderStats(folder: DriveFile) {
  const itemCount = Math.max(0, Number(folder.item_count || 0));
  const totalSize = Math.max(0, Number(folder.total_size || folder.size || 0));
  const fileLabel = `${itemCount} file${itemCount === 1 ? "" : "s"}`;
  if (totalSize > 0) {
    return `${fileLabel} · ${formatDriveBytes(totalSize)}`;
  }
  return fileLabel;
}

function isMountedDriveFolder(folder: DriveFile) {
  return Boolean((folder.share_owner_email || folder.share_owner_id || "").trim());
}

function canWriteDriveFolder(folder: DriveFile | null | undefined) {
  if (!folder || !isMountedDriveFolder(folder)) return true;
  return nativeSharePermissionAllowsWrite(folder.permissions || "");
}

function nativeSharePermissionAllowsWrite(value: string, requiredRight = "") {
  const normalized = (value || "").trim().toLowerCase();
  if (!normalized || ["r", "read", "reader", "view", "viewer"].includes(normalized)) return false;
  if (["owner", "manager", "admin"].includes(normalized)) return true;
  if (requiredRight) return normalized.includes(requiredRight);
  return ["w", "i", "d", "a"].some((right) => normalized.includes(right));
}

function driveOpenUrl(file: DriveFile, nativeZimbra = false) {
  if (nativeZimbra) {
    return `/api/drive/files/${encodeURIComponent(file.id)}/download?preview=1`;
  }
  return googleDriveOpenUrl(file);
}

function driveDownloadUrl(file: DriveFile, nativeZimbra = false) {
  if (nativeZimbra) {
    return `/api/drive/files/${encodeURIComponent(file.id)}/download`;
  }
  return googleDriveDownloadUrl(file);
}

function replySubject(subject: string) {
  const clean = cleanSubject(subject);
  return /^re:/i.test(clean) ? clean : `Re: ${clean}`;
}

function forwardSubject(subject: string) {
  const clean = cleanSubject(subject);
  return /^fwd:/i.test(clean) ? clean : `Fwd: ${clean}`;
}

function splitAddresses(value: string) {
  return value.split(",").map((item) => item.trim()).filter(Boolean);
}

function displayAddressTokens(value: string) {
  return splitAddresses(value).map((item) => item.trim()).filter(Boolean);
}

function extractAddressTokens(value: string) {
  const tokens = splitAddresses(value);
  const extracted: string[] = [];
  for (const token of tokens) {
    const emailMatch = token.match(/<([^>]+)>/);
    if (emailMatch?.[1]) {
      extracted.push(emailMatch[1].trim());
      continue;
    }
    const bareEmail = token.match(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/i)?.[0];
    if (bareEmail) {
      extracted.push(bareEmail.trim());
      continue;
    }
    extracted.push(token);
  }
  return extracted;
}

function uniqueAddresses(values: string[]) {
  const seen = new Set<string>();
  const result: string[] = [];
  for (const value of values.map((item) => item.trim()).filter(Boolean)) {
    const key = value.toLowerCase();
    if (!seen.has(key)) {
      seen.add(key);
      result.push(value);
    }
  }
  return result;
}

function quoteMessage(message: MessageDetail) {
  return `\n\nOn ${formatDate(message.date)}, ${message.sender_name || message.sender_email} wrote:\n${prefixQuotedText(message.text)}`;
}

function forwardedMessage(message: MessageDetail) {
  return [
    "",
    "",
    "---------- Forwarded message ----------",
    `From: ${message.sender_name || message.sender_email}`,
    `Date: ${formatDate(message.date)}`,
    `Subject: ${message.subject}`,
    `To: ${message.to}`,
    "",
    message.text
  ].join("\n");
}

function buildQuotedMessageHtml(message: MessageDetail) {
  const body = message.html?.trim()
    ? message.html
    : `<pre style="white-space:pre-wrap;word-break:break-word;margin:0">${escapeHtml(message.text || message.preview || "")}</pre>`;
  return [
    `<div style="font-family:Arial,sans-serif;font-size:14px;line-height:1.6;color:#0f172a">`,
    `<div style="margin:0 0 16px;color:#475569">On ${escapeHtml(formatDate(message.date))}, ${escapeHtml(message.sender_name || message.sender_email)} wrote:</div>`,
    `<blockquote style="margin:0;padding-left:16px;border-left:3px solid #cbd5e1">`,
    body,
    `</blockquote>`,
    `</div>`
  ].join("");
}

function buildForwardedMessageHtml(message: MessageDetail) {
  const body = message.html?.trim()
    ? message.html
    : `<pre style="white-space:pre-wrap;word-break:break-word;margin:0">${escapeHtml(message.text || message.preview || "")}</pre>`;
  return [
    `<div style="font-family:Arial,sans-serif;font-size:14px;line-height:1.6;color:#0f172a">`,
    `<div style="margin:0 0 16px">---------- Forwarded message ----------</div>`,
    `<div><strong>From:</strong> ${escapeHtml(message.sender_name || message.sender_email)}</div>`,
    `<div><strong>Date:</strong> ${escapeHtml(formatDate(message.date))}</div>`,
    `<div><strong>Subject:</strong> ${escapeHtml(message.subject)}</div>`,
    `<div><strong>To:</strong> ${escapeHtml(message.to || "")}</div>`,
    `<div style="margin-top:16px;border-top:1px solid #cbd5e1;padding-top:16px">`,
    body,
    `</div>`,
    `</div>`
  ].join("");
}

async function inlineMessageImages(html: string) {
  if (typeof window === "undefined" || !html.trim() || typeof DOMParser === "undefined") return html;
  const parser = new DOMParser();
  const document = parser.parseFromString(html, "text/html");
  const nodes = Array.from(document.querySelectorAll<HTMLElement>("img,source,[style]"));
  if (!nodes.length) return html;

  const inlineUrl = async (url: string) => {
    if (!url || url.startsWith("data:")) return url;
    if (!url.startsWith("/api/mail/messages/") && !/^https?:\/\//i.test(url)) return url;
    try {
      const response = await fetch(url, { credentials: "include" });
      if (!response.ok) return url;
      const blob = await response.blob();
      const dataUrl = await blobToDataUrl(blob);
      return dataUrl || url;
    } catch {
      return url;
    }
  };

  await Promise.all(nodes.map(async (node) => {
    const src = node.getAttribute("src");
    if (src) node.setAttribute("src", await inlineUrl(src));

    const srcset = node.getAttribute("srcset");
    if (srcset) {
      const rewritten = await Promise.all(
        srcset.split(",").map(async (candidate) => {
          const trimmed = candidate.trim();
          if (!trimmed) return trimmed;
          const parts = trimmed.split(/\s+/);
          const url = parts.shift() || "";
          const descriptor = parts.join(" ");
          const nextUrl = await inlineUrl(url);
          return [nextUrl, descriptor].filter(Boolean).join(" ").trim();
        })
      );
      node.setAttribute("srcset", rewritten.filter(Boolean).join(", "));
    }

    const style = node.getAttribute("style");
    if (style && /url\(/i.test(style)) {
      const rewrittenStyle = await replaceStyleUrls(style, inlineUrl);
      node.setAttribute("style", rewrittenStyle);
    }
  }));

  return serializeParsedHtml(document);
}

async function replaceStyleUrls(style: string, inlineUrl: (url: string) => Promise<string>) {
  const pattern = /url\((["']?)([^"')]+)\1\)/gi;
  let result = style;
  for (const match of style.matchAll(pattern)) {
    const replacement = `url("${await inlineUrl(match[2])}")`;
    result = result.replace(match[0], replacement);
  }
  return result;
}

function normalizeRecipientToken(value: string) {
  const trimmed = value.trim();
  const angleMatch = trimmed.match(/<([^>]+)>/);
  if (angleMatch?.[1]) {
    return angleMatch[1].trim().toLowerCase();
  }
  return trimmed.toLowerCase();
}

function describeSharePermissions(value: string) {
  const normalized = (value || "").trim().toLowerCase();
  if (normalized === "r") return "viewer";
  if (normalized === "rwidx" || normalized === "rwid" || normalized === "rwd" || normalized === "rw" || normalized.includes("w") || normalized.includes("d")) {
    return "manager";
  }
  return normalized || "viewer";
}

function ShareStatusRoleBadges({ status, permissions, t }: { status: string; permissions: string; t: ReturnType<typeof createTranslator> }) {
  return (
    <div className="flex shrink-0 flex-wrap justify-end gap-1.5">
      <span className={clsx("inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em]", shareStateBadgeClass(status || "pending"))}>
        {shareStatusLabel(status || "pending", t)}
      </span>
      <span className={clsx("inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-bold uppercase tracking-[0.08em]", shareRoleBadgeClass(permissions || "r"))}>
        {describeSharePermissions(permissions || "r")}
      </span>
    </div>
  );
}

function shareStatusLabel(value: string, t: ReturnType<typeof createTranslator>) {
  const normalized = (value || "").trim().toLowerCase();
  if (normalized === "accepted") return t("calendar.accepted");
  if (normalized === "active") return t("sharing.active");
  if (normalized === "declined") return t("calendar.declined");
  if (normalized === "revoked") return "Revoked";
  if (normalized === "pending") return "Pending";
  return normalized || "Pending";
}

function shareRoleBadgeClass(value: string) {
  const role = describeSharePermissions(value);
  if (role === "manager") {
    return "border border-amber-200 bg-amber-50 text-amber-800";
  }
  return "border border-sky-200 bg-sky-50 text-sky-800";
}

function shareStateBadgeClass(state: string) {
  const normalized = (state || "").trim().toLowerCase();
  if (normalized === "accepted" || normalized === "active") {
    return "border border-emerald-200 bg-emerald-50 text-emerald-800";
  }
  if (normalized === "revoked") {
    return "border border-rose-200 bg-rose-50 text-rose-800";
  }
  return "border border-amber-200 bg-amber-50 text-amber-800";
}

function shareNotificationStatus(notification: ShareNotification) {
  return (notification.status || "").trim().toLowerCase();
}

function isAcceptedShareNotification(notification: ShareNotification) {
  return shareNotificationStatus(notification) === "accepted";
}

function isRevokedShareNotification(notification: ShareNotification) {
  const status = shareNotificationStatus(notification);
  return status === "revoked" || status === "declined";
}

function isPendingShareNotification(notification: ShareNotification) {
  return !isAcceptedShareNotification(notification) && !isRevokedShareNotification(notification);
}

function shareNotificationsMatch(left: ShareNotification, right: ShareNotification) {
  const leftId = (left.id || "").trim();
  const rightId = (right.id || "").trim();
  if (leftId && rightId && leftId === rightId) return true;

  const leftItemId = (left.item_id || "").trim();
  const rightItemId = (right.item_id || "").trim();
  const leftGrantor = ((left.grantor_id || left.grantor_email || "")).trim().toLowerCase();
  const rightGrantor = ((right.grantor_id || right.grantor_email || "")).trim().toLowerCase();
  if (leftItemId && rightItemId && leftItemId === rightItemId && (!leftGrantor || !rightGrantor || leftGrantor === rightGrantor)) return true;

  const leftName = displayFolder(left.item_name || "").trim().toLowerCase();
  const rightName = displayFolder(right.item_name || "").trim().toLowerCase();
  const leftView = shareNotificationView(left);
  const rightView = shareNotificationView(right);
  return Boolean(leftName && rightName && leftName === rightName && leftGrantor && rightGrantor && leftGrantor === rightGrantor && leftView === rightView);
}

function hasShareRecipient(share: { email?: string }) {
  return Boolean((share.email || "").trim());
}

function shareNotificationView(notification: ShareNotification) {
  return (notification.item_view || "").trim().toLowerCase();
}

function isEmailShareNotification(notification: ShareNotification) {
  const view = shareNotificationView(notification);
  return !view || view === "message" || view === "mail" || view === "folder" || view === "conversation";
}

function isContactShareNotification(notification: ShareNotification) {
  const view = shareNotificationView(notification);
  return view === "contact" || view === "contacts";
}

function isCalendarShareNotification(notification: ShareNotification) {
  const view = shareNotificationView(notification);
  return view === "appointment" || view === "calendar";
}

function isTaskShareNotification(notification: ShareNotification) {
  const view = shareNotificationView(notification);
  return view === "task";
}

function shareNotificationKind(notification: ShareNotification): ShareResourceKind {
  if (isBriefcaseShareNotification(notification)) return "briefcase";
  if (isCalendarShareNotification(notification)) return "calendar";
  if (isContactShareNotification(notification)) return "contact";
  if (isTaskShareNotification(notification)) return "task";
  return "mail";
}

function shareResourceLabel(kind: ShareResourceKind, t: ReturnType<typeof createTranslator>) {
  if (kind === "calendar") return t("sharing.calendar");
  if (kind === "contact") return t("settings.contact");
  if (kind === "task") return t("sharing.task");
  if (kind === "briefcase") return t("sharing.briefcase");
  return t("sharing.email");
}

function shareNotificationSummary(mounted: number, pending: number) {
  return `${mounted} accepted · ${pending} pending`;
}

function findSharedFolderForNotification(folders: Folder[], notification: ShareNotification) {
  const grantorEmail = (notification.grantor_email || "").trim().toLowerCase();
  const grantorId = (notification.grantor_id || "").trim().toLowerCase();
  const itemName = displayFolder(notification.item_name || "").trim().toLowerCase();
  return folders.find((folder) => {
    const shareOwnerEmail = (folder.share_owner_email || "").trim().toLowerCase();
    const shareOwnerId = (folder.share_owner_id || "").trim().toLowerCase();
    const folderName = displayFolder(folder.name || "").trim().toLowerCase();
    const folderPath = (folder.abs_path || folder.path || "").trim().toLowerCase();
    return Boolean(folder.share_owner_email || folder.share_owner_id) && (
      (grantorEmail && shareOwnerEmail === grantorEmail) ||
      (grantorId && shareOwnerId === grantorId) ||
      (itemName && (folderName === itemName || folderPath.endsWith(`/${itemName}`) || folderPath.endsWith(itemName)))
    );
  }) || null;
}

function findContactFolderForShareNotification(folders: ContactFolder[], notification: ShareNotification) {
  const grantorEmail = (notification.grantor_email || "").trim().toLowerCase();
  const grantorId = (notification.grantor_id || "").trim().toLowerCase();
  const itemId = (notification.item_id || "").trim();
  const itemName = displayFolder(notification.item_name || "").trim().toLowerCase();
  return folders.find((folder) => {
    const shareOwnerEmail = (folder.share_owner_email || "").trim().toLowerCase();
    const shareOwnerId = (folder.share_owner_id || "").trim().toLowerCase();
    const folderId = (folder.id || "").trim();
    const folderName = displayFolder(folder.name || "").trim().toLowerCase();
    const folderPath = (folder.abs_path || folder.id || "").trim().toLowerCase();
    return Boolean(folder.share_owner_email || folder.share_owner_id) && (
      (itemId && folderId === itemId) ||
      (grantorEmail && shareOwnerEmail === grantorEmail) ||
      (grantorId && shareOwnerId === grantorId) ||
      (itemName && (folderName === itemName || folderPath.endsWith(`/${itemName}`) || folderPath.endsWith(itemName)))
    );
  }) || null;
}

function isBriefcaseShareNotification(notification: ShareNotification) {
  const view = (notification.item_view || "").trim().toLowerCase();
  const itemName = (notification.item_name || "").trim().toLowerCase();
  return view === "document" || view === "briefcase" || itemName.includes("briefcase");
}

function findDriveFolderForShareNotification(folders: DriveFile[], notification: ShareNotification) {
  const grantorEmail = (notification.grantor_email || "").trim().toLowerCase();
  const grantorId = (notification.grantor_id || "").trim().toLowerCase();
  const itemName = displayFolder(notification.item_name || "").trim().toLowerCase();
  return folders.find((folder) => {
    const folderOwnerEmail = (folder.share_owner_email || "").trim().toLowerCase();
    const folderOwnerId = (folder.share_owner_id || "").trim().toLowerCase();
    const folderName = displayFolder(folder.name || "").trim().toLowerCase();
    return (
      (grantorEmail && folderOwnerEmail === grantorEmail) ||
      (grantorId && folderOwnerId === grantorId) ||
      (itemName && folderName === itemName)
    );
  }) || null;
}

function isMountedCalendarSource(calendar: CalendarSource) {
  return Boolean((calendar.share_owner_email || calendar.share_owner_id || calendar.remote_id || "").trim()) || calendar.access_role === "reader";
}

function findCalendarForShareNotification(calendars: CalendarSource[], notification: ShareNotification) {
  const grantorEmail = (notification.grantor_email || "").trim().toLowerCase();
  const grantorId = (notification.grantor_id || "").trim().toLowerCase();
  const itemId = (notification.item_id || "").trim();
  const itemName = displayFolder(notification.item_name || "").trim().toLowerCase();
  return calendars.find((calendar) => {
    const ownerEmail = (calendar.share_owner_email || "").trim().toLowerCase();
    const ownerId = (calendar.share_owner_id || "").trim().toLowerCase();
    const calendarId = (calendar.id || "").trim();
    const remoteId = (calendar.remote_id || "").trim();
    const calendarName = displayFolder(calendar.summary || "").trim().toLowerCase();
    return isMountedCalendarSource(calendar) && (
      (itemId && (calendarId === itemId || remoteId === itemId)) ||
      (grantorEmail && ownerEmail === grantorEmail) ||
      (grantorId && ownerId === grantorId) ||
      (itemName && calendarName === itemName)
    );
  }) || null;
}

function isMountedTaskList(list: NativeZimbraTaskList) {
  return Boolean((list.share_owner_email || list.share_owner_id || list.remote_id || "").trim()) || Boolean((list.permissions || "").trim());
}

function displayMountedTaskSharePath(list: NativeZimbraTaskList) {
  const path = (list.abs_path || list.id || list.name || "").trim();
  if (path.toLowerCase().startsWith("/tasks/")) return `/${path.slice(7)}`;
  if (path.toLowerCase() === "/tasks") return `/${list.name || "Tasks"}`;
  return path || `/${list.name || "Task"}`;
}

function findTaskListForShareNotification(lists: NativeZimbraTaskList[], notification: ShareNotification) {
  const grantorEmail = (notification.grantor_email || "").trim().toLowerCase();
  const grantorId = (notification.grantor_id || "").trim().toLowerCase();
  const itemId = (notification.item_id || "").trim();
  const itemName = displayFolder(notification.item_name || "").trim().toLowerCase();
  return lists.find((list) => {
    const ownerEmail = (list.share_owner_email || "").trim().toLowerCase();
    const ownerId = (list.share_owner_id || "").trim().toLowerCase();
    const listId = (list.id || "").trim();
    const remoteId = (list.remote_id || "").trim();
    const listName = displayFolder(list.name || "").trim().toLowerCase();
    const listPath = (list.abs_path || "").trim().toLowerCase();
    return isMountedTaskList(list) && (
      (itemId && (listId === itemId || remoteId === itemId)) ||
      (grantorEmail && ownerEmail === grantorEmail) ||
      (grantorId && ownerId === grantorId) ||
      (itemName && (listName === itemName || listPath.endsWith(`/${itemName}`) || listPath.endsWith(itemName)))
    );
  }) || null;
}

function isMountedShareNotification(notification: ShareNotification, mailFolders: Folder[], contactFolders: ContactFolder[], calendars: CalendarSource[], taskLists: NativeZimbraTaskList[], briefcaseFolders: DriveFile[]) {
  if (isEmailShareNotification(notification)) {
    return Boolean(findSharedFolderForNotification(mailFolders, notification));
  }
  if (isContactShareNotification(notification)) {
    return Boolean(findContactFolderForShareNotification(contactFolders, notification));
  }
  if (isCalendarShareNotification(notification)) {
    return Boolean(findCalendarForShareNotification(calendars, notification));
  }
  if (isTaskShareNotification(notification)) {
    return Boolean(findTaskListForShareNotification(taskLists, notification));
  }
  if (isBriefcaseShareNotification(notification)) {
    return Boolean(findDriveFolderForShareNotification(briefcaseFolders, notification));
  }
  return false;
}

function findBriefcaseNotificationForMountedFolder(notifications: ShareNotification[], folder: DriveFile) {
  const shareOwnerEmail = (folder.share_owner_email || "").trim().toLowerCase();
  const shareOwnerId = (folder.share_owner_id || "").trim().toLowerCase();
  const folderName = displayFolder(folder.name || "").trim().toLowerCase();
  return notifications.find((notification) => {
    if (!isBriefcaseShareNotification(notification)) return false;
    const grantorEmail = (notification.grantor_email || "").trim().toLowerCase();
    const grantorId = (notification.grantor_id || "").trim().toLowerCase();
    const itemName = displayFolder(notification.item_name || "").trim().toLowerCase();
    return (
      (shareOwnerEmail && grantorEmail === shareOwnerEmail) ||
      (shareOwnerId && grantorId === shareOwnerId) ||
      (folderName && itemName === folderName)
    );
  }) || null;
}

function blobToDataUrl(blob: Blob): Promise<string> {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = () => resolve(String(reader.result || ""));
    reader.onerror = () => resolve("");
    reader.readAsDataURL(blob);
  });
}

function prefixQuotedText(text: string) {
  return text.split(/\r?\n/).map((line) => `> ${line}`).join("\n");
}

function formatStorage(kb: number) {
  if (kb >= 1024 * 1024) return `${(kb / 1024 / 1024).toFixed(2)} GB`;
  if (kb >= 1024) return `${(kb / 1024).toFixed(1)} MB`;
  return `${kb} KB`;
}

function clamp(value: number, min: number, max: number) {
  return Math.min(max, Math.max(min, value));
}

function serializeParsedHtml(document: Document) {
  return document.documentElement.outerHTML;
}

function escapeHtml(value: string) {
  return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
}

function stripSignatureHtml(value: string) {
  if (!value) return "";
  return value
    .replace(/<style[\s\S]*?<\/style>/gi, " ")
    .replace(/<script[\s\S]*?<\/script>/gi, " ")
    .replace(/<br\s*\/?>/gi, "\n")
    .replace(/<\/(p|div|li|tr|h\d)>/gi, "\n")
    .replace(/<[^>]+>/g, " ")
    .replace(/&nbsp;/gi, " ")
    .replace(/&amp;/gi, "&")
    .replace(/&lt;/gi, "<")
    .replace(/&gt;/gi, ">")
    .replace(/\r/g, "")
    .replace(/\n{3,}/g, "\n\n")
    .replace(/[ \t]{2,}/g, " ")
    .trim();
}

function htmlToPlainText(value: string) {
  if (typeof document === "undefined") return stripSignatureHtml(value);
  const element = document.createElement("div");
  element.innerHTML = value;
  return element.innerText.trim();
}

function FormatButton({ label, icon, onClick }: { label: string; icon: ReactNode; onClick: () => void }) {
  return (
    <button
      type="button"
      onMouseDown={(event) => event.preventDefault()}
      onClick={onClick}
      className="inline-flex h-8 w-8 items-center justify-center rounded-md text-slate-600 transition hover:bg-white hover:text-slate-950"
      aria-label={label}
      title={label}
    >
      {icon}
    </button>
  );
}

function ColorButton({ label, onChange }: { label: string; onChange: (color: string) => void }) {
  return (
    <label
      className="relative inline-flex h-8 w-8 cursor-pointer items-center justify-center rounded-md text-slate-600 transition hover:bg-white hover:text-slate-950"
      aria-label={label}
      title={label}
    >
      <Palette size={16} />
      <input type="color" className="absolute inset-0 h-full w-full cursor-pointer opacity-0" onChange={(event) => onChange(event.target.value)} />
    </label>
  );
}

function stripHtml(value: string) {
  if (!value) return "";
  return value
    .replace(/<style[\s\S]*?<\/style>/gi, " ")
    .replace(/<script[\s\S]*?<\/script>/gi, " ")
    .replace(/<br\s*\/?>/gi, "\n")
    .replace(/<\/(p|div|li|tr|h\d)>/gi, "\n")
    .replace(/<[^>]+>/g, " ")
    .replace(/&nbsp;/gi, " ")
    .replace(/&amp;/gi, "&")
    .replace(/&lt;/gi, "<")
    .replace(/&gt;/gi, ">")
    .replace(/\r/g, "")
    .replace(/\n{3,}/g, "\n\n")
    .replace(/[ \t]{2,}/g, " ")
    .trim();
}

function chooseReaderPlainText(text: string, htmlText: string, preview: string) {
  const normalizedText = normalizeReaderText(text);
  const normalizedPreview = normalizeReaderText(preview);
  const textLooksPreviewOnly = Boolean(
    normalizedText &&
      normalizedPreview &&
      (
        normalizedText === normalizedPreview ||
        (normalizedText.endsWith("...") && normalizedPreview.startsWith(normalizedText.replace(/\.+$/, "").trim().slice(0, 40))) ||
        (normalizedText.length <= normalizedPreview.length + 5 && normalizedPreview.includes(normalizedText))
      )
  );
  if (htmlText && (!text.trim() || textLooksPreviewOnly || htmlText.length > normalizedText.length + 80)) {
    return htmlText;
  }
  return text || htmlText || preview;
}

function normalizeReaderText(value: string) {
  return (value || "").replace(/\s+/g, " ").trim();
}

function nextFlags(flags: string[], seen?: boolean, starred?: boolean) {
  const set = new Set(flags);
  if (seen === true) set.delete("u");
  if (seen === false) set.add("u");
  if (starred === true) set.add("f");
  if (starred === false) set.delete("f");
  return Array.from(set);
}

function downloadFile(filename: string, content: string, type: string) {
  const blob = new Blob([content], { type });
  downloadBlob(filename, blob);
}

function downloadBlob(filename: string, blob: Blob) {
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = filename;
  link.click();
  URL.revokeObjectURL(url);
}

function sanitizeFilename(value: string) {
  return value
    .replace(/[\\/:*?"<>|]+/g, "-")
    .replace(/\s+/g, " ")
    .replace(/\.+$/g, "")
    .trim();
}

function fileToBase64(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      const result = String(reader.result || "");
      const commaIndex = result.indexOf(",");
      resolve(commaIndex >= 0 ? result.slice(commaIndex + 1) : result);
    };
    reader.onerror = () => reject(reader.error || new Error("Unable to read file"));
    reader.readAsDataURL(file);
  });
}

function contactsToCsv(contacts: Contact[]) {
  return ["full_name,email,company,phone,notes", ...contacts.map((contact) => [safeText(contact.full_name), safeText(contact.email), safeText(contact.company), safeText(contact.phone), safeText(contact.notes)].map(csvCell).join(","))].join("\n");
}

function parseContactsCsv(text: string): Partial<Contact>[] {
  return text.split(/\r?\n/).slice(1).filter(Boolean).map((line) => {
    const cells = line.split(",").map((value) => value.replace(/^"|"$/g, "").replace(/""/g, '"'));
    if (cells.length === 4) {
      const [full_name = "", email = "", company = "", notes = ""] = cells;
      return { full_name, email, company, notes };
    }
    const [full_name = "", email = "", company = "", phone = "", notes = ""] = cells;
    return { full_name, email, company, phone, notes };
  });
}

function csvCell(value: string) {
  return `"${value.replace(/"/g, '""')}"`;
}

function calendarToIcs(events: CalendarEvent[], brandName = "Webmail") {
  const lines = ["BEGIN:VCALENDAR", "VERSION:2.0", `PRODID:-//${brandName}//EN`];
  for (const event of events) {
    lines.push("BEGIN:VEVENT", `UID:${event.id}`, `SUMMARY:${event.summary}`, `DTSTART:${icsDate(event.start)}`, `DTEND:${icsDate(event.end)}`, `LOCATION:${event.location}`, `URL:${event.html_link}`, "END:VEVENT");
  }
  lines.push("END:VCALENDAR");
  return lines.join("\r\n");
}

function icsDate(value: string) {
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return "";
  return date.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
}
