"use client";

import { useRouter } from "next/navigation";
import Link from "next/link";
import type {
  CSSProperties,
  DragEvent as ReactDragEvent,
  FormEvent as ReactFormEvent,
  MouseEvent as ReactMouseEvent,
  PointerEvent as ReactPointerEvent,
  ReactNode,
  RefObject,
} from "react";
import {
  Fragment,
  useDeferredValue,
  useEffect,
  useLayoutEffect,
  useRef,
  useState,
  useTransition,
} from "react";
import { createPortal, useFormStatus } from "react-dom";
import {
  logoutAction,
  markMailboxMessagesReadAction,
  moveMailboxMessagesAction,
  saveMailboxCredentialsAction,
  updateMailboxSenderSpamRuleAction,
} from "@/app/actions/session";
import { BottomToast } from "@/components/bottom-toast";
import { CloseIconButton } from "@/components/close-icon-button";
import { MailAutoSendPanel } from "@/components/mail-auto-send-panel";
import { MailComposeForm } from "@/components/mail-compose-form";
import {
  MailSetupWorkspace,
  type MailSetupSection,
} from "@/components/mail-setup-workspace";
import type { MemberMailboxViewState } from "@/components/mail-members-panel";
import { SubmitButton } from "@/components/submit-button";
import type { MailBillingCancellationOverview } from "@/lib/billing-cancellation";
import type { MailPlanSummary } from "@/lib/mail-billing";
import type {
  MailBillingHistoryState,
  MailBillingTab,
} from "@/lib/mail-billing-history";
import {
  MAIL_LAYOUT_LIMITS,
  normalizeMailLayoutPreferences,
  type MailListSortOrder,
  type MailListViewMode,
  type MailLayoutPreferences,
} from "@/lib/mail-layout";
import type {
  MailAiAssistOverview,
  ManagedMailboxMember,
} from "@/lib/mail-automation";
import type { MailAutoSendOverview } from "@/lib/mail-auto-send";
import type {
  MailAppOverview,
  MailMessageAttachment,
  MailMessageDetail,
  MailMessageFilter,
  MailMessageSummary,
  MailSearchField,
  MailSearchSuggestion,
  MailSetupOverview,
} from "@/lib/official-mail";
import {
  DEFAULT_MAILBOX_PAGE_SIZE,
  MAILBOX_PAGE_SIZE_OPTIONS,
  normalizeMailboxPageSize,
} from "@/lib/mailbox-page-size";
import type {
  MailBillingHistoryPage,
  MailBillingOverview,
} from "@/lib/toss-pay";
import { OFFICIAL_MAIL_GUIDE_URL } from "@/lib/mail-urls";

type MailGateProps = {
  currentPanel: "auto-send" | "mail" | "setup";
  setupSection: MailSetupSection;
  setupOverview: MailSetupOverview | null;
  managedMembers: ManagedMailboxMember[];
  memberMailboxView: MemberMailboxViewState | null;
  aiAssistOverview: MailAiAssistOverview | null;
  autoSendOverview: MailAutoSendOverview | null;
  billingOverview: MailBillingOverview | null;
  billingCancellationOverview: MailBillingCancellationOverview | null;
  billingHistoryPage: MailBillingHistoryPage | null;
  billingHistoryState: MailBillingHistoryState;
  billingTab: MailBillingTab;
  planSummary: MailPlanSummary;
  canManageBilling: boolean;
  mailConfigured: boolean;
  userEmail: string;
  userDisplayName: string;
  mailbox: string;
  companyName: string;
  domain: string;
  data: MailAppOverview | null;
  currentFolder: string;
  currentView: "list" | "compose";
  composeMode: "forward" | "new" | "reply" | "replyAll";
  detailView: "body" | "source" | "logs";
  detailOpen: boolean;
  currentSearchField: MailSearchField;
  currentSearchQuery: string;
  layoutPreferences: MailLayoutPreferences;
  composeBccDefault: string;
  composeCcDefault: string;
  composeToDefault: string;
  composeSubjectDefault: string;
  composeBodyDefault: string;
  composeBodyHtmlDefault: string;
  notice: { tone: "error" | "success"; message: string } | null;
};

type NavItem = {
  id: string;
  label: string;
  count?: number;
  icon:
    | "inbox"
    | "sent"
    | "drafts"
    | "trash"
    | "spam"
    | "star"
    | "all"
    | "folder";
};

type SidebarFolderNavItem = {
  count: number;
  href: string;
  icon: "inbox" | "sent" | "drafts" | "trash" | "spam" | "folder";
  id: number;
  kind: "custom" | "system";
  label: string;
  systemName: string;
};

type SettingsMenuItem = {
  id: MailSetupSection | "logout";
  label: string;
};

type ComposeToolbarMessage = {
  bodyHtml?: string | null;
  id: number;
  bodyText?: string | null;
  fromAddress: string;
  fromName: string | null;
  receivedAt: string;
  snippet?: string;
  subject: string;
  toAddresses: string;
};

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

type SenderSpamPromptState = {
  scope: string;
  senderAddress: string;
  senderLabel: string;
};

type AttachmentPreviewState = {
  collection: "images" | "previewable";
  currentIndex: number;
  messageId: number;
  scope: string;
};

type MailboxDataFetchOptions = {
  folder?: string;
  messageId?: number | null;
  page?: number;
  pageSize?: number;
  preserveSelection?: boolean;
  refresh?: boolean;
  searchField?: MailSearchField;
  searchQuery?: string;
  showRefreshingState?: boolean;
  silent?: boolean;
  sortOrder?: MailListSortOrder;
  syncUrl?: boolean;
  tab?: MailMessageFilter;
};

type MailboxMoveResult = {
  deletedCount: number;
  deletedMessageIds: number[];
  movedCount: number;
  movedMessageIds: number[];
  spamSenderCount: number;
};

type MailboxMoveResponse = {
  error?: string;
  notice?: MailNotice | null;
  ok: boolean;
  result?: MailboxMoveResult;
};

type SidebarFolderAction = "backup" | "clear" | "delete" | "mark-read";

type SidebarFolderInlineEditorState =
  | {
      errorMessage?: string;
      insertAfterSystemName: string | null;
      insertAtTop: boolean;
      mode: "create";
      value: string;
    }
  | {
      errorMessage?: string;
      folderId: number;
      mode: "rename";
      systemName: string;
      value: string;
    };

type MailboxLiveUpdatePayload = {
  at: string;
  delta: number;
  mailbox: string;
  reason: "exists" | "expunge" | "flags";
};

type MailboxLiveErrorPayload = {
  at: string;
  mailbox: string;
  message: string;
};

type MailboxAutoSendCompletedPayload = {
  at: string;
  deliveryCount: number;
  mailbox: string;
  recipientEmail: string;
  subject: string;
};

type FolderSearchParamsOptions = {
  page?: number;
  pageSize?: number;
  searchField?: MailSearchField;
  searchQuery?: string;
  sortOrder?: MailListSortOrder;
  tab?: MailMessageFilter;
};

type PreviewMessage = {
  attachments: MailMessageAttachment[];
  bodyHtml: string | null;
  bodyHtmlDisplay: string | null;
  bodyText: string;
  fromAddress: string;
  fromName: string | null;
  id: number;
  isRead: boolean;
  isStarred: boolean;
  messageIdHeader: string | null;
  rawSource: string | null;
  receivedAt: string;
  snippet: string;
  subject: string;
  toAddresses: string;
  transportResponse: string | null;
  transportStatus: "saved" | "queued" | "sent" | "failed";
};

type LayoutResizePanel = "sidebar" | "list" | "list-height";
type ToolbarMenuKind = "filter" | "pageSize" | "sort" | "view";

type LayoutDragState = {
  containerWidth: number;
  containerHeight: number;
  isXlLayout: boolean;
  panel: LayoutResizePanel;
  startListHeight: number;
  startListWidth: number;
  startSidebarWidth: number;
  startX: number;
  startY: number;
};

function padNumber(value: number) {
  return String(value).padStart(2, "0");
}

function formatFullDate(value: string) {
  const date = new Date(value);
  const weekdays = ["일", "월", "화", "수", "목", "금", "토"];
  const hours = date.getHours();
  const period = hours >= 12 ? "PM" : "AM";
  const hour12 = hours % 12 || 12;

  return `${date.getFullYear()}.${padNumber(date.getMonth() + 1)}.${padNumber(
    date.getDate(),
  )} (${weekdays[date.getDay()]}) ${hour12}:${padNumber(date.getMinutes())} ${period}`;
}

function formatInboxTime(value: string) {
  const date = new Date(value);
  const now = new Date();
  const midnight = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  const targetMidnight = new Date(date.getFullYear(), date.getMonth(), date.getDate());
  const diff = midnight.getTime() - targetMidnight.getTime();
  const oneDay = 24 * 60 * 60 * 1000;

  if (diff === 0) {
    const hours = date.getHours();
    const period = hours >= 12 ? "오후" : "오전";
    const hour12 = hours % 12 || 12;
    return `${period} ${hour12}:${padNumber(date.getMinutes())}`;
  }

  if (diff === oneDay) {
    return "어제";
  }

  return `${padNumber(date.getMonth() + 1)}.${padNumber(date.getDate())}`;
}

function formatCount(value: number) {
  return value.toLocaleString("ko-KR");
}

function formatStorage(bytes: number | null) {
  if (bytes === null || !Number.isFinite(bytes)) {
    return "집계 중";
  }

  if (bytes <= 0) {
    return "0B";
  }

  const kib = 1024;
  const mib = kib * 1024;
  const gib = mib * 1024;

  if (bytes >= gib) {
    return `${(bytes / gib).toFixed(1)}GB`;
  }

  if (bytes >= mib) {
    const fractionDigits = bytes >= mib * 100 ? 0 : 1;
    return `${(bytes / mib).toFixed(fractionDigits)}MB`;
  }

  if (bytes >= kib) {
    return `${Math.round(bytes / kib)}KB`;
  }

  return `${Math.round(bytes)}B`;
}

function senderLabel(fromName: string | null, fromAddress: string) {
  return fromName?.trim() || fromAddress.split("@")[0] || fromAddress;
}

function primaryRecipient(toAddresses: string) {
  const firstRecipient = toAddresses
    .split(",")
    .map((recipient) => recipient.trim())
    .find(Boolean) ?? "";
  const matchedAddress = firstRecipient.match(/^(.*?)\s*<\s*([^>]+)\s*>$/);
  const displayName = matchedAddress?.[1]?.trim().replace(/^"|"$/g, "");
  const address = (matchedAddress?.[2] ?? firstRecipient).trim();

  return {
    address,
    label: displayName || address.split("@")[0] || address || "받는사람",
  };
}

function compactCount(count: number | undefined) {
  if (!count) return "";
  if (count > 999) return "999+";
  return String(count);
}

function folderLabelForSidebar(systemName: string) {
  if (systemName === "inbox") return "받은메일함";
  if (systemName === "sent") return "보낸메일함";
  if (systemName === "drafts") return "임시보관함";
  if (systemName === "spam") return "스팸메일함";
  if (systemName === "trash") return "휴지통";
  return "메일함";
}

function folderLabelForHeader(systemName: string, fallback: string) {
  if (systemName === "all") return "전체메일";
  return fallback || folderLabelForSidebar(systemName);
}

function isPrimaryMailboxFolder(systemName: string) {
  return systemName === "inbox" || systemName === "sent" || systemName === "drafts";
}

function isPersonalMailboxFolder(systemName: string, kind: "custom" | "system") {
  return kind === "custom";
}

function isSecondarySystemMailboxFolder(systemName: string) {
  return systemName === "spam" || systemName === "trash";
}

function searchFieldLabel(field: MailSearchField) {
  if (field === "from") return "보낸사람";
  if (field === "to") return "받는사람";
  if (field === "subject") return "제목";
  if (field === "body") return "내용";
  return "전체";
}

function sameNumberArray(left: number[], right: number[]) {
  if (left.length !== right.length) {
    return false;
  }

  for (let index = 0; index < left.length; index += 1) {
    if (left[index] !== right[index]) {
      return false;
    }
  }

  return true;
}

function splitAddressList(value: string) {
  return value
    .split(/[,;\n]+/)
    .map((item) => item.trim().toLowerCase())
    .filter(Boolean);
}

function prefixedSubject(subject: string, prefix: string) {
  const trimmed = subject.trim() || "(no subject)";
  return trimmed.toLowerCase().startsWith(prefix.toLowerCase()) ? trimmed : `${prefix} ${trimmed}`;
}

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

function plainTextToHtml(value: string) {
  const normalized = value.replace(/\r/g, "").trim();

  if (!normalized) {
    return "";
  }

  return normalized
    .split(/\n{2,}/)
    .map((block) => {
      const html = block
        .split("\n")
        .map((line) => {
          const escaped = escapeHtml(line).replace(/ {2}/g, " &nbsp;");
          return escaped || "<br>";
        })
        .join("<br>");

      return `<p>${html}</p>`;
    })
    .join("");
}

function originalMessageHtml(message: ComposeToolbarMessage) {
  return (
    message.bodyHtml?.trim() ||
    plainTextToHtml(message.bodyText?.trim() || message.snippet?.trim() || "")
  );
}

function quotedMessageBody(message: ComposeToolbarMessage) {
  return [
    "",
    "",
    "---------- 원본 메일 ----------",
    `보낸사람: ${message.fromName ? `${message.fromName} <${message.fromAddress}>` : message.fromAddress}`,
    `보낸시각: ${formatFullDate(message.receivedAt)}`,
    `제목: ${message.subject}`,
    `받는사람: ${message.toAddresses}`,
    "",
    message.bodyText?.trim() || message.snippet?.trim() || "",
  ].join("\n");
}

function quotedMessageHtml(
  message: ComposeToolbarMessage,
  action: "forward" | "reply" | "replyAll",
) {
  const sender = message.fromName
    ? `${message.fromName} <${message.fromAddress}>`
    : message.fromAddress;
  const bodyHtml = originalMessageHtml(message);
  const replyHeader = `${formatFullDate(message.receivedAt)}, ${sender}님이 작성:`;

  if (action === "forward") {
    return [
      "<p><br></p>",
      "<p><br></p>",
      '<p>---------- 원본 메일 ----------</p>',
      `<p>보낸사람: ${escapeHtml(sender)}</p>`,
      `<p>보낸시각: ${escapeHtml(formatFullDate(message.receivedAt))}</p>`,
      `<p>제목: ${escapeHtml(message.subject)}</p>`,
      `<p>받는사람: ${escapeHtml(message.toAddresses)}</p>`,
      "<p><br></p>",
      `<blockquote>${bodyHtml}</blockquote>`,
    ].join("");
  }

  return [
    "<p><br></p>",
    "<p><br></p>",
    `<div>${escapeHtml(replyHeader)}</div>`,
    `<blockquote>${bodyHtml}</blockquote>`,
  ].join("");
}

const MAIL_HTML_DOCUMENT_TAG_PATTERN = /<(?:!doctype|html|head|body)\b/i;

function buildMailboxPreviewDocument(html: string) {
  const normalized = html.trim();

  if (!normalized) {
    return "";
  }

  if (MAIL_HTML_DOCUMENT_TAG_PATTERN.test(normalized)) {
    return normalized;
  }

  return [
    "<!doctype html>",
    '<html lang="en">',
    "<head>",
    '<meta charset="utf-8">',
    '<meta name="viewport" content="width=device-width, initial-scale=1">',
    '<base target="_blank">',
    "</head>",
    `<body>${normalized}</body>`,
    "</html>",
  ].join("");
}

function MailHtmlPreview({ html }: { html: string }) {
  const iframeRef = useRef<HTMLIFrameElement | null>(null);
  const cleanupRef = useRef<Array<() => void>>([]);
  const resizeObserverRef = useRef<ResizeObserver | null>(null);
  const [frameHeight, setFrameHeight] = useState(420);
  const srcDoc = buildMailboxPreviewDocument(html);

  const clearFrameObservers = () => {
    cleanupRef.current.forEach((cleanup) => cleanup());
    cleanupRef.current = [];
    resizeObserverRef.current?.disconnect();
    resizeObserverRef.current = null;
  };

  const syncFrameHeight = () => {
    const iframe = iframeRef.current;
    const doc = iframe?.contentDocument;

    if (!iframe || !doc) {
      return;
    }

    const bodyHeight = Math.max(
      doc.body?.scrollHeight ?? 0,
      doc.body?.offsetHeight ?? 0,
      doc.body?.clientHeight ?? 0,
    );
    const documentHeight = Math.max(
      doc.documentElement?.scrollHeight ?? 0,
      doc.documentElement?.offsetHeight ?? 0,
      doc.documentElement?.clientHeight ?? 0,
    );
    const nextHeight = Math.max(bodyHeight, documentHeight, 240);

    setFrameHeight((current) => (Math.abs(current - nextHeight) > 1 ? nextHeight : current));
  };

  const bindFrameObservers = () => {
    clearFrameObservers();
    syncFrameHeight();

    const iframe = iframeRef.current;
    const doc = iframe?.contentDocument;
    const win = iframe?.contentWindow;

    if (!iframe || !doc || !win) {
      return;
    }

    win.addEventListener("resize", syncFrameHeight);
    cleanupRef.current.push(() => win.removeEventListener("resize", syncFrameHeight));

    for (const image of Array.from(doc.images)) {
      image.addEventListener("load", syncFrameHeight);
      image.addEventListener("error", syncFrameHeight);
      cleanupRef.current.push(() => {
        image.removeEventListener("load", syncFrameHeight);
        image.removeEventListener("error", syncFrameHeight);
      });
    }

    if (typeof ResizeObserver !== "undefined") {
      const observer = new ResizeObserver(() => syncFrameHeight());
      resizeObserverRef.current = observer;
      observer.observe(doc.documentElement);

      if (doc.body) {
        observer.observe(doc.body);
      }
    }
  };

  useEffect(() => {
    return () => {
      cleanupRef.current.forEach((cleanup) => cleanup());
      cleanupRef.current = [];
      resizeObserverRef.current?.disconnect();
      resizeObserverRef.current = null;
    };
  }, []);

  return (
    <iframe
      ref={iframeRef}
      title="메일 본문"
      srcDoc={srcDoc}
      onLoad={bindFrameObservers}
      sandbox="allow-popups allow-popups-to-escape-sandbox allow-same-origin"
      referrerPolicy="no-referrer"
      className="min-h-[240px] w-full border-0 bg-white"
      style={{ height: `${frameHeight}px` }}
    />
  );
}

function buildComposeHref(input: {
  action: "forward" | "reply" | "replyAll";
  currentFolder: string;
  ownAddresses: string[];
  message: ComposeToolbarMessage | null;
}) {
  if (!input.message) {
    return "";
  }

  const params = new URLSearchParams();
  params.set("view", "compose");
  params.set("folder", input.currentFolder === "all" ? "inbox" : input.currentFolder);
  params.set("message", String(input.message.id));

  if (input.action === "reply") {
    params.set("composeMode", "reply");
    return `/mail?${params.toString()}`;
  }

  if (input.action === "replyAll") {
    params.set("composeMode", "replyAll");
    return `/mail?${params.toString()}`;
  }

  params.set("composeMode", "forward");
  return `/mail?${params.toString()}`;
}

function buildDirectComposeHref(currentFolder: string, toAddress: string) {
  const params = new URLSearchParams();
  params.set("view", "compose");
  params.set("folder", currentFolder === "all" ? "inbox" : currentFolder);
  params.set("to", toAddress.trim().toLowerCase());
  return `/mail?${params.toString()}`;
}

function buildFolderSearchParams(
  folder: string,
  options?: FolderSearchParamsOptions,
) {
  const params = new URLSearchParams();
  const searchQuery = options?.searchQuery?.trim() ?? "";

  params.set("folder", folder);

  if (options?.tab && options.tab !== "all") {
    params.set("tab", options.tab);
  }

  if (options?.page && options.page > 1) {
    params.set("page", String(options.page));
  }

  if (
    options?.pageSize &&
    normalizeMailboxPageSize(options.pageSize) !== DEFAULT_MAILBOX_PAGE_SIZE
  ) {
    params.set("pageSize", String(normalizeMailboxPageSize(options.pageSize)));
  }

  if (options?.sortOrder === "oldest") {
    params.set("sort", "oldest");
  }

  if (searchQuery) {
    params.set("q", searchQuery);
  }

  if (searchQuery && options?.searchField && options.searchField !== "all") {
    params.set("field", options.searchField);
  }

  return params;
}

function folderHref(
  folder: string,
  options?: FolderSearchParamsOptions,
) {
  return `/mail?${buildFolderSearchParams(folder, options).toString()}`;
}

function pageHref(
  folder: string,
  page: number,
  tab: MailMessageFilter,
  options?: Pick<FolderSearchParamsOptions, "pageSize" | "searchField" | "searchQuery" | "sortOrder">,
) {
  return folderHref(folder, {
    page,
    pageSize: options?.pageSize,
    searchField: options?.searchField,
    searchQuery: options?.searchQuery,
    sortOrder: options?.sortOrder,
    tab,
  });
}

function setupHref(section: MailSetupSection = "domain") {
  return `/mail?panel=setup&section=${section}`;
}

function autoSendHref() {
  return "/mail?panel=auto-send";
}

function shouldPreventMailRowOpen(target: EventTarget | null) {
  if (!(target instanceof HTMLElement)) {
    return false;
  }

  return Boolean(target.closest("[data-row-action-stop='true']"));
}

function shouldBypassClientNavigation(event: ReactMouseEvent<HTMLElement>) {
  return (
    event.defaultPrevented ||
    event.button !== 0 ||
    event.metaKey ||
    event.ctrlKey ||
    event.shiftKey ||
    event.altKey
  );
}

function messageHref(
  folder: string,
  messageId: number,
  detailView: "body" | "source" | "logs",
  options?: FolderSearchParamsOptions,
) {
  const params = buildFolderSearchParams(folder, options);

  params.set("message", String(messageId));
  params.set("detail", detailView);

  return `/mail?${params.toString()}`;
}

function messageBodyHref(messageId: number) {
  const params = new URLSearchParams();
  params.set("message", String(messageId));
  return `/mail/message-body?${params.toString()}`;
}

function buildPaginationItems(currentPage: number, totalPages: number) {
  if (totalPages <= 1) {
    return [1];
  }

  const pages = new Set<number>([1, totalPages, currentPage]);

  for (let offset = 1; offset <= 1; offset += 1) {
    if (currentPage - offset > 1) {
      pages.add(currentPage - offset);
    }

    if (currentPage + offset < totalPages) {
      pages.add(currentPage + offset);
    }
  }

  const sortedPages = [...pages].sort((a, b) => a - b);
  const items: Array<number | "ellipsis"> = [];

  sortedPages.forEach((page, index) => {
    const previous = sortedPages[index - 1];

    if (previous && page - previous > 1) {
      items.push("ellipsis");
    }

    items.push(page);
  });

  return items;
}

function looksLikeAttachment(message: MailMessageSummary) {
  return /pdf|첨부|제안서|계약서|정리/i.test(`${message.subject} ${message.snippet}`);
}

function formatAttachmentSize(bytes: number) {
  if (!Number.isFinite(bytes) || bytes <= 0) {
    return "0B";
  }

  const units = ["B", "KB", "MB", "GB"];
  let value = bytes;
  let unitIndex = 0;

  while (value >= 1024 && unitIndex < units.length - 1) {
    value /= 1024;
    unitIndex += 1;
  }

  const fixed = value >= 10 || unitIndex === 0 ? value.toFixed(0) : value.toFixed(1);
  return `${fixed}${units[unitIndex]}`;
}

function attachmentLabel(attachment: MailMessageAttachment) {
  return attachment.extension ? attachment.extension.toUpperCase() : "FILE";
}

function attachmentTone(attachment: MailMessageAttachment) {
  const extension = attachment.extension.toLowerCase();
  const contentType = attachment.contentType.toLowerCase();

  if (contentType === "application/pdf" || extension === "pdf") {
    return "bg-[#fff1ed] text-[#d94b1a]";
  }

  if (extension === "hwp" || extension === "hwpx") {
    return "bg-[#eef6ff] text-[#2d7adf]";
  }

  if (contentType.startsWith("image/")) {
    return "bg-[#eef9f2] text-[#1f9152]";
  }

  if (contentType.startsWith("text/") || ["txt", "md", "csv", "json"].includes(extension)) {
    return "bg-[#f6f1ff] text-[#7452d6]";
  }

  return "bg-[#f4f6fb] text-[#5f708d]";
}

function isImageAttachmentPreview(attachment: MailMessageAttachment) {
  return attachment.contentType.toLowerCase().startsWith("image/");
}

function splitAttachmentFilename(filename: string) {
  const trimmed = filename.trim();
  const dotIndex = trimmed.lastIndexOf(".");

  if (dotIndex <= 0 || dotIndex === trimmed.length - 1) {
    return {
      extension: "",
      name: trimmed || "attachment",
    };
  }

  return {
    extension: trimmed.slice(dotIndex),
    name: trimmed.slice(0, dotIndex) || trimmed,
  };
}

function previewBodyFromSummary(message: MailMessageSummary) {
  if (message.snippet.trim()) {
    return `${message.snippet.trim()}\n\n메일 상세를 열면 전체 원문과 전송 로그를 확인할 수 있습니다.`;
  }

  return "메일 상세를 열면 본문 전체를 확인할 수 있습니다.";
}

function aiSummaryStatusLabel(message: MailMessageSummary) {
  if (message.aiSummaryStatus === "failed") {
    return message.aiSummaryError
      ? `AI 릴레이 실패: ${message.aiSummaryError}`
      : "AI 릴레이 실패";
  }

  if (message.aiSummaryStatus === "sending") {
    return message.aiSummaryResponse
      ? `AI 릴레이 처리 중: ${message.aiSummaryResponse}`
      : "AI 릴레이 처리 중";
  }

  return "";
}

function createPreviewMessage(
  selectedMessage: MailMessageDetail | null,
  fallbackMessage: MailMessageSummary | null,
) {
  if (selectedMessage) {
    return {
      attachments: selectedMessage.attachments,
      bodyHtml: selectedMessage.bodyHtml,
      bodyHtmlDisplay: selectedMessage.bodyHtmlDisplay,
      bodyText: selectedMessage.bodyText,
      fromAddress: selectedMessage.fromAddress,
      fromName: selectedMessage.fromName,
      id: selectedMessage.id,
      isRead: selectedMessage.isRead,
      isStarred: selectedMessage.isStarred,
      messageIdHeader: selectedMessage.messageIdHeader,
      rawSource: selectedMessage.rawSource,
      receivedAt: selectedMessage.receivedAt,
      snippet: selectedMessage.snippet,
      subject: selectedMessage.subject,
      toAddresses: selectedMessage.toAddresses,
      transportResponse: selectedMessage.transportResponse,
      transportStatus: selectedMessage.transportStatus,
    } satisfies PreviewMessage;
  }

  if (!fallbackMessage) {
    return null;
  }

  return {
    attachments: [],
    bodyHtml: null,
    bodyHtmlDisplay: null,
    bodyText: previewBodyFromSummary(fallbackMessage),
    fromAddress: fallbackMessage.fromAddress,
    fromName: fallbackMessage.fromName,
    id: fallbackMessage.id,
    isRead: fallbackMessage.isRead,
    isStarred: fallbackMessage.isStarred,
    messageIdHeader: null,
    rawSource: null,
    receivedAt: fallbackMessage.receivedAt,
    snippet: fallbackMessage.snippet,
    subject: fallbackMessage.subject,
    toAddresses: fallbackMessage.toAddresses,
    transportResponse: null,
    transportStatus: fallbackMessage.direction === "outbound" ? "sent" : "saved",
  } satisfies PreviewMessage;
}

function resolveMessageStarState(currentData: MailAppOverview | null, messageId: number) {
  const listMessage = currentData?.messages.find((message) => message.id === messageId);

  if (listMessage) {
    return listMessage.isStarred;
  }

  if (currentData?.selectedMessage?.id === messageId) {
    return currentData.selectedMessage.isStarred;
  }

  return null;
}

function buildOptimisticStarToggledMailData(
  currentData: MailAppOverview | null,
  messageId: number,
  nextStarred: boolean,
) {
  if (!currentData) {
    return currentData;
  }

  const currentStarred = resolveMessageStarState(currentData, messageId);

  if (currentStarred === null || currentStarred === nextStarred) {
    return currentData;
  }

  const shouldRemoveFromImportant = currentData.messageFilter === "important" && !nextStarred;
  const nextMessages = shouldRemoveFromImportant
    ? currentData.messages.filter((message) => message.id !== messageId)
    : currentData.messages.map((message) =>
        message.id === messageId ? { ...message, isStarred: nextStarred } : message,
      );
  const importantDelta = nextStarred ? 1 : -1;
  const nextImportantCount = Math.max(0, currentData.messageFilterCounts.important + importantDelta);
  const nextTotalMessages = shouldRemoveFromImportant
    ? Math.max(0, currentData.totalMessages - 1)
    : currentData.totalMessages;
  const nextTotalPages =
    shouldRemoveFromImportant && currentData.pageSize > 0
      ? Math.max(1, Math.ceil(nextTotalMessages / currentData.pageSize))
      : currentData.totalPages;
  const selectedMessageRemoved =
    shouldRemoveFromImportant && currentData.selectedMessage?.id === messageId;

  return {
    ...currentData,
    currentPage: Math.min(currentData.currentPage, nextTotalPages),
    messageFilterCounts: {
      ...currentData.messageFilterCounts,
      important: nextImportantCount,
    },
    messages: nextMessages,
    selectedMessage:
      currentData.selectedMessage?.id !== messageId
        ? currentData.selectedMessage
        : selectedMessageRemoved
          ? null
          : { ...currentData.selectedMessage, isStarred: nextStarred },
    selectedMessageLogs: selectedMessageRemoved ? [] : currentData.selectedMessageLogs,
    totalMessages: nextTotalMessages,
    totalPages: nextTotalPages,
  } satisfies MailAppOverview;
}

function buildOptimisticReadStateMailData(
  currentData: MailAppOverview | null,
  messageIds: number[],
  nextReadState: boolean,
) {
  if (!currentData || messageIds.length === 0) {
    return currentData;
  }

  const messageIdSet = new Set(messageIds);
  const currentReadStateById = new Map<number, boolean>();
  const folderSystemNameById = new Map<number, string>();

  for (const message of currentData.messages) {
    if (!messageIdSet.has(message.id)) {
      continue;
    }

    currentReadStateById.set(message.id, message.isRead);
    folderSystemNameById.set(message.id, message.folderSystemName);
  }

  if (currentData.selectedMessage && messageIdSet.has(currentData.selectedMessage.id)) {
    currentReadStateById.set(currentData.selectedMessage.id, currentData.selectedMessage.isRead);
    folderSystemNameById.set(
      currentData.selectedMessage.id,
      currentData.selectedMessage.folderSystemName,
    );
  }

  const changedMessageIds = [...messageIdSet].filter((messageId) => {
    const currentReadState = currentReadStateById.get(messageId);

    return typeof currentReadState === "boolean" && currentReadState !== nextReadState;
  });

  if (changedMessageIds.length === 0) {
    return currentData;
  }

  const changedMessageIdSet = new Set(changedMessageIds);
  const unreadDeltaByFolder = new Map<string, number>();
  let unreadDelta = 0;

  for (const messageId of changedMessageIds) {
    const delta = nextReadState ? -1 : 1;
    const folderSystemName = folderSystemNameById.get(messageId);

    unreadDelta += delta;

    if (folderSystemName) {
      unreadDeltaByFolder.set(
        folderSystemName,
        (unreadDeltaByFolder.get(folderSystemName) ?? 0) + delta,
      );
    }
  }

  const shouldRemoveFromUnreadFilter = currentData.messageFilter === "unread" && nextReadState;
  const removedFromCurrentListCount = shouldRemoveFromUnreadFilter
    ? currentData.messages.filter((message) => changedMessageIdSet.has(message.id)).length
    : 0;
  const nextTotalMessages = shouldRemoveFromUnreadFilter
    ? Math.max(0, currentData.totalMessages - removedFromCurrentListCount)
    : currentData.totalMessages;
  const nextTotalPages =
    shouldRemoveFromUnreadFilter && currentData.pageSize > 0
      ? Math.max(1, Math.ceil(nextTotalMessages / currentData.pageSize))
      : currentData.totalPages;

  return {
    ...currentData,
    currentPage: Math.min(currentData.currentPage, nextTotalPages),
    folders: currentData.folders.map((folder) => {
      const folderUnreadDelta = unreadDeltaByFolder.get(folder.systemName) ?? 0;

      if (folderUnreadDelta === 0) {
        return folder;
      }

      return {
        ...folder,
        unreadCount: Math.max(0, folder.unreadCount + folderUnreadDelta),
      };
    }),
    messageFilterCounts: {
      ...currentData.messageFilterCounts,
      unread: Math.max(0, currentData.messageFilterCounts.unread + unreadDelta),
    },
    messages: shouldRemoveFromUnreadFilter
      ? currentData.messages.filter((message) => !changedMessageIdSet.has(message.id))
      : currentData.messages.map((message) =>
          changedMessageIdSet.has(message.id) ? { ...message, isRead: nextReadState } : message,
        ),
    selectedMessage:
      currentData.selectedMessage && changedMessageIdSet.has(currentData.selectedMessage.id)
        ? { ...currentData.selectedMessage, isRead: nextReadState }
        : currentData.selectedMessage,
    totalMessages: nextTotalMessages,
    totalPages: nextTotalPages,
  } satisfies MailAppOverview;
}

function IconBase({
  children,
  className,
}: {
  children: ReactNode;
  className?: string;
}) {
  return (
    <svg
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="1.8"
      strokeLinecap="round"
      strokeLinejoin="round"
      className={className}
    >
      {children}
    </svg>
  );
}

function LogoMark({
  compact = false,
  responsive = false,
}: {
  compact?: boolean;
  responsive?: boolean;
}) {
  const wrapperClass = responsive ? "h-8 w-8 rounded-[10px]" : compact ? "h-8 w-8 rounded-[10px]" : "h-10 w-10";
  const iconClass = responsive
    ? "h-6 w-6"
    : compact
      ? "h-6 w-6"
      : "h-[22px] w-[22px]";

  return (
    <div className={`flex items-center justify-center ${wrapperClass}`}>
      <IconBase className={`${iconClass} text-[#2f6df6]`}>
        <rect x="3.5" y="5.5" width="17" height="13" rx="2.5" />
        <path d="m4.8 7 7.2 5.6L19.2 7" />
      </IconBase>
    </div>
  );
}

function MenuIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M4.5 7h15" />
      <path d="M4.5 12h15" />
      <path d="M4.5 17h15" />
    </IconBase>
  );
}

function SearchIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <circle cx="11" cy="11" r="5.6" />
      <path d="m19 19-3.6-3.6" />
    </IconBase>
  );
}

function HelpIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <circle cx="12" cy="12" r="8" />
      <path d="M9.8 9.6a2.5 2.5 0 1 1 3.6 2.2c-.9.5-1.4 1-1.4 2" />
      <path d="M12 16.7h.01" />
    </IconBase>
  );
}

function SparkIcon({ className }: { className?: string }) {
  return (
    <svg viewBox="0 0 24 24" fill="none" className={className}>
      <path
        d="m12 3 1.8 4.7L18.5 9.5l-4.7 1.8L12 16l-1.8-4.7L5.5 9.5l4.7-1.8z"
        stroke="currentColor"
        strokeWidth="1.8"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
      <path
        d="m18.6 14.6.8 2.1 2.1.8-2.1.8-.8 2.1-.8-2.1-2.1-.8 2.1-.8z"
        stroke="currentColor"
        strokeWidth="1.8"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
      <path
        d="m5.3 14.7.6 1.6 1.6.6-1.6.6-.6 1.6-.6-1.6-1.6-.6 1.6-.6z"
        stroke="currentColor"
        strokeWidth="1.8"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
    </svg>
  );
}

function ChevronDownIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="m7 10 5 5 5-5" />
    </IconBase>
  );
}

function MenuCheckIcon({ className }: { className?: string }) {
  return (
    <svg
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
      className={className}
    >
      <path d="m5 12 4.2 4.2L19 6.7" />
    </svg>
  );
}

function ComposeIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M4 16.5V20h3.5L18.7 8.8a1.8 1.8 0 0 0 0-2.6l-.9-.9a1.8 1.8 0 0 0-2.6 0z" />
      <path d="m13.8 5.7 4.5 4.5" />
    </IconBase>
  );
}

function InboxIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M4 7.8A1.8 1.8 0 0 1 5.8 6h12.4A1.8 1.8 0 0 1 20 7.8v8.4A1.8 1.8 0 0 1 18.2 18H5.8A1.8 1.8 0 0 1 4 16.2z" />
      <path d="M4 13h4l2 3h4l2-3h4" />
    </IconBase>
  );
}

function SentIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M4.5 11.5 19 5l-3 14-4.8-4.8L8 17z" />
    </IconBase>
  );
}

function DraftIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <rect x="5" y="4.5" width="14" height="15" rx="2.5" />
      <path d="m8 9 4 3 4-3" />
    </IconBase>
  );
}

function TrashIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M4.8 7h14.4" />
      <path d="m9 7 .6-1.6A1.8 1.8 0 0 1 11.3 4h1.4a1.8 1.8 0 0 1 1.7 1.4L15 7" />
      <path d="M6.5 7.5V18a2 2 0 0 0 2 2h7a2 2 0 0 0 2-2V7.5" />
      <path d="M10 11v5M14 11v5" />
    </IconBase>
  );
}

function SpamIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M12 3.8 18.5 6v5.8c0 3.8-2.6 6.6-6.5 8.4-3.9-1.8-6.5-4.6-6.5-8.4V6z" />
      <path d="M12 9v3.4" />
      <path d="M12 16h.01" />
    </IconBase>
  );
}

function StarIcon({ className, filled = false }: { className?: string; filled?: boolean }) {
  return (
    <IconBase className={className}>
      <path
        d="m12 4 2.3 4.7 5.2.8-3.7 3.7.9 5.1L12 16l-4.7 2.3.9-5.1L4.5 9.5l5.2-.8z"
        fill={filled ? "currentColor" : "none"}
      />
    </IconBase>
  );
}

function FolderIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M4.5 7.5A1.5 1.5 0 0 1 6 6h3l1.7 2H18a1.5 1.5 0 0 1 1.5 1.5v6.8A1.7 1.7 0 0 1 17.8 18H6.2a1.7 1.7 0 0 1-1.7-1.7z" />
    </IconBase>
  );
}

function UserIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <circle cx="12" cy="8" r="3.2" />
      <path d="M6.5 18.2a5.8 5.8 0 0 1 11 0" />
    </IconBase>
  );
}

function GlobeIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <circle cx="12" cy="12" r="8" />
      <path d="M4.5 12h15" />
      <path d="M12 4a12 12 0 0 1 0 16" />
      <path d="M12 4a12 12 0 0 0 0 16" />
    </IconBase>
  );
}

function UsersIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M9 11a2.8 2.8 0 1 0-2.8-2.8A2.8 2.8 0 0 0 9 11Z" />
      <path d="M15.5 10.3a2.3 2.3 0 1 0-2.3-2.3 2.3 2.3 0 0 0 2.3 2.3Z" />
      <path d="M4.8 18a4.8 4.8 0 0 1 8.4-2.9" />
      <path d="M14 18a4 4 0 0 1 5.2-2.6" />
    </IconBase>
  );
}

function ShieldIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M12 3.8 18.5 6v5.8c0 3.8-2.6 6.6-6.5 8.4-3.9-1.8-6.5-4.6-6.5-8.4V6z" />
      <path d="m9.4 12.1 1.7 1.7 3.5-3.6" />
    </IconBase>
  );
}

function LockIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <rect x="6.2" y="10.4" width="11.6" height="8.1" rx="2.2" />
      <path d="M8.8 10.4V8.8a3.2 3.2 0 0 1 6.4 0v1.6" />
      <path d="M12 13.7v1.7" />
    </IconBase>
  );
}

function BillingIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <rect x="4" y="6" width="16" height="12" rx="2.6" />
      <path d="M4 10h16" />
      <path d="M8 14h3" />
    </IconBase>
  );
}

function ScheduleIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <rect x="4.5" y="5.5" width="15" height="14" rx="3" />
      <path d="M8 3.8v3.3" />
      <path d="M16 3.8v3.3" />
      <path d="M4.5 10h15" />
      <path d="m10.2 14.5 1.5 1.5 3.1-3.4" />
    </IconBase>
  );
}

function LogIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M7 4.8h7l3 3V19a1.8 1.8 0 0 1-1.8 1.8H7A1.8 1.8 0 0 1 5.2 19V6.6A1.8 1.8 0 0 1 7 4.8Z" />
      <path d="M14 4.8v3.5h3.5" />
      <path d="M8.5 12h7" />
      <path d="M8.5 15.5h5.5" />
    </IconBase>
  );
}

function LogoutIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M10 4.8H7.2A1.8 1.8 0 0 0 5.4 6.6v10.8a1.8 1.8 0 0 0 1.8 1.8H10" />
      <path d="M14 8.2 18 12l-4 3.8" />
      <path d="M9.2 12H18" />
    </IconBase>
  );
}

function RefreshIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M20 11.5A8 8 0 0 0 6.4 5.9L4 8.3" />
      <path d="M4 4.6v3.7h3.7" />
      <path d="M4 12.5A8 8 0 0 0 17.6 18l2.4-2.4" />
      <path d="M20 19.4v-3.7h-3.7" />
    </IconBase>
  );
}

function MoreIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <circle cx="12" cy="6" r="1" fill="currentColor" stroke="none" />
      <circle cx="12" cy="12" r="1" fill="currentColor" stroke="none" />
      <circle cx="12" cy="18" r="1" fill="currentColor" stroke="none" />
    </IconBase>
  );
}

function BackIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="m15 6-6 6 6 6" />
    </IconBase>
  );
}

function FilterIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M4.5 6h15" />
      <path d="M7.5 12h9" />
      <path d="M10.5 18h3" />
    </IconBase>
  );
}

function ListOnlyViewIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <rect x="5" y="6" width="14" height="3" rx="1.2" />
      <rect x="5" y="10.5" width="14" height="3" rx="1.2" />
      <rect x="5" y="15" width="14" height="3" rx="1.2" />
    </IconBase>
  );
}

function SplitHorizontalViewIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <rect x="4.5" y="5" width="5.5" height="14" rx="1.4" />
      <rect x="11.5" y="5" width="8" height="14" rx="1.4" />
    </IconBase>
  );
}

function SplitVerticalViewIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <rect x="5" y="5" width="14" height="5.5" rx="1.4" />
      <rect x="5" y="12" width="14" height="7" rx="1.4" />
    </IconBase>
  );
}

function GripIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <circle cx="9" cy="7" r="1" fill="currentColor" stroke="none" />
      <circle cx="15" cy="7" r="1" fill="currentColor" stroke="none" />
      <circle cx="9" cy="12" r="1" fill="currentColor" stroke="none" />
      <circle cx="15" cy="12" r="1" fill="currentColor" stroke="none" />
      <circle cx="9" cy="17" r="1" fill="currentColor" stroke="none" />
      <circle cx="15" cy="17" r="1" fill="currentColor" stroke="none" />
    </IconBase>
  );
}

function ReplyIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="m10 8-5 4 5 4" />
      <path d="M5 12h9a5 5 0 0 1 5 5" />
    </IconBase>
  );
}

function ReplyAllIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="m9 8-5 4 5 4" />
      <path d="m13 8-5 4 5 4" />
      <path d="M8 12h6a5 5 0 0 1 5 5" />
    </IconBase>
  );
}

function ForwardIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="m14 8 5 4-5 4" />
      <path d="M19 12h-9a5 5 0 0 0-5 5" />
    </IconBase>
  );
}

function ExternalIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M14 5h5v5" />
      <path d="M19 5 9 15" />
      <path d="M11 5H7a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-4" />
    </IconBase>
  );
}

function DownloadIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M12 4v10" />
      <path d="m8.5 10.5 3.5 3.5 3.5-3.5" />
      <path d="M5 18.5h14" />
    </IconBase>
  );
}

function PreviewIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M2.5 12s3.6-6 9.5-6 9.5 6 9.5 6-3.6 6-9.5 6-9.5-6-9.5-6Z" />
      <circle cx="12" cy="12" r="2.8" />
    </IconBase>
  );
}

function CloseIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="m7 7 10 10" />
      <path d="m17 7-10 10" />
    </IconBase>
  );
}

function PlusIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M12 5v14" />
      <path d="M5 12h14" />
    </IconBase>
  );
}

function PaperclipIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="m9.5 13.5 5.2-5.1a2.6 2.6 0 1 1 3.6 3.7l-7 6.9a4.2 4.2 0 0 1-6-6l7.4-7.3" />
    </IconBase>
  );
}

function SpinnerIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <circle cx="12" cy="12" r="7.2" className="opacity-20" />
      <path d="M12 4.8a7.2 7.2 0 0 1 7.2 7.2" />
    </IconBase>
  );
}

function AlertIcon({ className }: { className?: string }) {
  return (
    <IconBase className={className}>
      <path d="M12 8v4" />
      <path d="M12 16h.01" />
      <path d="M10.2 4.7 3.5 16.3A2 2 0 0 0 5.2 19h13.6a2 2 0 0 0 1.7-2.7L13.8 4.7a2 2 0 0 0-3.6 0Z" />
    </IconBase>
  );
}

function MailRowIcon({
  className,
  unread,
}: {
  className?: string;
  unread: boolean;
}) {
  return (
    <svg viewBox="0 0 24 24" fill="none" className={className}>
      <rect
        x="4.5"
        y="6"
        width="15"
        height="12"
        rx="2.4"
        stroke="currentColor"
        strokeWidth="1.7"
      />
      <path
        d="m5.8 7.4 6.2 4.8 6.2-4.8"
        stroke="currentColor"
        strokeWidth="1.7"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
      {unread ? <circle cx="18.5" cy="7" r="2.2" fill="currentColor" stroke="none" /> : null}
    </svg>
  );
}

function iconForNav(type: NavItem["icon"], className: string) {
  if (type === "inbox") return <InboxIcon className={className} />;
  if (type === "sent") return <SentIcon className={className} />;
  if (type === "drafts") return <DraftIcon className={className} />;
  if (type === "trash") return <TrashIcon className={className} />;
  if (type === "spam") return <SpamIcon className={className} />;
  if (type === "star") return <StarIcon className={className} />;
  if (type === "folder") return <FolderIcon className={className} />;
  return <InboxIcon className={className} />;
}

function iconForSetupNav(section: MailSetupSection | "logout", className: string) {
  if (section === "account") return <UserIcon className={className} />;
  if (section === "domain") return <GlobeIcon className={className} />;
  if (section === "assistant") return <SparkIcon className={className} />;
  if (section === "members") return <UsersIcon className={className} />;
  if (section === "billing") return <BillingIcon className={className} />;
  if (section === "logout") return <LogoutIcon className={className} />;
  return <LogIcon className={className} />;
}

const SIDEBAR_MENU_ICON_CLASS = "h-[18px] w-[18px] shrink-0 text-[#303038]";
const SIDEBAR_MENU_TEXT_GAP_CLASS = "gap-[5px]";
const VIEW_MODE_LABEL: Record<MailListViewMode, string> = {
  "list-only": "메일 목록만 보기",
  "split-horizontal": "좌우 분할로 보기",
  "split-vertical": "상하 분할로 보기",
};
const VIEW_MODE_OPTIONS: readonly MailListViewMode[] = [
  "list-only",
  "split-horizontal",
  "split-vertical",
];
const FILTER_OPTIONS = [
  { id: "all", label: "전체" },
  { id: "unread", label: "안읽음" },
  { id: "important", label: "중요" },
  { id: "attachments", label: "첨부" },
] as const;

const MAIL_SORT_OPTIONS: Array<{ label: string; value: MailListSortOrder }> = [
  { label: "최신순", value: "latest" },
  { label: "오래된순", value: "oldest" },
];

function iconForViewMode(mode: MailListViewMode, className: string) {
  if (mode === "list-only") return <ListOnlyViewIcon className={className} />;
  if (mode === "split-horizontal") return <SplitHorizontalViewIcon className={className} />;
  return <SplitVerticalViewIcon className={className} />;
}

function circleIconButtonClass() {
  return "inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-full border border-transparent bg-transparent text-[#72829f] transition-all duration-200 hover:bg-white/70 hover:text-[#2d3d5c] hover:backdrop-blur-xl hover:backdrop-saturate-150";
}

function detailHeaderActionClass() {
  return "inline-flex h-10 w-10 cursor-pointer items-center justify-center rounded-full text-[#7b8ba7] transition-all duration-200 hover:-translate-y-0.5 hover:bg-[#f4f7fc] hover:text-[#2f6df6] hover:shadow-[0_10px_24px_rgba(25,38,72,0.08)]";
}

function mailboxBulkActionClass(options?: { enabled?: boolean; gapClassName?: string }) {
  const enabled = options?.enabled ?? true;
  const gapClassName = options?.gapClassName ? ` ${options.gapClassName}` : "";

  return `inline-flex h-7 items-center rounded-[10px] transition-colors${gapClassName} ${
    enabled
      ? "cursor-pointer text-[#5e6b81] hover:text-[#2f6df6]"
      : "cursor-not-allowed pointer-events-none text-[#c1c9d7]"
  }`;
}

function toolbarMenuButtonClass(active = false, options?: { mobileIconOnly?: boolean }) {
  const mobileIconOnlyClass = options?.mobileIconOnly
    ? "w-9 justify-center px-0 xl:w-auto xl:px-3.5"
    : "px-3.5";

  return `inline-flex h-9 cursor-pointer items-center gap-2 rounded-full ${mobileIconOnlyClass} text-[14px] transition-colors ${
    active
      ? "bg-[#eef4ff] text-[#2f6df6]"
      : "text-[#5f6f89] hover:bg-[#f4f7fc] hover:text-[#2f6df6]"
  }`;
}

function toolbarTextMenuButtonClass(active = false) {
  return `inline-flex h-9 shrink-0 cursor-pointer appearance-none items-center gap-1.5 border-0 bg-transparent px-0 text-[14px] font-medium leading-none outline-none transition-colors duration-150 focus-visible:outline-none focus-visible:ring-0 ${
    active ? "text-[#2f6df6]" : "text-[#5f6f89] hover:text-[#2f6df6]"
  }`;
}

function settingsMenuItemClass(active = false, disabled = false) {
  return `group flex w-full items-center gap-3 rounded-[16px] px-3 py-3 text-left text-[14px] transition-all duration-200 ${
    disabled
      ? "cursor-not-allowed pointer-events-none text-[#9aa8bf]"
      : active
      ? "bg-[#edf4ff] font-semibold text-[#2f6df6]"
      : "cursor-pointer text-[#465977] hover:bg-[#f7faff] hover:text-[#2f6df6]"
  }`;
}

function settingsMenuButtonClass(active = false, disabled = false) {
  return `group flex w-full appearance-none items-center gap-3 rounded-[16px] border-0 bg-transparent px-3 py-3 text-left text-[14px] transition-all duration-200 ${
    disabled
      ? "cursor-not-allowed pointer-events-none text-[#9aa8bf]"
      : active
      ? "bg-[#edf4ff] font-semibold text-[#2f6df6]"
      : "cursor-pointer text-[#465977] hover:bg-[#f7faff] hover:text-[#2f6df6]"
  }`;
}

function settingsMenuItemIconClass(active = false, disabled = false) {
  return `h-[18px] w-[18px] shrink-0 transition-colors duration-200 ${
    disabled
      ? "text-[#aab6c9]"
      : active
        ? "text-[#2f6df6]"
        : "text-[#7a8ba7] group-hover:text-[#2f6df6]"
  }`;
}

function popoverMenuSurfaceClass(extraClassName = "") {
  return `overflow-hidden rounded-[22px] border border-[#dfe8f8] bg-white p-2.5 text-[14px] shadow-[0_28px_60px_rgba(18,32,65,0.16)] ${extraClassName}`.trim();
}

function popoverMenuItemClass(options?: {
  active?: boolean;
  disabled?: boolean;
  gapClassName?: string;
}) {
  const active = options?.active ?? false;
  const disabled = options?.disabled ?? false;
  const gapClassName = options?.gapClassName ? ` ${options.gapClassName}` : "";

  return `group flex w-full appearance-none items-center rounded-[16px] border-0 bg-transparent px-3 py-3 text-left text-[14px] transition-all duration-200${gapClassName} ${
    disabled
      ? "cursor-not-allowed text-[#b8c3d5]"
      : active
        ? "bg-[#edf4ff] font-semibold text-[#2f6df6]"
        : "cursor-pointer text-[#465977] hover:bg-[#f7faff] hover:text-[#2f6df6]"
  }`;
}

function viewModeMenuItemClass(active = false) {
  return `group flex w-full appearance-none items-center gap-3 rounded-[16px] border-0 bg-transparent px-3 py-3 text-left text-[14px] transition-all duration-200 whitespace-nowrap pr-4 ${
    active
      ? "cursor-default bg-[#edf4ff] font-semibold text-[#2f6df6]"
      : "cursor-pointer text-[#465977] hover:bg-[#f7faff] hover:text-[#2f6df6]"
  }`;
}

function ActionTooltip({
  children,
  label,
}: {
  children: ReactNode;
  label: string;
}) {
  const anchorRef = useRef<HTMLSpanElement | null>(null);
  const [tooltipPosition, setTooltipPosition] = useState<{
    left: number;
    placement: "bottom" | "top";
    top: number;
  } | null>(null);

  const showTooltip = () => {
    const anchor = anchorRef.current;

    if (!anchor) {
      return;
    }

    const rect = anchor.getBoundingClientRect();
    const placement = rect.top > 48 ? "top" : "bottom";

    setTooltipPosition({
      left: rect.left + rect.width / 2,
      placement,
      top: placement === "top" ? rect.top - 10 : rect.bottom + 10,
    });
  };

  const hideTooltip = () => {
    setTooltipPosition(null);
  };

  useEffect(() => {
    if (!tooltipPosition) {
      return;
    }

    const dismissTooltip = () => {
      setTooltipPosition(null);
    };

    window.addEventListener("resize", dismissTooltip);
    window.addEventListener("scroll", dismissTooltip, true);

    return () => {
      window.removeEventListener("resize", dismissTooltip);
      window.removeEventListener("scroll", dismissTooltip, true);
    };
  }, [tooltipPosition]);

  return (
    <span
      ref={anchorRef}
      className="inline-flex"
      onBlur={hideTooltip}
      onFocus={showTooltip}
      onMouseEnter={showTooltip}
      onMouseLeave={hideTooltip}
    >
      {children}
      {tooltipPosition && typeof document !== "undefined"
        ? createPortal(
            <span
              role="tooltip"
              className={`pointer-events-none fixed z-[9999] flex -translate-x-1/2 flex-col items-center ${
                tooltipPosition.placement === "top" ? "-translate-y-full" : ""
              }`}
              style={{
                left: tooltipPosition.left,
                top: tooltipPosition.top,
              }}
            >
              {tooltipPosition.placement === "bottom" ? (
                <span className="-mb-px h-2 w-2 rotate-45 bg-[#182742]" />
              ) : null}
              <span className="whitespace-nowrap rounded-[10px] bg-[#182742] px-3 py-1.5 text-[11px] font-medium leading-none text-white shadow-[0_14px_34px_rgba(24,39,66,0.24)]">
                {label}
              </span>
              {tooltipPosition.placement === "top" ? (
                <span className="-mt-px h-2 w-2 rotate-45 bg-[#182742]" />
              ) : null}
            </span>,
            document.body,
          )
        : null}
    </span>
  );
}

function DraggableHorizontalScroll({
  children,
  className,
  innerClassName,
}: {
  children: ReactNode;
  className?: string;
  innerClassName?: string;
}) {
  const containerRef = useRef<HTMLDivElement | null>(null);
  const dragStateRef = useRef<{
    moved: boolean;
    pointerId: number;
    startScrollLeft: number;
    startX: number;
  } | null>(null);
  const suppressClickRef = useRef(false);
  const [dragging, setDragging] = useState(false);

  const isInteractiveDragTarget = (target: EventTarget | null) =>
    target instanceof HTMLElement &&
    Boolean(
      target.closest(
        [
          "a",
          "button",
          "input",
          "label",
          "select",
          "textarea",
          "[role='button']",
          "[data-draggable-scroll-ignore='true']",
          "[data-move-menu-root='true']",
          "[data-toolbar-menu-root='true']",
        ].join(","),
      ),
    );

  const finishDrag = () => {
    if (dragStateRef.current?.moved) {
      suppressClickRef.current = true;
      window.setTimeout(() => {
        suppressClickRef.current = false;
      }, 0);
    }

    dragStateRef.current = null;
    setDragging(false);
  };

  const handlePointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {
    if (event.pointerType === "touch" || event.button !== 0) {
      return;
    }

    if (isInteractiveDragTarget(event.target)) {
      return;
    }

    const container = containerRef.current;

    if (!container || container.scrollWidth <= container.clientWidth) {
      return;
    }

    dragStateRef.current = {
      moved: false,
      pointerId: event.pointerId,
      startScrollLeft: container.scrollLeft,
      startX: event.clientX,
    };
    container.setPointerCapture(event.pointerId);
  };

  const handlePointerMove = (event: ReactPointerEvent<HTMLDivElement>) => {
    const dragState = dragStateRef.current;
    const container = containerRef.current;

    if (!dragState || !container || dragState.pointerId !== event.pointerId) {
      return;
    }

    const deltaX = event.clientX - dragState.startX;

    if (!dragState.moved && Math.abs(deltaX) < 6) {
      return;
    }

    if (!dragState.moved) {
      dragState.moved = true;
      setDragging(true);
    }

    container.scrollLeft = dragState.startScrollLeft - deltaX;
    event.preventDefault();
  };

  const handlePointerUp = (event: ReactPointerEvent<HTMLDivElement>) => {
    if (dragStateRef.current?.pointerId !== event.pointerId) {
      return;
    }

    finishDrag();
  };

  const handlePointerCancel = (event: ReactPointerEvent<HTMLDivElement>) => {
    if (dragStateRef.current?.pointerId !== event.pointerId) {
      return;
    }

    finishDrag();
  };

  const handleClickCapture = (event: ReactMouseEvent<HTMLDivElement>) => {
    if (!suppressClickRef.current) {
      return;
    }

    suppressClickRef.current = false;
    event.preventDefault();
    event.stopPropagation();
  };

  return (
    <div
      ref={containerRef}
      onPointerDown={handlePointerDown}
      onPointerMove={handlePointerMove}
      onPointerUp={handlePointerUp}
      onPointerCancel={handlePointerCancel}
      onClickCapture={handleClickCapture}
      className={`${className ?? ""} ${dragging ? "cursor-grabbing select-none" : "cursor-grab"}`.trim()}
    >
      <div className={innerClassName}>{children}</div>
    </div>
  );
}

function ToolbarPortalMenu({
  align = "left",
  anchorRef,
  children,
  className,
  open,
}: {
  align?: "left" | "right";
  anchorRef: RefObject<HTMLElement | null>;
  children: ReactNode;
  className: string;
  open: boolean;
}) {
  const [style, setStyle] = useState<CSSProperties | null>(null);

  useLayoutEffect(() => {
    if (!open) {
      setStyle(null);
      return;
    }

    const updatePosition = () => {
      const anchor = anchorRef.current;

      if (!anchor) {
        setStyle(null);
        return;
      }

      const rect = anchor.getBoundingClientRect();
      setStyle({
        position: "fixed",
        top: rect.bottom + 10,
        ...(align === "right" ? { right: window.innerWidth - rect.right } : { left: rect.left }),
      });
    };

    updatePosition();
    window.addEventListener("resize", updatePosition);
    window.addEventListener("scroll", updatePosition, true);

    return () => {
      window.removeEventListener("resize", updatePosition);
      window.removeEventListener("scroll", updatePosition, true);
    };
  }, [align, anchorRef, open]);

  if (!open || !style) {
    return null;
  }

  return createPortal(
    <div data-toolbar-menu-root="true" className={className} style={style}>
      {children}
    </div>,
    document.body,
  );
}

function MoveMenuFieldset({ children }: { children: ReactNode }) {
  const { pending } = useFormStatus();

  return (
    <fieldset
      disabled={pending}
      className={`min-w-0 transition-opacity duration-200 ${
        pending ? "pointer-events-none opacity-55" : "opacity-100"
      }`}
    >
      {children}
    </fieldset>
  );
}

function MoveMenuPendingOverlay() {
  const { pending } = useFormStatus();

  if (!pending) {
    return null;
  }

  return (
    <div className="pointer-events-none absolute inset-0 z-20 flex items-center justify-center rounded-[18px] bg-[rgba(255,255,255,0.78)] backdrop-blur-[2px]">
      <div className="flex items-center gap-2 rounded-full bg-[#182742] px-4 py-2 text-[12px] font-semibold text-white shadow-[0_16px_34px_rgba(24,39,66,0.24)]">
        <SpinnerIcon className="h-4 w-4 animate-spin" />
        메일을 이동하는 중입니다...
      </div>
    </div>
  );
}

function MoveMenuSubmitButton({
  label,
  pendingLabel,
  variant,
  name,
  value,
}: {
  label: string;
  pendingLabel: string;
  variant: "primary" | "secondary";
  name?: string;
  value?: string;
}) {
  const { pending } = useFormStatus();
  const baseClassName =
    "inline-flex h-10 flex-1 items-center justify-center gap-2 rounded-[14px] px-4 text-[13px] font-semibold transition-all duration-200 disabled:cursor-not-allowed";
  const variantClassName =
    variant === "primary"
      ? "bg-[#2f6df6] text-white hover:bg-[#245de3]"
      : "border border-[#dbe5f7] bg-white text-[#344767] hover:bg-[#f7faff] hover:text-[#2f6df6]";

  return (
    <button
      type="submit"
      name={name}
      value={value}
      disabled={pending}
      className={`${baseClassName} ${variantClassName}`}
    >
      {pending ? (
        <>
          <SpinnerIcon className="h-[13px] w-[13px] animate-spin" />
          {pendingLabel}
        </>
      ) : (
        label
      )}
    </button>
  );
}

function SenderRulePromptFieldset({ children }: { children: ReactNode }) {
  const { pending } = useFormStatus();

  return (
    <fieldset
      disabled={pending}
      className={`min-w-0 transition-opacity duration-200 ${
        pending ? "pointer-events-none opacity-60" : "opacity-100"
      }`}
    >
      {children}
    </fieldset>
  );
}

function SenderRulePromptSubmitButton({
  label,
  pendingLabel,
  variant,
  name,
  value,
}: {
  label: string;
  pendingLabel: string;
  variant: "primary" | "secondary";
  name?: string;
  value?: string;
}) {
  const { pending } = useFormStatus();
  const baseClassName =
    "inline-flex h-10 items-center justify-center gap-2 rounded-[14px] px-4 text-[13px] font-semibold transition-all duration-200 disabled:cursor-not-allowed";
  const variantClassName =
    variant === "primary"
      ? "bg-white text-[#12203a] hover:bg-white/92"
      : "border border-white/14 bg-white/6 text-white/88 hover:bg-white/10";

  return (
    <button
      type="submit"
      name={name}
      value={value}
      disabled={pending}
      className={`${baseClassName} ${variantClassName}`}
    >
      {pending ? (
        <>
          <SpinnerIcon className="h-[14px] w-[14px] animate-spin" />
          {pendingLabel}
        </>
      ) : (
        label
      )}
    </button>
  );
}

function SenderRulePromptPendingOverlay() {
  const { pending } = useFormStatus();

  if (!pending) {
    return null;
  }

  return (
    <div className="pointer-events-none absolute inset-0 z-20 flex items-center justify-center rounded-[26px] bg-[rgba(9,13,21,0.46)] backdrop-blur-[6px]">
      <div className="flex items-center gap-2 rounded-full bg-[rgba(10,14,22,0.86)] px-4 py-2 text-[12px] font-semibold text-white ring-1 ring-white/10">
        <SpinnerIcon className="h-4 w-4 animate-spin" />
        설정을 적용하는 중입니다...
      </div>
    </div>
  );
}

function mailboxCheckboxClass() {
  return "h-[15px] w-[15px] rounded-[4px] border-[#cfd7e4] text-[#2f6df6] focus:ring-2 focus:ring-[#d7e5ff] focus:ring-offset-0";
}

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

function clampSidebarWidth(input: {
  containerWidth: number;
  isSetupPanel: boolean;
  isXlLayout: boolean;
  value: number;
}) {
  const minimumRemainingWidth =
    input.isSetupPanel || !input.isXlLayout
      ? MAIL_LAYOUT_LIMITS.contentMinWidth
      : MAIL_LAYOUT_LIMITS.list.min + MAIL_LAYOUT_LIMITS.detailMinWidth;
  const dynamicMax = Math.max(
    MAIL_LAYOUT_LIMITS.sidebar.min,
    Math.min(MAIL_LAYOUT_LIMITS.sidebar.max, input.containerWidth - minimumRemainingWidth),
  );

  return clamp(input.value, MAIL_LAYOUT_LIMITS.sidebar.min, dynamicMax);
}

function clampListWidth(input: {
  containerWidth: number;
  sidebarWidth: number;
  value: number;
}) {
  const dynamicMax = Math.max(
    MAIL_LAYOUT_LIMITS.list.min,
    Math.min(
      MAIL_LAYOUT_LIMITS.list.max,
      input.containerWidth - input.sidebarWidth - MAIL_LAYOUT_LIMITS.detailMinWidth,
    ),
  );

  return clamp(input.value, MAIL_LAYOUT_LIMITS.list.min, dynamicMax);
}

function clampListHeight(input: {
  containerHeight: number;
  value: number;
}) {
  const dynamicMax = Math.max(
    MAIL_LAYOUT_LIMITS.listHeight.min,
    Math.min(
      MAIL_LAYOUT_LIMITS.listHeight.max,
      input.containerHeight - MAIL_LAYOUT_LIMITS.detailMinHeight,
    ),
  );

  return clamp(input.value, MAIL_LAYOUT_LIMITS.listHeight.min, dynamicMax);
}

function ResizeHandle({
  active,
  ariaLabel,
  className,
  left,
  onPointerDown,
}: {
  active: boolean;
  ariaLabel: string;
  className: string;
  left: number;
  onPointerDown: (event: ReactPointerEvent<HTMLButtonElement>) => void;
}) {
  return (
    <div
      className={`pointer-events-none absolute inset-y-0 z-30 ${className}`}
      style={{ left: `${left}px` }}
    >
      <button
        type="button"
        aria-label={ariaLabel}
        onPointerDown={onPointerDown}
        className="pointer-events-auto absolute inset-y-0 left-1/2 w-4 -translate-x-1/2 cursor-col-resize touch-none group"
      >
        <span
          className={`absolute inset-y-0 left-1/2 w-px -translate-x-1/2 transition-colors ${
            active ? "bg-[#2f6df6]" : "bg-[#dfe7f5] group-hover:bg-[#7fa5ff]"
          }`}
        />
        <span
          className={`absolute left-1/2 top-1/2 flex h-14 w-[10px] -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full border shadow-[0_10px_26px_rgba(28,44,77,0.08)] transition-all ${
            active
              ? "border-[#cfe0ff] bg-[#eef4ff]"
              : "border-[#e6edf9] bg-white/96 group-hover:border-[#cfe0ff] group-hover:bg-[#f7faff]"
          }`}
        >
          <span className="h-7 w-[2px] rounded-full bg-[#c4d1e6]" />
        </span>
      </button>
    </div>
  );
}

function HorizontalResizeHandle({
  active,
  ariaLabel,
  className,
  left,
  onPointerDown,
  top,
}: {
  active: boolean;
  ariaLabel: string;
  className: string;
  left: number;
  onPointerDown: (event: ReactPointerEvent<HTMLButtonElement>) => void;
  top: string;
}) {
  return (
    <div
      className={`pointer-events-none absolute right-0 z-30 ${className}`}
      style={{ left: `${left}px`, top }}
    >
      <button
        type="button"
        aria-label={ariaLabel}
        onPointerDown={onPointerDown}
        className="pointer-events-auto absolute inset-x-0 top-1/2 h-4 -translate-y-1/2 cursor-row-resize touch-none group"
      >
        <span
          className={`absolute inset-x-0 top-1/2 h-px -translate-y-1/2 transition-colors ${
            active ? "bg-[#2f6df6]" : "bg-[#dfe7f5] group-hover:bg-[#7fa5ff]"
          }`}
        />
        <span
          className={`absolute left-1/2 top-1/2 flex h-[10px] w-14 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-full border shadow-[0_10px_26px_rgba(28,44,77,0.08)] transition-all ${
            active
              ? "border-[#cfe0ff] bg-[#eef4ff]"
              : "border-[#e6edf9] bg-white/96 group-hover:border-[#cfe0ff] group-hover:bg-[#f7faff]"
          }`}
        >
          <span className="h-[2px] w-7 rounded-full bg-[#c4d1e6]" />
        </span>
      </button>
    </div>
  );
}

export function MailGate({
  currentPanel,
  setupSection,
  setupOverview,
  managedMembers,
  memberMailboxView,
  aiAssistOverview,
  autoSendOverview,
  billingOverview,
  billingCancellationOverview,
  billingHistoryPage,
  billingHistoryState,
  billingTab,
  planSummary,
  canManageBilling,
  mailConfigured,
  userEmail,
  userDisplayName,
  mailbox,
  companyName,
  domain,
  data,
  currentFolder,
  currentView,
  composeMode,
  detailView,
  detailOpen,
  currentSearchField,
  currentSearchQuery,
  layoutPreferences,
  composeBccDefault,
  composeCcDefault,
  composeToDefault,
  composeSubjectDefault,
  composeBodyDefault,
  composeBodyHtmlDefault,
  notice,
}: MailGateProps) {
  const router = useRouter();
  const savedLayoutRef = useRef(normalizeMailLayoutPreferences(layoutPreferences));
  const filterMenuButtonRef = useRef<HTMLButtonElement | null>(null);
  const pageSizeMenuButtonRef = useRef<HTMLButtonElement | null>(null);
  const sortMenuButtonRef = useRef<HTMLButtonElement | null>(null);
  const viewMenuButtonRef = useRef<HTMLButtonElement | null>(null);
  const isSetupPanel = currentPanel === "setup";
  const isAutoSendPanel = currentPanel === "auto-send";
  const isMailboxPanel = currentPanel === "mail";
  const isStandaloneContentPanel = isSetupPanel || isAutoSendPanel;
  const [mailData, setMailData] = useState(data);
  const mailboxFetchStateRef = useRef({ inFlight: false, queuedSilentRefresh: false });
  const mailboxDataFetchRef = useRef<(options?: MailboxDataFetchOptions) => Promise<boolean>>(
    async () => false,
  );
  const [localNotice, setLocalNotice] = useState<MailNotice | null>(null);
  const [dismissedServerNoticeKey, setDismissedServerNoticeKey] = useState("");
  const [isRefreshing, setIsRefreshing] = useState(false);
  const [pendingMoveKey, setPendingMoveKey] = useState<string | null>(null);
  const [dismissedDetailScopeKey, setDismissedDetailScopeKey] = useState<string | null>(null);
  const currentMailboxFolder = mailData?.currentFolder ?? currentFolder;
  const resolvedMessageFilter = mailData?.messageFilter ?? "all";
  const resolvedCurrentPage = mailData?.currentPage ?? 1;
  const interactionScopeKey = `${currentMailboxFolder}:${resolvedMessageFilter}:${resolvedCurrentPage}:${currentView}:${detailView}:${detailOpen ? "1" : "0"}`;
  const [moveMenuState, setMoveMenuState] = useState<{ open: boolean; scope: string }>({
    open: false,
    scope: interactionScopeKey,
  });
  const [toolbarMenuState, setToolbarMenuState] = useState<{
    kind: ToolbarMenuKind | null;
    scope: string;
  }>({
    kind: null,
    scope: interactionScopeKey,
  });
  const [senderMenuState, setSenderMenuState] = useState<{ messageId: number | null; scope: string }>({
    messageId: null,
    scope: interactionScopeKey,
  });
  const [detailMenuState, setDetailMenuState] = useState<{ open: boolean; scope: string }>({
    open: false,
    scope: "",
  });
  const [sidebarFolderMenuState, setSidebarFolderMenuState] = useState<{
    folderId: number | null;
    scope: string;
  }>({
    folderId: null,
    scope: "",
  });
  const [sidebarFolderMenuPosition, setSidebarFolderMenuPosition] = useState<{
    top: number;
    left: number;
  } | null>(null);
  const [rawSourceModalState, setRawSourceModalState] = useState<{ open: boolean; scope: string }>({
    open: false,
    scope: "",
  });
  const [attachmentPreviewState, setAttachmentPreviewState] = useState<AttachmentPreviewState | null>(null);
  const [settingsMenuState, setSettingsMenuState] = useState<{ open: boolean; scope: string }>({
    open: false,
    scope: "",
  });
  const [selectionState, setSelectionState] = useState<{ ids: number[]; scope: string }>({
    ids: [],
    scope: interactionScopeKey,
  });
  const [senderSpamPrompt, setSenderSpamPrompt] = useState<SenderSpamPromptState | null>(null);
  const [senderSpamPromptTargetFolder, setSenderSpamPromptTargetFolder] = useState("inbox");
  const [senderSpamPromptNewFolderName, setSenderSpamPromptNewFolderName] = useState("");
  const [searchInput, setSearchInput] = useState(currentSearchQuery);
  const deferredSearchInput = useDeferredValue(searchInput.trim());
  const [searchSuggestions, setSearchSuggestions] = useState<MailSearchSuggestion[]>([]);
  const [searchLoading, setSearchLoading] = useState(false);
  const [searchOpen, setSearchOpen] = useState(false);
  const [searchHighlightedIndex, setSearchHighlightedIndex] = useState(-1);
  const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
  const [mobileSearchVisible, setMobileSearchVisible] = useState(false);
  const [viewportState, setViewportState] = useState({
    isLgViewport: false,
    isXlViewport: false,
  });
  const [pendingStarMessageIds, setPendingStarMessageIds] = useState<number[]>([]);
  const [pendingPanelNavigation, setPendingPanelNavigation] = useState<{
    href: string;
    intent: "auto-send" | "mailbox" | "setup";
  } | null>(null);
  const [isPanelNavigationPending, startPanelNavigationTransition] = useTransition();
  const [pendingMessageNavigationId, setPendingMessageNavigationId] = useState<number | null>(null);
  const [isMessageNavigationPending, startMessageNavigationTransition] = useTransition();
  const [layoutState, setLayoutState] = useState(() =>
    normalizeMailLayoutPreferences(layoutPreferences),
  );
  const [sortDisplayOrder, setSortDisplayOrder] = useState<MailListSortOrder>(
    normalizeMailLayoutPreferences(layoutPreferences).sortOrder,
  );
  const layoutStateRef = useRef(layoutState);
  const [dragState, setDragState] = useState<LayoutDragState | null>(null);
  const folders = mailData?.folders ?? [];
  const [folderOrderState, setFolderOrderState] = useState<number[]>(() =>
    folders.map((folder) => folder.id),
  );
  const folderOrderRef = useRef(folderOrderState);
  const folderDragStartOrderRef = useRef(folderOrderState);
  const [draggingFolderId, setDraggingFolderId] = useState<number | null>(null);
  const [dragOverFolderId, setDragOverFolderId] = useState<number | null>(null);
  const [draggingMessageIds, setDraggingMessageIds] = useState<number[] | null>(null);
  const [dragOverMessageFolder, setDragOverMessageFolder] = useState<string | null>(null);
  const [sidebarFolderActionState, setSidebarFolderActionState] = useState<{
    action: SidebarFolderAction | null;
    folderId: number | null;
  }>({
    action: null,
    folderId: null,
  });
  const [sidebarFolderEditorState, setSidebarFolderEditorState] =
    useState<SidebarFolderInlineEditorState | null>(null);
  const [sidebarFolderEditorPending, setSidebarFolderEditorPending] = useState(false);
  const [personalFoldersOpen, setPersonalFoldersOpen] = useState(true);
  const [moveTargetFolder, setMoveTargetFolder] = useState("");
  const [moveNewFolderName, setMoveNewFolderName] = useState("");

  useEffect(() => {
    layoutStateRef.current = layoutState;
  }, [layoutState]);

  const serverNoticeKey = notice ? `${notice.tone}:${notice.message}` : "";
  const serverNotice = notice && dismissedServerNoticeKey !== serverNoticeKey ? notice : null;
  const runtimeNotice = localNotice ?? serverNotice;

  useEffect(() => {
    if (!serverNoticeKey || typeof window === "undefined") {
      return;
    }

    const url = new URL(window.location.href);
    let changed = false;

    for (const key of ["success", "error", "details"]) {
      if (url.searchParams.has(key)) {
        url.searchParams.delete(key);
        changed = true;
      }
    }

    if (!changed) {
      return;
    }

    const nextUrl = `${url.pathname}${url.search}${url.hash}`;
    window.history.replaceState(window.history.state, "", nextUrl);
  }, [serverNoticeKey]);

  useEffect(() => {
    if (!runtimeNotice) {
      return;
    }

    const timer = window.setTimeout(() => {
      if (localNotice) {
        setLocalNotice((current) =>
          current?.message === localNotice.message && current?.tone === localNotice.tone
            ? null
            : current,
        );
        return;
      }

      if (serverNoticeKey) {
        setDismissedServerNoticeKey(serverNoticeKey);
      }
    }, 4200);

    return () => window.clearTimeout(timer);
  }, [localNotice, runtimeNotice, serverNoticeKey]);

  useEffect(() => {
    if (!isMessageNavigationPending) {
      setPendingMessageNavigationId(null);
    }
  }, [isMessageNavigationPending]);

  useEffect(() => {
    if (!isPanelNavigationPending) {
      setPendingPanelNavigation(null);
    }
  }, [isPanelNavigationPending]);

  useEffect(() => {
    savedLayoutRef.current = normalizeMailLayoutPreferences(layoutPreferences);
  }, [layoutPreferences]);

  useEffect(() => {
    setSortDisplayOrder(layoutState.sortOrder);
  }, [layoutState.sortOrder]);

  useLayoutEffect(() => {
    if (typeof window === "undefined") {
      return;
    }

    const lgMedia = window.matchMedia("(min-width: 1024px)");
    const xlMedia = window.matchMedia("(min-width: 1280px)");
    const updateViewportState = () => {
      setViewportState({
        isLgViewport: lgMedia.matches,
        isXlViewport: xlMedia.matches,
      });
    };

    updateViewportState();
    lgMedia.addEventListener("change", updateViewportState);
    xlMedia.addEventListener("change", updateViewportState);

    return () => {
      lgMedia.removeEventListener("change", updateViewportState);
      xlMedia.removeEventListener("change", updateViewportState);
    };
  }, []);

  useEffect(() => {
    if (viewportState.isLgViewport) {
      setMobileSidebarOpen(false);
      setMobileSearchVisible(false);
    }
  }, [viewportState.isLgViewport]);

  useEffect(() => {
    setMobileSidebarOpen(false);
    setMobileSearchVisible(false);
  }, [interactionScopeKey, currentPanel, setupSection, currentView]);

  const moveMenuOpen = moveMenuState.scope === interactionScopeKey && moveMenuState.open;
  const toolbarMenuKind =
    toolbarMenuState.scope === interactionScopeKey ? toolbarMenuState.kind : null;
  const filterMenuOpen = toolbarMenuKind === "filter";
  const pageSizeMenuOpen = toolbarMenuKind === "pageSize";
  const sortMenuOpen = toolbarMenuKind === "sort";
  const viewMenuOpen = toolbarMenuKind === "view";
  const senderMenuMessageId =
    senderMenuState.scope === interactionScopeKey ? senderMenuState.messageId : null;
  const sidebarFolderMenuId =
    sidebarFolderMenuState.scope === interactionScopeKey ? sidebarFolderMenuState.folderId : null;
  const allMessages = mailData?.messages ?? [];
  const messageMap = new Map(allMessages.map((message) => [message.id, message]));
  const selectedIdsFromState = (selectionState.scope === interactionScopeKey ? selectionState.ids : []).filter(
    (id) => messageMap.has(id),
  );
  const selectedMessage = detailOpen ? mailData?.selectedMessage ?? null : null;
  const folderMap = new Map(folders.map((folder) => [folder.systemName, folder]));
  const inboxFolder = folders.find((folder) => folder.systemName === "inbox") ?? null;
  const allFolderMessages = inboxFolder?.count ?? 0;
  const currentViewMode = layoutState.viewMode;
  const currentSortOrder = sortDisplayOrder;
  const isListOnlyMode = currentViewMode === "list-only";
  const isSplitHorizontalMode = currentViewMode === "split-horizontal";
  const isSplitVerticalMode = currentViewMode === "split-vertical";
  const effectiveFolderOrder = (() => {
    const nextIds = folders.map((folder) => folder.id);

    if (folderOrderState.length === 0) {
      return nextIds;
    }

    const preserved = folderOrderState.filter((id) => nextIds.includes(id));
    const missing = nextIds.filter((id) => !preserved.includes(id));
    return [...preserved, ...missing];
  })();
  const orderedFolderMap = new Map(folders.map((folder) => [folder.id, folder]));
  const orderedSidebarFolders = effectiveFolderOrder
    .map((id) => orderedFolderMap.get(id) ?? null)
    .filter((folder): folder is NonNullable<typeof folder> => Boolean(folder));

  for (const folder of folders) {
    if (!orderedSidebarFolders.some((item) => item.id === folder.id)) {
      orderedSidebarFolders.push(folder);
    }
  }

  useEffect(() => {
    folderOrderRef.current = effectiveFolderOrder;
  }, [effectiveFolderOrder]);

  const folderOrderAnimationKey = effectiveFolderOrder.join(":");

  useLayoutEffect(() => {
    const nextTopPositions = new Map<number, number>();

    folderRowRefs.current.forEach((node, id) => {
      nextTopPositions.set(id, node.getBoundingClientRect().top);
    });

    const previousTopPositions = folderRowTopPositionsRef.current;

    if (previousTopPositions.size > 0) {
      nextTopPositions.forEach((nextTop, id) => {
        if (draggingFolderId === id) {
          return;
        }

        const previousTop = previousTopPositions.get(id);
        const row = folderRowRefs.current.get(id);

        if (previousTop === undefined || !row) {
          return;
        }

        const deltaY = previousTop - nextTop;

        if (Math.abs(deltaY) < 1) {
          return;
        }

        folderRowAnimationsRef.current.get(id)?.cancel();

        const animation = row.animate(
          [
            { transform: `translateY(${deltaY}px)` },
            { transform: "translateY(0px)" },
          ],
          {
            duration: 240,
            easing: "cubic-bezier(0.22, 1, 0.36, 1)",
          },
        );

        const clearAnimation = () => {
          if (folderRowAnimationsRef.current.get(id) === animation) {
            folderRowAnimationsRef.current.delete(id);
          }
        };

        animation.addEventListener("finish", clearAnimation, { once: true });
        animation.addEventListener("cancel", clearAnimation, { once: true });
        folderRowAnimationsRef.current.set(id, animation);
      });
    }

    folderRowTopPositionsRef.current = nextTopPositions;
  }, [folderOrderAnimationKey, draggingFolderId]);

  const messageFilterCounts = mailData?.messageFilterCounts ?? {
    all: allMessages.length,
    unread: allMessages.filter((message) => !message.isRead).length,
    important: allMessages.filter((message) => message.isStarred).length,
    attachments: allMessages.filter(looksLikeAttachment).length,
  };
  const totalMessages = mailData?.totalMessages ?? allMessages.length;
  const totalPages = mailData?.totalPages ?? 1;
  const resolvedPageSize = mailData?.pageSize ?? DEFAULT_MAILBOX_PAGE_SIZE;
  const compactMailbox = mailbox || userEmail;
  const resolvedSearchField = mailData?.searchField ?? currentSearchField;
  const resolvedSearchQuery = (mailData?.searchQuery ?? currentSearchQuery).trim();
  const activeSearchBadgeVisible =
    resolvedSearchQuery.length > 0 &&
    resolvedSearchField !== "all" &&
    searchInput.trim() === resolvedSearchQuery;
  const mobileSearchExpanded =
    !viewportState.isLgViewport &&
    (mobileSearchVisible || searchInput.trim().length > 0 || resolvedSearchQuery.length > 0);

  const sidebarFolders: SidebarFolderNavItem[] = orderedSidebarFolders.map((folder) => ({
    id: folder.id,
    kind: folder.kind,
    systemName: folder.systemName,
    label: folder.kind === "custom" ? folder.name : folderLabelForSidebar(folder.systemName),
    count:
      folder.systemName === "inbox"
        ? folder.unreadCount || folder.count
        : folder.count,
    icon:
      folder.kind === "custom"
        ? "folder"
        : folder.systemName === "sent"
        ? "sent"
        : folder.systemName === "drafts"
          ? "drafts"
          : folder.systemName === "trash"
            ? "trash"
            : folder.systemName === "spam"
              ? "spam"
              : "inbox",
    href: folderHref(folder.systemName, {
      pageSize: resolvedPageSize,
      searchField: resolvedSearchField,
      searchQuery: resolvedSearchQuery,
      sortOrder: currentSortOrder,
      tab: "all",
    }),
  }));
  const primaryFolders = sidebarFolders.filter((folder) =>
    isPrimaryMailboxFolder(folder.systemName),
  );
  const personalFolders = sidebarFolders.filter((folder) =>
    isPersonalMailboxFolder(folder.systemName, folder.kind),
  );
  const secondarySystemFolders = sidebarFolders.filter((folder) =>
    isSecondarySystemMailboxFolder(folder.systemName),
  );
  const sidebarFolderMenuItem =
    sidebarFolderMenuId === null
      ? null
      : sidebarFolders.find((folder) => folder.id === sidebarFolderMenuId) ?? null;
  const allFolderHref = mailConfigured
    ? folderHref("all", {
        pageSize: resolvedPageSize,
        searchField: resolvedSearchField,
        searchQuery: resolvedSearchQuery,
        sortOrder: currentSortOrder,
        tab: "all",
      })
    : setupHref("domain");
  const allFolderNavigationIntent = mailConfigured ? "mailbox" : "setup";
  const senderSpamRestoreFolderOptions = [
    ...sidebarFolders.filter((folder) => folder.systemName === "inbox"),
    ...personalFolders,
  ];
  const settingsMenuItems: SettingsMenuItem[] = [
    { id: "account", label: "계정 설정" },
    { id: "assistant", label: "AI 어시스트" },
    ...(canManageBilling
      ? ([
          { id: "domain", label: "도메인 연결" },
          { id: "members", label: "멤버 관리" },
          { id: "billing", label: "결제 및 구독" },
        ] satisfies SettingsMenuItem[])
      : []),
    { id: "logout", label: "로그아웃" },
  ];
  const settingsMenuRef = useRef<HTMLDivElement | null>(null);
  const searchMenuRef = useRef<HTMLDivElement | null>(null);
  const searchInputRef = useRef<HTMLInputElement | null>(null);
  const detailPanelEnabled = isMailboxPanel && currentView !== "compose";

  const filteredMessages = allMessages;
  const searchDropdownVisible =
    searchOpen && isMailboxPanel && searchInput.trim().length > 0;

  const previewMessage = detailOpen ? createPreviewMessage(selectedMessage, null) : null;
  const previewAttachments = previewMessage?.attachments.filter(
    (attachment) => !(attachment.isInline && attachment.contentId),
  ) ?? [];
  const previewableAttachments = previewAttachments.filter((attachment) => attachment.isPreviewable);
  const imagePreviewableAttachments = previewableAttachments.filter((attachment) =>
    isImageAttachmentPreview(attachment),
  );
  const totalAttachmentSize = previewAttachments.reduce(
    (total, attachment) => total + attachment.sizeBytes,
    0,
  );
  const isLgViewport = viewportState.isLgViewport;
  const isXlViewport = viewportState.isXlViewport;
  const detailPanelScopeKey = detailPanelEnabled && detailOpen && previewMessage
    ? `${currentMailboxFolder}:${resolvedMessageFilter}:${resolvedCurrentPage}:${currentView}:${previewMessage.id}:${detailView}`
    : "";
  const splitPanelSupported =
    detailPanelEnabled &&
    !isListOnlyMode &&
    ((isSplitHorizontalMode && isXlViewport) || (isSplitVerticalMode && isLgViewport));
  const splitDetailPreviewDismissed =
    detailPanelScopeKey !== "" && dismissedDetailScopeKey === detailPanelScopeKey;
  const showSplitDetailPanel = splitPanelSupported;
  const showStandaloneMessageView =
    detailPanelEnabled &&
    detailOpen &&
    Boolean(previewMessage) &&
    (isListOnlyMode || !splitPanelSupported);
  const attachmentPreviewItems =
    attachmentPreviewState?.collection === "images"
      ? imagePreviewableAttachments
      : previewableAttachments;
  const attachmentPreviewModalOpen = Boolean(
    attachmentPreviewState &&
      attachmentPreviewState.scope === detailPanelScopeKey &&
      attachmentPreviewItems[attachmentPreviewState.currentIndex],
  );
  const activeAttachmentPreview =
    attachmentPreviewModalOpen && attachmentPreviewState
      ? attachmentPreviewItems[attachmentPreviewState.currentIndex] ?? null
      : null;
  const activeAttachmentPreviewUrl =
    activeAttachmentPreview && attachmentPreviewState
      ? `/api/mailbox/attachment?message=${attachmentPreviewState.messageId}&index=${activeAttachmentPreview.index}&mode=inline`
      : "";
  const activeAttachmentPreviewIsImage = activeAttachmentPreview
    ? isImageAttachmentPreview(activeAttachmentPreview)
    : false;
  const activeAttachmentPreviewFile =
    activeAttachmentPreview ? splitAttachmentFilename(activeAttachmentPreview.filename) : null;
  const attachmentPreviewCountLabel =
    attachmentPreviewState && attachmentPreviewItems.length > 0
      ? `${attachmentPreviewState.currentIndex + 1}/${attachmentPreviewItems.length}`
      : "";
  const selectedIds =
    selectedIdsFromState.length > 0
      ? selectedIdsFromState
      : !isListOnlyMode && previewMessage
        ? [previewMessage.id]
        : [];
  const activePreviewMessageId = previewMessage?.id ?? null;
  const activeMessageStarPending =
    activePreviewMessageId !== null && pendingStarMessageIds.includes(activePreviewMessageId);
  const showPanelNavigationOverlay =
    pendingPanelNavigation !== null && isPanelNavigationPending;
  const showMessageNavigationOverlay =
    pendingMessageNavigationId !== null && isMessageNavigationPending;
  const showContentNavigationOverlay =
    showMessageNavigationOverlay || showPanelNavigationOverlay;
  const showMobileFullContentNavigationOverlay =
    !isLgViewport && showContentNavigationOverlay;
  const contentNavigationDescription = showMessageNavigationOverlay
    ? "메일 내용을 불러오고 있습니다."
    : pendingPanelNavigation?.intent === "setup"
      ? "설정 화면을 불러오고 있습니다."
      : pendingPanelNavigation?.intent === "auto-send"
        ? "자동발송 예약 화면을 불러오고 있습니다."
      : "메일함을 불러오고 있습니다.";
  const showPrimaryContentNavigationOverlay =
    !showMobileFullContentNavigationOverlay &&
    (showPanelNavigationOverlay || (showMessageNavigationOverlay && !showSplitDetailPanel));
  const showDetailContentNavigationOverlay =
    !showMobileFullContentNavigationOverlay &&
    showContentNavigationOverlay &&
    showSplitDetailPanel;
  const showEmbeddedContentNavigationOverlay =
    !showMobileFullContentNavigationOverlay && showContentNavigationOverlay;
  const renderContentNavigationOverlay = (className = "absolute inset-0 z-[120] flex items-center justify-center bg-[rgba(252,253,255,0.96)] transition-opacity duration-200") =>
    showContentNavigationOverlay ? (
      <div className={className}>
        <div className="flex flex-col items-center gap-4 text-center">
          <span className="inline-flex h-14 w-14 items-center justify-center rounded-full bg-white shadow-[0_18px_42px_rgba(32,52,89,0.08)]">
            <span className="h-6 w-6 animate-spin rounded-full border-[2.5px] border-transparent border-r-[#2f6df6] border-t-[#2f6df6]" />
          </span>
          <div className="space-y-1">
            <p className="text-[18px] font-semibold tracking-[-0.03em] text-[#1a2943]">로딩중</p>
            <p className="text-[13px] text-[#72839f]">{contentNavigationDescription}</p>
          </div>
        </div>
      </div>
    ) : null;
  const backToListHref = folderHref(currentMailboxFolder, {
    page: resolvedCurrentPage,
    pageSize: resolvedPageSize,
    searchField: resolvedSearchField,
    searchQuery: resolvedSearchQuery,
    sortOrder: currentSortOrder,
    tab: resolvedMessageFilter,
  });
  const currentFolderLabel =
    currentMailboxFolder === "all"
      ? "전체메일"
      : folderLabelForHeader(
          currentMailboxFolder,
          folderMap.get(currentMailboxFolder)?.name ?? "받은메일함",
        );
  const currentSidebarFolderItem =
    currentMailboxFolder === "all"
      ? null
      : sidebarFolders.find((folder) => folder.systemName === currentMailboxFolder) ?? null;
  const currentFolderClearPending =
    currentMailboxFolder === "trash" &&
    currentSidebarFolderItem !== null &&
    sidebarFolderActionState.folderId === currentSidebarFolderItem.id &&
    sidebarFolderActionState.action === "clear";
  const renderFolderSummaryTrailingAction = () => {
    if (currentMailboxFolder === "trash" && currentSidebarFolderItem) {
      return (
        <button
          type="button"
          onClick={() => void runSidebarFolderAction(currentSidebarFolderItem, "clear")}
          disabled={currentFolderClearPending}
          className={`ml-2 transition-colors ${
            currentFolderClearPending
              ? "cursor-wait text-[#c1c9d7]"
              : "cursor-pointer text-[#8a94a8] hover:text-[#2f6df6]"
          }`}
        >
          휴지통 비우기
        </button>
      );
    }

    return (
      <Link
        href={folderHref(currentMailboxFolder, {
          page: 1,
          pageSize: resolvedPageSize,
          searchField: resolvedSearchField,
          searchQuery: resolvedSearchQuery,
          sortOrder: currentSortOrder,
          tab: resolvedMessageFilter === "unread" ? "all" : "unread",
        })}
        prefetch={false}
        scroll={false}
        className={`ml-2 transition-colors hover:text-[#2f6df6] ${
          resolvedMessageFilter === "unread" ? "font-semibold text-[#2f6df6]" : "text-[#8a94a8]"
        }`}
      >
        안읽음 {formatCount(messageFilterCounts.unread)}
      </Link>
    );
  };

  const selectedMessages = filteredMessages.filter((message) => selectedIds.includes(message.id));
  const activeMessageId =
    selectedMessage?.id ?? (selectedMessages.length === 1 ? selectedMessages[0].id : null);
  const toolbarMessage: ComposeToolbarMessage | null =
    selectedMessages.length === 1
      ? {
          id: selectedMessages[0].id,
          bodyText: selectedMessages[0].snippet,
          fromAddress: selectedMessages[0].fromAddress,
          fromName: selectedMessages[0].fromName,
          receivedAt: selectedMessages[0].receivedAt,
          snippet: selectedMessages[0].snippet,
          subject: selectedMessages[0].subject,
          toAddresses: selectedMessages[0].toAddresses,
        }
      : null;

  const checkedMessageIds = selectedIds;
  const checkedMessageIdsValue = checkedMessageIds.join(",");
  const hasCheckedMessages = checkedMessageIds.length > 0;
  const standaloneMessageIdsValue =
    showStandaloneMessageView && previewMessage ? String(previewMessage.id) : "";
  const draggingMessageIdSet = new Set(draggingMessageIds ?? []);
  const selectedMessagesAllRead =
    hasCheckedMessages && selectedMessages.every((message) => message.isRead);
  const bulkReadToggleLabel = selectedMessagesAllRead ? "안읽음" : "읽음";
  const bulkReadToggleValue = selectedMessagesAllRead ? "unread" : "read";
  const allVisibleSelected =
    filteredMessages.length > 0 && filteredMessages.every((message) => selectedIds.includes(message.id));
  const activeToolbarMessage: ComposeToolbarMessage | null =
    toolbarMessage ??
    (previewMessage
      ? {
          id: previewMessage.id,
          bodyHtml: previewMessage.bodyHtml,
          bodyText: previewMessage.bodyText,
          fromAddress: previewMessage.fromAddress,
          fromName: previewMessage.fromName,
          receivedAt: previewMessage.receivedAt,
          snippet: previewMessage.snippet,
          subject: previewMessage.subject,
          toAddresses: previewMessage.toAddresses,
        }
      : null);
  const ownAddresses = [compactMailbox, userEmail];
  const replyHref = buildComposeHref({
    action: "reply",
    currentFolder: currentMailboxFolder,
    ownAddresses,
    message: activeToolbarMessage,
  });
  const replyAllHref = buildComposeHref({
    action: "replyAll",
    currentFolder: currentMailboxFolder,
    ownAddresses,
    message: activeToolbarMessage,
  });
  const forwardHref = buildComposeHref({
    action: "forward",
    currentFolder: currentMailboxFolder,
    ownAddresses,
    message: activeToolbarMessage,
  });

  const syncError = mailData?.syncError ?? "";
  const reconnectRequired =
    Boolean(syncError) &&
    (syncError === "mailbox-auth-missing" ||
      syncError === "mailbox-auth-invalid" ||
      syncError.toLowerCase().includes("auth") ||
      syncError.toLowerCase().includes("login") ||
      syncError.toLowerCase().includes("credential"));

  const composeHref = mailConfigured ? "/mail?view=compose" : setupHref("domain");
  const sessionDomain = setupOverview?.domain || domain || compactMailbox.split("@")[1] || "";
  const settingsMenuScopeKey = `${currentPanel}:${setupSection}:${currentMailboxFolder}:${currentView}:${resolvedCurrentPage}:${resolvedMessageFilter}`;
  const settingsMenuOpen =
    settingsMenuState.open && settingsMenuState.scope === settingsMenuScopeKey;
  const composeFormKey = [
    composeBccDefault,
    composeCcDefault,
    composeToDefault,
    composeSubjectDefault,
    composeBodyDefault,
  ].join("::");
  const verticalSplitDividerTop = `clamp(${MAIL_LAYOUT_LIMITS.listHeight.min}px, ${layoutState.listHeight}px, calc(100% - ${MAIL_LAYOUT_LIMITS.detailMinHeight}px))`;
  const layoutGridStyle = {
    "--mail-sidebar-width": `${layoutState.sidebarWidth}px`,
    "--mail-list-width": `${layoutState.listWidth}px`,
    "--mail-list-height": `${layoutState.listHeight}px`,
    "--mail-list-height-clamped": verticalSplitDividerTop,
  } as CSSProperties;
  const paginationItems = buildPaginationItems(resolvedCurrentPage, totalPages);
  const currentFolderTotalCount =
    currentMailboxFolder === "all"
      ? allFolderMessages
      : folderMap.get(currentMailboxFolder)?.count ?? totalMessages;
  const moveFolderOptionGroups = [
    {
      key: "primary",
      items: primaryFolders,
    },
    {
      key: "personal",
      items: personalFolders,
    },
  ].filter((group) => group.items.length > 0);
  const rawSourceText = previewMessage?.rawSource?.trim() ?? "";
  const mailboxQuotaUsedBytes = mailData?.mailboxQuotaUsedBytes ?? null;
  const mailboxQuotaBytes = mailData?.mailboxQuotaBytes ?? null;
  const mailboxQuotaIsUnlimited = mailData?.mailboxQuotaIsUnlimited ?? false;
  const usagePercent =
    mailData?.mailboxQuotaUsagePercent !== null && mailData?.mailboxQuotaUsagePercent !== undefined
      ? Math.max(0, Math.min(100, mailData.mailboxQuotaUsagePercent))
      : mailboxQuotaUsedBytes !== null && mailboxQuotaBytes && mailboxQuotaBytes > 0
        ? Math.max(0, Math.min(100, Math.round((mailboxQuotaUsedBytes / mailboxQuotaBytes) * 100)))
        : null;
  const usageSummary =
    mailboxQuotaUsedBytes === null
      ? "집계 중"
      : mailboxQuotaIsUnlimited
        ? `${formatStorage(mailboxQuotaUsedBytes)} / 무제한`
        : mailboxQuotaBytes === null
          ? formatStorage(mailboxQuotaUsedBytes)
          : `${formatStorage(mailboxQuotaUsedBytes)} / ${formatStorage(mailboxQuotaBytes)}`;
  const usageProgressValue = usagePercent ?? 0;
  const usageProgressRatio = usageProgressValue / 100;
  const usageProgressStartHue = Math.round(144 - usageProgressRatio * 136);
  const usageProgressEndHue = Math.max(0, usageProgressStartHue - 22);
  const usageProgressFillStyle = {
    backgroundImage: `linear-gradient(90deg, hsl(${usageProgressStartHue} 72% 58%) 0%, hsl(${usageProgressEndHue} 88% 56%) 100%)`,
    boxShadow: `0 10px 24px hsla(${usageProgressEndHue}, 85%, 50%, 0.24)`,
  } satisfies CSSProperties;
  const availableMoveFolder =
    sidebarFolders.find((folder) => folder.systemName === currentMailboxFolder) ??
    primaryFolders[0] ??
    personalFolders[0] ??
    null;
  const resolvedMoveTargetFolder = moveTargetFolder || availableMoveFolder?.systemName || "inbox";
  const personalFoldersExpanded =
    personalFoldersOpen || personalFolders.some((folder) => folder.systemName === currentMailboxFolder);

  const openComposeToAddress = (address: string) => {
    setSenderMenuState({ messageId: null, scope: interactionScopeKey });
    router.push(buildDirectComposeHref(currentMailboxFolder, address));
  };

  const copyToClipboard = async (value: string, message: string) => {
    try {
      if (typeof navigator !== "undefined" && navigator.clipboard?.writeText) {
        await navigator.clipboard.writeText(value);
      } else if (typeof document !== "undefined") {
        const helper = document.createElement("textarea");
        helper.value = value;
        helper.setAttribute("readonly", "true");
        helper.style.position = "fixed";
        helper.style.opacity = "0";
        document.body.appendChild(helper);
        helper.select();
        document.execCommand("copy");
        helper.remove();
      } else {
        throw new Error("clipboard-unavailable");
      }

      setLocalNotice({ tone: "success", message });
    } catch {
      setLocalNotice({
        tone: "error",
        message: "클립보드에 복사하지 못했습니다.",
      });
    }
  };

  const markMessagesReadOptimistically = (messageIds: number[], nextReadState: boolean) => {
    setMailData((currentData) =>
      buildOptimisticReadStateMailData(currentData, messageIds, nextReadState),
    );
  };

  const toggleMessageStarByClient = async (messageId: number) => {
    if (pendingStarMessageIds.includes(messageId)) {
      return false;
    }

    const currentStarred = resolveMessageStarState(mailData, messageId);

    if (currentStarred === null) {
      return false;
    }

    const nextStarred = !currentStarred;
    const previousData = mailData;
    const shouldReconcileImportantFilter =
      previousData?.messageFilter === "important" && !nextStarred;

    setMailData((currentData) =>
      buildOptimisticStarToggledMailData(currentData, messageId, nextStarred),
    );
    setPendingStarMessageIds((current) => [...current, messageId]);

    try {
      const response = await fetch("/api/mailbox/star", {
        body: JSON.stringify({
          isStarred: nextStarred,
          messageId,
        }),
        headers: {
          "Content-Type": "application/json",
        },
        method: "POST",
      });

      if (response.status === 401) {
        window.location.assign("/login");
        return false;
      }

      const payload = (await response.json().catch(() => null)) as {
        isStarred?: boolean;
        notice?: MailNotice | null;
        ok?: boolean;
      } | null;

      if (!response.ok || !payload?.ok || typeof payload.isStarred !== "boolean") {
        throw new Error(payload?.notice?.message || "star-failed");
      }

      if (payload.isStarred !== nextStarred) {
        setMailData((currentData) =>
          buildOptimisticStarToggledMailData(currentData, messageId, payload.isStarred as boolean),
        );
      }

      if (shouldReconcileImportantFilter) {
        router.replace(
          folderHref(currentMailboxFolder, {
            page: resolvedCurrentPage,
            pageSize: resolvedPageSize,
            searchField: resolvedSearchField,
            searchQuery: resolvedSearchQuery,
            sortOrder: currentSortOrder,
            tab: resolvedMessageFilter,
          }),
          { scroll: false },
        );
        void fetchMailboxData({
          messageId: null,
          preserveSelection: false,
          silent: true,
        });
      }

      return true;
    } catch (error) {
      setMailData(previousData);
      setLocalNotice({
        tone: "error",
        message:
          error instanceof Error && error.message
            ? error.message
            : "중요 표시를 바꾸는 중 문제가 발생했습니다.",
      });
      return false;
    } finally {
      setPendingStarMessageIds((current) => current.filter((id) => id !== messageId));
    }
  };

  const fetchMailboxData = async (options: MailboxDataFetchOptions = {}) => {
    if (!mailConfigured) {
      return false;
    }

    if (mailboxFetchStateRef.current.inFlight) {
      if (options.silent && !options.refresh) {
        mailboxFetchStateRef.current.queuedSilentRefresh = true;
      }

      return false;
    }

    mailboxFetchStateRef.current.inFlight = true;

    if (options.showRefreshingState) {
      setIsRefreshing(true);
    }

    try {
      const targetFolder = options.folder ?? currentMailboxFolder;
      const targetPage = options.page ?? resolvedCurrentPage;
      const targetPageSize = normalizeMailboxPageSize(options.pageSize ?? resolvedPageSize);
      const targetSearchField = options.searchField ?? resolvedSearchField;
      const targetSearchQuery = options.searchQuery ?? resolvedSearchQuery;
      const targetSortOrder = options.sortOrder ?? layoutStateRef.current.sortOrder;
      const targetTab = options.tab ?? resolvedMessageFilter;
      const targetMessageId =
        options.messageId === undefined ? selectedMessage?.id ?? null : options.messageId;
      const params = buildFolderSearchParams(targetFolder, {
        page: targetPage,
        pageSize: targetPageSize,
        searchField: targetSearchField,
        searchQuery: targetSearchQuery,
        sortOrder: targetSortOrder,
        tab: targetTab,
      });

      if (targetMessageId) {
        params.set("message", String(targetMessageId));
      }

      if (options.refresh) {
        params.set("refresh", "1");
      }

      const response = await fetch(`/api/mailbox?${params.toString()}`, {
        method: "GET",
        cache: "no-store",
      });

      if (response.status === 401) {
        window.location.assign("/login");
        return false;
      }

      const payload = (await response.json()) as {
        data?: MailAppOverview | null;
        notice?: MailNotice | null;
      };

      if (payload.data) {
        setMailData(payload.data);

        if (options.syncUrl && typeof window !== "undefined") {
          const nextUrl = folderHref(payload.data.currentFolder, {
            page: payload.data.currentPage,
            pageSize: payload.data.pageSize,
            searchField: payload.data.searchField,
            searchQuery: payload.data.searchQuery,
            sortOrder: targetSortOrder,
            tab: payload.data.messageFilter,
          });
          window.history.replaceState(window.history.state, "", nextUrl);
        }

        if (!options.preserveSelection) {
          setSelectionState({ ids: [], scope: interactionScopeKey });
          setMoveMenuState({ open: false, scope: interactionScopeKey });
        }
      }

      if (!options.silent) {
        setLocalNotice(
          payload.notice ??
            (options.refresh
              ? {
                  tone: "success",
                  message: "메일함을 다시 동기화했습니다.",
                }
              : null),
        );
      }

      return true;
    } catch {
      if (!options.silent) {
        setLocalNotice({
          tone: "error",
          message: "메일함 새로고침 중 오류가 발생했습니다.",
        });
      }

      return false;
    } finally {
      mailboxFetchStateRef.current.inFlight = false;

      if (options.showRefreshingState) {
        setIsRefreshing(false);
      }

      if (mailboxFetchStateRef.current.queuedSilentRefresh) {
        mailboxFetchStateRef.current.queuedSilentRefresh = false;
        void fetchMailboxData({ preserveSelection: true, silent: true });
      }
    }
  };

  const syncMailbox = async () => {
    if (isRefreshing || !mailConfigured) {
      return;
    }

    await fetchMailboxData({
      preserveSelection: false,
      refresh: true,
      showRefreshingState: true,
    });
  };

  const applySearch = (field: MailSearchField, query: string) => {
    const normalizedQuery = query.trim();

    setSearchInput(normalizedQuery);
    setSearchOpen(false);
    setSearchSuggestions([]);
    setSearchHighlightedIndex(-1);
    setDismissedDetailScopeKey(null);
    router.push(
      folderHref(currentMailboxFolder, {
        page: 1,
        pageSize: resolvedPageSize,
        searchField: normalizedQuery ? field : "all",
        searchQuery: normalizedQuery,
        sortOrder: currentSortOrder,
        tab: resolvedMessageFilter,
      }),
      { scroll: false },
    );
  };

  const clearSearch = () => {
    setSearchInput("");
    setSearchOpen(false);
    setSearchSuggestions([]);
    setSearchHighlightedIndex(-1);

    if (!resolvedSearchQuery) {
      searchInputRef.current?.focus();
      return;
    }

    setDismissedDetailScopeKey(null);
    router.push(
      folderHref(currentMailboxFolder, {
        page: 1,
        pageSize: resolvedPageSize,
        sortOrder: currentSortOrder,
        tab: resolvedMessageFilter,
      }),
      { scroll: false },
    );
    searchInputRef.current?.focus();
  };

  const applySearchSuggestion = (suggestion: MailSearchSuggestion) => {
    applySearch(suggestion.field, suggestion.value);
  };

  const applyPageSize = async (nextPageSize: number) => {
    const pageSize = normalizeMailboxPageSize(nextPageSize);

    if (pageSize === resolvedPageSize) {
      return;
    }

    setToolbarMenuKind(null);
    setDismissedDetailScopeKey(null);
    setSelectionState({ ids: [], scope: interactionScopeKey });
    setMoveMenuState({ open: false, scope: interactionScopeKey });

    const updated = await fetchMailboxData({
      messageId: null,
      page: 1,
      pageSize,
      preserveSelection: false,
      searchField: resolvedSearchField,
      searchQuery: resolvedSearchQuery,
      silent: true,
      sortOrder: currentSortOrder,
      syncUrl: true,
      tab: resolvedMessageFilter,
    });

    if (!updated) {
      setLocalNotice({
        tone: "error",
        message: "표시 개수를 변경하는 중 오류가 발생했습니다.",
      });
    }
  };

  const visibleSearchSuggestions = searchInput.trim() ? searchSuggestions : [];

  useEffect(() => {
    if (!searchDropdownVisible) {
      return;
    }

    const handlePointerDown = (event: MouseEvent) => {
      const target = event.target;

      if (!(target instanceof HTMLElement)) {
        return;
      }

      if (!target.closest("[data-mail-search-root='true']")) {
        setSearchOpen(false);
        setSearchHighlightedIndex(-1);
      }
    };

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setSearchOpen(false);
        setSearchHighlightedIndex(-1);
      }
    };

    document.addEventListener("mousedown", handlePointerDown);
    document.addEventListener("keydown", handleKeyDown);

    return () => {
      document.removeEventListener("mousedown", handlePointerDown);
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [searchDropdownVisible]);

  useEffect(() => {
    if (!isMailboxPanel || !mailConfigured || !searchOpen || !deferredSearchInput) {
      return;
    }

    const controller = new AbortController();
    const params = new URLSearchParams({
      folder: currentMailboxFolder,
      q: deferredSearchInput,
    });
    const timer = window.setTimeout(async () => {
      setSearchLoading(true);

      try {
        const response = await fetch(`/api/mailbox/search?${params.toString()}`, {
          cache: "no-store",
          method: "GET",
          signal: controller.signal,
        });

        if (!response.ok) {
          throw new Error(`mail-search-failed:${response.status}`);
        }

        const payload = (await response.json()) as {
          suggestions?: MailSearchSuggestion[];
        };
        const nextSuggestions = payload.suggestions ?? [];

        setSearchSuggestions(nextSuggestions);
        setSearchHighlightedIndex((current) =>
          nextSuggestions.length === 0 ? -1 : Math.min(current, nextSuggestions.length - 1),
        );
      } catch (error) {
        if (
          error instanceof DOMException &&
          (error.name === "AbortError" || error.message === "The operation was aborted.")
        ) {
          return;
        }

        setSearchSuggestions([]);
        setSearchHighlightedIndex(-1);
      } finally {
        setSearchLoading(false);
      }
    }, 120);

    return () => {
      controller.abort();
      window.clearTimeout(timer);
    };
  }, [currentMailboxFolder, deferredSearchInput, isMailboxPanel, mailConfigured, searchOpen]);

  useEffect(() => {
    if (senderMenuMessageId === null) {
      return;
    }

    const handlePointerDown = (event: MouseEvent) => {
      const target = event.target;

      if (!(target instanceof HTMLElement)) {
        return;
      }

      if (!target.closest("[data-sender-menu-root='true']")) {
        setSenderMenuState({ messageId: null, scope: interactionScopeKey });
      }
    };

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setSenderMenuState({ messageId: null, scope: interactionScopeKey });
      }
    };

    document.addEventListener("mousedown", handlePointerDown);
    document.addEventListener("keydown", handleKeyDown);

    return () => {
      document.removeEventListener("mousedown", handlePointerDown);
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [senderMenuMessageId, interactionScopeKey]);

  useEffect(() => {
    if (!moveMenuOpen) {
      return;
    }

    const handlePointerDown = (event: MouseEvent) => {
      const target = event.target;

      if (!(target instanceof HTMLElement)) {
        return;
      }

      if (!target.closest("[data-move-menu-root='true']")) {
        setMoveMenuState({ open: false, scope: interactionScopeKey });
      }
    };

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setMoveMenuState({ open: false, scope: interactionScopeKey });
      }
    };

    document.addEventListener("mousedown", handlePointerDown);
    document.addEventListener("keydown", handleKeyDown);

    return () => {
      document.removeEventListener("mousedown", handlePointerDown);
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [interactionScopeKey, moveMenuOpen]);

  useEffect(() => {
    if (!toolbarMenuKind) {
      return;
    }

    const handlePointerDown = (event: MouseEvent) => {
      const target = event.target;

      if (!(target instanceof HTMLElement)) {
        return;
      }

      if (!target.closest("[data-toolbar-menu-root='true']")) {
        setToolbarMenuState({ kind: null, scope: interactionScopeKey });
      }
    };

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setToolbarMenuState({ kind: null, scope: interactionScopeKey });
      }
    };

    document.addEventListener("mousedown", handlePointerDown);
    document.addEventListener("keydown", handleKeyDown);

    return () => {
      document.removeEventListener("mousedown", handlePointerDown);
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [interactionScopeKey, toolbarMenuKind]);

  useEffect(() => {
    if (sidebarFolderMenuId === null) {
      return;
    }

    const updatePosition = () => {
      const row = folderRowRefs.current.get(sidebarFolderMenuId);

      if (!row) {
        setSidebarFolderMenuPosition(null);
        return;
      }

      const rect = row.getBoundingClientRect();
      setSidebarFolderMenuPosition({
        top: window.scrollY + rect.top + rect.height / 2,
        left: window.scrollX + rect.right + 10,
      });
    };

    const handlePointerDown = (event: MouseEvent) => {
      const target = event.target;

      if (!(target instanceof HTMLElement)) {
        return;
      }

      if (!target.closest("[data-sidebar-folder-menu-root='true']")) {
        setSidebarFolderMenuState({ folderId: null, scope: interactionScopeKey });
      }
    };

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setSidebarFolderMenuState({ folderId: null, scope: interactionScopeKey });
      }
    };

    const animationFrameId = window.requestAnimationFrame(updatePosition);

    document.addEventListener("mousedown", handlePointerDown);
    document.addEventListener("keydown", handleKeyDown);
    document.addEventListener("scroll", updatePosition, true);
    window.addEventListener("resize", updatePosition);

    return () => {
      window.cancelAnimationFrame(animationFrameId);
      document.removeEventListener("mousedown", handlePointerDown);
      document.removeEventListener("keydown", handleKeyDown);
      document.removeEventListener("scroll", updatePosition, true);
      window.removeEventListener("resize", updatePosition);
    };
  }, [interactionScopeKey, sidebarFolderMenuId]);

  useEffect(() => {
    if (!settingsMenuOpen) {
      return;
    }

    const handlePointerDown = (event: MouseEvent) => {
      const target = event.target;

      if (!(target instanceof HTMLElement)) {
        return;
      }

      if (!target.closest("[data-settings-menu-root='true']")) {
        setSettingsMenuState({ open: false, scope: settingsMenuScopeKey });
      }
    };

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setSettingsMenuState({ open: false, scope: settingsMenuScopeKey });
      }
    };

    document.addEventListener("mousedown", handlePointerDown);
    document.addEventListener("keydown", handleKeyDown);

    return () => {
      document.removeEventListener("mousedown", handlePointerDown);
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [settingsMenuOpen, settingsMenuScopeKey]);

  useEffect(() => {
    mailboxDataFetchRef.current = fetchMailboxData;
  });

  useEffect(() => {
    if ((!isMailboxPanel && !isAutoSendPanel) || !mailConfigured || reconnectRequired) {
      return;
    }

    const eventMode = isMailboxPanel ? "all" : "auto-send";
    const source = new EventSource(
      `/api/mailbox/live?folder=${encodeURIComponent(currentMailboxFolder)}&events=${eventMode}`,
    );

    const handleMailboxUpdated = (event: Event) => {
      if (!isMailboxPanel) {
        return;
      }
      if (!(event instanceof MessageEvent)) {
        return;
      }

      let payload: MailboxLiveUpdatePayload | null = null;

      try {
        payload = JSON.parse(event.data) as MailboxLiveUpdatePayload;
      } catch {
        return;
      }

      void mailboxDataFetchRef.current({ preserveSelection: true, silent: true }).then((updated) => {
        if (
          updated &&
          payload &&
          payload.reason === "exists" &&
          payload.delta > 0 &&
          (currentMailboxFolder === "all" || currentMailboxFolder === "inbox")
        ) {
          setLocalNotice({
            tone: "success",
            message:
              payload.delta === 1
                ? "새 메일 1건이 도착했습니다."
                : `새 메일 ${payload.delta}건이 도착했습니다.`,
          });
        }
      });
    };

    const handleAutoSendCompleted = (event: Event) => {
      if (!(event instanceof MessageEvent)) {
        return;
      }

      try {
        const payload = JSON.parse(event.data) as MailboxAutoSendCompletedPayload;
        const deliveryCount = Math.max(1, Number(payload.deliveryCount) || 1);
        setLocalNotice({
          tone: "success",
          message:
            deliveryCount === 1
              ? `자동발송 메일을 ${payload.recipientEmail}에게 보냈어요.`
              : `자동발송 메일 ${deliveryCount}건을 보냈어요.`,
        });
      } catch {
        return;
      }
    };

    const handleMailboxError = (event: Event) => {
      if (!isMailboxPanel) {
        return;
      }
      if (!(event instanceof MessageEvent)) {
        return;
      }

      try {
        const payload = JSON.parse(event.data) as MailboxLiveErrorPayload;

        if (
          payload.message === "mailbox-auth-missing" ||
          payload.message === "mailbox-auth-invalid"
        ) {
          setLocalNotice({
            tone: "error",
            message: "실시간 메일 동기화를 시작할 수 없습니다. 메일함 인증 정보를 다시 확인해주세요.",
          });
        }
      } catch {
        // Ignore malformed realtime error events.
      }
    };

    source.addEventListener("mailbox-updated", handleMailboxUpdated);
    source.addEventListener("auto-send-completed", handleAutoSendCompleted);
    source.addEventListener("mailbox-error", handleMailboxError);

    return () => {
      source.removeEventListener("mailbox-updated", handleMailboxUpdated);
      source.removeEventListener("auto-send-completed", handleAutoSendCompleted);
      source.removeEventListener("mailbox-error", handleMailboxError);
      source.close();
    };
  }, [
    currentMailboxFolder,
    detailView,
    isAutoSendPanel,
    isMailboxPanel,
    mailConfigured,
    reconnectRequired,
    resolvedCurrentPage,
    resolvedMessageFilter,
    selectedMessage?.id,
  ]);

  const saveLayoutPreferences = async (nextLayout: MailLayoutPreferences) => {
    try {
      const response = await fetch("/api/mail-layout", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(nextLayout),
      });

      if (!response.ok) {
        throw new Error(`mail-layout-save-failed:${response.status}`);
      }

      const payload = (await response.json()) as {
        preferences?: MailLayoutPreferences;
      };

      savedLayoutRef.current = normalizeMailLayoutPreferences(payload.preferences ?? nextLayout);
    } catch (error) {
      console.error("Failed to save mail layout preferences", error);
    }
  };

  const applyLayoutPreferences = (nextLayout: MailLayoutPreferences) => {
    const normalized = normalizeMailLayoutPreferences(nextLayout);
    layoutStateRef.current = normalized;
    setLayoutState(normalized);
    setSortDisplayOrder(normalized.sortOrder);
    void saveLayoutPreferences(normalized);
    return normalized;
  };

  const setToolbarMenuKind = (kind: ToolbarMenuKind | null) => {
    setToolbarMenuState({ kind, scope: interactionScopeKey });
  };

  const navigateWithinMailbox = (
    href: string,
    options?: {
      intent?: "auto-send" | "mailbox" | "setup";
      replace?: boolean;
    },
  ) => {
    if (typeof window !== "undefined") {
      const currentUrl = new URL(window.location.href);
      const nextUrl = new URL(href, window.location.origin);

      if (
        currentUrl.pathname === nextUrl.pathname &&
        currentUrl.search === nextUrl.search &&
        currentUrl.hash === nextUrl.hash
      ) {
        return;
      }
    }

    setDismissedDetailScopeKey(null);
    setToolbarMenuKind(null);
    setMoveMenuState({ open: false, scope: interactionScopeKey });
    setSenderMenuState({ messageId: null, scope: interactionScopeKey });
    setSidebarFolderMenuState({ folderId: null, scope: interactionScopeKey });
    setSettingsMenuState((current) => ({ ...current, open: false }));
    setSearchOpen(false);
    setSearchHighlightedIndex(-1);
    setMobileSidebarOpen(false);
    setMobileSearchVisible(false);
    setPendingPanelNavigation({
      href,
      intent: options?.intent ?? "mailbox",
    });

    startPanelNavigationTransition(() => {
      if (options?.replace) {
        router.replace(href, { scroll: false });
        return;
      }

      router.push(href, { scroll: false });
    });
  };

  const handleMailboxNavigationLinkClick = (
    event: ReactMouseEvent<HTMLAnchorElement>,
    href: string,
    options?: {
      intent?: "auto-send" | "mailbox" | "setup";
      replace?: boolean;
    },
  ) => {
    if (shouldBypassClientNavigation(event)) {
      return;
    }

    event.preventDefault();
    navigateWithinMailbox(href, options);
  };

  const applyViewMode = (viewMode: MailListViewMode) => {
    if (layoutStateRef.current.viewMode === viewMode) {
      setToolbarMenuKind(null);
      return;
    }

    applyLayoutPreferences({
      ...layoutStateRef.current,
      viewMode,
    });
    setDismissedDetailScopeKey(null);
    setToolbarMenuKind(null);

    if (viewMode === "list-only") {
      setSelectionState({ ids: [], scope: interactionScopeKey });
    } else if (activePreviewMessageId) {
      setSelectionState({ ids: [activePreviewMessageId], scope: interactionScopeKey });
    }
  };

  const applySortOrder = async (sortOrder: MailListSortOrder) => {
    if (sortDisplayOrder === sortOrder) {
      return;
    }

    setSortDisplayOrder(sortOrder);
    applyLayoutPreferences({
      ...layoutStateRef.current,
      sortOrder,
    });
    setToolbarMenuKind(null);
    setDismissedDetailScopeKey(null);
    setSelectionState({ ids: [], scope: interactionScopeKey });
    setMoveMenuState({ open: false, scope: interactionScopeKey });

    const updated = await fetchMailboxData({
      messageId: null,
      page: 1,
      pageSize: resolvedPageSize,
      preserveSelection: false,
      searchField: resolvedSearchField,
      searchQuery: resolvedSearchQuery,
      silent: true,
      sortOrder,
      syncUrl: true,
      tab: resolvedMessageFilter,
    });

    if (!updated) {
      const fallbackLayout = normalizeMailLayoutPreferences(savedLayoutRef.current);
      layoutStateRef.current = fallbackLayout;
      setLayoutState(fallbackLayout);
      setSortDisplayOrder(fallbackLayout.sortOrder);
      setLocalNotice({
        tone: "error",
        message: "정렬을 변경하는 중 오류가 발생했습니다.",
      });
    }
  };

  const saveFolderOrder = async (nextOrder: number[]) => {
    try {
      const response = await fetch("/api/mail-layout", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ folderOrder: nextOrder }),
      });

      if (!response.ok) {
        throw new Error(`mail-folder-order-save-failed:${response.status}`);
      }
    } catch (error) {
      console.error("Failed to save mailbox folder order", error);
      setLocalNotice({
        tone: "error",
        message: "메일함 순서를 저장하는 중 오류가 발생했습니다.",
      });
    }
  };

  const folderRowRefs = useRef(new Map<number, HTMLDivElement>());
  const folderRowTopPositionsRef = useRef(new Map<number, number>());
  const folderRowAnimationsRef = useRef(new Map<number, Animation>());
  const sidebarFolderEditorInputRef = useRef<HTMLInputElement | null>(null);
  const folderDragPreviewRef = useRef<HTMLDivElement | null>(null);
  const messageRowRefs = useRef(new Map<number, HTMLDivElement>());
  const messageDragPreviewRef = useRef<HTMLDivElement | null>(null);

  useEffect(() => {
    return () => {
      folderRowAnimationsRef.current.forEach((animation) => animation.cancel());
      folderRowAnimationsRef.current.clear();
    };
  }, []);

  const clearFolderDragPreview = () => {
    folderDragPreviewRef.current?.remove();
    folderDragPreviewRef.current = null;
  };

  const clearMessageDragPreview = () => {
    messageDragPreviewRef.current?.remove();
    messageDragPreviewRef.current = null;
  };

  const finishMessageDrag = () => {
    clearMessageDragPreview();
    setDraggingMessageIds(null);
    setDragOverMessageFolder(null);
  };

  const canDropMessagesToFolder = (
    targetFolderSystemName: string,
    messageIdsInput: number[] | null = draggingMessageIds,
  ) => {
    if (!messageIdsInput || messageIdsInput.length === 0 || targetFolderSystemName === "all") {
      return false;
    }

    const messages = messageIdsInput
      .map((messageId) => messageMap.get(messageId) ?? null)
      .filter((message): message is MailMessageSummary => Boolean(message));

    if (messages.length === 0) {
      return false;
    }

    if (
      targetFolderSystemName === "sent" &&
      messages.some((message) => message.direction !== "outbound")
    ) {
      return false;
    }

    return messages.some(
      (message) =>
        message.folderSystemName !== targetFolderSystemName ||
        targetFolderSystemName === "trash",
    );
  };

  const buildOptimisticMovedMailData = (
    currentData: MailAppOverview | null,
    messageIdsInput: number[],
    targetFolderSystemName: string,
  ) => {
    if (!currentData) {
      return currentData;
    }

    const messageIdsSet = new Set(messageIdsInput);
    const movingMessages = currentData.messages.filter((message) => messageIdsSet.has(message.id));
    const movedAwayMessages = movingMessages.filter(
      (message) =>
        message.folderSystemName !== targetFolderSystemName ||
        targetFolderSystemName === "trash",
    );

    if (movedAwayMessages.length === 0) {
      return currentData;
    }

    const movedAwayIds = new Set(movedAwayMessages.map((message) => message.id));
    const nextMessages = currentData.messages.filter((message) => !movedAwayIds.has(message.id));
    const nextFolders = currentData.folders.map((folder) => {
      let nextCount = folder.count;
      let nextUnreadCount = folder.unreadCount;

      for (const message of movedAwayMessages) {
        if (folder.systemName === message.folderSystemName) {
          nextCount -= 1;

          if (!message.isRead) {
            nextUnreadCount -= 1;
          }
        }

        if (folder.systemName === targetFolderSystemName) {
          if (targetFolderSystemName === "trash" && message.folderSystemName === "trash") {
            continue;
          }

          nextCount += 1;

          if (!message.isRead) {
            nextUnreadCount += 1;
          }
        }
      }

      return {
        ...folder,
        count: Math.max(0, nextCount),
        unreadCount: Math.max(0, nextUnreadCount),
      };
    });
    const nextFilterCounts = {
      all: Math.max(0, currentData.messageFilterCounts.all - movedAwayMessages.length),
      unread: Math.max(
        0,
        currentData.messageFilterCounts.unread -
          movedAwayMessages.filter((message) => !message.isRead).length,
      ),
      important: Math.max(
        0,
        currentData.messageFilterCounts.important -
          movedAwayMessages.filter((message) => message.isStarred).length,
      ),
      attachments: Math.max(
        0,
        currentData.messageFilterCounts.attachments -
          movedAwayMessages.filter((message) => looksLikeAttachment(message)).length,
      ),
    };
    const nextTotalMessages = Math.max(0, currentData.totalMessages - movedAwayMessages.length);
    const nextTotalPages =
      currentData.pageSize > 0
        ? Math.max(1, Math.ceil(nextTotalMessages / currentData.pageSize))
        : currentData.totalPages;
    const selectedMessageMoved =
      currentData.selectedMessage !== null && movedAwayIds.has(currentData.selectedMessage.id);

    return {
      ...currentData,
      currentPage: Math.min(currentData.currentPage, nextTotalPages),
      folders: nextFolders,
      messageFilterCounts: nextFilterCounts,
      messages: nextMessages,
      selectedMessage: selectedMessageMoved ? null : currentData.selectedMessage,
      selectedMessageLogs: selectedMessageMoved ? [] : currentData.selectedMessageLogs,
      totalMessages: nextTotalMessages,
      totalPages: nextTotalPages,
    };
  };

  const moveMessagesByClient = async (messageIdsInput: number[], targetFolderSystemName: string) => {
    const messageIds = [...new Set(messageIdsInput)];
    const moveKey = `${targetFolderSystemName}:${messageIds.sort((a, b) => a - b).join(",")}`;

    if (pendingMoveKey) {
      return false;
    }

    if (!canDropMessagesToFolder(targetFolderSystemName, messageIds)) {
      return false;
    }

    const previousData = mailData;
    const previousSelectionIds = [...selectedIds];
    const activeMessageId = previousData?.selectedMessage?.id ?? null;
    const activeMessageMoved =
      activeMessageId !== null && messageIds.includes(activeMessageId);
    const nextData = buildOptimisticMovedMailData(previousData, messageIds, targetFolderSystemName);

    if (nextData !== previousData) {
      setMailData(nextData);
    }

    setSelectionState({ ids: [], scope: interactionScopeKey });
    setMoveMenuState({ open: false, scope: interactionScopeKey });
    setSenderMenuState({ messageId: null, scope: interactionScopeKey });
    setPendingMoveKey(moveKey);

    if (activeMessageMoved) {
      router.replace(
        folderHref(currentMailboxFolder, {
          page: resolvedCurrentPage,
          pageSize: resolvedPageSize,
          searchField: resolvedSearchField,
          searchQuery: resolvedSearchQuery,
          sortOrder: currentSortOrder,
          tab: resolvedMessageFilter,
        }),
        { scroll: false },
      );
    }

    try {
      const response = await fetch("/api/mailbox/move", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          messageIds,
          targetFolder: targetFolderSystemName,
        }),
      });

      if (response.status === 401) {
        window.location.assign("/login");
        return false;
      }

      const payload = (await response.json()) as MailboxMoveResponse;

      if (!response.ok || !payload.ok) {
        throw new Error(payload.error ?? "move-failed");
      }

      setLocalNotice(
        payload.notice ?? {
          tone: "success",
          message:
            targetFolderSystemName === "spam"
              ? "선택한 발송자의 모든 메일을 스팸함으로 이동했습니다."
              : targetFolderSystemName === "trash"
                ? "선택한 메일을 휴지통으로 이동했습니다."
                : "선택한 메일을 폴더로 이동했습니다.",
        },
      );
      void fetchMailboxData({ preserveSelection: false, silent: true });
      return true;
    } catch (error) {
      setMailData(previousData);
      setSelectionState({ ids: previousSelectionIds, scope: interactionScopeKey });
      setLocalNotice({
        tone: "error",
        message:
          error instanceof Error && error.message === "move-sent-only"
            ? "보낸 메일만 보낸메일함으로 이동할 수 있습니다."
            : error instanceof Error && error.message === "move-conflict"
              ? "메일함 상태가 최신이 아니어서 이동에 실패했습니다. 메일함을 다시 동기화한 뒤 다시 시도해주세요."
            : "메일 이동 중 오류가 발생했습니다.",
      });
      return false;
    } finally {
      setPendingMoveKey((current) => (current === moveKey ? null : current));
    }
  };

  const beginMessageDrag =
    (messageId: number) => (event: ReactDragEvent<HTMLDivElement>) => {
      if (shouldPreventMailRowOpen(event.target)) {
        event.preventDefault();
        return;
      }

      const nextDraggedIds =
        selectedIds.includes(messageId) && selectedIds.length > 0 ? [...selectedIds] : [messageId];

      if (!(selectedIds.includes(messageId) && selectedIds.length === nextDraggedIds.length)) {
        setSelectionState({ ids: nextDraggedIds, scope: interactionScopeKey });
      }

      event.dataTransfer.effectAllowed = "move";
      event.dataTransfer.setData("text/plain", nextDraggedIds.join(","));
      clearMessageDragPreview();

      const row = messageRowRefs.current.get(messageId);

      if (row) {
        const dragPreview = row.cloneNode(true);

        if (dragPreview instanceof HTMLDivElement) {
          const { width, height } = row.getBoundingClientRect();
          dragPreview.style.position = "fixed";
          dragPreview.style.top = "-9999px";
          dragPreview.style.left = "-9999px";
          dragPreview.style.width = `${Math.ceil(width)}px`;
          dragPreview.style.height = `${Math.ceil(height)}px`;
          dragPreview.style.pointerEvents = "none";
          dragPreview.style.margin = "0";
          dragPreview.style.zIndex = "9999";
          dragPreview.style.overflow = "visible";
          dragPreview.style.borderRadius = "0";
          dragPreview.style.opacity = "0.98";
          dragPreview.style.background = "#edf4ff";
          dragPreview.style.boxShadow = "0 16px 34px rgba(25, 38, 72, 0.14)";

          const countBadge = document.createElement("div");
          countBadge.style.position = "absolute";
          countBadge.style.right = "12px";
          countBadge.style.bottom = "-14px";
          countBadge.style.display = "flex";
          countBadge.style.alignItems = "flex-end";
          countBadge.style.gap = "6px";

          const countPill = document.createElement("span");
          countPill.textContent = String(nextDraggedIds.length);
          countPill.style.display = "inline-flex";
          countPill.style.alignItems = "center";
          countPill.style.justifyContent = "center";
          countPill.style.minWidth = "38px";
          countPill.style.height = "28px";
          countPill.style.padding = "0 10px";
          countPill.style.borderRadius = "9px";
          countPill.style.background = "#ffffff";
          countPill.style.color = "#1f2c45";
          countPill.style.font = "600 14px var(--font-pretendard), sans-serif";
          countPill.style.boxShadow = "0 10px 22px rgba(25, 38, 72, 0.16)";

          const pointerBubble = document.createElement("span");
          pointerBubble.textContent = "↘";
          pointerBubble.style.display = "inline-flex";
          pointerBubble.style.alignItems = "center";
          pointerBubble.style.justifyContent = "center";
          pointerBubble.style.width = "18px";
          pointerBubble.style.height = "18px";
          pointerBubble.style.borderRadius = "999px";
          pointerBubble.style.background = "#19b25f";
          pointerBubble.style.color = "#ffffff";
          pointerBubble.style.font = "700 11px system-ui, sans-serif";
          pointerBubble.style.boxShadow = "0 8px 18px rgba(25, 178, 95, 0.28)";

          countBadge.appendChild(countPill);
          countBadge.appendChild(pointerBubble);
          dragPreview.appendChild(countBadge);
          document.body.appendChild(dragPreview);
          messageDragPreviewRef.current = dragPreview;
          event.dataTransfer.setDragImage(dragPreview, 28, Math.max(16, Math.floor(height / 2)));
        }
      }

      setDraggingMessageIds(nextDraggedIds);
      setDragOverMessageFolder(null);
    };

  const beginFolderDrag =
    (folderId: number) => (event: ReactDragEvent<HTMLButtonElement>) => {
      event.stopPropagation();
      event.dataTransfer.effectAllowed = "move";
      event.dataTransfer.setData("text/plain", String(folderId));
      clearFolderDragPreview();

      const folderRow = folderRowRefs.current.get(folderId);

      if (folderRow) {
        const dragPreview = folderRow.cloneNode(true);

        if (dragPreview instanceof HTMLDivElement) {
          const { width, height } = folderRow.getBoundingClientRect();
          dragPreview.style.position = "fixed";
          dragPreview.style.top = "-9999px";
          dragPreview.style.left = "-9999px";
          dragPreview.style.width = `${Math.ceil(width)}px`;
          dragPreview.style.height = `${Math.ceil(height)}px`;
          dragPreview.style.pointerEvents = "none";
          dragPreview.style.margin = "0";
          dragPreview.style.zIndex = "9999";
          dragPreview.style.opacity = "0.98";
          dragPreview.style.transform = "rotate(-1.25deg) scale(1.02)";
          dragPreview.style.borderRadius = "14px";
          dragPreview.style.background = "#ffffff";
          dragPreview.style.boxShadow = "0 22px 48px rgba(25, 38, 72, 0.18)";
          document.body.appendChild(dragPreview);
          folderDragPreviewRef.current = dragPreview;
          event.dataTransfer.setDragImage(dragPreview, 28, Math.max(18, Math.floor(height / 2)));
        }
      }

      folderDragStartOrderRef.current = [...folderOrderRef.current];
      setDraggingFolderId(folderId);
      setDragOverFolderId(folderId);
    };

  const handleFolderDragOver =
    (targetFolderId: number) => (event: ReactDragEvent<HTMLDivElement>) => {
      if (draggingFolderId === null) {
        return;
      }

      event.preventDefault();
      event.dataTransfer.dropEffect = "move";

      if (draggingFolderId === targetFolderId) {
        setDragOverFolderId(targetFolderId);
        return;
      }

      setDragOverFolderId(targetFolderId);
      setFolderOrderState(() => {
        const next = [...folderOrderRef.current];
        const sourceIndex = next.indexOf(draggingFolderId);
        const targetIndex = next.indexOf(targetFolderId);

        if (sourceIndex === -1 || targetIndex === -1 || sourceIndex === targetIndex) {
          return next;
        }

        const [moved] = next.splice(sourceIndex, 1);
        next.splice(targetIndex, 0, moved);
        return next;
      });
    };

  const finishFolderDrag = () => {
    if (draggingFolderId === null) {
      return;
    }

    const previousOrder = folderDragStartOrderRef.current;
    const nextOrder = [...folderOrderRef.current];
    clearFolderDragPreview();
    setDraggingFolderId(null);
    setDragOverFolderId(null);

    if (!sameNumberArray(previousOrder, nextOrder)) {
      void saveFolderOrder(nextOrder);
    }
  };

  const runSidebarFolderAction = async (
    item: SidebarFolderNavItem,
    action: SidebarFolderAction,
  ) => {
    if (sidebarFolderActionState.folderId === item.id && sidebarFolderActionState.action === action) {
      return;
    }

    setSidebarFolderMenuState({ folderId: null, scope: interactionScopeKey });
    setSidebarFolderActionState({ folderId: item.id, action });

    try {
      const response = await fetch("/api/mailbox/folder-actions", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          action,
          folder: item.systemName,
          label: item.label,
        }),
      });

      if (response.status === 401) {
        window.location.assign("/login");
        return;
      }

      const payload = (await response.json()) as {
        error?: string;
        notice?: MailNotice | null;
        ok?: boolean;
      };

      if (!response.ok || !payload.ok) {
        throw new Error(payload.notice?.message ?? payload.error ?? "folder-action-failed");
      }

      setLocalNotice(
        payload.notice ?? {
          tone: "success",
          message: "폴더 작업을 완료했습니다.",
        },
      );
      setSelectionState({ ids: [], scope: interactionScopeKey });
      setSenderMenuState({ messageId: null, scope: interactionScopeKey });
      setMoveMenuState({ open: false, scope: interactionScopeKey });

      if (action === "delete" && currentMailboxFolder === item.systemName) {
        router.push(
          folderHref("inbox", {
            page: 1,
            pageSize: resolvedPageSize,
            searchField: resolvedSearchField,
            searchQuery: resolvedSearchQuery,
            sortOrder: currentSortOrder,
            tab: "all",
          }),
          { scroll: false },
        );
        return;
      }

      await fetchMailboxData({ preserveSelection: false, silent: true });
    } catch (error) {
      setLocalNotice({
        tone: "error",
        message:
          error instanceof Error && error.message
            ? error.message
            : "폴더 작업 중 오류가 발생했습니다.",
      });
    } finally {
      setSidebarFolderActionState({ folderId: null, action: null });
    }
  };

  const renderSidebarFolderItem = (item: SidebarFolderNavItem, options?: { draggable?: boolean }) => {
    const active = showMailboxSidebarActiveState && currentMailboxFolder === item.systemName;
    const dragging = draggingFolderId === item.id;
    const draggable = Boolean(options?.draggable);
    const messageDropAllowed =
      draggingFolderId === null && canDropMessagesToFolder(item.systemName);
    const messageDropActive = messageDropAllowed && dragOverMessageFolder === item.systemName;
    const menuOpen = sidebarFolderMenuId === item.id;
    const rowTone = active
      ? "bg-[#eaf2ff] text-[#2f6df6] shadow-[inset_0_0_0_1px_rgba(47,109,246,0.04)]"
      : dragging
        ? "bg-white text-[#31415d]"
        : "text-[#33445f] hover:bg-[#f4f6fa] hover:text-[#2f6df6]";
    const itemNavigationHref = mailConfigured ? item.href : setupHref("domain");
    const itemNavigationIntent = mailConfigured ? "mailbox" : "setup";

    return (
      <div
        key={item.id}
        ref={(node) => {
          if (node) {
            folderRowRefs.current.set(item.id, node);
          } else {
            folderRowRefs.current.delete(item.id);
          }
        }}
        onDragOver={(event) => {
          if (draggingFolderId !== null && draggable) {
            handleFolderDragOver(item.id)(event);
            return;
          }

          if (!messageDropAllowed) {
            return;
          }

          event.preventDefault();
          event.dataTransfer.dropEffect = "move";

          if (dragOverMessageFolder !== item.systemName) {
            setDragOverMessageFolder(item.systemName);
          }
        }}
        onDragLeave={(event) => {
          if (!messageDropAllowed || dragOverMessageFolder !== item.systemName) {
            return;
          }

          const currentTarget = event.currentTarget;
          const { clientX, clientY } = event;
          const nextTarget = event.relatedTarget;

          if (nextTarget instanceof Node && event.currentTarget.contains(nextTarget)) {
            return;
          }

          window.requestAnimationFrame(() => {
            const hoveredElement = document.elementFromPoint(clientX, clientY);

            if (hoveredElement instanceof Node && currentTarget.contains(hoveredElement)) {
              return;
            }

            setDragOverMessageFolder((current) =>
              current === item.systemName ? null : current,
            );
          });
        }}
        onDrop={(event) => {
          if (draggingFolderId !== null && draggable) {
            event.preventDefault();
            finishFolderDrag();
            return;
          }

          if (!messageDropAllowed || draggingMessageIds === null) {
            return;
          }

          event.preventDefault();
          event.stopPropagation();
          const draggedIds = [...draggingMessageIds];
          finishMessageDrag();
          void moveMessagesByClient(draggedIds, item.systemName);
        }}
        className={`group flex items-center gap-1 rounded-[10px] transition-all duration-150 will-change-transform ${
          draggable && dragOverFolderId === item.id && draggingFolderId !== item.id
            ? "bg-[#f4f8ff] shadow-[inset_0_0_0_1px_rgba(47,109,246,0.12)]"
            : ""
        } ${
          messageDropActive
            ? "bg-[#f7fbff] shadow-[inset_0_0_0_2px_rgba(47,109,246,0.72),0_10px_24px_rgba(47,109,246,0.12)]"
            : ""
        } ${dragging ? "scale-[1.01] bg-white opacity-80 shadow-[0_18px_38px_rgba(25,38,72,0.12)]" : ""}`}
      >
        {draggable ? (
          <button
            type="button"
            draggable
            aria-label={`${item.label} 순서 변경`}
            onDragStart={beginFolderDrag(item.id)}
            onDragEnd={finishFolderDrag}
            className="inline-flex h-9 w-7 shrink-0 cursor-grab items-center justify-center rounded-[10px] text-[#9ca9bc] transition-colors hover:bg-[#f3f6fb] hover:text-[#61738f] active:cursor-grabbing"
          >
            <GripIcon className="h-[15px] w-[15px]" />
          </button>
        ) : null}

        <div
          className={`relative flex min-w-0 flex-1 cursor-pointer items-center rounded-[10px] px-2 py-2 text-[14px] transition-all duration-200 ${rowTone}`}
          data-sidebar-folder-menu-root="true"
          onClick={(event) => {
            if (shouldBypassClientNavigation(event)) {
              return;
            }

            navigateWithinMailbox(itemNavigationHref, { intent: itemNavigationIntent });
          }}
        >
          <Link
            href={itemNavigationHref}
            prefetch={false}
            scroll={false}
            onClick={(event) =>
              handleMailboxNavigationLinkClick(event, itemNavigationHref, {
                intent: itemNavigationIntent,
              })
            }
            className={`flex min-w-0 flex-1 items-center ${SIDEBAR_MENU_TEXT_GAP_CLASS}`}
          >
            {iconForNav(item.icon, SIDEBAR_MENU_ICON_CLASS)}
            <span className="flex min-w-0 items-center gap-1.5">
              <span className={`truncate ${active ? "font-semibold" : "font-medium"}`}>{item.label}</span>
              <span
                className={`shrink-0 text-[12px] ${
                  active ? "font-semibold text-[#2f6df6]" : "text-[#70829f]"
                }`}
              >
                {compactCount(item.count)}
              </span>
            </span>
          </Link>

          <div className="ml-1 flex shrink-0 items-center">
            <button
              type="button"
              aria-expanded={menuOpen}
              aria-haspopup="menu"
              onClick={(event) => {
                event.stopPropagation();
                setSidebarFolderMenuState((current) =>
                  current.scope === interactionScopeKey && current.folderId === item.id
                    ? { folderId: null, scope: interactionScopeKey }
                    : { folderId: item.id, scope: interactionScopeKey },
                );
              }}
              className={`inline-flex h-6 w-6 cursor-pointer items-center justify-center rounded-[7px] text-[#8a96ab] transition-all duration-150 ${
                menuOpen
                  ? "bg-white text-[#556885]"
                  : "pointer-events-none opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:opacity-100 hover:bg-white hover:text-[#2f6df6]"
              }`}
            >
              <MoreIcon className="h-[14px] w-[14px]" />
            </button>
          </div>
        </div>
      </div>
    );
  };

  const renderSidebarFolderMenuPortal = () => {
    if (!sidebarFolderMenuItem || !sidebarFolderMenuPosition || typeof document === "undefined") {
      return null;
    }

    const actionPending = sidebarFolderActionState.folderId === sidebarFolderMenuItem.id;
    const sidebarFolderMenuItemClass = (disabled = false) =>
      popoverMenuItemClass({ disabled });

    return createPortal(
      <div
        data-sidebar-folder-menu-root="true"
        className={`absolute z-[120] w-max min-w-[188px] -translate-y-1/2 ${popoverMenuSurfaceClass()}`}
        style={{
          top: `${sidebarFolderMenuPosition.top}px`,
          left: `${sidebarFolderMenuPosition.left}px`,
        }}
      >
        <button
          type="button"
          onClick={() => void runSidebarFolderAction(sidebarFolderMenuItem, "mark-read")}
          disabled={actionPending}
          className={sidebarFolderMenuItemClass(actionPending)}
        >
          모두 읽음 표시
        </button>
        <button
          type="button"
          onClick={() => void runSidebarFolderAction(sidebarFolderMenuItem, "clear")}
          disabled={actionPending}
          className={sidebarFolderMenuItemClass(actionPending)}
        >
          비우기
        </button>
        <button
          type="button"
          onClick={() => void runSidebarFolderAction(sidebarFolderMenuItem, "backup")}
          disabled={actionPending}
          className={sidebarFolderMenuItemClass(actionPending)}
        >
          백업하기
        </button>
        {sidebarFolderMenuItem.kind === "custom" ? (
          <>
            <div className="my-2 border-t border-[#edf2fb]" />
            <button
              type="button"
              onClick={() => openSidebarFolderRenameEditor(sidebarFolderMenuItem)}
              disabled={actionPending || sidebarFolderEditorPending}
              className={sidebarFolderMenuItemClass(
                actionPending || sidebarFolderEditorPending,
              )}
            >
              이름 바꾸기
            </button>
            <button
              type="button"
              onClick={() =>
                openSidebarFolderCreateEditor({
                  insertAfterSystemName: sidebarFolderMenuItem.systemName,
                })
              }
              disabled={actionPending || sidebarFolderEditorPending}
              className={sidebarFolderMenuItemClass(
                actionPending || sidebarFolderEditorPending,
              )}
            >
              하위 메일함 추가
            </button>
            <button
              type="button"
              onClick={() => void runSidebarFolderAction(sidebarFolderMenuItem, "delete")}
              disabled={actionPending}
              className={sidebarFolderMenuItemClass(actionPending)}
            >
              메일함 삭제
            </button>
          </>
        ) : null}
      </div>,
      document.body,
    );
  };

  const openSidebarFolderCreateEditor = (options?: {
    insertAfterSystemName?: string | null;
    insertAtTop?: boolean;
  }) => {
    setSidebarFolderMenuState({ folderId: null, scope: interactionScopeKey });
    setPersonalFoldersOpen(true);
    setSidebarFolderEditorState({
      errorMessage: undefined,
      insertAfterSystemName: options?.insertAfterSystemName ?? null,
      insertAtTop: options?.insertAtTop ?? false,
      mode: "create",
      value: "새 메일함",
    });
  };

  const openSidebarFolderRenameEditor = (item: SidebarFolderNavItem) => {
    setSidebarFolderMenuState({ folderId: null, scope: interactionScopeKey });
    setPersonalFoldersOpen(true);
    setSidebarFolderEditorState({
      errorMessage: undefined,
      folderId: item.id,
      mode: "rename",
      systemName: item.systemName,
      value: item.label,
    });
  };

  const closeSidebarFolderEditor = () => {
    if (sidebarFolderEditorPending) {
      return;
    }

    setSidebarFolderEditorState(null);
  };

  const submitSidebarFolderEditor = async (
    editorStateSnapshot: SidebarFolderInlineEditorState | null,
  ) => {
    if (!editorStateSnapshot || sidebarFolderEditorPending) {
      return;
    }

    const nextName = editorStateSnapshot.value.trim();

    if (!nextName) {
      setSidebarFolderEditorState((current) =>
        current
          ? {
              ...current,
              errorMessage: "메일함 이름을 입력해주세요.",
            }
          : current,
      );
      window.requestAnimationFrame(() => {
        sidebarFolderEditorInputRef.current?.focus();
        sidebarFolderEditorInputRef.current?.select();
      });
      return;
    }

    setSidebarFolderEditorPending(true);

    try {
      const response = await fetch("/api/mailbox/folder-actions", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(
          editorStateSnapshot.mode === "create"
            ? {
                action: "create",
                insertAfterFolder: editorStateSnapshot.insertAfterSystemName,
                insertAtTop: editorStateSnapshot.insertAtTop,
                name: nextName,
              }
            : {
                action: "rename",
                folder: editorStateSnapshot.systemName,
                label: nextName,
                name: nextName,
              },
        ),
      });

      if (response.status === 401) {
        window.location.assign("/login");
        return;
      }

      const payload = (await response.json()) as {
        error?: string;
        notice?: MailNotice | null;
        ok?: boolean;
      };

      if (!response.ok || !payload.ok) {
        const failureMessage =
          payload.notice?.message ??
          (payload.error === "folder-name-exists"
            ? "같은 이름의 메일함이 이미 있습니다. 다른 이름을 입력해주세요."
            : payload.error === "folder-name-required"
              ? "메일함 이름을 입력해주세요."
              : editorStateSnapshot.mode === "create"
                ? "메일함 생성 중 오류가 발생했습니다."
                : "메일함 이름 변경 중 오류가 발생했습니다.");

        setSidebarFolderEditorState((current) =>
          current
            ? {
                ...current,
                errorMessage: failureMessage,
              }
            : current,
        );
        setLocalNotice(payload.notice ?? { tone: "error", message: failureMessage });
        window.requestAnimationFrame(() => {
          sidebarFolderEditorInputRef.current?.focus();
          sidebarFolderEditorInputRef.current?.select();
        });
        return;
      }

      setLocalNotice(
        payload.notice ?? {
          message:
            editorStateSnapshot.mode === "create"
              ? "메일함을 만들었습니다."
              : "메일함 이름을 변경했습니다.",
          tone: "success",
        },
      );
      setSidebarFolderEditorState(null);
      await fetchMailboxData({ preserveSelection: false, silent: true });
    } catch {
      setSidebarFolderEditorState((current) =>
        current
          ? {
              ...current,
              errorMessage:
                editorStateSnapshot.mode === "create"
                  ? "메일함 생성 중 오류가 발생했습니다."
                  : "메일함 이름 변경 중 오류가 발생했습니다.",
            }
          : current,
      );
      setLocalNotice({
        tone: "error",
        message:
          editorStateSnapshot.mode === "create"
            ? "메일함 생성 중 오류가 발생했습니다."
            : "메일함 이름 변경 중 오류가 발생했습니다.",
      });
      window.requestAnimationFrame(() => {
        sidebarFolderEditorInputRef.current?.focus();
        sidebarFolderEditorInputRef.current?.select();
      });
    } finally {
      setSidebarFolderEditorPending(false);
    }
  };

  const handleSidebarFolderEditorSubmit = (event: ReactFormEvent<HTMLFormElement>) => {
    event.preventDefault();

    if (sidebarFolderEditorState) {
      void submitSidebarFolderEditor(sidebarFolderEditorState);
    }
  };

  const renderSidebarFolderInlineEditor = () => {
    if (!sidebarFolderEditorState) {
      return null;
    }

    return (
      <div className="group flex items-center gap-1 rounded-[10px]">
        <div className="h-9 w-7 shrink-0" />
        <form
          onSubmit={handleSidebarFolderEditorSubmit}
          className="relative flex min-w-0 flex-1 flex-col rounded-[10px] bg-[#eaf2ff] px-2 py-2 text-[14px] text-[#2f6df6] shadow-[inset_0_0_0_1px_rgba(47,109,246,0.14)]"
        >
          <div className="flex min-w-0 items-center gap-[5px]">
            <FolderIcon className={SIDEBAR_MENU_ICON_CLASS} />
            <input
              ref={sidebarFolderEditorInputRef}
              type="text"
              value={sidebarFolderEditorState.value}
              disabled={sidebarFolderEditorPending}
              onChange={(event) =>
                setSidebarFolderEditorState((current) =>
                  current
                    ? {
                        ...current,
                        errorMessage: undefined,
                        value: event.target.value,
                      }
                    : current,
                )
              }
              onBlur={(event) => event.currentTarget.form?.requestSubmit()}
              onKeyDown={(event) => {
                if (event.key === "Escape") {
                  event.preventDefault();
                  closeSidebarFolderEditor();
                }
              }}
              className={`h-[28px] min-w-0 flex-1 rounded-[6px] bg-white px-2 text-[14px] font-medium outline-none placeholder:text-[#83a1e4] ${
                sidebarFolderEditorState.errorMessage
                  ? "border border-[#f08b8b] text-[#b42318]"
                  : "border border-[#5f93ff] text-[#2f6df6]"
              }`}
            />
          </div>
          {sidebarFolderEditorState.errorMessage ? (
            <p className="mt-1.5 pl-6 text-[12px] leading-5 text-[#c23333]">
              {sidebarFolderEditorState.errorMessage}
            </p>
          ) : null}
        </form>
      </div>
    );
  };

  useEffect(() => {
    if (!sidebarFolderEditorState) {
      return;
    }

    const animationFrameId = window.requestAnimationFrame(() => {
      sidebarFolderEditorInputRef.current?.focus();
      sidebarFolderEditorInputRef.current?.select();
    });

    return () => {
      window.cancelAnimationFrame(animationFrameId);
    };
  }, [sidebarFolderEditorState]);

  useEffect(
    () => () => {
      clearFolderDragPreview();
      clearMessageDragPreview();
    },
    [],
  );

  const beginResize =
    (panel: LayoutResizePanel) => (event: ReactPointerEvent<HTMLButtonElement>) => {
      const layoutRoot =
        panel === "list-height"
          ? event.currentTarget.closest("[data-mail-vertical-split-root='true']")
          : event.currentTarget.closest("[data-mail-layout-root='true']");

      if (!(layoutRoot instanceof HTMLDivElement)) {
        return;
      }

      const rect = layoutRoot.getBoundingClientRect();

      event.preventDefault();
      setDragState({
        containerHeight: rect.height,
        containerWidth: rect.width,
        isXlLayout: window.matchMedia("(min-width: 1280px)").matches && !isStandaloneContentPanel,
        panel,
        startListHeight: layoutState.listHeight,
        startListWidth: layoutState.listWidth,
        startSidebarWidth: layoutState.sidebarWidth,
        startX: event.clientX,
        startY: event.clientY,
      });
    };

  const toggleSelection = (messageId: number) => {
    setMoveMenuState({ open: false, scope: interactionScopeKey });
    setSelectionState((prev) => {
      const baseIds = prev.scope === interactionScopeKey ? prev.ids : [];
      return {
        ids: baseIds.includes(messageId)
          ? baseIds.filter((id) => id !== messageId)
          : [...baseIds, messageId],
        scope: interactionScopeKey,
      };
    });
  };

  const toggleSelectAll = () => {
    setMoveMenuState({ open: false, scope: interactionScopeKey });

    if (allVisibleSelected) {
      setSelectionState({ ids: [], scope: interactionScopeKey });
      return;
    }

    setSelectionState({
      ids: filteredMessages.map((message) => message.id),
      scope: interactionScopeKey,
    });
  };

  const previewLines = previewMessage?.bodyText
    .split(/\r?\n/)
    .map((line) => line.trimEnd())
    .filter((line, index, array) => !(line === "" && array[index - 1] === ""))
    .slice(0, 14);
  const previewHtml = previewMessage?.bodyHtmlDisplay?.trim() ?? "";
  const detailMenuOpen =
    detailMenuState.open && detailMenuState.scope === detailPanelScopeKey && detailPanelScopeKey !== "";
  const rawSourceModalOpen =
    rawSourceModalState.open &&
    rawSourceModalState.scope === detailPanelScopeKey &&
    detailPanelScopeKey !== "";
  const showMailboxSidebarActiveState = isMailboxPanel && currentView !== "compose";

  useEffect(() => {
    if (!detailMenuOpen) {
      return;
    }

    const handlePointerDown = (event: MouseEvent) => {
      const target = event.target;

      if (!(target instanceof HTMLElement)) {
        return;
      }

      if (!target.closest("[data-detail-menu-root='true']")) {
        setDetailMenuState({ open: false, scope: detailPanelScopeKey });
      }
    };

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setDetailMenuState({ open: false, scope: detailPanelScopeKey });
      }
    };

    document.addEventListener("mousedown", handlePointerDown);
    document.addEventListener("keydown", handleKeyDown);

    return () => {
      document.removeEventListener("mousedown", handlePointerDown);
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [detailMenuOpen, detailPanelScopeKey]);

  useEffect(() => {
    if (!attachmentPreviewState) {
      return;
    }

    if (
      !detailPanelScopeKey ||
      attachmentPreviewState.scope !== detailPanelScopeKey ||
      attachmentPreviewItems.length === 0
    ) {
      setAttachmentPreviewState(null);
      return;
    }

    const maxIndex = attachmentPreviewItems.length - 1;

    if (attachmentPreviewState.currentIndex > maxIndex) {
      setAttachmentPreviewState((current) =>
        current
          ? {
              ...current,
              currentIndex: maxIndex,
            }
          : current,
      );
    }
  }, [attachmentPreviewItems.length, attachmentPreviewState, detailPanelScopeKey]);

  useEffect(() => {
    if (!attachmentPreviewModalOpen || !attachmentPreviewState) {
      return;
    }

    const previousOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key === "Escape") {
        setAttachmentPreviewState(null);
        return;
      }

      if (event.key === "ArrowLeft") {
        setAttachmentPreviewState((current) =>
          current && current.currentIndex > 0
            ? { ...current, currentIndex: current.currentIndex - 1 }
            : current,
        );
        return;
      }

      if (event.key === "ArrowRight") {
        setAttachmentPreviewState((current) =>
          current && current.currentIndex < attachmentPreviewItems.length - 1
            ? { ...current, currentIndex: current.currentIndex + 1 }
            : current,
        );
      }
    };

    document.addEventListener("keydown", handleKeyDown);

    return () => {
      document.body.style.overflow = previousOverflow;
      document.removeEventListener("keydown", handleKeyDown);
    };
  }, [attachmentPreviewItems.length, attachmentPreviewModalOpen, attachmentPreviewState]);

  const openMessage = (messageId: number) => {
    if (detailOpen && activeMessageId === messageId) {
      return;
    }

    setDismissedDetailScopeKey(null);
    setToolbarMenuKind(null);
    setMoveMenuState({ open: false, scope: interactionScopeKey });
    setSelectionState({
      ids: layoutStateRef.current.viewMode === "list-only" ? [] : [messageId],
      scope: interactionScopeKey,
    });
    setPendingMessageNavigationId(messageId);
    startMessageNavigationTransition(() => {
      router.push(
        messageHref(currentMailboxFolder, messageId, detailView, {
          page: resolvedCurrentPage,
          pageSize: resolvedPageSize,
          searchField: resolvedSearchField,
          searchQuery: resolvedSearchQuery,
          sortOrder: layoutStateRef.current.sortOrder,
          tab: resolvedMessageFilter,
        }),
        { scroll: false },
      );
    });
  };

  const openMessagePopup = (messageId: number) => {
    if (typeof window === "undefined") {
      return;
    }

    const popupUrl = messageBodyHref(messageId);

    const popupWidth = Math.min(1280, Math.max(960, Math.floor(window.innerWidth * 0.82)));
    const popupHeight = Math.min(920, Math.max(720, Math.floor(window.innerHeight * 0.88)));
    const popupLeft = Math.max(0, Math.floor(window.screenX + (window.outerWidth - popupWidth) / 2));
    const popupTop = Math.max(0, Math.floor(window.screenY + (window.outerHeight - popupHeight) / 2));
    const popupFeatures = [
      `width=${popupWidth}`,
      `height=${popupHeight}`,
      `left=${popupLeft}`,
      `top=${popupTop}`,
      "popup=yes",
      "resizable=yes",
      "scrollbars=yes",
    ].join(",");
    const popup = window.open(
      popupUrl,
      `official-mail-message-${messageId}`,
      popupFeatures,
    );

    popup?.focus();
  };

  const openAttachmentPreview = (messageId: number, attachment: MailMessageAttachment) => {
    if (!detailPanelScopeKey) {
      return;
    }

    const collection = isImageAttachmentPreview(attachment) ? "images" : "previewable";
    const items = collection === "images" ? imagePreviewableAttachments : previewableAttachments;
    const currentIndex = items.findIndex(
      (item) =>
        item.index === attachment.index &&
        item.filename === attachment.filename &&
        item.contentType === attachment.contentType,
    );

    if (currentIndex < 0) {
      return;
    }

    setAttachmentPreviewState({
      collection,
      currentIndex,
      messageId,
      scope: detailPanelScopeKey,
    });
  };

  const downloadAttachment = (messageId: number, attachment: MailMessageAttachment) => {
    if (typeof window === "undefined") {
      return;
    }

    const downloadUrl = `/api/mailbox/attachment?message=${messageId}&index=${attachment.index}&mode=download`;
    const anchor = document.createElement("a");
    anchor.href = downloadUrl;
    anchor.rel = "noopener";
    anchor.style.display = "none";
    document.body.appendChild(anchor);
    anchor.click();
    window.setTimeout(() => anchor.remove(), 0);
  };

  const downloadAllAttachments = (messageId: number, attachments: MailMessageAttachment[]) => {
    if (typeof window === "undefined") {
      return;
    }

    attachments.forEach((attachment, index) => {
      window.setTimeout(() => {
        downloadAttachment(messageId, attachment);
      }, index * 140);
    });
  };

  useEffect(() => {
    if (!dragState) {
      return;
    }

    const handlePointerMove = (event: PointerEvent) => {
      if (dragState.panel === "list-height") {
        const delta = event.clientY - dragState.startY;

        setLayoutState((prev) => {
          const listHeight = clampListHeight({
            containerHeight: dragState.containerHeight,
            value: dragState.startListHeight + delta,
          });

          if (prev.listHeight === listHeight) {
            return prev;
          }

          return { ...prev, listHeight };
        });
        return;
      }

      const delta = event.clientX - dragState.startX;

      setLayoutState((prev) => {
        if (dragState.panel === "sidebar") {
          const sidebarWidth = clampSidebarWidth({
            containerWidth: dragState.containerWidth,
            isSetupPanel: isStandaloneContentPanel,
            isXlLayout: dragState.isXlLayout,
            value: dragState.startSidebarWidth + delta,
          });
          const listWidth =
            !isStandaloneContentPanel && dragState.isXlLayout
              ? clampListWidth({
                  containerWidth: dragState.containerWidth,
                  sidebarWidth,
                  value: dragState.startListWidth,
                })
              : prev.listWidth;

          if (
            prev.sidebarWidth === sidebarWidth &&
            prev.listWidth === listWidth
          ) {
            return prev;
          }

          return { ...prev, sidebarWidth, listWidth };
        }

        const listWidth = clampListWidth({
          containerWidth: dragState.containerWidth,
          sidebarWidth: prev.sidebarWidth,
          value: dragState.startListWidth + delta,
        });

        if (prev.listWidth === listWidth) {
          return prev;
        }

        return { ...prev, listWidth };
      });
    };

    const finishDrag = () => {
      const nextLayout = normalizeMailLayoutPreferences(layoutStateRef.current);
      const savedLayout = savedLayoutRef.current;

      if (
        nextLayout.sidebarWidth !== savedLayout.sidebarWidth ||
        nextLayout.listWidth !== savedLayout.listWidth ||
        nextLayout.listHeight !== savedLayout.listHeight
      ) {
        void saveLayoutPreferences(nextLayout);
      }

      setDragState(null);
    };

    const previousCursor = document.body.style.cursor;
    const previousUserSelect = document.body.style.userSelect;

    // eslint-disable-next-line react-hooks/immutability
    document.body.style.cursor = dragState.panel === "list-height" ? "row-resize" : "col-resize";
    // eslint-disable-next-line react-hooks/immutability
    document.body.style.userSelect = "none";
    window.addEventListener("pointermove", handlePointerMove);
    window.addEventListener("pointerup", finishDrag);
    window.addEventListener("pointercancel", finishDrag);

    return () => {
      document.body.style.cursor = previousCursor;
      document.body.style.userSelect = previousUserSelect;
      window.removeEventListener("pointermove", handlePointerMove);
      window.removeEventListener("pointerup", finishDrag);
      window.removeEventListener("pointercancel", finishDrag);
    };
  }, [dragState, isStandaloneContentPanel]);

  const renderMoveMenuPopover = (messageIdsValue: string) => {
    const inputId = `move-folder-name-${messageIdsValue.replace(/[^a-z0-9]+/gi, "-") || "default"}`;

    return (
      <form
        action={moveMailboxMessagesAction}
        className="absolute left-0 top-[calc(100%+10px)] z-30 w-[280px] overflow-hidden rounded-[18px] border border-[#e4ebf8] bg-white p-3 shadow-[0_20px_44px_rgba(25,38,72,0.12)]"
      >
        <input type="hidden" name="folder" value={currentMailboxFolder} />
        <input type="hidden" name="detail" value={detailView} />
        <input type="hidden" name="page" value={resolvedCurrentPage} />
        <input type="hidden" name="pageSize" value={resolvedPageSize} />
        <input type="hidden" name="tab" value={resolvedMessageFilter} />
        <input type="hidden" name="field" value={resolvedSearchField} />
        <input type="hidden" name="q" value={resolvedSearchQuery} />
        <input type="hidden" name="messageIds" value={messageIdsValue} />
        <input type="hidden" name="targetFolder" value={resolvedMoveTargetFolder} />
        <input type="hidden" name="newFolderName" value={moveNewFolderName.trim()} />
        <MoveMenuFieldset>
          <div className="space-y-2">
            {moveFolderOptionGroups.map((group, groupIndex) => (
              <div
                key={group.key}
                className={groupIndex === 0 ? "space-y-1.5" : "space-y-1.5 border-t border-[#edf2f8] pt-2"}
              >
                {group.items.map((item) => {
                  const selected = resolvedMoveTargetFolder === item.systemName;

                  return (
                    <button
                      key={item.systemName}
                      type="button"
                      onClick={() => setMoveTargetFolder(item.systemName)}
                      className={`flex w-full cursor-pointer items-center rounded-[12px] px-3 py-2 text-left text-[12px] font-medium transition-colors ${
                        selected
                          ? "border border-[#dbe6ff] bg-[#edf4ff] font-semibold text-[#2f6df6]"
                          : "border border-transparent text-[#344767] hover:bg-[#f6f9ff] hover:text-[#2f6df6]"
                      }`}
                    >
                      <span className="flex min-w-0 items-center gap-1.5">
                        <span className="truncate">{item.label}</span>
                        <span className={`shrink-0 text-[12px] ${selected ? "text-[#2f6df6]" : "text-[#8c98ad]"}`}>
                          {compactCount(item.count)}
                        </span>
                      </span>
                    </button>
                  );
                })}
              </div>
            ))}
          </div>

          <div className="mt-3 rounded-[14px] border border-[#e8eef9] bg-[#fbfcff] p-3">
            <div className="flex items-center gap-2">
              <label htmlFor={inputId} className="sr-only">
                이동할 메일함 직접 입력
              </label>
              <input
                id={inputId}
                type="text"
                value={moveNewFolderName}
                onChange={(event) => setMoveNewFolderName(event.target.value)}
                placeholder="새 메일함"
                className="h-10 min-w-0 flex-1 rounded-[12px] border border-[#dbe5f7] bg-white px-3 text-[13px] text-[#243555] outline-none transition-colors placeholder:text-[#97a7c2] focus:border-[#bcd1ff]"
              />
              <button
                type="button"
                onClick={() => {
                  const nextFolderName = moveNewFolderName.trim();

                  if (!nextFolderName) {
                    setLocalNotice({
                      tone: "error",
                      message: "새 메일함 이름을 입력해주세요.",
                    });
                    return;
                  }

                  setMoveTargetFolder("__new__");
                  setMoveNewFolderName(nextFolderName);
                }}
                className="om-btn-secondary h-10 shrink-0 rounded-[12px] px-3 text-[12px] text-[#344767]"
              >
                추가
              </button>
            </div>
            {resolvedMoveTargetFolder === "__new__" && moveNewFolderName.trim() ? (
              <p className="mt-2 text-[12px] text-[#5f7396]">
                새 메일함 <span className="font-semibold text-[#2f6df6]">{moveNewFolderName.trim()}</span>
                으로 이동합니다.
              </p>
            ) : null}
          </div>

          <div className="mt-3 flex items-center gap-2">
            <MoveMenuSubmitButton label="이동" pendingLabel="이동 중..." variant="primary" />
            <MoveMenuSubmitButton
              label="계속 이동"
              pendingLabel="처리 중..."
              variant="secondary"
              name="continueMove"
              value="1"
            />
          </div>
        </MoveMenuFieldset>
        <MoveMenuPendingOverlay />
      </form>
    );
  };

  const renderMessageDetailContent = ({ standalone }: { standalone: boolean }) => {
    if (!previewMessage || (!standalone && splitDetailPreviewDismissed)) {
      return (
        <div className="flex h-full flex-col items-center justify-center px-8 text-center">
          <p className="text-[16px] font-semibold tracking-[-0.03em] text-[#1f2c45]">
            메일을 선택해주세요.
          </p>
          <p className="mt-2 text-[13px] leading-6 text-[#7f8da7]">
            선택한 메일의 내용이 이 영역에 표시됩니다.
          </p>
        </div>
      );
    }

    return (
      <>
        {standalone ? (
          <>
            <div className="border-b border-[#edf1f6] px-3 pb-3 pt-4 sm:px-4 lg:px-8 lg:pb-3 lg:pt-6">
              <div className="flex flex-wrap items-center gap-x-2 gap-y-2 text-[15px] leading-none sm:gap-x-3 sm:text-[16px]">
                <Link
                  href={backToListHref}
                  prefetch={false}
                  scroll={false}
                  className="inline-flex items-center gap-2 text-[#111a33] transition-colors hover:text-[#2f6df6]"
                >
                  <BackIcon className="h-[18px] w-[18px]" />
                  <span className="text-[16px] font-semibold tracking-[-0.03em] sm:text-[17px]">
                    {currentFolderLabel}
                  </span>
                </Link>
                <span className="font-semibold text-[#2f6df6]">{formatCount(totalMessages)}</span>
                <span className="text-[#7c879b]">/ {formatCount(currentFolderTotalCount)}</span>
                {renderFolderSummaryTrailingAction()}
              </div>
            </div>

            <div className="border-b border-[#edf1f6] px-3 py-3 sm:px-4 lg:px-8">
              <DraggableHorizontalScroll
                className="-mx-1 overflow-x-auto pb-1 text-[14px] text-[#5f6f89] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
                innerClassName="flex min-w-max items-center gap-x-5 gap-y-2 px-1"
              >
                {replyHref ? (
                  <Link href={replyHref} prefetch={false} className={mailboxBulkActionClass()}>
                    답장
                  </Link>
                ) : (
                  <span className={mailboxBulkActionClass({ enabled: false })}>답장</span>
                )}
                {replyAllHref ? (
                  <Link href={replyAllHref} prefetch={false} className={mailboxBulkActionClass()}>
                    전체답장
                  </Link>
                ) : (
                  <span className={mailboxBulkActionClass({ enabled: false })}>전체답장</span>
                )}
                {forwardHref ? (
                  <Link href={forwardHref} prefetch={false} className={mailboxBulkActionClass()}>
                    전달
                  </Link>
                ) : (
                  <span className={mailboxBulkActionClass({ enabled: false })}>전달</span>
                )}

                {currentMailboxFolder === "trash" ? (
                  <form action={moveMailboxMessagesAction}>
                    <input type="hidden" name="folder" value={currentMailboxFolder} />
                    <input type="hidden" name="detail" value={detailView} />
                    <input type="hidden" name="page" value={resolvedCurrentPage} />
                    <input type="hidden" name="pageSize" value={resolvedPageSize} />
                    <input type="hidden" name="tab" value={resolvedMessageFilter} />
                    <input type="hidden" name="field" value={resolvedSearchField} />
                    <input type="hidden" name="q" value={resolvedSearchQuery} />
                    <input type="hidden" name="messageIds" value={standaloneMessageIdsValue} />
                    <button
                      type="submit"
                      name="targetFolder"
                      value="inbox"
                      className={mailboxBulkActionClass()}
                    >
                      복구
                    </button>
                  </form>
                ) : null}

                <button
                  type="button"
                  disabled={pendingMoveKey !== null || !previewMessage}
                  onClick={() => {
                    if (previewMessage) {
                      void moveMessagesByClient([previewMessage.id], "trash");
                    }
                  }}
                  className={mailboxBulkActionClass({ enabled: pendingMoveKey === null && Boolean(previewMessage) })}
                >
                  {pendingMoveKey ? (
                    <span className="inline-flex items-center gap-1.5">
                      <SpinnerIcon className="h-[13px] w-[13px] animate-spin" />
                      삭제
                    </span>
                  ) : (
                    "삭제"
                  )}
                </button>

                <form action={moveMailboxMessagesAction}>
                  <input type="hidden" name="folder" value={currentMailboxFolder} />
                  <input type="hidden" name="detail" value={detailView} />
                  <input type="hidden" name="page" value={resolvedCurrentPage} />
                  <input type="hidden" name="pageSize" value={resolvedPageSize} />
                  <input type="hidden" name="tab" value={resolvedMessageFilter} />
                  <input type="hidden" name="field" value={resolvedSearchField} />
                  <input type="hidden" name="q" value={resolvedSearchQuery} />
                  <input type="hidden" name="messageIds" value={standaloneMessageIdsValue} />
                  <button
                    type="submit"
                    name="targetFolder"
                    value="spam"
                    className={mailboxBulkActionClass()}
                  >
                    스팸신고
                  </button>
                </form>

                <form
                  action={markMailboxMessagesReadAction}
                  onSubmit={() => {
                    markMessagesReadOptimistically([previewMessage.id], !previewMessage.isRead);
                  }}
                >
                  <input type="hidden" name="folder" value={currentMailboxFolder} />
                  <input type="hidden" name="detail" value={detailView} />
                  <input type="hidden" name="page" value={resolvedCurrentPage} />
                  <input type="hidden" name="pageSize" value={resolvedPageSize} />
                  <input type="hidden" name="tab" value={resolvedMessageFilter} />
                  <input type="hidden" name="field" value={resolvedSearchField} />
                  <input type="hidden" name="q" value={resolvedSearchQuery} />
                  <input type="hidden" name="messageIds" value={standaloneMessageIdsValue} />
                  <input
                    type="hidden"
                    name="readState"
                    value={previewMessage.isRead ? "unread" : "read"}
                  />
                  <button type="submit" className={mailboxBulkActionClass()}>
                    {previewMessage.isRead ? "안읽음" : "읽음"}
                  </button>
                </form>

                <div className="relative inline-flex" data-move-menu-root="true">
                  <button
                    type="button"
                    onClick={() => {
                      setMoveTargetFolder(
                        currentMailboxFolder === "all" ? "inbox" : currentMailboxFolder || "inbox",
                      );
                      setMoveMenuState((prev) => ({
                        open: !(prev.scope === interactionScopeKey && prev.open),
                        scope: interactionScopeKey,
                      }));
                    }}
                    className={mailboxBulkActionClass({ gapClassName: "gap-1" })}
                  >
                    이동
                    <ChevronDownIcon className="h-[11px] w-[11px]" />
                  </button>
                  {moveMenuOpen ? renderMoveMenuPopover(standaloneMessageIdsValue) : null}
                </div>

                <div className="relative inline-flex" data-detail-menu-root="true">
                  <button
                    type="button"
                    onClick={() =>
                      setDetailMenuState((prev) => ({
                        open: !(prev.open && prev.scope === detailPanelScopeKey),
                        scope: detailPanelScopeKey,
                      }))
                    }
                    className={mailboxBulkActionClass({ gapClassName: "gap-1" })}
                  >
                    더보기
                    <ChevronDownIcon className="h-[11px] w-[11px]" />
                  </button>
                  {detailMenuOpen ? (
                    <div
                      className={`absolute left-0 top-[calc(100%+10px)] z-30 w-[188px] ${popoverMenuSurfaceClass()}`}
                    >
                      <button
                        type="button"
                        disabled={!rawSourceText}
                        onClick={() => {
                          if (!rawSourceText) {
                            return;
                          }

                          setDetailMenuState({ open: false, scope: detailPanelScopeKey });
                          setRawSourceModalState({
                            open: true,
                            scope: detailPanelScopeKey,
                          });
                        }}
                        className={popoverMenuItemClass({ disabled: !rawSourceText })}
                      >
                        메일 원본 보기
                      </button>
                    </div>
                  ) : null}
                </div>
              </DraggableHorizontalScroll>
            </div>
          </>
        ) : null}

        <div className="border-b border-[#edf2fb] px-3 py-4 sm:px-4 lg:px-8">
          <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between lg:gap-6">
            <div className="min-w-0">
              <div className="flex items-center gap-[10px]">
                <ActionTooltip label={previewMessage.isStarred ? "중요 표시 해제" : "중요 표시"}>
                  <button
                    type="button"
                    onClick={() => {
                      void toggleMessageStarByClient(previewMessage.id);
                    }}
                    disabled={activeMessageStarPending}
                    aria-label={previewMessage.isStarred ? "중요 표시 해제" : "중요 표시"}
                    className={`inline-flex h-5 w-5 shrink-0 items-center justify-center transition-colors ${
                      activeMessageStarPending ? "cursor-wait opacity-60" : "cursor-pointer"
                    } ${
                      previewMessage.isStarred
                        ? "text-[#2f6df6] hover:text-[#245de3]"
                        : "text-[#c4cddd] hover:text-[#88a4ea]"
                    }`}
                  >
                    <StarIcon filled={previewMessage.isStarred} className="h-5 w-5" />
                  </button>
                </ActionTooltip>
                <h3 className="truncate text-[20px] font-semibold tracking-[-0.04em] text-[#1a2943] sm:text-[22px] lg:text-[24px]">
                  {previewMessage.subject || "(제목 없음)"}
                </h3>
              </div>

              <div className="mt-4 min-w-0">
                <div className="flex flex-wrap items-center gap-2 text-[16px]">
                  <span className="font-semibold text-[#1f2d46]">
                    {senderLabel(previewMessage.fromName, previewMessage.fromAddress)}
                  </span>
                  <span className="text-[#5c6d88]">&lt;{previewMessage.fromAddress}&gt;</span>
                  {!standalone ? <ChevronDownIcon className="h-4 w-4 text-[#8796b2]" /> : null}
                </div>
                <div className="mt-2 flex flex-wrap items-center gap-3 text-[15px] text-[#607390]">
                  <span>받는사람</span>
                  <span className="text-[#30425f]">{previewMessage.toAddresses}</span>
                  {!standalone ? <ChevronDownIcon className="h-4 w-4 text-[#8796b2]" /> : null}
                </div>
              </div>
            </div>

            <div className="flex shrink-0 flex-col gap-4 lg:items-end lg:gap-5">
              <div className="text-[14px] text-[#72839f]">{formatFullDate(previewMessage.receivedAt)}</div>
              {!standalone ? (
                <div className="flex flex-wrap items-center gap-1">
                  <form
                    action={markMailboxMessagesReadAction}
                    onSubmit={() => {
                      markMessagesReadOptimistically([previewMessage.id], !previewMessage.isRead);
                    }}
                  >
                    <input type="hidden" name="folder" value={currentMailboxFolder} />
                    <input type="hidden" name="detail" value={detailView} />
                    <input type="hidden" name="page" value={resolvedCurrentPage} />
                    <input type="hidden" name="pageSize" value={resolvedPageSize} />
                    <input type="hidden" name="tab" value={resolvedMessageFilter} />
                    <input type="hidden" name="field" value={resolvedSearchField} />
                    <input type="hidden" name="q" value={resolvedSearchQuery} />
                    <input type="hidden" name="message" value={previewMessage.id} />
                    <input type="hidden" name="messageIds" value={previewMessage.id} />
                    <input
                      type="hidden"
                      name="readState"
                      value={previewMessage.isRead ? "unread" : "read"}
                    />
                    <button
                      type="submit"
                      aria-label={previewMessage.isRead ? "안읽음으로 표시" : "읽음으로 표시"}
                      className="inline-flex h-10 cursor-pointer items-center rounded-full px-4 text-[13px] font-medium text-[#60718e] transition-all duration-200 hover:bg-[#f4f7fc] hover:text-[#2f6df6] hover:shadow-[0_10px_24px_rgba(25,38,72,0.08)]"
                    >
                      {previewMessage.isRead ? "안읽음" : "읽음"}
                    </button>
                  </form>
                  {replyHref ? (
                    <ActionTooltip label="답장">
                      <Link
                        href={replyHref}
                        prefetch={false}
                        aria-label="답장"
                        className={detailHeaderActionClass()}
                      >
                        <ReplyIcon className="h-5 w-5" />
                      </Link>
                    </ActionTooltip>
                  ) : null}
                  {replyAllHref ? (
                    <ActionTooltip label="전체 답장">
                      <Link
                        href={replyAllHref}
                        prefetch={false}
                        aria-label="전체 답장"
                        className={detailHeaderActionClass()}
                      >
                        <ReplyAllIcon className="h-5 w-5" />
                      </Link>
                    </ActionTooltip>
                  ) : null}
                  {forwardHref ? (
                    <ActionTooltip label="전달">
                      <Link
                        href={forwardHref}
                        prefetch={false}
                        aria-label="전달"
                        className={detailHeaderActionClass()}
                      >
                        <ForwardIcon className="h-5 w-5" />
                      </Link>
                    </ActionTooltip>
                  ) : null}
                  <ActionTooltip label="상세 패널 닫기">
                    <button
                      type="button"
                      aria-label="닫기"
                      onClick={() => setDismissedDetailScopeKey(detailPanelScopeKey)}
                      className={detailHeaderActionClass()}
                    >
                      <CloseIcon className="h-5 w-5" />
                    </button>
                  </ActionTooltip>
                  <div className="relative" data-detail-menu-root="true">
                    <ActionTooltip label="추가 메뉴">
                      <button
                        type="button"
                        aria-label="추가 메뉴"
                        onClick={() =>
                          setDetailMenuState((prev) => ({
                            open: !(prev.open && prev.scope === detailPanelScopeKey),
                            scope: detailPanelScopeKey,
                          }))
                        }
                        className={detailHeaderActionClass()}
                      >
                        <MoreIcon className="h-5 w-5" />
                      </button>
                    </ActionTooltip>

                    {detailMenuOpen ? (
                      <div
                        className={`absolute right-0 top-[calc(100%+8px)] z-30 w-[188px] ${popoverMenuSurfaceClass()}`}
                      >
                        <button
                          type="button"
                          disabled={!rawSourceText}
                          onClick={() => {
                            if (!rawSourceText) {
                              return;
                            }

                            setDetailMenuState({ open: false, scope: detailPanelScopeKey });
                            setRawSourceModalState({
                              open: true,
                              scope: detailPanelScopeKey,
                            });
                          }}
                          className={popoverMenuItemClass({ disabled: !rawSourceText })}
                        >
                          메일 원본 보기
                        </button>
                      </div>
                    ) : null}
                  </div>
                </div>
              ) : null}
            </div>
          </div>
        </div>

        <div className="min-h-0 flex-1 overflow-y-auto px-3 py-5 sm:px-4 sm:py-6 lg:px-8 lg:py-8">
          <div className="w-full">
            {previewAttachments.length > 0 ? (
              <section className="mb-8">
                <div className="flex flex-wrap items-center justify-between gap-3 border-b border-[#e8edf6] pb-3">
                  <div className="flex flex-wrap items-center gap-3 text-[15px] text-[#5d6f8d]">
                    <div className="flex items-center gap-2 text-[#1c2a43]">
                      <PaperclipIcon className="h-[16px] w-[16px]" />
                      <span className="font-semibold">
                        첨부 {previewAttachments.length}개
                      </span>
                    </div>
                    <span>{formatAttachmentSize(totalAttachmentSize)}</span>
                    <button
                      type="button"
                      onClick={() => downloadAllAttachments(previewMessage.id, previewAttachments)}
                      className="cursor-pointer text-[#2f6df6] transition-colors hover:text-[#245de3]"
                    >
                      모두 저장
                    </button>
                    {previewableAttachments.length > 0 ? (
                      <button
                        type="button"
                        onClick={() =>
                          openAttachmentPreview(
                            previewMessage.id,
                            imagePreviewableAttachments[0] ?? previewableAttachments[0],
                          )
                        }
                        className="cursor-pointer text-[#2f6df6] transition-colors hover:text-[#245de3]"
                      >
                        {imagePreviewableAttachments.length > 0
                          ? "이미지로 보기"
                          : "미리보기"}
                      </button>
                    ) : null}
                  </div>
                </div>

                <div className="mt-4 overflow-hidden border border-[#e2e9f5] bg-white">
                  {previewAttachments.map((attachment, index) => (
                    <div
                      key={`${attachment.index}:${attachment.filename}:${index}`}
                      className={`flex items-center gap-4 px-4 py-3 ${
                        index === 0 ? "" : "border-t border-[#eef2f8]"
                      }`}
                    >
                      {isImageAttachmentPreview(attachment) ? (
                        <button
                          type="button"
                          aria-label={`${attachment.filename} 이미지 미리보기`}
                          onClick={() => openAttachmentPreview(previewMessage.id, attachment)}
                          className="flex h-10 w-10 shrink-0 cursor-pointer overflow-hidden rounded-[10px] border border-[#e2e9f5] bg-[#f5f8fd] transition-transform duration-200 hover:scale-[1.03]"
                        >
                          <img
                            src={`/api/mailbox/attachment?message=${previewMessage.id}&index=${attachment.index}&mode=inline`}
                            alt={attachment.filename}
                            className="h-full w-full object-cover"
                            loading="lazy"
                            draggable={false}
                          />
                        </button>
                      ) : (
                        <div
                          className={`flex h-10 w-10 shrink-0 items-center justify-center text-[11px] font-semibold tracking-[0.04em] ${attachmentTone(
                            attachment,
                          )}`}
                        >
                          {attachmentLabel(attachment)}
                        </div>
                      )}

                      <div className="min-w-0 flex-1">
                        {attachment.isPreviewable ? (
                          <button
                            type="button"
                            onClick={() => openAttachmentPreview(previewMessage.id, attachment)}
                            className="block w-full cursor-pointer truncate text-left text-[15px] font-medium text-[#1f2d46] transition-colors hover:text-[#2f6df6]"
                          >
                            {attachment.filename}
                          </button>
                        ) : (
                          <p className="truncate text-[15px] font-medium text-[#1f2d46]">
                            {attachment.filename}
                          </p>
                        )}
                        <div className="mt-1 flex items-center gap-2 text-[13px] text-[#7a8ba7]">
                          <span>{formatAttachmentSize(attachment.sizeBytes)}</span>
                          {attachment.isInline ? <span>인라인</span> : null}
                        </div>
                      </div>

                      <div className="flex shrink-0 items-center gap-2">
                        {attachment.isPreviewable ? (
                          <button
                            type="button"
                            aria-label={`${attachment.filename} 미리보기`}
                            onClick={() => openAttachmentPreview(previewMessage.id, attachment)}
                            className="inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-full text-[#8b97aa] transition-colors hover:bg-[#f4f7fc] hover:text-[#2f6df6]"
                          >
                            <PreviewIcon className="h-[16px] w-[16px]" />
                          </button>
                        ) : null}
                        <button
                          type="button"
                          aria-label={`${attachment.filename} 다운로드`}
                          onClick={() => downloadAttachment(previewMessage.id, attachment)}
                          className="inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-full text-[#8b97aa] transition-colors hover:bg-[#f4f7fc] hover:text-[#2f6df6]"
                        >
                          <DownloadIcon className="h-[16px] w-[16px]" />
                        </button>
                      </div>
                    </div>
                  ))}
                </div>
              </section>
            ) : null}

            {previewHtml ? (
              <MailHtmlPreview
                key={previewMessage ? `${previewMessage.id}:${previewHtml.length}` : "mail-preview"}
                html={previewHtml}
              />
            ) : (
              <div className="space-y-5 text-[17px] leading-[2] text-[#2c3b56]">
                {(previewLines ?? []).map((line, index) => (
                  <p key={`${line}-${index}`} className={line === "" ? "h-4" : ""}>
                    {line || "\u00A0"}
                  </p>
                ))}
              </div>
            )}
          </div>
        </div>
      </>
    );
  };

  const renderAttachmentPreviewModal = () => {
    if (
      !attachmentPreviewModalOpen ||
      !attachmentPreviewState ||
      !activeAttachmentPreview ||
      !activeAttachmentPreviewFile ||
      typeof document === "undefined"
    ) {
      return null;
    }

    const canShowPrevious = attachmentPreviewState.currentIndex > 0;
    const canShowNext = attachmentPreviewState.currentIndex < attachmentPreviewItems.length - 1;
    const moveButtonClass = (disabled: boolean) =>
      `inline-flex h-14 w-14 items-center justify-center rounded-full border border-white/12 bg-[rgba(11,16,30,0.76)] text-white shadow-[0_20px_50px_rgba(0,0,0,0.28)] backdrop-blur-[18px] transition-all duration-200 ${
        disabled
          ? "cursor-not-allowed opacity-35"
          : "cursor-pointer hover:bg-[rgba(22,32,58,0.92)] hover:text-[#dce7ff]"
      }`;

    return createPortal(
      <div className="fixed inset-0 z-[96] bg-[rgba(3,8,20,0.88)] text-white backdrop-blur-[10px]">
        <button
          type="button"
          aria-label="첨부파일 미리보기 닫기"
          onClick={() => setAttachmentPreviewState(null)}
          className="absolute inset-0 cursor-default"
        />

        <div className="relative z-[97] flex h-full flex-col">
          <div className="flex items-center justify-between gap-4 border-b border-white/10 px-4 py-4 sm:px-6">
            <div className="min-w-0">
              <div className="flex min-w-0 flex-wrap items-end gap-x-2 gap-y-1">
                <strong className="truncate text-[20px] font-semibold tracking-[-0.03em] text-white sm:text-[24px]">
                  {activeAttachmentPreviewFile.name}
                  {activeAttachmentPreviewFile.extension ? (
                    <span className="text-white/52">{activeAttachmentPreviewFile.extension}</span>
                  ) : null}
                </strong>
                <span className="text-[13px] text-white/58">
                  {formatAttachmentSize(activeAttachmentPreview.sizeBytes)}
                </span>
              </div>
            </div>

            <div className="flex shrink-0 items-center gap-2 sm:gap-3">
              {attachmentPreviewItems.length > 1 ? (
                <span className="hidden text-[13px] font-semibold text-white/72 sm:inline-flex">
                  {attachmentPreviewCountLabel}
                </span>
              ) : null}
              <button
                type="button"
                onClick={() =>
                  downloadAttachment(attachmentPreviewState.messageId, activeAttachmentPreview)
                }
                className="inline-flex h-11 items-center gap-2 rounded-full border border-white/12 bg-white/6 px-4 text-[13px] font-semibold text-white transition-colors hover:bg-white/12"
              >
                <DownloadIcon className="h-[16px] w-[16px]" />
                다운로드
              </button>
              <button
                type="button"
                aria-label="첨부파일 미리보기 닫기"
                onClick={() => setAttachmentPreviewState(null)}
                className="inline-flex h-11 w-11 items-center justify-center rounded-full border border-white/12 bg-white/6 text-white transition-colors hover:bg-white/12"
              >
                <CloseIcon className="h-[18px] w-[18px]" />
              </button>
            </div>
          </div>

          <div className="relative flex min-h-0 flex-1 items-center justify-center px-4 py-6 sm:px-6 sm:py-8">
            <div className="relative flex h-full max-h-[calc(100vh-148px)] w-full max-w-[1320px] items-center justify-center">
              {activeAttachmentPreviewIsImage ? (
                <img
                  src={activeAttachmentPreviewUrl}
                  alt={activeAttachmentPreview.filename}
                  draggable={false}
                  className="max-h-full max-w-full select-none rounded-[18px] object-contain shadow-[0_30px_80px_rgba(0,0,0,0.3)]"
                />
              ) : (
                <div className="h-full w-full overflow-hidden rounded-[18px] border border-white/12 bg-white shadow-[0_30px_80px_rgba(0,0,0,0.24)]">
                  <iframe
                    title={activeAttachmentPreview.filename}
                    src={activeAttachmentPreviewUrl}
                    className="h-full w-full bg-white"
                  />
                </div>
              )}

              {attachmentPreviewItems.length > 1 ? (
                <>
                  <button
                    type="button"
                    aria-label="이전 첨부 보기"
                    disabled={!canShowPrevious}
                    onClick={() =>
                      setAttachmentPreviewState((current) =>
                        current && current.currentIndex > 0
                          ? { ...current, currentIndex: current.currentIndex - 1 }
                          : current,
                      )
                    }
                    className={`absolute left-0 top-1/2 -translate-y-1/2 sm:left-2 ${moveButtonClass(
                      !canShowPrevious,
                    )}`}
                  >
                    <BackIcon className="h-6 w-6" />
                  </button>
                  <button
                    type="button"
                    aria-label="다음 첨부 보기"
                    disabled={!canShowNext}
                    onClick={() =>
                      setAttachmentPreviewState((current) =>
                        current && current.currentIndex < attachmentPreviewItems.length - 1
                          ? { ...current, currentIndex: current.currentIndex + 1 }
                          : current,
                      )
                    }
                    className={`absolute right-0 top-1/2 -translate-y-1/2 sm:right-2 ${moveButtonClass(
                      !canShowNext,
                    )}`}
                  >
                    <BackIcon className="h-6 w-6 rotate-180" />
                  </button>
                </>
              ) : null}
            </div>

            {attachmentPreviewItems.length > 1 ? (
              <div className="pointer-events-none absolute bottom-6 left-1/2 -translate-x-1/2 rounded-full bg-[rgba(9,14,26,0.72)] px-4 py-2 text-[13px] font-semibold text-white/88 shadow-[0_16px_40px_rgba(0,0,0,0.24)] backdrop-blur-[16px] sm:hidden">
                {attachmentPreviewCountLabel}
              </div>
            ) : null}
          </div>
        </div>
      </div>,
      document.body,
    );
  };

  return (
    <div className="relative h-full w-full overflow-hidden bg-[#fcfdff] text-[#13213b]">
      {senderSpamPrompt && senderSpamPrompt.scope === interactionScopeKey ? (
        <div
          className="pointer-events-none fixed inset-x-0 bottom-4 z-[95] flex justify-center px-4 sm:bottom-6"
          style={{ paddingBottom: "env(safe-area-inset-bottom)" }}
        >
          <form
            action={updateMailboxSenderSpamRuleAction}
            onSubmit={() => {
              setSenderSpamPrompt(null);
              setSenderSpamPromptTargetFolder("inbox");
              setSenderSpamPromptNewFolderName("");
            }}
            className="pointer-events-auto relative w-full max-w-[720px] overflow-hidden rounded-[26px] bg-[rgba(12,18,30,0.92)] px-5 py-5 text-white shadow-[0_24px_60px_rgba(2,6,18,0.38)] ring-1 ring-white/10 backdrop-blur-[22px] backdrop-saturate-150"
          >
            <input type="hidden" name="folder" value={currentMailboxFolder} />
            <input type="hidden" name="detail" value={detailView} />
            <input type="hidden" name="page" value={resolvedCurrentPage} />
            <input type="hidden" name="pageSize" value={resolvedPageSize} />
            <input type="hidden" name="tab" value={resolvedMessageFilter} />
            <input type="hidden" name="field" value={resolvedSearchField} />
            <input type="hidden" name="q" value={resolvedSearchQuery} />
            <input type="hidden" name="activeMessageId" value={activeMessageId ? String(activeMessageId) : ""} />
            <input type="hidden" name="senderAddress" value={senderSpamPrompt.senderAddress} />
            <input type="hidden" name="mode" value="unspam" />
            <input type="hidden" name="targetFolder" value={senderSpamPromptTargetFolder} />
            <input type="hidden" name="newFolderName" value={senderSpamPromptNewFolderName.trim()} />

            <SenderRulePromptFieldset>
              <div className="flex items-start justify-between gap-4">
                <div className="min-w-0">
                  <p className="text-[12px] font-semibold tracking-[0.08em] text-[#7ea8ff]">스팸 해제</p>
                  <p className="mt-2 text-[18px] font-semibold tracking-[-0.03em] text-white">
                    {senderSpamPrompt.senderLabel}
                  </p>
                  <p className="mt-2 text-[13px] leading-6 text-white/72">
                    이 발송자를 자동 스팸 분류 대상에서 제외합니다. 기존 스팸메일함 메일을 받은메일함이나 원하는 메일함으로 다시 이동할지 선택하세요.
                  </p>
                </div>
                <button
                  type="button"
                  aria-label="확인 닫기"
                  onClick={() => {
                    setSenderSpamPrompt(null);
                    setSenderSpamPromptTargetFolder("inbox");
                    setSenderSpamPromptNewFolderName("");
                  }}
                  className="inline-flex h-9 w-9 shrink-0 cursor-pointer items-center justify-center rounded-full text-white/52 transition-colors hover:bg-white/8 hover:text-white"
                >
                  <CloseIcon className="h-[16px] w-[16px]" />
                </button>
              </div>

              <div className="mt-4 rounded-[20px] border border-white/10 bg-white/5 p-4">
                <p className="text-[12px] font-semibold text-white/66">기존 스팸 메일 이동 대상</p>
                <div className="mt-3 flex flex-wrap gap-2">
                  {senderSpamRestoreFolderOptions.map((item) => {
                    const selected = senderSpamPromptTargetFolder === item.systemName;
                    return (
                      <button
                        key={item.systemName}
                        type="button"
                        onClick={() => setSenderSpamPromptTargetFolder(item.systemName)}
                        className={`inline-flex cursor-pointer items-center gap-2 rounded-full px-3 py-2 text-[12px] font-medium transition-colors ${
                          selected
                            ? "bg-white text-[#12203a]"
                            : "bg-white/7 text-white/82 hover:bg-white/12"
                        }`}
                      >
                        <span>{item.label}</span>
                        <span className={selected ? "text-[#4b607f]" : "text-white/50"}>
                          {compactCount(item.count)}
                        </span>
                      </button>
                    );
                  })}
                </div>

                <div className="mt-4 rounded-[16px] border border-white/10 bg-[rgba(255,255,255,0.04)] p-3">
                  <div className="flex items-center gap-2">
                    <label htmlFor="sender-spam-restore-folder" className="sr-only">
                      새 메일함
                    </label>
                    <input
                      id="sender-spam-restore-folder"
                      type="text"
                      value={senderSpamPromptNewFolderName}
                      onChange={(event) => setSenderSpamPromptNewFolderName(event.target.value)}
                      placeholder="새 메일함"
                      className="h-10 min-w-0 flex-1 rounded-[12px] border border-white/10 bg-white/92 px-3 text-[13px] text-[#223250] outline-none placeholder:text-[#8fa0ba] focus:border-[#bcd1ff]"
                    />
                    <button
                      type="button"
                      onClick={() => {
                        const nextFolderName = senderSpamPromptNewFolderName.trim();

                        if (!nextFolderName) {
                          setLocalNotice({
                            tone: "error",
                            message: "새 메일함 이름을 입력해주세요.",
                          });
                          return;
                        }

                        setSenderSpamPromptTargetFolder("__new__");
                        setSenderSpamPromptNewFolderName(nextFolderName);
                      }}
                      className="inline-flex h-10 shrink-0 cursor-pointer items-center justify-center rounded-[12px] border border-white/10 bg-white/8 px-3 text-[13px] font-semibold text-white/88 transition-colors hover:bg-white/12"
                    >
                      추가
                    </button>
                  </div>
                  {senderSpamPromptTargetFolder === "__new__" && senderSpamPromptNewFolderName.trim() ? (
                    <p className="mt-2 text-[12px] text-white/62">
                      새 메일함 <span className="font-semibold text-white">{senderSpamPromptNewFolderName.trim()}</span>
                      으로 이동합니다.
                    </p>
                  ) : null}
                </div>
              </div>

              <div className="mt-4 grid gap-2 sm:grid-cols-[minmax(0,1fr)_180px]">
                <SenderRulePromptSubmitButton
                  label="선택한 메일함으로 이동"
                  pendingLabel="이동 중..."
                  variant="primary"
                  name="moveExistingMessages"
                  value="1"
                />
                <SenderRulePromptSubmitButton
                  label="기존 메일은 그대로"
                  pendingLabel="해제 중..."
                  variant="secondary"
                  name="moveExistingMessages"
                  value="0"
                />
              </div>
            </SenderRulePromptFieldset>
            <SenderRulePromptPendingOverlay />
          </form>
        </div>
      ) : null}

      {runtimeNotice ? (
        <BottomToast
          notice={runtimeNotice}
          onClose={() => {
            if (localNotice) {
              setLocalNotice(null);
              return;
            }

            if (serverNoticeKey) {
              setDismissedServerNoticeKey(serverNoticeKey);
            }
          }}
        />
      ) : null}

      <div className="flex h-full flex-col transition-[opacity,filter,transform] duration-300">
        <header className="shrink-0 border-b border-[#e9eef8] bg-white">
          <div className="flex min-h-[60px] flex-wrap items-center gap-3 px-3 py-2 sm:px-4 lg:grid lg:h-[60px] lg:grid-cols-[220px_minmax(0,1fr)_auto] lg:py-0">
            <div className="flex min-w-0 flex-1 items-center">
              <button
                type="button"
                aria-label="메일함 메뉴 열기"
                onClick={() => setMobileSidebarOpen(true)}
                className="inline-flex h-[18px] w-[18px] shrink-0 cursor-pointer items-center justify-center text-[#72829f] transition-colors hover:text-[#2f6df6] lg:hidden"
              >
                <MenuIcon className="h-[18px] w-[18px]" />
              </button>

              <Link
                href={mailConfigured ? "/mail?folder=all" : "/mail?panel=setup&section=domain"}
                prefetch={false}
                onClick={(event) =>
                  handleMailboxNavigationLinkClick(
                    event,
                    mailConfigured ? "/mail?folder=all" : "/mail?panel=setup&section=domain",
                    {
                      intent: mailConfigured ? "mailbox" : "setup",
                    },
                  )
                }
                className="flex min-w-0 items-center rounded-[18px]"
              >
                <div className="flex min-w-0 items-center">
                  <span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-[10px] text-[#2f6df6]">
                    <IconBase className="h-6 w-6">
                      <rect x="3.5" y="5.5" width="17" height="13" rx="2.5" />
                      <path d="m4.8 7 7.2 5.6L19.2 7" />
                    </IconBase>
                  </span>
                  <span className="truncate text-[18px] font-extrabold tracking-[-0.07em] text-[#2f6df6]">
                    오피셜메일
                  </span>
                </div>
              </Link>
            </div>

            <div
              className={`${
                mobileSearchExpanded ? "order-3 flex basis-full" : "hidden"
              } lg:order-none lg:flex lg:basis-auto lg:justify-center lg:px-4`}
            >
              <div
                ref={searchMenuRef}
                data-mail-search-root="true"
                className="relative w-full lg:max-w-[640px]"
              >
                <label className="flex h-[44px] w-full items-center gap-3 rounded-full border border-[#edf2fb] bg-[#fbfcff] px-4 text-[14px] text-[#9aa8bf] shadow-[0_18px_45px_rgba(47,109,246,0.05)] transition-all duration-200 hover:border-[#d9e4fb] hover:bg-white hover:shadow-[0_22px_52px_rgba(47,109,246,0.08)] focus-within:border-[#cfe0ff] focus-within:bg-white focus-within:shadow-[0_22px_52px_rgba(47,109,246,0.1)] lg:px-5">
                  <SearchIcon className="h-5 w-5 shrink-0" />
                  {activeSearchBadgeVisible ? (
                    <span className="om-badge om-badge-md om-badge-info shrink-0">
                      {searchFieldLabel(resolvedSearchField)}
                    </span>
                  ) : null}
                  <input
                    ref={searchInputRef}
                    type="text"
                    value={searchInput}
                    disabled={!isMailboxPanel || !mailConfigured}
                    placeholder={
                      !isMailboxPanel || !mailConfigured
                        ? "도메인 연결 후 메일 검색"
                        : "보낸사람, 받는사람, 제목, 내용 검색"
                    }
                    onFocus={() => {
                      if (isMailboxPanel && mailConfigured) {
                        setSearchOpen(true);
                      }
                    }}
                    onChange={(event) => {
                      setSearchInput(event.target.value);
                      setSearchOpen(true);
                      setSearchHighlightedIndex(-1);
                    }}
                    onKeyDown={(event) => {
                      if (event.key === "ArrowDown") {
                        if (visibleSearchSuggestions.length === 0) {
                          return;
                        }

                        event.preventDefault();
                        setSearchOpen(true);
                        setSearchHighlightedIndex((current) =>
                          current >= visibleSearchSuggestions.length - 1 ? 0 : current + 1,
                        );
                        return;
                      }

                      if (event.key === "ArrowUp") {
                        if (visibleSearchSuggestions.length === 0) {
                          return;
                        }

                        event.preventDefault();
                        setSearchOpen(true);
                        setSearchHighlightedIndex((current) =>
                          current <= 0 ? visibleSearchSuggestions.length - 1 : current - 1,
                        );
                        return;
                      }

                      if (event.key === "Enter") {
                        event.preventDefault();

                        if (
                          searchHighlightedIndex >= 0 &&
                          visibleSearchSuggestions[searchHighlightedIndex]
                        ) {
                          applySearchSuggestion(visibleSearchSuggestions[searchHighlightedIndex]);
                          return;
                        }

                        applySearch("all", searchInput);
                      }
                    }}
                    className="w-full bg-transparent text-[#344767] outline-none placeholder:text-[#9aa8bf] disabled:cursor-not-allowed disabled:text-[#a7b2c6]"
                  />
                  {searchLoading ? (
                    <span className="shrink-0 text-[12px] font-medium text-[#8a98b2]">
                      검색 중
                    </span>
                  ) : null}
                  {(searchInput.trim() || resolvedSearchQuery) && !searchLoading ? (
                    <button
                      type="button"
                      aria-label="검색 지우기"
                      onClick={clearSearch}
                      className="inline-flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-full text-[#8b98b0] transition-colors hover:bg-[#eef4ff] hover:text-[#2f6df6]"
                    >
                      <CloseIcon className="h-[14px] w-[14px]" />
                    </button>
                  ) : null}
                </label>

                {searchDropdownVisible ? (
                  <div className="absolute inset-x-0 top-[calc(100%+10px)] z-40 overflow-hidden rounded-[22px] border border-[#dfe8f8] bg-white shadow-[0_30px_65px_rgba(18,32,65,0.16)]">
                    {searchLoading || searchInput.trim() !== deferredSearchInput ? (
                      <div className="px-5 py-4 text-[13px] text-[#7b89a2]">
                        검색 중입니다.
                      </div>
                    ) : visibleSearchSuggestions.length > 0 ? (
                      <div className="max-h-[420px] overflow-y-auto py-2">
                        {visibleSearchSuggestions.map((suggestion, index) => (
                          <button
                            key={`${suggestion.field}:${suggestion.messageId}:${suggestion.value}:${index}`}
                            type="button"
                            onMouseDown={(event) => event.preventDefault()}
                            onClick={() => applySearchSuggestion(suggestion)}
                            className={`flex w-full cursor-pointer items-start gap-4 px-5 py-3 text-left transition-colors ${
                              index === searchHighlightedIndex
                                ? "bg-[#f4f8ff]"
                                : "hover:bg-[#f7faff]"
                            }`}
                          >
                            <span className="mt-0.5 om-badge om-badge-sm om-badge-info shrink-0">
                              {searchFieldLabel(suggestion.field)}
                            </span>
                            <span className="min-w-0 flex-1">
                              <span className="block truncate text-[14px] font-semibold text-[#22314e]">
                                {suggestion.value}
                              </span>
                              <span className="mt-1 block truncate text-[12px] text-[#70819d]">
                                {suggestion.preview}
                              </span>
                            </span>
                            <span className="shrink-0 text-[11px] text-[#96a4bc]">
                              {formatInboxTime(suggestion.receivedAt)}
                            </span>
                          </button>
                        ))}
                      </div>
                    ) : (
                      <div className="px-5 py-4 text-[13px] text-[#7b89a2]">
                        일치하는 메일이 없습니다.
                      </div>
                    )}
                  </div>
                ) : null}
              </div>
            </div>

            <div className="ml-auto flex shrink-0 items-center gap-2 sm:gap-3">
              <button
                type="button"
                aria-label={mobileSearchExpanded ? "검색 닫기" : "검색 열기"}
                onClick={() => {
                  setMobileSearchVisible((current) => {
                    const next = !current;
                    if (next) {
                      window.requestAnimationFrame(() => searchInputRef.current?.focus());
                    }
                    return next;
                  });
                }}
                className={`inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-full transition-colors lg:hidden ${
                  mobileSearchExpanded
                    ? "bg-[#eef4ff] text-[#2f6df6]"
                    : "text-[#72829f] hover:bg-[#f4f7fc] hover:text-[#2f6df6]"
                }`}
              >
                <SearchIcon className="h-[18px] w-[18px]" />
              </button>

              <Link
                href={OFFICIAL_MAIL_GUIDE_URL}
                aria-label="오피셜메일 가이드 열기"
                target="_blank"
                rel="noopener noreferrer"
                className={`hidden lg:inline-flex ${circleIconButtonClass()}`}
              >
                <HelpIcon className="h-5 w-5" />
              </Link>

              {canManageBilling ? (
                <Link
                  href={setupHref("billing")}
                  prefetch={false}
                  className={`group hidden h-9 items-center gap-2 px-1 text-[13px] font-semibold transition-colors duration-200 lg:inline-flex ${
                    planSummary.tier === "growth"
                      ? "text-[#2f6df6] hover:text-[#255ce0]"
                      : "text-[#5f6f89] hover:text-[#2d3d5c]"
                  }`}
                >
                  <span
                    className={`h-2.5 w-2.5 rounded-full ${
                      planSummary.aiAssistAvailable ? "bg-[#2f6df6]" : "bg-[#9aa8bf]"
                    }`}
                  />
                  <span className="whitespace-nowrap">{planSummary.label}</span>
                  <span
                    className={`hidden md:inline-flex items-center rounded-full border px-2 py-1 text-[12px] font-semibold leading-none ${
                      planSummary.aiAssistAvailable
                        ? "border-[#bfd4ff] text-[#2f6df6]"
                        : "border-[#d8e0ec] text-[#7f8da3]"
                    }`}
                  >
                    {planSummary.badgeLabel}
                  </span>
                </Link>
              ) : (
                <div
                  className={`hidden h-9 items-center gap-2 px-1 text-[13px] font-semibold lg:inline-flex ${
                    planSummary.tier === "growth" ? "text-[#2f6df6]" : "text-[#5f6f89]"
                  }`}
                >
                  <span
                    className={`h-2.5 w-2.5 rounded-full ${
                      planSummary.aiAssistAvailable ? "bg-[#2f6df6]" : "bg-[#9aa8bf]"
                    }`}
                  />
                  <span className="whitespace-nowrap">{planSummary.label}</span>
                  <span
                    className={`hidden md:inline-flex items-center rounded-full border px-2 py-1 text-[12px] font-semibold leading-none ${
                      planSummary.aiAssistAvailable
                        ? "border-[#bfd4ff] text-[#2f6df6]"
                        : "border-[#d8e0ec] text-[#7f8da3]"
                    }`}
                  >
                    {planSummary.badgeLabel}
                  </span>
                </div>
              )}

            <div ref={settingsMenuRef} data-settings-menu-root="true" className="relative">
              <button
                type="button"
                aria-expanded={settingsMenuOpen}
                aria-haspopup="menu"
                onClick={() =>
                  setSettingsMenuState((current) =>
                    current.open && current.scope === settingsMenuScopeKey
                      ? { open: false, scope: settingsMenuScopeKey }
                      : { open: true, scope: settingsMenuScopeKey },
                  )
                }
                className={`inline-flex cursor-pointer items-center gap-3 rounded-full border px-3 py-2 transition-all duration-200 ${
                  settingsMenuOpen || isSetupPanel
                    ? "border-transparent bg-white/78 text-[#2f6df6] backdrop-blur-xl backdrop-saturate-150"
                    : "border-transparent bg-white text-[#62738f] hover:bg-white/70 hover:text-[#2d3d5c] hover:backdrop-blur-xl hover:backdrop-saturate-150"
                }`}
              >
                <span className="text-[13px] font-semibold text-[#1f2c45] lg:hidden">설정</span>
                <div className="hidden min-w-0 text-left lg:block">
                  <p className="truncate text-[15px] font-semibold text-[#1f2c45]">{userDisplayName}</p>
                  <p className="truncate text-[14px] text-[#6981a6]">{compactMailbox}</p>
                </div>
                <ChevronDownIcon
                  className={`h-[15px] w-[15px] transition-transform duration-200 ${
                    settingsMenuOpen ? "rotate-180" : ""
                  }`}
                />
              </button>

              {settingsMenuOpen ? (
                <div className="absolute right-0 top-[calc(100%+12px)] z-50 w-[284px] overflow-hidden rounded-[22px] border border-[#dfe8f8] bg-white shadow-[0_28px_60px_rgba(18,32,65,0.16)]">
                  <div className="border-b border-[#edf2fb] px-5 py-4">
                    <p className="text-[14px] font-semibold text-[#1f2c45]">{userDisplayName}</p>
                    <p className="mt-1 truncate text-[12px] font-medium text-[#2f6df6]">
                      {compactMailbox}
                    </p>
                  </div>

                  <div className="p-2.5">
                    {settingsMenuItems.map((item) => {
                      const active =
                        item.id !== "logout" && isSetupPanel && setupSection === item.id;

                      if (item.id === "logout") {
                        return (
                          <form key={item.id} action={logoutAction} className="contents">
                            <button type="submit" className={settingsMenuButtonClass()}>
                              {iconForSetupNav(item.id, settingsMenuItemIconClass())}
                              <span className="truncate">{item.label}</span>
                            </button>
                          </form>
                        );
                      }

                      return (
                        <Link
                          key={item.id}
                          href={setupHref(item.id as MailSetupSection)}
                          prefetch={false}
                          onClick={(event) =>
                            handleMailboxNavigationLinkClick(event, setupHref(item.id as MailSetupSection), {
                              intent: "setup",
                            })
                          }
                          className={settingsMenuItemClass(active)}
                        >
                          {iconForSetupNav(item.id, settingsMenuItemIconClass(active))}
                          <span className="truncate">{item.label}</span>
                        </Link>
                      );
                    })}
                  </div>
                </div>
              ) : null}
            </div>
          </div>
          </div>
        </header>

        {!isLgViewport && mobileSidebarOpen ? (
          <button
            type="button"
            aria-label="메일함 메뉴 닫기"
            onClick={() => setMobileSidebarOpen(false)}
            className="fixed inset-0 z-[84] bg-[rgba(15,23,42,0.34)] backdrop-blur-[2px] lg:hidden"
          />
        ) : null}

        <div
          data-mail-layout-root="true"
          data-mail-vertical-split-root={
            isMailboxPanel && isSplitVerticalMode && showSplitDetailPanel
              ? "true"
              : undefined
          }
          style={layoutGridStyle}
          className={`relative grid min-h-0 flex-1 grid-cols-1 ${
            isStandaloneContentPanel
              ? "lg:grid-cols-[var(--mail-sidebar-width)_minmax(0,1fr)]"
              : isSplitHorizontalMode && showSplitDetailPanel
                ? "lg:grid-cols-[var(--mail-sidebar-width)_minmax(0,1fr)] xl:grid-cols-[var(--mail-sidebar-width)_var(--mail-list-width)_minmax(0,1fr)]"
                : isSplitVerticalMode && showSplitDetailPanel
                  ? "lg:grid-cols-[var(--mail-sidebar-width)_minmax(0,1fr)] lg:grid-rows-[var(--mail-list-height-clamped)_minmax(0,1fr)]"
                  : "lg:grid-cols-[var(--mail-sidebar-width)_minmax(0,1fr)]"
          }`}
        >
          {showMobileFullContentNavigationOverlay
            ? renderContentNavigationOverlay(
                "absolute inset-0 z-[120] flex items-center justify-center bg-[rgba(252,253,255,0.96)] transition-opacity duration-200 lg:hidden",
              )
            : null}
          <ResizeHandle
            active={dragState?.panel === "sidebar"}
            ariaLabel="사이드바 너비 조절"
            className="hidden lg:block"
            left={layoutState.sidebarWidth}
            onPointerDown={beginResize("sidebar")}
          />
          {isMailboxPanel && isSplitHorizontalMode && showSplitDetailPanel ? (
            <ResizeHandle
              active={dragState?.panel === "list"}
              ariaLabel="메일 목록 너비 조절"
              className="hidden xl:block"
              left={layoutState.sidebarWidth + layoutState.listWidth}
              onPointerDown={beginResize("list")}
            />
          ) : null}
          {isMailboxPanel && isSplitVerticalMode && showSplitDetailPanel ? (
            <HorizontalResizeHandle
              active={dragState?.panel === "list-height"}
              ariaLabel="메일 목록 높이 조절"
              className="hidden lg:block"
              left={layoutState.sidebarWidth}
              onPointerDown={beginResize("list-height")}
              top="var(--mail-list-height-clamped)"
            />
          ) : null}

          <aside
            className={`min-h-0 overflow-visible border-r border-[#e9eef8] bg-white ${
              mobileSidebarOpen
                ? "fixed inset-y-0 left-0 z-[85] flex w-[min(70vw,360px)] flex-col shadow-[0_28px_64px_rgba(15,23,42,0.18)] lg:static lg:z-auto lg:w-auto lg:shadow-none"
                : "hidden lg:flex lg:flex-col"
            } ${isMailboxPanel && isSplitVerticalMode && showSplitDetailPanel ? "lg:row-span-2" : ""}`}
          >
            <div className="flex h-[60px] shrink-0 items-center justify-between border-b border-[#e9eef8] px-4 lg:hidden">
              <div className="flex min-w-0 items-center">
                <LogoMark compact />
                <span className="truncate text-[18px] font-extrabold tracking-[-0.07em] text-[#2f6df6]">
                  오피셜메일
                </span>
              </div>
              <button
                type="button"
                aria-label="메일함 메뉴 닫기"
                onClick={() => setMobileSidebarOpen(false)}
                className="inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-full text-[#72829f] transition-colors hover:bg-[#f4f7fc] hover:text-[#2f6df6]"
              >
                <CloseIcon className="h-[18px] w-[18px]" />
              </button>
            </div>

            <div className="flex min-h-0 flex-1 flex-col px-4 pt-4">
              <Link
                href={composeHref}
                prefetch={false}
                className="inline-flex h-10 shrink-0 items-center justify-center gap-3 rounded-[14px] bg-[linear-gradient(135deg,#2f6df6,#245de3)] px-4 text-[13px] font-semibold text-white shadow-[0_18px_40px_rgba(47,109,246,0.22)] transition-all hover:-translate-y-0.5 hover:shadow-[0_24px_50px_rgba(47,109,246,0.28)]"
              >
                <ComposeIcon className="h-[18px] w-[18px]" />
                메일 작성
              </Link>

              <div className="mt-6 min-h-0 flex-1 overflow-y-auto pr-1">
                <div className="space-y-1.5">
                <div className="group flex items-center gap-1 rounded-[10px]">
                  <div
                    className={`relative flex min-w-0 flex-1 cursor-pointer items-center rounded-[10px] px-2 py-2 text-[14px] transition-all duration-200 ${
                      showMailboxSidebarActiveState && currentMailboxFolder === "all"
                        ? "bg-[#eaf2ff] text-[#2f6df6] shadow-[inset_0_0_0_1px_rgba(47,109,246,0.04)]"
                        : "text-[#33445f] hover:bg-[#f4f6fa] hover:text-[#2f6df6]"
                    }`}
                    onClick={(event) => {
                      if (shouldBypassClientNavigation(event)) {
                        return;
                      }

                      navigateWithinMailbox(allFolderHref, {
                        intent: allFolderNavigationIntent,
                      });
                    }}
                  >
                    <Link
                      href={allFolderHref}
                      prefetch={false}
                      scroll={false}
                      onClick={(event) =>
                        handleMailboxNavigationLinkClick(event, allFolderHref, {
                          intent: allFolderNavigationIntent,
                        })
                      }
                      className={`flex min-w-0 flex-1 items-center ${SIDEBAR_MENU_TEXT_GAP_CLASS}`}
                    >
                      {iconForNav("all", SIDEBAR_MENU_ICON_CLASS)}
                      <span className="flex min-w-0 items-center gap-1.5">
                        <span
                          className={`truncate ${
                            showMailboxSidebarActiveState && currentMailboxFolder === "all"
                              ? "font-semibold"
                              : "font-medium"
                          }`}
                        >
                          전체메일
                        </span>
                        <span
                          className={`shrink-0 text-[12px] ${
                            showMailboxSidebarActiveState && currentMailboxFolder === "all"
                              ? "font-semibold text-[#2f6df6]"
                              : "text-[#70829f]"
                          }`}
                        >
                          {compactCount(allFolderMessages)}
                        </span>
                      </span>
                    </Link>
                  </div>
                </div>

                {primaryFolders.map((item) => renderSidebarFolderItem(item))}

                <div className="mt-4 border-t border-[#eef2fa] pt-4">
                  <div className="group flex items-center gap-1 rounded-[10px]">
                    <div className="relative flex min-w-0 flex-1 items-center rounded-[10px] px-2 py-2 text-[14px] text-[#33445f] transition-all duration-200 hover:bg-[#f4f6fa] hover:text-[#2f6df6]">
                      <button
                        type="button"
                        onClick={() => setPersonalFoldersOpen((current) => !current)}
                        className="flex min-w-0 flex-1 cursor-pointer items-center text-left"
                      >
                        <span className={`flex min-w-0 items-center ${SIDEBAR_MENU_TEXT_GAP_CLASS}`}>
                          <FolderIcon className={SIDEBAR_MENU_ICON_CLASS} />
                          <span className="flex min-w-0 items-center gap-1.5">
                            <span className="truncate font-medium">내 메일함</span>
                            <span className="shrink-0 text-[12px] text-[#70829f]">
                              {compactCount(personalFolders.length)}
                            </span>
                          </span>
                        </span>
                      </button>
                      <div className="ml-2 flex shrink-0 items-center gap-1">
                        <button
                          type="button"
                          aria-label="새 메일함 추가"
                          onClick={() => openSidebarFolderCreateEditor({ insertAtTop: true })}
                          className={`inline-flex h-6 w-6 items-center justify-center rounded-[7px] text-[#8a96ab] transition-all duration-150 ${
                            sidebarFolderEditorState?.mode === "create" && sidebarFolderEditorState.insertAtTop
                              ? "bg-white text-[#556885]"
                              : "pointer-events-none opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 group-focus-within:pointer-events-auto group-focus-within:opacity-100 hover:bg-white hover:text-[#2f6df6]"
                          }`}
                        >
                          <PlusIcon className="h-[13px] w-[13px]" />
                        </button>
                        <button
                          type="button"
                          aria-label={personalFoldersExpanded ? "내 메일함 접기" : "내 메일함 펼치기"}
                          onClick={() => setPersonalFoldersOpen((current) => !current)}
                          className="inline-flex h-6 w-6 cursor-pointer items-center justify-center rounded-[7px] text-[#8a96ab] transition-colors hover:bg-white hover:text-[#2f6df6]"
                        >
                          <ChevronDownIcon
                            className={`h-[13px] w-[13px] transition-transform duration-200 ${
                              personalFoldersExpanded ? "rotate-180" : ""
                            }`}
                          />
                        </button>
                      </div>
                    </div>
                  </div>

                  <div
                    className={`overflow-hidden transition-[max-height,opacity] duration-300 ${
                      personalFoldersExpanded ? "max-h-[720px] opacity-100" : "max-h-0 opacity-0"
                    }`}
                  >
                    <div className="mt-1 space-y-1.5 pl-1">
                      {sidebarFolderEditorState?.mode === "create" && sidebarFolderEditorState.insertAtTop
                        ? renderSidebarFolderInlineEditor()
                        : null}
                      {personalFolders.map((item) => (
                        <Fragment key={item.id}>
                          {sidebarFolderEditorState?.mode === "rename" &&
                          sidebarFolderEditorState.folderId === item.id
                            ? renderSidebarFolderInlineEditor()
                            : renderSidebarFolderItem(item, { draggable: true })}
                          {sidebarFolderEditorState?.mode === "create" &&
                          sidebarFolderEditorState.insertAfterSystemName === item.systemName
                            ? renderSidebarFolderInlineEditor()
                            : null}
                        </Fragment>
                      ))}
                    </div>
                  </div>
                </div>

                {secondarySystemFolders.length > 0 ? (
                  <div className="mt-4 space-y-1.5 border-t border-[#eef2fa] pt-4">
                    {secondarySystemFolders.map((item) => renderSidebarFolderItem(item))}
                  </div>
                ) : null}

                <div className="mt-4 space-y-1.5">
                  {planSummary.aiAssistAvailable ? (
                    <Link
                      href={autoSendHref()}
                      prefetch={false}
                      onClick={(event) =>
                        handleMailboxNavigationLinkClick(event, autoSendHref(), {
                          intent: "auto-send",
                        })
                      }
                      className={`flex min-h-10 w-full items-center gap-[5px] rounded-[10px] px-2 py-2 text-[14px] font-medium transition-all duration-200 ${
                        isAutoSendPanel
                          ? "bg-[#eaf2ff] text-[#2f6df6] shadow-[inset_0_0_0_1px_rgba(47,109,246,0.04)]"
                          : "text-[#33445f] hover:bg-[#f4f6fa] hover:text-[#2f6df6]"
                      }`}
                    >
                      <ScheduleIcon className={SIDEBAR_MENU_ICON_CLASS} />
                      <span className="min-w-0 flex-1 truncate">자동발송 예약</span>
                      <span className="shrink-0 text-[12px] font-semibold text-[#70829f]">
                        열기
                      </span>
                    </Link>
                  ) : (
                    <div
                      aria-disabled="true"
                      title="성장 플랜에서 사용할 수 있습니다."
                      className="flex min-h-10 w-full cursor-not-allowed items-center gap-[5px] rounded-[10px] px-2 py-2 text-[14px] font-medium text-[#8f9cb0]"
                    >
                      <ScheduleIcon className="h-[18px] w-[18px] shrink-0 text-[#aab6c9]" />
                      <span className="min-w-0 flex-1 truncate">자동발송 예약</span>
                      <span className="ml-auto inline-flex h-7 w-7 items-center justify-center text-[#9aa8bf]">
                        <LockIcon className="h-[18px] w-[18px]" />
                      </span>
                    </div>
                  )}
                </div>
                </div>
              </div>
            </div>

            <div className="shrink-0 border-t border-[#eef2fa]">
              <div className="space-y-4 px-4 pb-4 pt-6">
                {reconnectRequired ? (
                  <form
                    action={saveMailboxCredentialsAction}
                    className="rounded-[20px] border border-[#ffe2b4] bg-[#fffaf1] p-4 shadow-[0_12px_32px_rgba(252,193,56,0.08)]"
                  >
                    <input type="hidden" name="folder" value={currentMailboxFolder} />
                    <input type="hidden" name="detail" value={detailView} />
                    <input type="hidden" name="page" value={resolvedCurrentPage} />
                    <input type="hidden" name="pageSize" value={resolvedPageSize} />
                    <input type="hidden" name="tab" value={resolvedMessageFilter} />
                    <input type="hidden" name="field" value={resolvedSearchField} />
                    <input type="hidden" name="q" value={resolvedSearchQuery} />
                    <input type="hidden" name="message" value={activeMessageId ? String(activeMessageId) : ""} />
                    <p className="text-[13px] font-semibold text-[#9a5600]">메일함 재연결</p>
                    <p className="mt-2 text-[13px] leading-6 text-[#856f50]">
                      메일 비밀번호를 다시 저장하면 동기화를 재개할 수 있습니다.
                    </p>
                    <input
                      required
                      name="mailboxPassword"
                      type="password"
                      autoComplete="current-password"
                      placeholder="메일함 비밀번호"
                      className="mt-3 h-10 w-full rounded-[12px] border border-[#f4cf8a] bg-white px-3 text-[13px] outline-none placeholder:text-[#b9a483]"
                    />
                    <SubmitButton
                      label="비밀번호 저장"
                      pendingLabel="연결 중..."
                      className="mt-3 inline-flex h-10 w-full items-center justify-center rounded-[12px] bg-[#f4b545] text-[13px] font-semibold text-[#5a3b00] transition-colors hover:bg-[#ecab34]"
                    />
                  </form>
                ) : null}

                <div className="overflow-hidden rounded-[24px] border border-[#d7e4ff] bg-[linear-gradient(135deg,#2f6df6_0%,#5d92ff_58%,#84afff_100%)] text-white">
                  <div className="px-5 py-4">
                    <div className="flex items-start justify-between gap-3">
                      <div className="min-w-0">
                        <p className="text-[12px] font-semibold uppercase tracking-[0.12em] text-white/72">
                          AI Assist Bridge
                        </p>
                        <p className="mt-1.5 text-[16px] font-semibold leading-6">
                          메일 요약·답장 릴레이
                        </p>
                        <p className="mt-1 text-[12px] text-white/72">AI 자동화</p>
                      </div>
                      <span className="inline-flex h-10 w-10 shrink-0 items-center justify-center rounded-[18px] bg-white/14 text-white/92">
                        <SparkIcon className="h-5 w-5" />
                      </span>
                    </div>
                    <p className="mt-3 text-[12px] leading-5 text-white/80">
                      {aiAssistOverview?.enabled
                        ? `${aiAssistOverview.notificationEmail ?? "알림 메일"}로 요약 전송 중`
                        : planSummary.aiAssistAvailable
                          ? "요약 메일 답장을 원본 발신자에게 전달합니다."
                          : canManageBilling
                            ? "성장 플랜을 시작하면 요약 메일과 답장 릴레이를 바로 사용할 수 있습니다."
                            : "대표 관리자 계정에서 성장 플랜이 활성화되면 사용할 수 있습니다."}
                    </p>
                    <Link
                      href={
                        planSummary.aiAssistAvailable
                          ? setupHref("assistant")
                          : canManageBilling
                            ? setupHref("billing")
                            : setupHref("assistant")
                      }
                      prefetch={false}
                      className="mt-4 inline-flex h-10 w-full items-center justify-center rounded-[14px] bg-white px-4 text-[13px] font-semibold text-[#2f6df6] transition-all duration-200 hover:-translate-y-0.5 hover:bg-[#f7faff]"
                    >
                      {planSummary.aiAssistAvailable
                        ? "AI 어시스트 설정 열기"
                        : canManageBilling
                          ? "성장 플랜 시작하기"
                          : "AI 어시스트 설정 보기"}
                    </Link>
                  </div>
                </div>

                <div className="border-t border-[#edf2fb] px-0 pt-4">
                  <div className="flex items-center justify-between">
                    <span className="text-[14px] font-semibold text-[#243555]">사용량</span>
                    <span className="text-[14px] text-[#5a6f95]">
                      {usageSummary}
                    </span>
                  </div>
                  <div className="relative mt-4 h-4 overflow-hidden rounded-full bg-[linear-gradient(180deg,#f7faff,#eaf0fb)] shadow-[inset_0_1px_0_rgba(255,255,255,0.92),inset_0_-1px_0_rgba(148,163,184,0.08)]">
                    <div
                      className="relative h-full rounded-full transition-[width] duration-300 ease-out"
                      style={{
                        width: `${usageProgressValue}%`,
                        ...usageProgressFillStyle,
                      }}
                    >
                      <div className="pointer-events-none absolute inset-0 bg-[linear-gradient(180deg,rgba(255,255,255,0.34),rgba(255,255,255,0))]" />
                    </div>
                    <span
                      className={`absolute inset-0 flex items-center justify-center text-[11px] font-semibold ${
                        usagePercent !== null && usagePercent >= 50
                          ? "text-white"
                          : "text-[#42536f]"
                      }`}
                    >
                      {usagePercent === null ? "집계 중" : `${usagePercent}%`}
                    </span>
                  </div>
                </div>

              </div>
            </div>
          </aside>

          {isSetupPanel ? (
            <section className="relative h-full min-h-0 min-w-0 overflow-hidden bg-white lg:col-span-1">
              <MailSetupWorkspace
                section={setupSection}
                overview={setupOverview}
                aiAssistOverview={aiAssistOverview}
                billingOverview={billingOverview}
                billingCancellationOverview={billingCancellationOverview}
                billingHistoryPage={billingHistoryPage}
                billingHistoryState={billingHistoryState}
                billingTab={billingTab}
                managedMembers={managedMembers}
                memberMailboxView={memberMailboxView}
                mailData={mailData}
                planSummary={planSummary}
                canManageBilling={canManageBilling}
                sessionCompanyName={companyName}
                sessionDisplayName={userDisplayName}
                sessionDomain={sessionDomain}
                sessionEmail={userEmail}
                sessionMailbox={compactMailbox}
              />
              {showEmbeddedContentNavigationOverlay ? renderContentNavigationOverlay() : null}
            </section>
          ) : isAutoSendPanel ? (
            <section className="relative h-full min-h-0 min-w-0 overflow-y-auto bg-white lg:col-span-1">
              <div className="h-full w-full">
                <MailAutoSendPanel
                  overview={autoSendOverview}
                  planSummary={planSummary}
                  canManageBilling={canManageBilling}
                />
              </div>
              {showEmbeddedContentNavigationOverlay ? renderContentNavigationOverlay() : null}
            </section>
          ) : (
            <>
              <section className={`relative min-h-0 bg-white ${isSplitHorizontalMode && showSplitDetailPanel ? "border-r border-[#e9eef8]" : ""}`}>
                {currentView === "compose" ? (
                  <div className="relative h-full min-h-0">
                    <MailComposeForm
                      key={composeFormKey}
                      mailboxAddress={compactMailbox}
                      composeMode={composeMode}
                      currentFolder={currentMailboxFolder}
                      defaultBcc={composeBccDefault}
                      defaultBody={composeBodyDefault}
                      defaultBodyHtml={composeBodyHtmlDefault}
                      defaultCc={composeCcDefault}
                      defaultSubject={composeSubjectDefault}
                      defaultTo={composeToDefault}
                    />
                    {showEmbeddedContentNavigationOverlay ? renderContentNavigationOverlay() : null}
                  </div>
                ) : (
                  <div className="flex h-full min-h-0 flex-col bg-white">
                    {showStandaloneMessageView ? (
                      <div className="relative flex h-full min-h-0 flex-col">
                        {renderMessageDetailContent({ standalone: true })}
                        {showEmbeddedContentNavigationOverlay ? renderContentNavigationOverlay() : null}
                      </div>
                    ) : (
                      <>
                        <div className="border-b border-[#edf1f6] px-3 pb-3 pt-4 sm:px-4 lg:px-8 lg:pb-3 lg:pt-6">
                          <div className="flex flex-wrap items-center gap-x-2 gap-y-2 text-[15px] leading-none sm:gap-x-3 sm:text-[16px]">
                            <h2 className="text-[16px] font-semibold tracking-[-0.03em] text-[#111a33] sm:text-[17px]">
                              {currentFolderLabel}
                            </h2>
                            <span className="font-semibold text-[#2f6df6]">
                              {formatCount(totalMessages)}
                            </span>
                            <span className="text-[#7c879b]">/ {formatCount(currentFolderTotalCount)}</span>
                            {renderFolderSummaryTrailingAction()}
                            {selectedIds.length > 0 ? (
                              <span className="text-[#8a94a8]">선택 {formatCount(selectedIds.length)}</span>
                            ) : null}
                          </div>
                        </div>

                        <div className="relative flex min-h-0 flex-1 flex-col">
                          <div className="border-b border-[#edf1f6] px-3 py-3 sm:px-4 lg:px-8">
                            <div className="flex flex-col gap-3 text-[14px] text-[#727f95] lg:flex-row lg:items-center lg:justify-between">
                              <DraggableHorizontalScroll
                                className="-mx-1 overflow-x-auto pb-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
                                innerClassName="flex min-w-max items-center gap-x-4 gap-y-2 px-1"
                              >
                                <button
                                  type="button"
                                  onClick={toggleSelectAll}
                                  className="inline-flex h-8 cursor-pointer items-center gap-2 rounded-[10px] pr-1 text-[#5e6b81] transition-colors hover:text-[#2f6df6]"
                                >
                                  <input
                                    type="checkbox"
                                    checked={allVisibleSelected}
                                    readOnly
                                    aria-label="전체 선택"
                                    className={mailboxCheckboxClass()}
                                  />
                                  <ChevronDownIcon className="h-[11px] w-[11px]" />
                                </button>

                                {hasCheckedMessages ? (
                                  <form
                                    action={markMailboxMessagesReadAction}
                                    onSubmit={() => {
                                      markMessagesReadOptimistically(
                                        checkedMessageIds,
                                        bulkReadToggleValue !== "unread",
                                      );
                                    }}
                                  >
                                    <input type="hidden" name="folder" value={currentMailboxFolder} />
                                    <input type="hidden" name="detail" value={detailView} />
                                    <input type="hidden" name="page" value={resolvedCurrentPage} />
                                    <input type="hidden" name="pageSize" value={resolvedPageSize} />
                                    <input type="hidden" name="tab" value={resolvedMessageFilter} />
                                    <input type="hidden" name="field" value={resolvedSearchField} />
                                    <input type="hidden" name="q" value={resolvedSearchQuery} />
                                    <input type="hidden" name="messageIds" value={checkedMessageIdsValue} />
                                    <input type="hidden" name="readState" value={bulkReadToggleValue} />
                                    <button type="submit" className={mailboxBulkActionClass()}>
                                      {bulkReadToggleLabel}
                                    </button>
                                  </form>
                                ) : (
                                  <span className={mailboxBulkActionClass({ enabled: false })}>
                                    {bulkReadToggleLabel}
                                  </span>
                                )}

                                {currentMailboxFolder === "trash" ? (
                                  hasCheckedMessages ? (
                                    <form action={moveMailboxMessagesAction}>
                                      <input type="hidden" name="folder" value={currentMailboxFolder} />
                                      <input type="hidden" name="detail" value={detailView} />
                                      <input type="hidden" name="page" value={resolvedCurrentPage} />
                                      <input type="hidden" name="pageSize" value={resolvedPageSize} />
                                      <input type="hidden" name="tab" value={resolvedMessageFilter} />
                                      <input type="hidden" name="field" value={resolvedSearchField} />
                                      <input type="hidden" name="q" value={resolvedSearchQuery} />
                                      <input type="hidden" name="messageIds" value={checkedMessageIdsValue} />
                                      <button
                                        type="submit"
                                        name="targetFolder"
                                        value="inbox"
                                        className={mailboxBulkActionClass()}
                                      >
                                        복구
                                      </button>
                                    </form>
                                  ) : (
                                    <span className={mailboxBulkActionClass({ enabled: false })}>복구</span>
                                  )
                                ) : null}

                                {hasCheckedMessages ? (
                                  <button
                                    type="button"
                                    disabled={pendingMoveKey !== null}
                                    onClick={() => void moveMessagesByClient(checkedMessageIds, "trash")}
                                    className={mailboxBulkActionClass({ enabled: pendingMoveKey === null })}
                                  >
                                    {pendingMoveKey ? (
                                      <span className="inline-flex items-center gap-1.5">
                                        <SpinnerIcon className="h-[13px] w-[13px] animate-spin" />
                                        삭제
                                      </span>
                                    ) : (
                                      "삭제"
                                    )}
                                  </button>
                                ) : (
                                  <span className={mailboxBulkActionClass({ enabled: false })}>삭제</span>
                                )}

                              {hasCheckedMessages ? (
                                <form action={moveMailboxMessagesAction}>
                                  <input type="hidden" name="folder" value={currentMailboxFolder} />
                                  <input type="hidden" name="detail" value={detailView} />
                                  <input type="hidden" name="page" value={resolvedCurrentPage} />
                                  <input type="hidden" name="pageSize" value={resolvedPageSize} />
                                  <input type="hidden" name="tab" value={resolvedMessageFilter} />
                                  <input type="hidden" name="field" value={resolvedSearchField} />
                                  <input type="hidden" name="q" value={resolvedSearchQuery} />
                                  <input type="hidden" name="messageIds" value={checkedMessageIdsValue} />
                                  <button
                                    type="submit"
                                    name="targetFolder"
                                    value="spam"
                                    className={mailboxBulkActionClass()}
                                  >
                                    스팸신고
                                  </button>
                                </form>
                              ) : (
                                <span className={mailboxBulkActionClass({ enabled: false })}>스팸신고</span>
                              )}

                              {replyHref ? (
                                <Link href={replyHref} prefetch={false} className={mailboxBulkActionClass()}>
                                  답장
                                </Link>
                              ) : (
                                <span className={mailboxBulkActionClass({ enabled: false })}>답장</span>
                              )}

                              {replyAllHref ? (
                                <Link href={replyAllHref} prefetch={false} className={mailboxBulkActionClass()}>
                                  전체답장
                                </Link>
                              ) : (
                                <span className={mailboxBulkActionClass({ enabled: false })}>전체답장</span>
                              )}

                              {forwardHref ? (
                                <Link href={forwardHref} prefetch={false} className={mailboxBulkActionClass()}>
                                  전달
                                </Link>
                              ) : (
                                <span className={mailboxBulkActionClass({ enabled: false })}>전달</span>
                              )}

                              {hasCheckedMessages ? (
                                <div className="relative inline-flex" data-move-menu-root="true">
                                  <button
                                    type="button"
                                    onClick={() => {
                                      setMoveTargetFolder(
                                        (currentMailboxFolder === "all" ? "inbox" : currentMailboxFolder) || "inbox",
                                      );
                                      setMoveMenuState((prev) => ({
                                        open: !(prev.scope === interactionScopeKey && prev.open),
                                        scope: interactionScopeKey,
                                      }));
                                    }}
                                    className={mailboxBulkActionClass({ gapClassName: "gap-1" })}
                                  >
                                    이동
                                    <ChevronDownIcon className="h-[11px] w-[11px]" />
                                  </button>
                                  {moveMenuOpen ? renderMoveMenuPopover(checkedMessageIdsValue) : null}
                                </div>
                              ) : (
                                <span className={mailboxBulkActionClass({ enabled: false, gapClassName: "gap-1" })}>
                                  이동
                                  <ChevronDownIcon className="h-[11px] w-[11px]" />
                                </span>
                              )}

                              <div className="relative inline-flex" data-toolbar-menu-root="true">
                                <button
                                  ref={filterMenuButtonRef}
                                  type="button"
                                  onClick={() =>
                                    setToolbarMenuKind(filterMenuOpen ? null : "filter")
                                  }
                                  className={toolbarMenuButtonClass(filterMenuOpen)}
                                >
                                  <FilterIcon className="h-[15px] w-[15px]" />
                                  필터
                                  <ChevronDownIcon
                                    className={`h-[11px] w-[11px] transition-transform duration-200 ${
                                      filterMenuOpen ? "rotate-180" : ""
                                    }`}
                                  />
                                </button>

                                <ToolbarPortalMenu
                                  anchorRef={filterMenuButtonRef}
                                  className={`z-[9999] w-max min-w-[188px] ${popoverMenuSurfaceClass()}`}
                                  open={filterMenuOpen}
                                >
                                  {FILTER_OPTIONS.map((option) => {
                                    const selected = resolvedMessageFilter === option.id;
                                    return (
                                      <button
                                        key={option.id}
                                        type="button"
                                        onClick={() => {
                                          setToolbarMenuKind(null);
                                          setSelectionState({ ids: [], scope: interactionScopeKey });
                                          setMoveMenuState({ open: false, scope: interactionScopeKey });
                                          router.push(
                                            folderHref(currentMailboxFolder, {
                                              page: 1,
                                              pageSize: resolvedPageSize,
                                              searchField: resolvedSearchField,
                                              searchQuery: resolvedSearchQuery,
                                              sortOrder: currentSortOrder,
                                              tab: option.id,
                                            }),
                                            { scroll: false },
                                          );
                                        }}
                                        className={popoverMenuItemClass({ active: selected })}
                                      >
                                        {option.label}
                                        {selected ? <span className="sr-only">선택됨</span> : null}
                                      </button>
                                    );
                                  })}
                                </ToolbarPortalMenu>
                              </div>
                              </DraggableHorizontalScroll>

                              <div className="flex items-center justify-end gap-2">
                                <button
                                  type="button"
                                  onClick={() => {
                                    void syncMailbox();
                                  }}
                                  disabled={isRefreshing}
                                  aria-label="메일함 동기화"
                                  className="inline-flex h-9 w-9 cursor-pointer items-center justify-center rounded-full text-[#7d8798] transition-colors hover:bg-[#f4f7fc] hover:text-[#2f6df6] disabled:cursor-not-allowed disabled:text-[#c1c9d7]"
                                >
                                  <RefreshIcon className={`h-[15px] w-[15px] ${isRefreshing ? "animate-spin" : ""}`} />
                                </button>

                              <div className="relative inline-flex" data-toolbar-menu-root="true">
                                <button
                                  ref={sortMenuButtonRef}
                                  type="button"
                                  aria-label="메일 정렬"
                                  aria-expanded={sortMenuOpen}
                                  aria-haspopup="menu"
                                  onClick={() => setToolbarMenuKind(sortMenuOpen ? null : "sort")}
                                  className={toolbarTextMenuButtonClass(sortMenuOpen)}
                                >
                                  <span>{currentSortOrder === "oldest" ? "오래된순" : "최신순"}</span>
                                  <ChevronDownIcon
                                    className={`h-[11px] w-[11px] transition-transform duration-200 ${
                                      sortMenuOpen ? "rotate-180" : ""
                                    }`}
                                  />
                                </button>

                                <ToolbarPortalMenu
                                  align="right"
                                  anchorRef={sortMenuButtonRef}
                                  className={`z-[9999] w-max min-w-[188px] ${popoverMenuSurfaceClass()}`}
                                  open={sortMenuOpen}
                                >
                                  {MAIL_SORT_OPTIONS.map((option) => {
                                    const selected = currentSortOrder === option.value;
                                    return (
                                      <button
                                        key={option.value}
                                        type="button"
                                        onClick={() => {
                                          if (selected) {
                                            setToolbarMenuKind(null);
                                            return;
                                          }

                                          void applySortOrder(option.value);
                                        }}
                                        className={viewModeMenuItemClass(selected)}
                                      >
                                        <span>{option.label}</span>
                                        {selected ? (
                                          <>
                                            <span className="ml-auto inline-flex items-center text-[#2f6df6]">
                                              <MenuCheckIcon className="h-[14px] w-[14px]" />
                                            </span>
                                            <span className="sr-only">선택됨</span>
                                          </>
                                        ) : null}
                                      </button>
                                    );
                                  })}
                                </ToolbarPortalMenu>
                              </div>

                              <div className="relative inline-flex" data-toolbar-menu-root="true">
                                <button
                                  ref={pageSizeMenuButtonRef}
                                  type="button"
                                  aria-label="페이지당 메일 표시 개수"
                                  aria-expanded={pageSizeMenuOpen}
                                  aria-haspopup="menu"
                                  onClick={() => setToolbarMenuKind(pageSizeMenuOpen ? null : "pageSize")}
                                  className={toolbarTextMenuButtonClass(pageSizeMenuOpen)}
                                >
                                  <span>{resolvedPageSize}개씩 보기</span>
                                  <ChevronDownIcon
                                    className={`h-[11px] w-[11px] transition-transform duration-200 ${
                                      pageSizeMenuOpen ? "rotate-180" : ""
                                    }`}
                                  />
                                </button>

                                <ToolbarPortalMenu
                                  align="right"
                                  anchorRef={pageSizeMenuButtonRef}
                                  className={`z-[9999] w-max min-w-[188px] ${popoverMenuSurfaceClass()}`}
                                  open={pageSizeMenuOpen}
                                >
                                  {MAILBOX_PAGE_SIZE_OPTIONS.map((pageSize) => {
                                    const selected = resolvedPageSize === pageSize;
                                    return (
                                      <button
                                        key={pageSize}
                                        type="button"
                                        onClick={() => {
                                          if (selected) {
                                            setToolbarMenuKind(null);
                                            return;
                                          }

                                          void applyPageSize(pageSize);
                                        }}
                                        className={viewModeMenuItemClass(selected)}
                                      >
                                        <span>{pageSize}개씩 보기</span>
                                        {selected ? (
                                          <>
                                            <span className="ml-auto inline-flex items-center text-[#2f6df6]">
                                              <MenuCheckIcon className="h-[14px] w-[14px]" />
                                            </span>
                                            <span className="sr-only">선택됨</span>
                                          </>
                                        ) : null}
                                      </button>
                                    );
                                  })}
                                </ToolbarPortalMenu>
                              </div>

                              <div className="relative inline-flex" data-toolbar-menu-root="true">
                                <button
                                  ref={viewMenuButtonRef}
                                  type="button"
                                  onClick={() => setToolbarMenuKind(viewMenuOpen ? null : "view")}
                                  className={toolbarMenuButtonClass(viewMenuOpen, {
                                    mobileIconOnly: true,
                                  })}
                                  aria-label="보기방식"
                                >
                                  {iconForViewMode(currentViewMode, "h-[15px] w-[15px]")}
                                  <span className="hidden whitespace-nowrap xl:inline">보기방식</span>
                                  <ChevronDownIcon
                                    className={`hidden h-[11px] w-[11px] transition-transform duration-200 xl:block ${
                                      viewMenuOpen ? "rotate-180" : ""
                                    }`}
                                  />
                                </button>

                                <ToolbarPortalMenu
                                  align="right"
                                  anchorRef={viewMenuButtonRef}
                                  className={`z-[9999] w-max min-w-[188px] ${popoverMenuSurfaceClass()}`}
                                  open={viewMenuOpen}
                                >
                                  {VIEW_MODE_OPTIONS.map((mode) => {
                                    const selected = currentViewMode === mode;
                                    return (
                                      <button
                                        key={mode}
                                        type="button"
                                        onClick={() => applyViewMode(mode)}
                                        className={viewModeMenuItemClass(selected)}
                                      >
                                        {iconForViewMode(mode, "h-[15px] w-[15px]")}
                                        <span>{VIEW_MODE_LABEL[mode]}</span>
                                        {selected ? (
                                          <>
                                            <span className="ml-auto inline-flex items-center text-[#2f6df6]">
                                              <svg
                                                viewBox="0 0 24 24"
                                                fill="none"
                                                stroke="currentColor"
                                                strokeWidth="2"
                                                strokeLinecap="round"
                                                strokeLinejoin="round"
                                                className="h-[14px] w-[14px]"
                                              >
                                                <path d="m5 12 4.2 4.2L19 6.7" />
                                              </svg>
                                            </span>
                                            <span className="sr-only">선택됨</span>
                                          </>
                                        ) : null}
                                      </button>
                                    );
                                  })}
                                </ToolbarPortalMenu>
                              </div>
                              </div>
                            </div>
                          </div>

                          <div className="min-h-0 flex-1 overflow-y-auto">
                            {filteredMessages.length > 0 ? (
                              <div className="divide-y divide-[#edf1f6]">
                                {filteredMessages.map((message) => {
                                const active = activeMessageId === message.id;
                                const checked = selectedIds.includes(message.id);
                                const unread = !message.isRead;
                                const showAttachment = looksLikeAttachment(message);
                                const important = message.isStarred;
                                const sentMessage = message.direction === "outbound";
                                const recipient = primaryRecipient(message.toAddresses);
                                const messageContactAddress = sentMessage ? recipient.address : message.fromAddress;
                                const messageContactLabel = sentMessage
                                  ? recipient.label
                                  : senderLabel(message.fromName, message.fromAddress);
                                const messageContactRole = sentMessage ? "받는사람" : "보낸사람";
                                const senderMenuOpen = senderMenuMessageId === message.id;
                                const rowFolderLabel =
                                  currentMailboxFolder === "all" && message.folderSystemName !== "inbox"
                                    ? folderLabelForHeader(message.folderSystemName, message.folderName)
                                    : "";
                                const aiStatusLabel = aiSummaryStatusLabel(message);
                                const handleRowClick = (event: ReactMouseEvent<HTMLDivElement>) => {
                                  if (shouldPreventMailRowOpen(event.target)) {
                                    return;
                                  }

                                  openMessage(message.id);
                                };
                                const renderSenderCell = (compactLayout: boolean) => (
                                  <div
                                    className={`${compactLayout ? "relative min-w-0" : "relative pr-4"}`}
                                    data-row-action-stop="true"
                                    data-sender-menu-root="true"
                                  >
                                    <button
                                      type="button"
                                      onClick={() =>
                                        setSenderMenuState((prev) => ({
                                          messageId:
                                            prev.scope === interactionScopeKey && prev.messageId === message.id
                                              ? null
                                              : message.id,
                                          scope: interactionScopeKey,
                                        }))
                                      }
                                      onContextMenu={(event) => {
                                        event.preventDefault();
                                        setSenderMenuState({
                                          messageId: message.id,
                                          scope: interactionScopeKey,
                                        });
                                      }}
                                      className={`truncate cursor-pointer text-left transition-all hover:text-[#2f6df6] hover:underline ${
                                        unread ? "font-bold text-[#111a33]" : "font-normal text-[#2f3d54]"
                                      }`}
                                    >
                                      {messageContactLabel}
                                    </button>

                                    {senderMenuOpen ? (
                                      <div
                                        className={`absolute left-0 top-[calc(100%+6px)] z-30 w-[208px] ${popoverMenuSurfaceClass()}`}
                                      >
                                        <button
                                          type="button"
                                          onClick={() => openComposeToAddress(messageContactAddress)}
                                          className={popoverMenuItemClass()}
                                        >
                                          메일 쓰기
                                        </button>
                                        <button
                                          type="button"
                                          onClick={() => {
                                            setSenderMenuState({ messageId: null, scope: interactionScopeKey });
                                            openMessage(message.id);
                                          }}
                                          className={popoverMenuItemClass()}
                                        >
                                          이 메일 열기
                                        </button>
                                        <button
                                          type="button"
                                          onClick={() => {
                                            setSenderMenuState({ messageId: null, scope: interactionScopeKey });
                                            void copyToClipboard(
                                              messageContactAddress,
                                              `${messageContactRole} 이메일 주소를 복사했습니다.`,
                                            );
                                          }}
                                          className={popoverMenuItemClass()}
                                        >
                                          이메일 주소 복사
                                        </button>
                                        <button
                                          type="button"
                                          onClick={() => {
                                            setSenderMenuState({ messageId: null, scope: interactionScopeKey });
                                            void copyToClipboard(
                                              messageContactLabel,
                                              `${messageContactRole} 이름을 복사했습니다.`,
                                            );
                                          }}
                                          className={popoverMenuItemClass()}
                                        >
                                          이름 복사
                                        </button>

                                        {message.direction === "inbound" ? (
                                          <>
                                            <div className="my-2 border-t border-[#edf2fb]" />

                                            {message.folderSystemName === "spam" ? (
                                              <button
                                                type="button"
                                                onClick={() => {
                                                  setSenderMenuState({ messageId: null, scope: interactionScopeKey });
                                                setSenderSpamPrompt({
                                                  scope: interactionScopeKey,
                                                  senderAddress: message.fromAddress,
                                                  senderLabel: messageContactLabel,
                                                });
                                                setSenderSpamPromptTargetFolder("inbox");
                                                setSenderSpamPromptNewFolderName("");
                                              }}
                                                className={popoverMenuItemClass()}
                                              >
                                                스팸 해제
                                              </button>
                                            ) : (
                                              <form
                                                action={updateMailboxSenderSpamRuleAction}
                                                onSubmit={() =>
                                                  setSenderMenuState({ messageId: null, scope: interactionScopeKey })
                                                }
                                              >
                                                <input type="hidden" name="folder" value={currentMailboxFolder} />
                                                <input type="hidden" name="detail" value={detailView} />
                                                <input type="hidden" name="page" value={resolvedCurrentPage} />
                                                <input type="hidden" name="pageSize" value={resolvedPageSize} />
                                                <input type="hidden" name="tab" value={resolvedMessageFilter} />
                                                <input type="hidden" name="field" value={resolvedSearchField} />
                                                <input type="hidden" name="q" value={resolvedSearchQuery} />
                                                <input
                                                  type="hidden"
                                                  name="activeMessageId"
                                                  value={activeMessageId ? String(activeMessageId) : ""}
                                                />
                                                <input type="hidden" name="senderAddress" value={message.fromAddress} />
                                                <input type="hidden" name="mode" value="spam" />
                                                <button
                                                  type="submit"
                                                  className={popoverMenuItemClass()}
                                                >
                                                  스팸 등록
                                                </button>
                                              </form>
                                            )}
                                          </>
                                        ) : null}
                                      </div>
                                    ) : null}
                                  </div>
                                );
                                const messageContentCell = (
                                  <div className="flex min-w-0 items-center gap-2 text-left">
                                    <div className="min-w-0 truncate text-[12px] text-[#4b576b]">
                                      {rowFolderLabel ? (
                                        <span className="mr-1 text-[#7a879c]">[{rowFolderLabel}]</span>
                                      ) : null}
                                      <span
                                        className={`mr-2 ${
                                          unread ? "font-bold text-[#16233c]" : "font-normal text-[#1f2c45]"
                                        }`}
                                      >
                                        {message.subject.trim() || "(제목 없음)"}
                                      </span>
                                      {message.snippet.trim() ? (
                                        <span className="text-[#6f7c92]">{message.snippet.trim()}</span>
                                      ) : null}
                                    </div>
                                    <div
                                      className="flex shrink-0 items-center gap-1 text-[#9aa5b7]"
                                      data-row-action-stop="true"
                                    >
                                      {message.aiSummaryStatus === "failed" ? (
                                        <span
                                          className="inline-flex h-[15px] w-[15px] items-center justify-center text-[#e5484d]"
                                          title={aiStatusLabel}
                                          aria-label={aiStatusLabel}
                                        >
                                          <AlertIcon className="h-[14px] w-[14px]" />
                                        </span>
                                      ) : null}
                                      {message.aiSummaryStatus === "sending" ? (
                                        <span
                                          className="inline-flex h-[15px] w-[15px] items-center justify-center text-[#2f6df6]"
                                          title={aiStatusLabel}
                                          aria-label={aiStatusLabel}
                                        >
                                          <SpinnerIcon className="h-[13px] w-[13px] animate-spin" />
                                        </span>
                                      ) : null}
                                      {showAttachment ? <PaperclipIcon className="h-[13px] w-[13px]" /> : null}
                                      <button
                                        type="button"
                                        onClick={(event) => {
                                          event.preventDefault();
                                          event.stopPropagation();
                                          openMessagePopup(message.id);
                                        }}
                                        className="inline-flex cursor-pointer items-center justify-center rounded-[8px] transition-colors hover:text-[#2f6df6]"
                                        aria-label="새 창으로 열기"
                                      >
                                        <ExternalIcon className="h-[13px] w-[13px]" />
                                      </button>
                                    </div>
                                  </div>
                                );
                                const renderMessageTimeCell = (className: string) => (
                                  <div
                                    className={`${className} ${
                                      unread ? "font-semibold text-[#23324b]" : "font-normal text-[#7c8799]"
                                    }`}
                                  >
                                    {formatInboxTime(message.receivedAt)}
                                  </div>
                                );

                                return (
                                  <div
                                    key={message.id}
                                    ref={(node) => {
                                      if (node) {
                                        messageRowRefs.current.set(message.id, node);
                                      } else {
                                        messageRowRefs.current.delete(message.id);
                                      }
                                    }}
                                    draggable
                                    onDragStart={beginMessageDrag(message.id)}
                                    onDragEnd={finishMessageDrag}
                                    onClick={handleRowClick}
                                    className={`grid cursor-pointer px-3 text-[12px] leading-[1.25] transition-colors min-h-0 grid-cols-[15px_32px_32px_minmax(0,1fr)] items-start py-1.5 sm:px-4 lg:min-h-[39px] lg:grid-cols-[15px_32px_32px_154px_minmax(0,1fr)_94px] lg:items-center lg:px-8 lg:py-0 ${
                                      checked || draggingMessageIdSet.has(message.id)
                                        ? "bg-[#edf4ff]"
                                      : active
                                          ? "bg-[#f5f9ff]"
                                          : "hover:bg-[#fafcff]"
                                    }`}
                                  >
                                <div className="flex items-center justify-center" data-row-action-stop="true">
                                  <input
                                    type="checkbox"
                                    checked={checked}
                                    onChange={() => toggleSelection(message.id)}
                                    className={mailboxCheckboxClass()}
                                  />
                                </div>

                                <div className="flex items-center justify-center" data-row-action-stop="true">
                                  <button
                                    type="button"
                                    onClick={() => {
                                      void toggleMessageStarByClient(message.id);
                                    }}
                                    disabled={pendingStarMessageIds.includes(message.id)}
                                    className={`inline-flex h-[17px] w-[17px] items-center justify-center transition-colors ${
                                      pendingStarMessageIds.includes(message.id)
                                        ? "cursor-wait opacity-60"
                                        : "cursor-pointer"
                                    } ${
                                      important
                                        ? "text-[#5b88ff] hover:text-[#2f6df6]"
                                        : "text-[#c4cddd] hover:text-[#89a7ef]"
                                    }`}
                                    aria-label={important ? "중요 표시 해제" : "중요 표시"}
                                  >
                                    <StarIcon filled={important} className="h-[17px] w-[17px]" />
                                  </button>
                                </div>

                                <button
                                  type="button"
                                  onClick={() => openComposeToAddress(message.fromAddress)}
                                  data-row-action-stop="true"
                                  className="flex cursor-pointer items-center justify-center rounded-[8px] text-left transition-colors hover:text-[#2f6df6]"
                                  aria-label={`${message.fromAddress} 주소로 메일 쓰기`}
                                >
                                  <MailRowIcon
                                    unread={unread}
                                    className={`h-[18px] w-[18px] ${
                                      unread ? "text-[#8ec0ff]" : "text-[#c5cfdf]"
                                    }`}
                                  />
                                </button>

                                <>
                                  <div className="min-w-0 lg:hidden">
                                    <div className="flex items-start justify-between gap-3">
                                      {renderSenderCell(true)}
                                      {renderMessageTimeCell(
                                        "shrink-0 whitespace-nowrap pt-px text-right",
                                      )}
                                    </div>
                                    <div className="mt-1.5">{messageContentCell}</div>
                                  </div>
                                  <div className="hidden lg:block">{renderSenderCell(false)}</div>
                                  <div className="hidden py-[11px] lg:block">{messageContentCell}</div>
                                  {renderMessageTimeCell(
                                    "hidden whitespace-nowrap py-[11px] pr-3 text-right lg:block",
                                  )}
                                </>
                              </div>
                            );
                                })}
                              </div>
                            ) : (
                              <div className="flex h-full items-center justify-center px-8 text-[13px] text-[#7f8da7]">
                                표시할 메일이 없습니다.
                              </div>
                            )}
                          </div>

                          <div className="flex items-center justify-center gap-2 border-t border-[#edf1f6] px-6 py-4 text-[12px] text-[#72829f]">
                            {resolvedCurrentPage > 1 ? (
                              <Link
                                href={pageHref(currentMailboxFolder, resolvedCurrentPage - 1, resolvedMessageFilter, {
                                  pageSize: resolvedPageSize,
                                  searchField: resolvedSearchField,
                                  searchQuery: resolvedSearchQuery,
                                  sortOrder: currentSortOrder,
                                })}
                                prefetch={false}
                                scroll={false}
                                className="inline-flex h-8 min-w-8 items-center justify-center rounded-full transition-colors hover:bg-[#f4f7fc] hover:text-[#2f6df6]"
                              >
                                ‹
                              </Link>
                            ) : (
                              <span className="inline-flex h-8 min-w-8 items-center justify-center rounded-full text-[#c0cadb]">
                                ‹
                              </span>
                            )}

                      {paginationItems.map((item, index) =>
                        item === "ellipsis" ? (
                          <span key={`ellipsis-${index}`} className="px-1 text-[#a1aec5]">
                            …
                          </span>
                        ) : item === resolvedCurrentPage ? (
                          <span
                            key={item}
                            className="inline-flex h-8 min-w-8 items-center justify-center rounded-[9px] border border-[#b9d0ff] bg-[#ffffff] px-2 font-semibold text-[#2f6df6]"
                          >
                            {item}
                          </span>
                        ) : (
                          <Link
                            key={item}
                            href={pageHref(currentMailboxFolder, item, resolvedMessageFilter, {
                              pageSize: resolvedPageSize,
                              searchField: resolvedSearchField,
                              searchQuery: resolvedSearchQuery,
                              sortOrder: currentSortOrder,
                            })}
                            prefetch={false}
                            scroll={false}
                            className="inline-flex h-8 min-w-8 items-center justify-center rounded-[9px] px-2 transition-colors hover:bg-[#f4f7fc] hover:text-[#2f6df6]"
                          >
                            {item}
                          </Link>
                        ),
                      )}

                            {resolvedCurrentPage < totalPages ? (
                              <Link
                                href={pageHref(currentMailboxFolder, resolvedCurrentPage + 1, resolvedMessageFilter, {
                                  pageSize: resolvedPageSize,
                                  searchField: resolvedSearchField,
                                  searchQuery: resolvedSearchQuery,
                                  sortOrder: currentSortOrder,
                                })}
                                prefetch={false}
                                scroll={false}
                                className="inline-flex h-8 min-w-8 items-center justify-center rounded-full transition-colors hover:bg-[#f4f7fc] hover:text-[#2f6df6]"
                              >
                                ›
                              </Link>
                            ) : (
                              <span className="inline-flex h-8 min-w-8 items-center justify-center rounded-full text-[#c0cadb]">
                                ›
                              </span>
                            )}
                          </div>

                          {showPrimaryContentNavigationOverlay
                            ? renderContentNavigationOverlay(
                                "absolute inset-0 z-[120] flex items-center justify-center bg-[rgba(252,253,255,0.96)] transition-opacity duration-200",
                              )
                            : null}
                        </div>
                      </>
                    )}
                  </div>
                )}
              </section>

              {showSplitDetailPanel ? (
              <section
                className={`${
                  isSplitHorizontalMode
                    ? "relative hidden min-h-0 overflow-hidden xl:flex xl:flex-col"
                    : "relative min-h-0 flex flex-col overflow-hidden border-t border-[#e9eef8]"
                } bg-white`}
              >
                {renderMessageDetailContent({ standalone: false })}
                {showDetailContentNavigationOverlay ? renderContentNavigationOverlay() : null}
              </section>
              ) : null}
            </>
          )}
        </div>
      </div>

      {renderSidebarFolderMenuPortal()}
      {renderAttachmentPreviewModal()}

      {rawSourceModalOpen && previewMessage ? (
        <div className="fixed inset-0 z-[80] flex items-center justify-center bg-[rgba(15,23,42,0.42)] px-6 py-8">
          <button
            type="button"
            aria-label="메일 원본 보기 닫기"
            onClick={() => setRawSourceModalState({ open: false, scope: detailPanelScopeKey })}
            className="absolute inset-0 cursor-default"
          />
          <div className="relative z-[81] flex max-h-[min(88vh,960px)] w-full max-w-[1100px] flex-col overflow-hidden rounded-[24px] border border-[#dfe7f5] bg-white shadow-[0_30px_80px_rgba(15,23,42,0.24)]">
            <div className="flex items-center justify-between border-b border-[#edf2fb] px-7 py-5">
              <div>
                <p className="text-[18px] font-semibold text-[#1a2943]">메일 원본 보기</p>
                <p className="mt-1 text-[13px] text-[#72839f]">
                  {previewMessage.subject || "(제목 없음)"}
                </p>
              </div>
              <div className="flex items-center gap-2">
                <button
                  type="button"
                  onClick={() => {
                    void copyToClipboard(rawSourceText, "메일 원본을 복사했습니다.");
                  }}
                  className="om-btn-secondary h-10 rounded-[12px] px-4 text-[13px] text-[#344767]"
                >
                  복사
                </button>
                <CloseIconButton
                  ariaLabel="메일 원본 보기 닫기"
                  onClick={() => setRawSourceModalState({ open: false, scope: detailPanelScopeKey })}
                />
              </div>
            </div>
            <div className="min-h-0 flex-1 overflow-auto bg-[#f8fbff] px-7 py-6">
              <pre className="whitespace-pre-wrap break-all rounded-[18px] border border-[#e7eef9] bg-white p-5 text-[12px] leading-6 text-[#243555]">
                {rawSourceText || "표시할 메일 원본이 없습니다."}
              </pre>
            </div>
          </div>
        </div>
      ) : null}
    </div>
  );
}
