"use client"

import {
  useCallback,
  useEffect,
  useLayoutEffect,
  useMemo,
  useRef,
  useState,
  type ComponentType,
  type DragEvent,
  type ElementType,
  type MouseEvent,
  type ReactNode,
  type SVGProps,
} from "react"
import { Icon, addCollection } from "@iconify/react"
import { icons as mdiIcons } from "@iconify-json/mdi"
import { attachmentsForEmailList } from "@/lib/attachment-display"
import { resolveParsedCalendarInvitation } from "@/lib/resolve-email-calendar-invitation"
import { VIDEO_CONFERENCE_LOGOS } from "@/lib/calendar-invitation"
import { ensureVcLogosCollection } from "@/lib/register-vc-logos"
import { useEmailDrag } from "@/lib/drag-context"
import {
  Star,
  ChevronLeft,
  ChevronRight,
  MoreVertical,
  RefreshCw,
  ChevronDown,
  Tag,
  Users,
  Info,
  MessageSquare,
  Reply,
  ReplyAll,
  Forward,
  Paperclip,
  Archive,
  Trash2,
  Mail,
  MailOpen,
  Clock,
  ListTodo,
  FolderInput,
  VolumeX,
  Search,
  SquareArrowOutUpRight,
  File,
  Image as ImageIcon,
  ShieldAlert,
  ArrowLeft,
  Plus,
  Send,
  Pencil,
  CalendarClock,
  X,
  CheckSquare,
  Inbox as InboxIcon,
} from "lucide-react"
import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import { Input } from "@/components/ui/input"
import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuSeparator,
  ContextMenuSub,
  ContextMenuSubContent,
  ContextMenuSubTrigger,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip"
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
import {
  Empty,
  EmptyDescription,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
} from "@/components/ui/empty"
import { cn } from "@/lib/utils"
import {
  buildLabelTextToNavColorClass,
  MailLabelPillStrip,
} from "@/components/gmail/mail-label-pills"
import { emails, type Email, type EmailAttachment } from "@/lib/email-data"
import { useScheduledMail } from "@/lib/scheduled-mail-context"
import { useMailStore } from "@/lib/stores/mail-store"
import {
  emailMatchesFolder,
  type MailNavFolderMaps,
} from "@/lib/mail-folder-filter"
import { cleanSenderName, resolveSenderEmail } from "@/lib/sender-display"
import { getMailNavFolderLabel, type FolderTreeNode } from "@/lib/sidebar-nav-data"
import { mailNavVisitKey } from "@/lib/mail-folder-display"
import { MailFolderStackIndicator } from "@/components/gmail/mail-folder-stack-indicator"
import { useSidebarNav, registerNavEmailSync } from "@/lib/sidebar-nav-context"
import { ContactHoverCard } from "./contact-hover-card"
import { EmailLabelPickerBlock } from "@/components/gmail/email-label-picker-block"
import type { CatalogLabelPresence } from "@/components/gmail/email-label-picker-block"
import { MobileXsBulkSheets } from "@/components/gmail/mobile-xs-bulk-sheets"
import {
  useMoveTargets,
  type MoveTarget,
} from "@/components/gmail/move-to-menu-items"
import { EmailView } from "./email-view"
import { buildListMailIndex } from "./email-list-row"
import {
  useComposeActions,
  useComposeDrafts,
  type Contact,
} from "@/lib/compose-context"
import { computeFolderUnreadCounts } from "@/lib/mail-nav-metrics"
import {
  effectiveLabels,
  mergeEmailLabelEdits,
  mergeEmailNotSpam,
} from "@/lib/label-edits"
import type { LabelEditState } from "@/lib/stores/mail-store"
import type { MailRouteState } from "@/lib/mail-url"
import { readXsMatches, useIsXs } from "@/hooks/use-xs"

addCollection(mdiIcons)

const LIST_PAGE_SIZE = 50
const PULL_HOLD_HEIGHT = 48
const PULL_REFRESH_THRESHOLD = 56
const PULL_REFRESH_MAX = 112
const PULL_SNAP_BACK_TRANSITION =
  "transform 0.24s cubic-bezier(0.32, 0.72, 0, 1)"
const REFRESH_SPIN_CLASS = "animate-[spin_0.55s_linear_infinite]"
const PULL_ICON_FADE_MS = 120
/** Tirage (px) avant que le spinner ne devienne visible. */
const PULL_SPINNER_REVEAL_OFFSET = 26

function computePullOffset(delta: number): number {
  if (delta <= 0) return 0
  const damped = delta * 0.48
  const capped = Math.min(PULL_REFRESH_MAX, damped)
  const ratio = capped / PULL_REFRESH_MAX
  return capped * (1 - ratio * 0.12)
}

function computeSpinnerRevealProgress(y: number): number {
  if (y <= PULL_SPINNER_REVEAL_OFFSET) return 0
  const range = Math.max(1, PULL_REFRESH_THRESHOLD - PULL_SPINNER_REVEAL_OFFSET)
  return Math.min(1, ((y - PULL_SPINNER_REVEAL_OFFSET) / range) * 1.35)
}

/** Libellés système qu’on ne propose pas dans « Ajouter le libellé ». */
const LABEL_PICKER_EXCLUDE = new Set(["inbox", "sent", "drafts", "spam", "starred"])

function collectTreeLabels(nodes: FolderTreeNode[]): string[] {
  const out: string[] = []
  for (const n of nodes) {
    out.push(n.label)
    if (n.children?.length) out.push(...collectTreeLabels(n.children))
  }
  return out
}

function formatScheduledDateTimeDisplay(iso: string | undefined): string {
  if (!iso) return "—"
  const d = new Date(iso)
  if (Number.isNaN(d.getTime())) return "—"
  return d.toLocaleString("fr-FR", { dateStyle: "medium", timeStyle: "short" })
}

function scheduledIsoToDatetimeLocalValue(iso: string | undefined): string {
  if (!iso) return ""
  const d = new Date(iso)
  if (Number.isNaN(d.getTime())) return ""
  const p = (n: number) => String(n).padStart(2, "0")
  return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}T${p(d.getHours())}:${p(d.getMinutes())}`
}

function parseDatetimeLocalToIso(value: string): string | null {
  const d = new Date(value)
  if (Number.isNaN(d.getTime())) return null
  return d.toISOString()
}

/** Cibles du clic droit : sélection courante ou ligne seule ; en Planifié, seulement les ids réellement planifiés. */
function contextMenuTargetIdsForRow(
  emailId: string,
  selectedEmails: string[],
  selectedFolder: string,
  pool: Email[]
): string[] {
  const raw = selectedEmails.includes(emailId) ? selectedEmails : [emailId]
  if (selectedFolder !== "scheduled") return raw
  const onlyScheduled = raw.filter((id) =>
    pool.some((e) => e.id === id && e.labels?.includes("scheduled"))
  )
  return onlyScheduled.length > 0 ? onlyScheduled : [emailId]
}

function applyNavRenameToEdits(
  pool: Email[],
  prev: LabelEditState,
  from: string,
  to: string
): LabelEditState {
  const lcFrom = from.toLowerCase()
  const toTrim = to.trim()
  if (!toTrim) return prev
  const nextAdd = { ...prev.additions }
  const nextRem = { ...prev.removals }
  for (const e of pool) {
    const id = e.id
    const eff = effectiveLabels(e, prev.additions, prev.removals)
    if (!eff.some((l) => l.toLowerCase() === lcFrom)) continue
    const wanted = eff.map((l) => (l.toLowerCase() === lcFrom ? toTrim : l))
    delete nextAdd[id]
    delete nextRem[id]
    const base = e.labels ?? []
    const removals = base.filter(
      (b) => !wanted.some((w) => w.toLowerCase() === b.toLowerCase())
    )
    const additions = wanted.filter(
      (w) => !base.some((b) => b.toLowerCase() === w.toLowerCase())
    )
    if (removals.length) nextRem[id] = removals
    if (additions.length) nextAdd[id] = additions
  }
  return { additions: nextAdd, removals: nextRem }
}

function applyNavRemoveLabelToEdits(
  pool: Email[],
  prev: LabelEditState,
  label: string
): LabelEditState {
  const lc = label.toLowerCase()
  const nextAdd = { ...prev.additions }
  const nextRem = { ...prev.removals }
  for (const e of pool) {
    const id = e.id
    const eff = effectiveLabels(e, prev.additions, prev.removals)
    if (!eff.some((l) => l.toLowerCase() === lc)) continue
    const wanted = eff.filter((l) => l.toLowerCase() !== lc)
    delete nextAdd[id]
    delete nextRem[id]
    const base = e.labels ?? []
    const removals = base.filter(
      (b) => !wanted.some((w) => w.toLowerCase() === b.toLowerCase())
    )
    const additions = wanted.filter(
      (w) => !base.some((b) => b.toLowerCase() === w.toLowerCase())
    )
    if (removals.length) nextRem[id] = removals
    if (additions.length) nextAdd[id] = additions
  }
  return { additions: nextAdd, removals: nextRem }
}


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

function importantSignalIcon(isSpam: boolean, isImportant: boolean): string {
  if (isSpam) return "mdi:flag-outline"
  if (isImportant) return "mdi:label-variant"
  return "mdi:label-variant-outline"
}

type TabBadgeTone = "green" | "blue" | "orange" | "purple"

interface CategoryTab {
  id: string
  label: string
  icon: ElementType
  badgeTone?: TabBadgeTone
}

const categoryTabs: CategoryTab[] = [
  { id: "primary", label: "Principale", icon: Inbox, badgeTone: "blue" },
  {
    id: "promotions",
    label: "Promotions",
    icon: Tag,
    badgeTone: "green",
  },
  {
    id: "social",
    label: "Réseaux sociaux",
    icon: Users,
    badgeTone: "blue",
  },
  {
    id: "updates",
    label: "Notifications",
    icon: Info,
    badgeTone: "orange",
  },
  { id: "forums", label: "Forums", icon: MessageSquare, badgeTone: "purple" },
]

const CATEGORY_TAB_ICON_STROKE = 2.5

function categoryBadgeClass(tone: TabBadgeTone) {
  return cn(
    "shrink-0 rounded-full px-2 py-0.5 text-[11px] font-medium leading-none text-white",
    tone === "green" && "bg-[#1e8e3e]",
    tone === "blue" && "bg-[#0b57d0]",
    tone === "orange" && "bg-[#e8710a]",
    tone === "purple" && "bg-[#9334e6]"
  )
}

function categoryBadgeDotClass(tone: TabBadgeTone) {
  return cn(
    "absolute -right-0.5 -top-0.5 size-2 rounded-full ring-2 ring-white",
    tone === "green" && "bg-[#1e8e3e]",
    tone === "blue" && "bg-[#0b57d0]",
    tone === "orange" && "bg-[#e8710a]",
    tone === "purple" && "bg-[#9334e6]"
  )
}

function Inbox({ className, strokeWidth = CATEGORY_TAB_ICON_STROKE, ...props }: SVGProps<SVGSVGElement>) {
  return (
    <svg
      className={className}
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth={strokeWidth}
      strokeLinecap="round"
      strokeLinejoin="round"
      {...props}
    >
      <polyline points="22 12 16 12 14 15 10 15 8 12 2 12" />
      <path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" />
    </svg>
  )
}

function ListAttachmentChip({ att }: { att: EmailAttachment }) {
  return (
    <span className="inline-flex max-w-[min(100%,280px)] min-w-0 shrink items-center gap-1.5 rounded-full border border-[#dadce0] bg-transparent px-2.5 py-1 text-[13px] leading-snug text-[#3c4043]">
      {att.kind === "pdf" ? (
        <File className="size-4 shrink-0 fill-[#d93025]" strokeWidth={0} aria-hidden />
      ) : att.kind === "image" ? (
        <ImageIcon
          className="size-4 shrink-0 text-[#5f6368] [&_circle]:fill-none [&_path]:fill-none [&_path]:stroke-current [&_rect]:fill-current [&_rect]:opacity-[0.32]"
          strokeWidth={1.5}
          aria-hidden
        />
      ) : (
        <File className="size-4 shrink-0 fill-[#5f6368]" strokeWidth={0} aria-hidden />
      )}
      <span className="min-w-0 truncate">{att.name}</span>
    </span>
  )
}

function EmailListAttachmentRow({
  emailId,
  attachments,
}: {
  emailId: string
  attachments: EmailAttachment[]
}) {
  const containerRef = useRef<HTMLDivElement>(null)
  const measureRef = useRef<HTMLDivElement>(null)
  const [collapsed, setCollapsed] = useState(false)
  const attachSig = attachments.map((a) => `${a.name}\u0001${a.kind ?? ""}`).join("\u0002")

  const updateCollapsed = useCallback(() => {
    const container = containerRef.current
    const measure = measureRef.current
    if (!container || !measure || attachments.length <= 1) {
      setCollapsed(false)
      return
    }
    const available = container.clientWidth
    const needed = measure.scrollWidth
    setCollapsed(needed > available + 1)
  }, [attachSig, attachments.length])

  useLayoutEffect(() => {
    updateCollapsed()
  }, [updateCollapsed])

  useEffect(() => {
    const el = containerRef.current
    if (!el || typeof ResizeObserver === "undefined") return
    const ro = new ResizeObserver(() => updateCollapsed())
    ro.observe(el)
    return () => ro.disconnect()
  }, [updateCollapsed])

  const othersLabel =
    attachments.length - 1 === 1 ? "1 autre" : `${attachments.length - 1} autres`
  const othersTitle = attachments
    .slice(1)
    .map((a) => a.name)
    .join(", ")

  return (
    <div ref={containerRef} className="relative min-w-0 w-full">
      {attachments.length > 1 && (
        <div
          ref={measureRef}
          className="pointer-events-none invisible absolute left-0 top-0 z-[-1] flex w-max flex-nowrap gap-1.5"
          aria-hidden
        >
          {attachments.map((att, idx) => (
            <ListAttachmentChip key={`${emailId}-m-${idx}`} att={att} />
          ))}
        </div>
      )}
      <div className="flex min-w-0 flex-nowrap items-center gap-1.5 overflow-hidden">
        {collapsed && attachments.length > 1 ? (
          <>
            <ListAttachmentChip att={attachments[0]!} />
            <span
              className="shrink-0 rounded-full border border-[#dadce0] bg-[#f1f3f4] px-2.5 py-1 text-[13px] leading-snug text-[#5f6368]"
              title={othersTitle}
            >
              {othersLabel}
            </span>
          </>
        ) : (
          attachments.map((att, idx) => (
            <ListAttachmentChip key={`${emailId}-v-${idx}`} att={att} />
          ))
        )}
      </div>
    </div>
  )
}

function MoveToDropdownItems({
  targets,
  onMoveTo,
}: {
  targets: { recents: MoveTarget[]; system: MoveTarget[]; folders: MoveTarget[] }
  onMoveTo: (targetId: string) => void
}) {
  return (
    <>
      {targets.recents.length > 0 && (
        <>
          <div className="px-3 py-1.5 text-[11px] font-medium uppercase tracking-wide text-[#5f6368]">
            Récents
          </div>
          {targets.recents.map((t) => (
            <DropdownMenuItem key={`recent-${t.id}`} onSelect={() => onMoveTo(t.id)}>
              <span className="flex items-center gap-2">
                {t.icon}
                <Clock className="size-3 shrink-0 text-[#9aa0a6]" strokeWidth={1.5} />
              </span>
              {t.label}
            </DropdownMenuItem>
          ))}
          <DropdownMenuSeparator />
        </>
      )}
      {targets.system.map((t) => (
        <DropdownMenuItem key={t.id} onSelect={() => onMoveTo(t.id)}>
          {t.icon}
          {t.label}
        </DropdownMenuItem>
      ))}
      {targets.folders.length > 0 && (
        <>
          <DropdownMenuSeparator />
          <div className="px-3 py-1.5 text-[11px] font-medium uppercase tracking-wide text-[#5f6368]">
            Dossiers
          </div>
          {targets.folders.map((t) => (
            <DropdownMenuItem
              key={t.id}
              onSelect={() => onMoveTo(t.id)}
              style={{ paddingLeft: `${12 + t.depth * 16}px` }}
            >
              {t.icon}
              {t.label}
            </DropdownMenuItem>
          ))}
        </>
      )}
    </>
  )
}

function MoveToContextMenuItems({
  targets,
  onMoveTo,
}: {
  targets: { recents: MoveTarget[]; system: MoveTarget[]; folders: MoveTarget[] }
  onMoveTo: (targetId: string) => void
}) {
  return (
    <>
      {targets.recents.length > 0 && (
        <>
          <div className="px-3 py-1.5 text-[11px] font-medium uppercase tracking-wide text-[#5f6368]">
            Récents
          </div>
          {targets.recents.map((t) => (
            <ContextMenuItem key={`recent-${t.id}`} onSelect={() => onMoveTo(t.id)}>
              <span className="flex items-center gap-2">
                {t.icon}
                <Clock className="size-3 shrink-0 text-[#9aa0a6]" strokeWidth={1.5} />
              </span>
              {t.label}
            </ContextMenuItem>
          ))}
          <ContextMenuSeparator />
        </>
      )}
      {targets.system.map((t) => (
        <ContextMenuItem key={t.id} onSelect={() => onMoveTo(t.id)}>
          {t.icon}
          {t.label}
        </ContextMenuItem>
      ))}
      {targets.folders.length > 0 && (
        <>
          <ContextMenuSeparator />
          <div className="px-3 py-1.5 text-[11px] font-medium uppercase tracking-wide text-[#5f6368]">
            Dossiers
          </div>
          {targets.folders.map((t) => (
            <ContextMenuItem
              key={t.id}
              onSelect={() => onMoveTo(t.id)}
              style={{ paddingLeft: `${12 + t.depth * 16}px` }}
            >
              {t.icon}
              {t.label}
            </ContextMenuItem>
          ))}
        </>
      )}
    </>
  )
}

interface EmailListProps {
  selectedFolder: string
  /** Onglet catégories (boîte de réception), depuis l’URL. */
  inboxTab: string
  /** Page de liste (1-based), depuis l’URL. */
  listPage: number
  openMailId: string | null
  onMailRouteNavigate: (patch: Partial<MailRouteState>) => void
  onSelectFolder?: (folder: string) => void
  onFolderUnreadCountsChange?: (counts: Record<string, number>) => void
}

function listRowCheckboxClass(circular: boolean) {
  return cn(
    "size-4 min-h-4 min-w-4 shrink-0 border-[1.5px] border-[#c2c2c2] bg-transparent shadow-none dark:bg-transparent focus-visible:ring-[#c2c2c2]/30 data-[state=checked]:border-[#1a73e8] data-[state=checked]:bg-[#1a73e8] data-[state=checked]:text-white",
    circular ? "rounded-full" : "rounded-[2.5px]"
  )
}

function listRowQuickHoverTrayToneClass(isSelected: boolean, isRead: boolean) {
  return isSelected
    ? "bg-[#e8f0fe]"
    : isRead
      ? "bg-[#f5f5f5]"
      : "bg-white"
}

export function EmailList({
  selectedFolder,
  inboxTab,
  listPage,
  openMailId,
  onMailRouteNavigate,
  onSelectFolder,
  onFolderUnreadCountsChange,
}: EmailListProps) {
  const isViewMode = openMailId !== null

  const { savedThreadReplyDrafts } = useComposeDrafts()
  const {
    openComposeWithInitial,
    closeAllInlineComposes,
    pruneInlineComposesToOpenThread,
  } = useComposeActions()

  const {
    scheduledEmails,
    snoozedEmails,
    sentPlaceholderEmails,
    requestDeleteScheduled,
    requestArchiveScheduled,
    requestSnoozeScheduled,
    requestToggleReadScheduled,
    requestRescheduleScheduled,
    requestGetScheduledEditPayload,
    requestSendScheduledNow,
    requestSnoozeMailboxEmail,
    requestRestoreSnoozedToInbox,
  } = useScheduledMail()

  const allEmails = useMemo(
    () => [...emails, ...scheduledEmails, ...snoozedEmails, ...sentPlaceholderEmails],
    [scheduledEmails, snoozedEmails, sentPlaceholderEmails]
  )

  const sidebarNav = useSidebarNav()
  const navMaps = useMemo<MailNavFolderMaps>(
    () => ({
      folderIdToLabel: sidebarNav.folderIdToLabel,
      folderTree: sidebarNav.folderTree,
    }),
    [sidebarNav.folderIdToLabel, sidebarNav.folderTree]
  )

  const listRowLabelBgByTextLower = useMemo(
    () => buildLabelTextToNavColorClass(sidebarNav.folderTree, sidebarNav.labelRows),
    [sidebarNav.folderTree, sidebarNav.labelRows]
  )

  const [rescheduleTarget, setRescheduleTarget] = useState<{
    id: string
    value: string
    /** Faux pendant la fermeture du Popover : la barre d’actions reste visible (évite saut d’ancrage). */
    panelOpen: boolean
  } | null>(null)
  const rescheduleDismissTimeoutsRef = useRef<
    Map<string, ReturnType<typeof setTimeout>>
  >(new Map())

  const scheduleReschedulePopoverDismiss = useCallback((rowId: string) => {
    const existing = rescheduleDismissTimeoutsRef.current.get(rowId)
    if (existing) clearTimeout(existing)
    const t = setTimeout(() => {
      rescheduleDismissTimeoutsRef.current.delete(rowId)
      setRescheduleTarget((p) => (p?.id === rowId ? null : p))
    }, 280)
    rescheduleDismissTimeoutsRef.current.set(rowId, t)
  }, [])

  useEffect(() => {
    const m = rescheduleDismissTimeoutsRef.current
    return () => {
      for (const t of m.values()) clearTimeout(t)
      m.clear()
    }
  }, [])

  useEffect(() => {
    ensureVcLogosCollection()
  }, [])

  const [cmScheduledRescheduleValue, setCmScheduledRescheduleValue] =
    useState("")

  const handleEditScheduledMail = useCallback(
    async (id: string) => {
      const payload = await requestGetScheduledEditPayload(id)
      if (!payload) return
      openComposeWithInitial({
        to: payload.to,
        subject: payload.subject,
        bodyHtml: payload.bodyHtml,
        editingScheduledId: id,
        scheduledSendAtIso: payload.sendAtIso,
        focusToOnMount: false,
        focusBodyOnMount: true,
      })
    },
    [requestGetScheduledEditPayload, openComposeWithInitial]
  )

  useEffect(() => {
    if (!openMailId) {
      closeAllInlineComposes()
    } else {
      pruneInlineComposesToOpenThread(openMailId)
    }
  }, [
    openMailId,
    closeAllInlineComposes,
    pruneInlineComposesToOpenThread,
  ])

  const { beginDrag, registerOnDrop } = useEmailDrag()
  const starredEmails = useMailStore((s) => s.starredIds)
  const importantEmails = useMailStore((s) => s.importantIds)
  const [selectedEmails, setSelectedEmails] = useState<string[]>([])
  const readOverrides = useMailStore((s) => s.readOverrides)
  const labelEdits = useMailStore((s) => s.labelEdits)
  const mailActions = useRef(useMailStore.getState()).current
  const setReadOverrides = useCallback(
    (updater: (prev: Record<string, boolean>) => Record<string, boolean>) => {
      const current = useMailStore.getState().readOverrides
      const next = updater(current)
      if (next !== current) mailActions.setReadOverrides(next)
    },
    [mailActions]
  )
  const setLabelEdits = useCallback(
    (updater: (prev: LabelEditState) => LabelEditState) => {
      mailActions.setLabelEdits(updater)
    },
    [mailActions]
  )

  useEffect(() => {
    registerNavEmailSync({
      renameLabel: (from, to) => {
        setLabelEdits((prev) => applyNavRenameToEdits(allEmails, prev, from, to))
      },
      removeLabel: (label) => {
        setLabelEdits((prev) => applyNavRemoveLabelToEdits(allEmails, prev, label))
      },
    })
    return () => registerNavEmailSync(null)
  }, [allEmails])
  const [labelPickerQuery, setLabelPickerQuery] = useState("")
  const hiddenEmailIds = useMailStore((s) => s.hiddenEmailIds)
  const notSpamEmailIds = useMailStore((s) => s.notSpamEmailIds)
  const recentMoveTargets = useMailStore((s) => s.recentMoveTargets)
  const rowContextMenuOpenedAtRef = useRef(0)
  const contextMenuTargetIdsRef = useRef<string[]>([])
  const lastSelectionAnchorIdRef = useRef<string | null>(null)
  const [bulkSelectMenuOpen, setBulkSelectMenuOpen] = useState(false)
  const [isRefreshing, setIsRefreshing] = useState(false)
  const [mobileVisibleCount, setMobileVisibleCount] = useState(LIST_PAGE_SIZE)
  const [mobileSelectionMode, setMobileSelectionMode] = useState(false)
  const [mobileXsMoreMenuOpen, setMobileXsMoreMenuOpen] = useState(false)
  const [mobileXsMoveSheetOpen, setMobileXsMoveSheetOpen] = useState(false)
  const [mobileXsLabelSheetOpen, setMobileXsLabelSheetOpen] = useState(false)
  const isXs = useIsXs()

  const openMobileXsMoveSheet = useCallback(() => {
    setMobileXsMoreMenuOpen(false)
    window.setTimeout(() => setMobileXsMoveSheetOpen(true), 0)
  }, [])

  const handleMobileXsMoveSheetOpenChange = useCallback((open: boolean) => {
    setMobileXsMoveSheetOpen(open)
    if (!open) {
      setMobileSelectionMode(false)
      setSelectedEmails([])
    }
  }, [])

  const openMobileXsLabelSheet = useCallback(() => {
    setMobileXsMoreMenuOpen(false)
    window.setTimeout(() => setMobileXsLabelSheetOpen(true), 0)
  }, [])
  const listViewportRef = useRef<HTMLDivElement>(null)
  const pullContentRef = useRef<HTMLDivElement>(null)
  const pullIconRef = useRef<SVGSVGElement>(null)
  const pullTouchStartYRef = useRef(0)
  const pullActiveRef = useRef(false)
  const pullYRef = useRef(0)
  const pullRafRef = useRef<number | null>(null)
  const pendingPullYRef = useRef(0)
  const seenEmailIdsRaw = useMailStore((s) => s.seenEmailIds)
  const seenEmailIds = useMemo(() => new Set(seenEmailIdsRaw), [seenEmailIdsRaw])

  const markEmailSeen = useCallback((id: string) => {
    mailActions.markSeen(id)
  }, [mailActions])

  const folderFilterCtx = useMemo(
    () => ({
      starredEmailIds: starredEmails,
      importantEmailIds: importantEmails,
    }),
    [starredEmails, importantEmails]
  )

  const handleRefreshMessages = useCallback(async () => {
    if (isRefreshing) return
    setIsRefreshing(true)
    try {
      await new Promise((resolve) => setTimeout(resolve, 900))
    } finally {
      setIsRefreshing(false)
    }
  }, [isRefreshing])

  const applyPullVisual = useCallback((y: number, animate: boolean) => {
    const content = pullContentRef.current
    const icon = pullIconRef.current
    const transition = animate ? PULL_SNAP_BACK_TRANSITION : "none"
    if (content) {
      content.style.transition = transition
      content.style.transform = `translate3d(0, ${y}px, 0)`
    }
    if (icon) {
      if (y === 0) {
        icon.style.transition = animate
          ? `opacity ${PULL_ICON_FADE_MS}ms ease-out, transform ${PULL_ICON_FADE_MS}ms ease-out`
          : "none"
        icon.style.opacity = "0"
        icon.style.transform = "rotate(0deg)"
        icon.style.removeProperty("animation")
      } else {
        const progress = computeSpinnerRevealProgress(y)
        icon.style.transition = animate
          ? `opacity ${PULL_ICON_FADE_MS}ms ease-out, transform ${PULL_ICON_FADE_MS}ms ease-out`
          : "none"
        icon.style.opacity = String(progress)
        icon.style.transform = `rotate(${Math.min(320, progress * 320)}deg)`
      }
    }
  }, [])

  const schedulePullVisual = useCallback(
    (y: number) => {
      pendingPullYRef.current = y
      if (pullRafRef.current != null) return
      pullRafRef.current = requestAnimationFrame(() => {
        pullRafRef.current = null
        applyPullVisual(pendingPullYRef.current, false)
      })
    },
    [applyPullVisual]
  )

  const resetPullVisual = useCallback(
    (animate: boolean) => {
      if (pullRafRef.current != null) {
        cancelAnimationFrame(pullRafRef.current)
        pullRafRef.current = null
      }
      pullYRef.current = 0
      pendingPullYRef.current = 0
      applyPullVisual(0, animate)
    },
    [applyPullVisual]
  )

  const armPullRefreshSpinner = useCallback(() => {
    const icon = pullIconRef.current
    if (!icon) return
    icon.style.transition = "none"
    icon.style.opacity = "1"
    icon.style.removeProperty("transform")
    icon.style.animation = "spin 0.55s linear infinite"
  }, [])

  const releasePull = useCallback(async () => {
    if (pullRafRef.current != null) {
      cancelAnimationFrame(pullRafRef.current)
      pullRafRef.current = null
    }
    const offset = pullYRef.current
    if (offset >= PULL_REFRESH_THRESHOLD) {
      pullYRef.current = PULL_HOLD_HEIGHT
      applyPullVisual(PULL_HOLD_HEIGHT, false)
      armPullRefreshSpinner()
      void handleRefreshMessages()
      return
    }
    pullYRef.current = 0
    applyPullVisual(0, true)
  }, [applyPullVisual, armPullRefreshSpinner, handleRefreshMessages])

  useEffect(() => {
    if (isViewMode || !isXs || isRefreshing) return
    pullYRef.current = 0
    applyPullVisual(0, true)
  }, [isRefreshing, isViewMode, isXs, applyPullVisual])

  const filteredEmails = useMemo(() => {
    const hiddenSet = new Set(hiddenEmailIds)
    const subtreeIdsCache = new Map<string, string[] | null>()
    let visible = allEmails.filter((email) => !hiddenSet.has(email.id))
    const hasLabelEdits =
      labelEdits &&
      (Object.keys(labelEdits.additions).length > 0 ||
        Object.keys(labelEdits.removals).length > 0)
    if (hasLabelEdits || notSpamEmailIds.length > 0) {
      visible = visible.map((e) =>
        mergeEmailNotSpam(mergeEmailLabelEdits(e, labelEdits), notSpamEmailIds)
      )
    }
    let rows = visible.filter((email) =>
      emailMatchesFolder(
        email,
        selectedFolder,
        folderFilterCtx,
        navMaps,
        subtreeIdsCache
      )
    )
    if (selectedFolder === "inbox") {
      rows = rows.filter((email) => email.category === inboxTab)
    }
    return rows
  }, [
    selectedFolder,
    inboxTab,
    hiddenEmailIds,
    folderFilterCtx,
    labelEdits,
    notSpamEmailIds,
    allEmails,
    navMaps,
  ])

  const inboxCategoryTabLabel = useMemo(
    () => categoryTabs.find((t) => t.id === inboxTab)?.label ?? inboxTab,
    [inboxTab]
  )

  const mobileUnreadCount = useMemo(
    () => filteredEmails.filter((e) => !(readOverrides[e.id] ?? e.read)).length,
    [filteredEmails, readOverrides]
  )

  const mobileFolderLabel = useMemo(
    () =>
      selectedFolder === "inbox" && inboxTab !== "primary"
        ? inboxCategoryTabLabel
        : getMailNavFolderLabel(selectedFolder, sidebarNav.folderIdToLabel),
    [selectedFolder, inboxTab, inboxCategoryTabLabel, sidebarNav.folderIdToLabel]
  )

  useEffect(() => {
    setMobileSelectionMode(false)
    setSelectedEmails([])
  }, [selectedFolder, inboxTab])

  const totalPages = useMemo(
    () => Math.max(1, Math.ceil(filteredEmails.length / LIST_PAGE_SIZE)),
    [filteredEmails.length]
  )

  const pagedEmails = useMemo(() => {
    const start = (listPage - 1) * LIST_PAGE_SIZE
    return filteredEmails.slice(start, start + LIST_PAGE_SIZE)
  }, [filteredEmails, listPage])

  const listEmails = useMemo(() => {
    if (isXs && !isViewMode) {
      return filteredEmails.slice(0, mobileVisibleCount)
    }
    return pagedEmails
  }, [isXs, isViewMode, filteredEmails, mobileVisibleCount, pagedEmails])

  const listMailIndex = useMemo(() => buildListMailIndex(allEmails), [allEmails])

  const listRowExtras = useMemo(() => {
    const invitationById = new Map<
      string,
      ReturnType<typeof resolveParsedCalendarInvitation>
    >()
    const attachmentsById = new Map<string, EmailAttachment[]>()
    for (const e of listEmails) {
      invitationById.set(e.id, resolveParsedCalendarInvitation(e))
      attachmentsById.set(e.id, attachmentsForEmailList(e))
    }
    return { invitationById, attachmentsById }
  }, [listEmails])

  useEffect(() => {
    if (isXs) return
    if (listPage > totalPages) {
      onMailRouteNavigate({ page: totalPages })
    }
  }, [isXs, listPage, totalPages, onMailRouteNavigate])

  useEffect(() => {
    if (isXs && !isViewMode) return
    listViewportRef.current?.scrollTo(0, 0)
  }, [listPage, selectedFolder, inboxTab, isXs, isViewMode])

  useEffect(() => {
    if (!isXs) return
    setMobileVisibleCount(LIST_PAGE_SIZE)
    listViewportRef.current?.scrollTo(0, 0)
  }, [selectedFolder, inboxTab, isXs])

  useEffect(() => {
    const root = listViewportRef.current
    if (!root || !isXs || isViewMode) return

    const onScroll = () => {
      if (mobileVisibleCount >= filteredEmails.length) return
      const nearBottom =
        root.scrollTop + root.clientHeight >= root.scrollHeight - 120
      if (nearBottom) {
        setMobileVisibleCount((prev) =>
          Math.min(prev + LIST_PAGE_SIZE, filteredEmails.length)
        )
      }
    }

    root.addEventListener("scroll", onScroll, { passive: true })
    return () => root.removeEventListener("scroll", onScroll)
  }, [isXs, isViewMode, mobileVisibleCount, filteredEmails.length])

  useEffect(() => {
    const root = listViewportRef.current
    if (!root || !isXs || isViewMode) return

    const onTouchStart = (e: TouchEvent) => {
      if (root.scrollTop > 0 || isRefreshing) return
      pullActiveRef.current = true
      pullTouchStartYRef.current = e.touches[0]?.clientY ?? 0
    }

    const onTouchMove = (e: TouchEvent) => {
      if (!pullActiveRef.current || isRefreshing) return
      const y = e.touches[0]?.clientY ?? 0
      const delta = y - pullTouchStartYRef.current
      if (root.scrollTop > 0) {
        pullActiveRef.current = false
        resetPullVisual(true)
        return
      }
      if (delta <= 0) {
        resetPullVisual(true)
        return
      }
      e.preventDefault()
      const next = computePullOffset(delta)
      pullYRef.current = next
      schedulePullVisual(next)
    }

    const endPull = () => {
      if (!pullActiveRef.current) return
      pullActiveRef.current = false
      void releasePull()
    }

    root.addEventListener("touchstart", onTouchStart, { passive: true })
    root.addEventListener("touchmove", onTouchMove, { passive: false })
    root.addEventListener("touchend", endPull)
    root.addEventListener("touchcancel", endPull)
    return () => {
      if (pullRafRef.current != null) {
        cancelAnimationFrame(pullRafRef.current)
        pullRafRef.current = null
      }
      root.removeEventListener("touchstart", onTouchStart)
      root.removeEventListener("touchmove", onTouchMove)
      root.removeEventListener("touchend", endPull)
      root.removeEventListener("touchcancel", endPull)
    }
  }, [isXs, isViewMode, isRefreshing, releasePull, resetPullVisual, schedulePullVisual])

  const moveTargets = useMoveTargets({
    folderTree: sidebarNav.folderTree,
    recentMoveTargets,
    currentFolderId: selectedFolder,
  })

  const collectAllFolderLabels = useCallback((): Set<string> => {
    const s = new Set<string>()
    const walk = (nodes: FolderTreeNode[]) => {
      for (const n of nodes) {
        s.add(n.label.toLowerCase())
        if (n.children?.length) walk(n.children)
      }
    }
    walk(sidebarNav.folderTree)
    return s
  }, [sidebarNav.folderTree])

  const moveEmailsToTarget = useCallback(
    (emailIds: string[], targetId: string) => {
      if (emailIds.length === 0) return
      const folderLabel = sidebarNav.folderIdToLabel[targetId]
      const isSystemTarget = ["inbox", "sent", "drafts", "spam", "trash"].includes(targetId)
      const allFolderLabels = collectAllFolderLabels()

      setLabelEdits((prev) => {
        const nextAdd = { ...prev.additions }
        const nextRem = { ...prev.removals }

        for (const id of emailIds) {
          const email = allEmails.find((e) => e.id === id)
          const currentLabels = effectiveLabels(email, nextAdd, nextRem)

          if (isSystemTarget) {
            if (targetId === "inbox") {
              for (const lab of currentLabels) {
                if (allFolderLabels.has(lab.toLowerCase())) {
                  const cur = nextRem[id] ?? []
                  if (!cur.some((l) => l.toLowerCase() === lab.toLowerCase())) {
                    nextRem[id] = [...cur, lab]
                  }
                  if (nextAdd[id]?.length) {
                    nextAdd[id] = nextAdd[id].filter((l) => l.toLowerCase() !== lab.toLowerCase())
                    if (nextAdd[id].length === 0) delete nextAdd[id]
                  }
                }
              }
            }
          } else if (folderLabel) {
            for (const lab of currentLabels) {
              if (allFolderLabels.has(lab.toLowerCase()) && lab.toLowerCase() !== folderLabel.toLowerCase()) {
                const cur = nextRem[id] ?? []
                if (!cur.some((l) => l.toLowerCase() === lab.toLowerCase())) {
                  nextRem[id] = [...cur, lab]
                }
                if (nextAdd[id]?.length) {
                  nextAdd[id] = nextAdd[id].filter((l) => l.toLowerCase() !== lab.toLowerCase())
                  if (nextAdd[id].length === 0) delete nextAdd[id]
                }
              }
            }
            if (!currentLabels.some((l) => l.toLowerCase() === folderLabel.toLowerCase())) {
              nextAdd[id] = [...(nextAdd[id] ?? []), folderLabel]
            }
            if (nextRem[id]?.length) {
              nextRem[id] = nextRem[id].filter((l) => l.toLowerCase() !== folderLabel.toLowerCase())
              if (nextRem[id].length === 0) delete nextRem[id]
            }
            const inboxIdx = currentLabels.findIndex((l) => l.toLowerCase() === "inbox")
            if (inboxIdx >= 0 || !email?.labels?.length || email.labels.includes("inbox")) {
              const cur = nextRem[id] ?? []
              if (!cur.some((l) => l.toLowerCase() === "inbox")) {
                nextRem[id] = [...cur, "inbox"]
              }
            }
          }
        }
        return { additions: nextAdd, removals: nextRem }
      })

      if (!isSystemTarget || targetId === "inbox") {
        mailActions.pushRecentMoveTarget(targetId)
      }

      if (isSystemTarget && targetId !== "inbox") {
        mailActions.hideEmails(emailIds)
        mailActions.pushRecentMoveTarget(targetId)
      }
    },
    [allEmails, sidebarNav.folderIdToLabel, collectAllFolderLabels, setLabelEdits, mailActions]
  )

  const catalogLabels = useMemo(() => {
    const s = new Set<string>()
    for (const l of collectTreeLabels(sidebarNav.folderTree)) s.add(l)
    for (const row of sidebarNav.labelRows) s.add(row.label)
    for (const e of allEmails) {
      const eff = mergeEmailNotSpam(
        mergeEmailLabelEdits(e, labelEdits),
        notSpamEmailIds
      )
      for (const lab of eff.labels ?? []) {
        if (!LABEL_PICKER_EXCLUDE.has(lab)) s.add(lab)
      }
    }
    return [...s].sort((a, b) => a.localeCompare(b, "fr"))
  }, [sidebarNav.folderTree, sidebarNav.labelRows, allEmails, labelEdits, notSpamEmailIds])

  const resolveLabelCasing = useCallback(
    (raw: string) => {
      const t = raw.trim()
      if (!t) return ""
      const hit = catalogLabels.find((c) => c.toLowerCase() === t.toLowerCase())
      return hit ?? t
    },
    [catalogLabels]
  )

  const addLabelToEmails = useCallback(
    (ids: string[], label: string) => {
      const resolved = resolveLabelCasing(label)
      if (!resolved || ids.length === 0) return
      sidebarNav.ensureLabelRowForLabelText(resolved)
      setLabelEdits((prev) => {
        const nextAdd = { ...prev.additions }
        const nextRem = { ...prev.removals }
        for (const id of ids) {
          if (nextRem[id]?.length) {
            nextRem[id] = nextRem[id].filter(
              (x) => x.toLowerCase() !== resolved.toLowerCase()
            )
            if (nextRem[id].length === 0) delete nextRem[id]
          }
          const base = allEmails.find((e) => e.id === id)
          const merged = effectiveLabels(base, nextAdd, nextRem)
          if (merged.some((x) => x.toLowerCase() === resolved.toLowerCase())) {
            continue
          }
          nextAdd[id] = [...(nextAdd[id] ?? []), resolved]
        }
        return { additions: nextAdd, removals: nextRem }
      })
    },
    [resolveLabelCasing, allEmails, sidebarNav]
  )

  const getCatalogLabelPresence = useCallback(
    (ids: string[], catalogLabel: string): CatalogLabelPresence => {
      const resolved = resolveLabelCasing(catalogLabel)
      if (!resolved || ids.length === 0) return "none"
      const lc = resolved.toLowerCase()
      let n = 0
      for (const id of ids) {
        const e = allEmails.find((x) => x.id === id)
        const eff = effectiveLabels(e, labelEdits.additions, labelEdits.removals)
        if (eff.some((l) => l.toLowerCase() === lc)) n++
      }
      if (n === 0) return "none"
      if (n === ids.length) return "all"
      return "some"
    },
    [allEmails, labelEdits, resolveLabelCasing]
  )

  const toggleLabelOnEmails = useCallback(
    (ids: string[], label: string) => {
      const resolved = resolveLabelCasing(label)
      if (!resolved || ids.length === 0) return

      setLabelEdits((prev) => {
        const presence = (id: string) => {
          const e = allEmails.find((x) => x.id === id)
          if (!e) return false
          return effectiveLabels(e, prev.additions, prev.removals).some(
            (l) => l.toLowerCase() === resolved.toLowerCase()
          )
        }
        const allHave = ids.every((id) => presence(id))
        const nextAdd = { ...prev.additions }
        const nextRem = { ...prev.removals }

        if (allHave) {
          for (const id of ids) {
            if (nextAdd[id]?.length) {
              const filtered = nextAdd[id].filter(
                (l) => l.toLowerCase() !== resolved.toLowerCase()
              )
              if (filtered.length) nextAdd[id] = filtered
              else delete nextAdd[id]
            }
            const e = allEmails.find((x) => x.id === id)
            if (!e) continue
            const still = effectiveLabels(e, nextAdd, nextRem).some(
              (l) => l.toLowerCase() === resolved.toLowerCase()
            )
            if (still) {
              const cur = nextRem[id] ?? []
              if (!cur.some((l) => l.toLowerCase() === resolved.toLowerCase())) {
                nextRem[id] = [...cur, resolved]
              }
            } else if (nextRem[id]?.length) {
              const fr = nextRem[id].filter(
                (l) => l.toLowerCase() !== resolved.toLowerCase()
              )
              if (fr.length) nextRem[id] = fr
              else delete nextRem[id]
            }
          }
        } else {
          const anyMissing = ids.some((id) => !presence(id))
          if (anyMissing) {
            queueMicrotask(() => sidebarNav.ensureLabelRowForLabelText(resolved))
          }
          for (const id of ids) {
            const e = allEmails.find((x) => x.id === id)
            if (!e) continue
            const had = effectiveLabels(e, prev.additions, prev.removals).some(
              (l) => l.toLowerCase() === resolved.toLowerCase()
            )
            if (nextRem[id]?.length) {
              const fr = nextRem[id].filter(
                (l) => l.toLowerCase() !== resolved.toLowerCase()
              )
              if (fr.length) nextRem[id] = fr
              else delete nextRem[id]
            }
            if (!had) {
              if (!nextAdd[id]) nextAdd[id] = []
              if (!nextAdd[id].some((l) => l.toLowerCase() === resolved.toLowerCase())) {
                nextAdd[id] = [...nextAdd[id], resolved]
              }
            }
          }
        }
        return { additions: nextAdd, removals: nextRem }
      })
    },
    [allEmails, resolveLabelCasing, sidebarNav]
  )

  const folderUnreadCounts = useMemo(
    () =>
      computeFolderUnreadCounts(
        allEmails,
        folderFilterCtx,
        hiddenEmailIds,
        readOverrides,
        navMaps,
        labelEdits,
        notSpamEmailIds
      ),
    [
      folderFilterCtx,
      hiddenEmailIds,
      readOverrides,
      allEmails,
      navMaps,
      labelEdits,
      notSpamEmailIds,
    ]
  )

  const pageIds = useMemo(() => listEmails.map((e) => e.id), [listEmails])
  const selectedOnPageCount = useMemo(
    () => pageIds.filter((id) => selectedEmails.includes(id)).length,
    [pageIds, selectedEmails]
  )
  const allPageSelected = pageIds.length > 0 && selectedOnPageCount === pageIds.length
  const somePageSelected = selectedOnPageCount > 0 && !allPageSelected
  const selectAllChecked: boolean | "indeterminate" = allPageSelected
    ? true
    : somePageSelected
      ? "indeterminate"
      : false

  const toggleStar = (id: string) => {
    mailActions.toggleStar(id)
  }

  const toggleImportant = (id: string) => {
    mailActions.toggleImportant(id)
  }

  const toggleSelect = (id: string) => {
    setSelectedEmails(prev =>
      prev.includes(id) ? prev.filter(e => e !== id) : [...prev, id]
    )
  }

  const selectRangeInclusive = (fromId: string, toId: string) => {
    const ids = pageIds
    const i0 = ids.indexOf(fromId)
    const i1 = ids.indexOf(toId)
    if (i0 === -1 || i1 === -1) return
    const lo = Math.min(i0, i1)
    const hi = Math.max(i0, i1)
    const range = ids.slice(lo, hi + 1)
    setSelectedEmails((prev) => [...new Set([...prev, ...range])])
  }

  const handleSelectAllChange = (checked: boolean | "indeterminate") => {
    if (checked === true) {
      setSelectedEmails((prev) => [...new Set([...prev, ...pageIds])])
    } else {
      setSelectedEmails((prev) => prev.filter((id) => !pageIds.includes(id)))
    }
  }

  const mergePageSelection = (subsetOfPageIds: string[]) => {
    setSelectedEmails((prev) => {
      const outsidePage = prev.filter((id) => !pageIds.includes(id))
      return [...new Set([...outsidePage, ...subsetOfPageIds])]
    })
  }

  const effectiveRead = (email: Email) =>
    readOverrides[email.id] !== undefined ? readOverrides[email.id]! : email.read

  const seenSerialized = useMemo(
    () => [...seenEmailIds].sort().join(","),
    [seenEmailIds]
  )

  /** Onglets catégories : « nouveaux » + ligne d’expéditeurs = non vus (pas encore aperçus dans la liste), pas non lus. */
  const { unseenInTabById, tabUnseenSenderLineById } = useMemo(() => {
    const seen = new Set(
      seenSerialized.length > 0 ? seenSerialized.split(",") : []
    )
    const hidden = new Set(hiddenEmailIds)
    const visible = allEmails
      .filter((email) => !hidden.has(email.id))
      .map((e) =>
        mergeEmailNotSpam(mergeEmailLabelEdits(e, labelEdits), notSpamEmailIds)
      )
    const inboxPool = visible.filter((e) =>
      emailMatchesFolder(e, "inbox", folderFilterCtx, navMaps)
    )
    const counts: Record<string, number> = {}
    const preview: Record<string, string> = {}
    for (const tab of categoryTabs) {
      const rows = inboxPool.filter(
        (e) => e.category === tab.id && !seen.has(e.id)
      )
      counts[tab.id] = rows.length
      const chain: string[] = []
      const used = new Set<string>()
      for (const e of rows) {
        const n = cleanSenderName(e.sender).trim()
        if (!n || used.has(n)) continue
        used.add(n)
        chain.push(n)
        if (chain.length >= 6) break
      }
      preview[tab.id] = chain.join(", ")
    }
    return { unseenInTabById: counts, tabUnseenSenderLineById: preview }
  }, [folderFilterCtx, hiddenEmailIds, labelEdits, seenSerialized, allEmails, navMaps, notSpamEmailIds])

  const effectiveStarred = (email: Email) =>
    starredEmails.includes(email.id) || email.starred

  const selectMenuAll = () => mergePageSelection(pageIds)
  const selectMenuNone = () =>
    setSelectedEmails((prev) => prev.filter((id) => !pageIds.includes(id)))
  const selectMenuRead = () =>
    mergePageSelection(
      listEmails.filter((e) => effectiveRead(e)).map((e) => e.id)
    )
  const selectMenuUnread = () =>
    mergePageSelection(
      listEmails.filter((e) => !effectiveRead(e)).map((e) => e.id)
    )
  const selectMenuStarred = () =>
    mergePageSelection(
      listEmails.filter((e) => effectiveStarred(e)).map((e) => e.id)
    )
  const selectMenuUnstarred = () =>
    mergePageSelection(
      listEmails.filter((e) => !effectiveStarred(e)).map((e) => e.id)
    )

  const handleRowCheckboxClickCapture = (id: string, e: MouseEvent) => {
    if (e.shiftKey && lastSelectionAnchorIdRef.current != null) {
      e.preventDefault()
      e.stopPropagation()
      selectRangeInclusive(lastSelectionAnchorIdRef.current, id)
      lastSelectionAnchorIdRef.current = id
    }
  }

  const bulkTargetIds = useMemo(
    () => pageIds.filter((id) => selectedEmails.includes(id)),
    [pageIds, selectedEmails]
  )
  const hasUnreadInSelection = useMemo(() => {
    for (const id of bulkTargetIds) {
      const email = allEmails.find((e) => e.id === id)
      if (!email) continue
      const isRead =
        readOverrides[id] !== undefined ? readOverrides[id]! : email.read
      if (!isRead) return true
    }
    return false
  }, [bulkTargetIds, readOverrides, allEmails])
  const showBulkToolbar = bulkTargetIds.length > 0

  const clearBulkSelection = (ids: string[]) => {
    setSelectedEmails((prev) => prev.filter((id) => !ids.includes(id)))
  }

  const bulkHideFromList = (ids: string[]) => {
    if (ids.length === 0) return
    mailActions.hideEmails(ids)
    clearBulkSelection(ids)
  }

  const bulkArchive = () => bulkHideFromList(bulkTargetIds)
  const bulkDelete = () => bulkHideFromList(bulkTargetIds)
  const bulkSpam = () => bulkHideFromList(bulkTargetIds)

  const handleEmailsDroppedOnTarget = useCallback(
    (targetId: string, _targetLabel: string, ids: string[]) => {
      if (ids.length === 0) return
      moveEmailsToTarget(ids, targetId)
      setSelectedEmails((prev) => prev.filter((id) => !ids.includes(id)))
    },
    [moveEmailsToTarget]
  )

  useEffect(() => {
    return registerOnDrop(handleEmailsDroppedOnTarget)
  }, [registerOnDrop, handleEmailsDroppedOnTarget])

  const startRowDrag = useCallback(
    (rowId: string, e: DragEvent<HTMLDivElement>) => {
      if (isXs) return
      const inSelection = selectedEmails.includes(rowId)
      const ids =
        inSelection && bulkTargetIds.length > 0 ? bulkTargetIds : [rowId]
      if (e.dataTransfer) {
        e.dataTransfer.effectAllowed = "move"
        try {
          e.dataTransfer.setData("text/plain", ids.join(","))
        } catch {
          /* some browsers throw if called outside dragstart context */
        }
        const ghost = document.createElement("div")
        ghost.style.position = "fixed"
        ghost.style.top = "-1000px"
        ghost.style.left = "-1000px"
        ghost.style.width = "1px"
        ghost.style.height = "1px"
        ghost.style.opacity = "0"
        document.body.appendChild(ghost)
        e.dataTransfer.setDragImage(ghost, 0, 0)
        window.setTimeout(() => {
          if (ghost.parentNode) ghost.parentNode.removeChild(ghost)
        }, 0)
      }
      beginDrag(ids, selectedFolder, e.clientX, e.clientY)
    },
    [beginDrag, isXs, selectedEmails, bulkTargetIds, selectedFolder]
  )

  const bulkMarkRead = () => {
    if (bulkTargetIds.length === 0) return
    setReadOverrides((prev) => {
      const next = { ...prev }
      for (const id of bulkTargetIds) next[id] = true
      return next
    })
  }

  const bulkMarkUnread = () => {
    if (bulkTargetIds.length === 0) return
    setReadOverrides((prev) => {
      const next = { ...prev }
      for (const id of bulkTargetIds) next[id] = false
      return next
    })
  }

  const markAllInViewAsRead = useCallback(() => {
    setReadOverrides((prev) => {
      const next = { ...prev }
      for (const e of filteredEmails) next[e.id] = true
      return next
    })
  }, [filteredEmails])

  const bulkMoveTo = useCallback(
    (targetId: string) => {
      if (bulkTargetIds.length === 0) return
      moveEmailsToTarget(bulkTargetIds, targetId)
      if (targetId !== "inbox") {
        setSelectedEmails((prev) => prev.filter((id) => !bulkTargetIds.includes(id)))
      }
    },
    [bulkTargetIds, moveEmailsToTarget]
  )

  // --- View mode helpers ---
  const openEmail = useMemo(() => {
    if (!openMailId) return null
    const raw = allEmails.find((e) => e.id === openMailId) ?? null
    if (!raw) return null
    if (raw.labels?.includes("scheduled")) return null
    return mergeEmailNotSpam(mergeEmailLabelEdits(raw, labelEdits), notSpamEmailIds)
  }, [openMailId, labelEdits, allEmails, notSpamEmailIds])
  const openMailIndex = useMemo(
    () => (openMailId ? filteredEmails.findIndex((e) => e.id === openMailId) : -1),
    [openMailId, filteredEmails]
  )

  useEffect(() => {
    if (!openMailId) return
    markEmailSeen(openMailId)
    setReadOverrides((prev) =>
      prev[openMailId] !== undefined ? prev : { ...prev, [openMailId]: true }
    )
  }, [openMailId, markEmailSeen])

  const navigateToMail = useCallback(
    (id: string | null) => {
      onMailRouteNavigate({ mailId: id })
    },
    [onMailRouteNavigate]
  )

  useEffect(() => {
    if (!openMailId) return
    const raw = allEmails.find((e) => e.id === openMailId)
    if (raw?.labels?.includes("scheduled")) {
      navigateToMail(null)
    }
  }, [openMailId, allEmails, navigateToMail])

  const goBack = useCallback(() => navigateToMail(null), [navigateToMail])

  const closeViewIfShowingEmail = useCallback(
    (emailId: string) => {
      if (openMailId === emailId) goBack()
    },
    [openMailId, goBack]
  )

  const restoreSnoozedRowToMailbox = useCallback(
    (emailRow: Email) => {
      void requestRestoreSnoozedToInbox(emailRow)
      if (emailRow.id.startsWith("snz-")) {
        const baseId = emailRow.id.slice(4)
        if (baseId.length > 0) mailActions.unhideEmail(baseId)
        onSelectFolder?.("inbox")
      } else {
        onSelectFolder?.("scheduled")
      }
      closeViewIfShowingEmail(emailRow.id)
    },
    [
      requestRestoreSnoozedToInbox,
      mailActions,
      closeViewIfShowingEmail,
      onSelectFolder,
    ]
  )

  const handleCategoryInboxTabClick = useCallback(
    (tabId: string) => {
      onMailRouteNavigate({
        inboxTab: tabId,
        page: 1,
        mailId: null,
      })
    },
    [onMailRouteNavigate]
  )

  const goListPrevPage = useCallback(() => {
    if (listPage <= 1) return
    onMailRouteNavigate({ page: listPage - 1 })
  }, [listPage, onMailRouteNavigate])

  const goListNextPage = useCallback(() => {
    if (listPage >= totalPages) return
    onMailRouteNavigate({ page: listPage + 1 })
  }, [listPage, totalPages, onMailRouteNavigate])

  const goToPrev = useCallback(() => {
    if (openMailIndex > 0) {
      const id = filteredEmails[openMailIndex - 1]!.id
      markEmailSeen(id)
      setReadOverrides((prev) => ({ ...prev, [id]: true }))
      navigateToMail(id)
    }
  }, [openMailIndex, filteredEmails, navigateToMail, markEmailSeen])

  const goToNext = useCallback(() => {
    if (openMailIndex >= 0 && openMailIndex < filteredEmails.length - 1) {
      const id = filteredEmails[openMailIndex + 1]!.id
      markEmailSeen(id)
      setReadOverrides((prev) => ({ ...prev, [id]: true }))
      navigateToMail(id)
    }
  }, [openMailIndex, filteredEmails, navigateToMail, markEmailSeen])

  const handleOpenEmail = useCallback(
    (id: string) => {
      const em = allEmails.find((e) => e.id === id)
      if (em?.labels?.includes("scheduled")) return
      markEmailSeen(id)
      setReadOverrides((prev) => ({ ...prev, [id]: true }))
      navigateToMail(id)
    },
    [navigateToMail, markEmailSeen, allEmails]
  )

  const openDraftInCompose = useCallback(
    (email: Email) => {
      markEmailSeen(email.id)
      setReadOverrides((prev) => ({ ...prev, [email.id]: true }))
      const to: Contact[] = email.senderEmail
        ? [{ name: email.sender.trim(), email: email.senderEmail }]
        : []
      const body =
        email.body ??
        (email.preview
          ? `<p style="color:#5f6368">${escapeHtml(email.preview)}</p>`
          : "<p></p>")
      openComposeWithInitial({
        to,
        subject: email.subject,
        bodyHtml: body,
        focusToOnMount: false,
        focusBodyOnMount: true,
      })
    },
    [markEmailSeen, openComposeWithInitial]
  )

  const handleRowActivate = useCallback(
    (email: Email) => {
      if (email.labels?.includes("scheduled")) return
      if (email.labels?.includes("drafts")) {
        openDraftInCompose(email)
        return
      }
      handleOpenEmail(email.id)
    },
    [handleOpenEmail, openDraftInCompose]
  )

  const viewModeIsRead = useMemo(() => {
    if (!openEmail) return true
    return readOverrides[openEmail.id] !== undefined
      ? readOverrides[openEmail.id]!
      : openEmail.read
  }, [openEmail, readOverrides])

  const singleArchive = useCallback(() => {
    if (!openMailId) return
    mailActions.hideEmail(openMailId)
    goBack()
  }, [openMailId, goBack, mailActions])

  const singleDelete = useCallback(() => {
    if (!openMailId) return
    mailActions.hideEmail(openMailId)
    goBack()
  }, [openMailId, goBack, mailActions])

  const singleSpam = useCallback(() => {
    if (!openMailId) return
    mailActions.hideEmail(openMailId)
    goBack()
  }, [openMailId, goBack, mailActions])

  const singleNotSpam = useCallback(() => {
    if (!openMailId) return
    mailActions.markNotSpam(openMailId)
    onSelectFolder?.("inbox")
    goBack()
  }, [openMailId, goBack, onSelectFolder, mailActions])

  const singleToggleRead = useCallback(() => {
    if (!openMailId) return
    setReadOverrides((prev) => ({ ...prev, [openMailId]: !viewModeIsRead }))
  }, [openMailId, viewModeIsRead])

  const singleMoveTo = useCallback(
    (targetId: string) => {
      if (!openMailId) return
      moveEmailsToTarget([openMailId], targetId)
      const isSystemHide = ["sent", "drafts", "spam", "trash"].includes(targetId)
      if (isSystemHide || targetId !== "inbox") {
        goBack()
      }
    },
    [openMailId, goBack, moveEmailsToTarget]
  )

  const handleNavigateToLabel = useCallback(
    (label: string) => {
      const folderId =
        sidebarNav.emailLabelToSidebarFolderId[label] ?? label
      onSelectFolder?.(folderId)
    },
    [onSelectFolder, sidebarNav.emailLabelToSidebarFolderId]
  )

  useEffect(() => {
    onFolderUnreadCountsChange?.(folderUnreadCounts)
  }, [folderUnreadCounts, onFolderUnreadCountsChange])

  const listRowsDep = listEmails.map((e) => e.id).join(",")
  useEffect(() => {
    const root = listViewportRef.current
    if (!root) return
    const obs = new IntersectionObserver(
      (entries) => {
        for (const en of entries) {
          if (!en.isIntersecting) continue
          const id = (en.target as HTMLElement).dataset.emailRowId
          if (id) markEmailSeen(id)
        }
      },
      { root, threshold: 0.12, rootMargin: "0px" }
    )
    root.querySelectorAll<HTMLElement>("[data-email-row-id]").forEach((el) => {
      obs.observe(el)
    })
    return () => obs.disconnect()
  }, [listRowsDep, markEmailSeen])

  // --- keyboard shortcuts for view mode ---
  useEffect(() => {
    if (!isViewMode) return
    const handler = (e: KeyboardEvent) => {
      if (e.key === "Escape") { goBack(); return }
      if (e.key === "ArrowLeft" || e.key === "k") { goToPrev(); return }
      if (e.key === "ArrowRight" || e.key === "j") { goToNext(); return }
    }
    window.addEventListener("keydown", handler)
    return () => window.removeEventListener("keydown", handler)
  }, [isViewMode, goBack, goToPrev, goToNext])

  const dropdownSurfaceClass =
    "min-w-[220px] rounded-lg border border-[#dadce0] bg-white p-0 py-1 text-[#3c4043] shadow-lg [&_[data-slot=dropdown-menu-item]]:gap-3 [&_[data-slot=dropdown-menu-item]]:rounded-none [&_[data-slot=dropdown-menu-item]]:px-3 [&_[data-slot=dropdown-menu-item]]:py-2 [&_[data-slot=dropdown-menu-item]]:text-sm [&_[data-slot=dropdown-menu-item]:focus]:bg-[#f1f3f4] [&_[data-slot=dropdown-menu-sub-trigger]]:gap-3 [&_[data-slot=dropdown-menu-sub-trigger]]:rounded-none [&_[data-slot=dropdown-menu-sub-trigger]]:px-3 [&_[data-slot=dropdown-menu-sub-trigger]]:py-2 [&_[data-slot=dropdown-menu-sub-trigger]]:text-sm [&_[data-slot=dropdown-menu-sub-trigger]:focus]:bg-[#f1f3f4] [&_[data-slot=dropdown-menu-sub-content]]:min-w-[200px] [&_[data-slot=dropdown-menu-sub-content]]:rounded-lg [&_[data-slot=dropdown-menu-sub-content]]:border [&_[data-slot=dropdown-menu-sub-content]]:border-[#dadce0] [&_[data-slot=dropdown-menu-sub-content]]:bg-white [&_[data-slot=dropdown-menu-sub-content]]:p-0 [&_[data-slot=dropdown-menu-sub-content]]:py-1 [&_[data-slot=dropdown-menu-sub-content]]:shadow-lg [&_[data-slot=dropdown-menu-separator]]:mx-0 [&_[data-slot=dropdown-menu-separator]]:my-1 [&_[data-slot=dropdown-menu-separator]]:bg-[#eceff1]"

  const mainScrollClass =
    "min-h-0 flex-1 overflow-y-auto overflow-x-hidden rounded-b-2xl border-0 bg-white shadow-none outline-none " +
    "[scrollbar-color:#9aa0a6_#ffffff] [scrollbar-width:auto] " +
    "[&::-webkit-scrollbar]:w-2.5 [&::-webkit-scrollbar]:border-0 [&::-webkit-scrollbar]:bg-white " +
    "[&::-webkit-scrollbar-track]:border-0 [&::-webkit-scrollbar-track]:bg-white [&::-webkit-scrollbar-track]:shadow-none " +
    "[&::-webkit-scrollbar-thumb]:rounded-none [&::-webkit-scrollbar-thumb]:border-0 [&::-webkit-scrollbar-thumb]:shadow-none " +
    "[&::-webkit-scrollbar-thumb]:bg-[#9aa0a6] hover:[&::-webkit-scrollbar-thumb]:bg-[#5f6368] " +
    "[&::-webkit-scrollbar-corner]:border-0 [&::-webkit-scrollbar-corner]:bg-white"

  return (
    <div className="flex h-full min-h-0 flex-1 flex-col">
      {/* Mobile xs top bar */}
      {!isViewMode && (
        <div className="relative z-20 flex shrink-0 items-center gap-2 border-b border-gray-200 bg-white px-4 py-2.5 sm:hidden">
          <div className="min-w-0 flex-1">
            <h1 className="truncate text-base font-semibold text-[#1f1f1f] leading-tight">
              {mobileFolderLabel}
            </h1>
            <p className="text-xs text-[#5f6368] leading-snug">
              {filteredEmails.length} message{filteredEmails.length !== 1 ? "s" : ""}
              {mobileUnreadCount > 0 && ` · ${mobileUnreadCount} non lu${mobileUnreadCount !== 1 ? "s" : ""}`}
            </p>
          </div>
          <Button
            type="button"
            variant="ghost"
            size={mobileSelectionMode ? "icon" : "sm"}
            className={cn(
              "shrink-0 text-[#444746]",
              mobileSelectionMode
                ? "size-9 rounded-full border border-gray-200 bg-white/80 shadow-md backdrop-blur"
                : "h-9 min-h-9 gap-1.5 rounded-full border border-gray-200 bg-white/80 px-3 text-xs font-medium shadow-md backdrop-blur"
            )}
            onClick={() => {
              setMobileSelectionMode((p) => !p)
              if (mobileSelectionMode) setSelectedEmails([])
            }}
            aria-label={mobileSelectionMode ? "Annuler la sélection" : "Sélection"}
          >
            {mobileSelectionMode ? (
              <X className="size-[18px]" strokeWidth={1.5} />
            ) : (
              <>
                <CheckSquare className="size-4" strokeWidth={1.5} />
                <span>Sélection</span>
              </>
            )}
          </Button>
          <DropdownMenu
            open={mobileXsMoreMenuOpen}
            onOpenChange={setMobileXsMoreMenuOpen}
          >
            <DropdownMenuTrigger asChild>
              <Button
                type="button"
                variant="ghost"
                size="icon"
                className="size-9 shrink-0 rounded-full border border-gray-200 bg-white/80 text-[#444746] shadow-md backdrop-blur"
                aria-label="Plus d'actions"
              >
                <MoreVertical className="size-[18px]" strokeWidth={1.5} />
              </Button>
            </DropdownMenuTrigger>
            <DropdownMenuContent
              align="end"
              sideOffset={4}
              className={cn(dropdownSurfaceClass, "min-w-[260px]")}
            >
              {showBulkToolbar ? (
                <>
                  <DropdownMenuItem onSelect={bulkArchive}>
                    <Archive className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
                    Archiver
                  </DropdownMenuItem>
                  <DropdownMenuItem onSelect={bulkDelete}>
                    <Trash2 className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
                    Supprimer
                  </DropdownMenuItem>
                  <DropdownMenuItem onSelect={bulkSpam}>
                    <ShieldAlert className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
                    Signaler comme spam
                  </DropdownMenuItem>
                  <DropdownMenuItem
                    onSelect={hasUnreadInSelection ? bulkMarkRead : bulkMarkUnread}
                  >
                    {hasUnreadInSelection ? (
                      <>
                        <MailOpen className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
                        Marquer comme lu
                      </>
                    ) : (
                      <>
                        <Mail className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
                        Marquer comme non lu
                      </>
                    )}
                  </DropdownMenuItem>
                  <DropdownMenuSeparator />
                  <DropdownMenuItem
                    onSelect={(e) => {
                      e.preventDefault()
                      openMobileXsMoveSheet()
                    }}
                  >
                    <FolderInput className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
                    <span className="flex-1">Déplacer vers</span>
                    <ChevronRight className="ml-auto size-4 text-[#5f6368]" strokeWidth={1.5} />
                  </DropdownMenuItem>
                  <DropdownMenuItem
                    onSelect={(e) => {
                      e.preventDefault()
                      openMobileXsLabelSheet()
                    }}
                  >
                    <Tag className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
                    <span className="flex-1">Ajouter le libellé</span>
                    <ChevronRight className="ml-auto size-4 text-[#5f6368]" strokeWidth={1.5} />
                  </DropdownMenuItem>
                  <DropdownMenuItem>
                    <VolumeX className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
                    Ignorer la conversation
                  </DropdownMenuItem>
                </>
              ) : (
                <>
                  <DropdownMenuItem onSelect={markAllInViewAsRead}>
                    <MailOpen className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
                    Tout marquer comme lu
                  </DropdownMenuItem>
                  <DropdownMenuSeparator />
                  <div
                    className="px-3 py-2 text-sm leading-snug text-[#5f6368] select-none"
                    role="note"
                  >
                    Sélectionnez des messages pour plus d&apos;actions
                  </div>
                </>
              )}
            </DropdownMenuContent>
          </DropdownMenu>
          <MobileXsBulkSheets
            moveSheetOpen={mobileXsMoveSheetOpen}
            onMoveSheetOpenChange={handleMobileXsMoveSheetOpenChange}
            labelSheetOpen={mobileXsLabelSheetOpen}
            onLabelSheetOpenChange={setMobileXsLabelSheetOpen}
            labelPickerQuery={labelPickerQuery}
            onLabelPickerQueryChange={setLabelPickerQuery}
            catalogLabels={catalogLabels}
            moveTargets={moveTargets}
            onMoveTo={bulkMoveTo}
            getLabelPresence={(lab) => getCatalogLabelPresence(bulkTargetIds, lab)}
            onToggleCatalogLabel={(lab) => toggleLabelOnEmails(bulkTargetIds, lab)}
            onCreateLabel={(lab) => {
              addLabelToEmails(bulkTargetIds, lab)
              setLabelPickerQuery("")
            }}
          />
        </div>
      )}

      {/* Toolbar — relative: scroll lives in sibling below */}
      <div
        className={cn(
          "relative z-20 flex shrink-0 min-h-12 gap-2 rounded-t-2xl border-b border-gray-200 bg-white py-1.5 pl-2 pr-4",
          isViewMode ? "items-start" : "items-center",
          !isViewMode && "max-sm:hidden"
        )}
      >

        {isViewMode ? (
          /* ── VIEW MODE TOOLBAR ── */
          <TooltipProvider delayDuration={400}>
            <Tooltip>
              <TooltipTrigger asChild>
                <Button
                  type="button"
                  variant="ghost"
                  size="icon"
                  className="h-9 w-9 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                  aria-label="Retour à la boîte de réception"
                  onClick={goBack}
                >
                  <ArrowLeft className="h-[18px] w-[18px]" strokeWidth={1.5} />
                </Button>
              </TooltipTrigger>
              <TooltipContent side="bottom" className="text-xs">
                Retour à la boîte de réception
              </TooltipContent>
            </Tooltip>

            <div className="flex min-w-0 flex-wrap items-center gap-0.5 pl-1">
              {openEmail?.spam === true ? (
                <>
                  <div className="flex min-w-0 shrink-0 flex-wrap items-center gap-0.5">
                    <Button
                      type="button"
                      variant="ghost"
                      size="sm"
                      className="h-9 shrink-0 px-2.5 text-sm font-medium text-[#444746] hover:bg-[#f1f3f4]"
                      onClick={singleDelete}
                    >
                      Supprimer définitivement
                    </Button>
                    <Button
                      type="button"
                      variant="ghost"
                      size="sm"
                      className="h-9 shrink-0 px-2.5 text-sm font-medium text-[#444746] hover:bg-[#f1f3f4]"
                      onClick={singleNotSpam}
                    >
                      Non-spam
                    </Button>
                  </div>

                  <span className="mx-1 h-6 w-px shrink-0 bg-[#dadce0]" aria-hidden />

                  <div className="flex shrink-0 items-center gap-0.5">
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="icon"
                          className="h-9 w-9 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                          aria-label="Archiver"
                          onClick={singleArchive}
                        >
                          <Archive className="h-[18px] w-[18px]" strokeWidth={1.5} />
                        </Button>
                      </TooltipTrigger>
                      <TooltipContent side="bottom" className="text-xs">Archiver</TooltipContent>
                    </Tooltip>
                  </div>

                  <span className="mx-1 h-6 w-px shrink-0 bg-[#dadce0]" aria-hidden />

                  <div className="flex min-w-0 shrink-0 items-center gap-0.5">
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="icon"
                          className="h-9 w-9 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                          aria-label={viewModeIsRead ? "Marquer comme non lu" : "Marquer comme lu"}
                          onClick={singleToggleRead}
                        >
                          {viewModeIsRead ? (
                            <Mail className="h-[18px] w-[18px]" strokeWidth={1.5} />
                          ) : (
                            <MailOpen className="h-[18px] w-[18px]" strokeWidth={1.5} />
                          )}
                        </Button>
                      </TooltipTrigger>
                      <TooltipContent side="bottom" className="text-xs">
                        {viewModeIsRead ? "Marquer comme non lu" : "Marquer comme lu"}
                      </TooltipContent>
                    </Tooltip>

                    <DropdownMenu>
                      <DropdownMenuTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="sm"
                          className="h-9 w-9 shrink-0 gap-1 px-0 text-[#444746] hover:bg-[#f1f3f4] lg:h-9 lg:w-auto lg:px-2"
                          aria-label="Déplacer vers"
                        >
                          <FolderInput className="h-[18px] w-[18px] shrink-0" strokeWidth={1.5} />
                          <span className="hidden max-w-32 truncate lg:inline">
                            Déplacer vers
                          </span>
                          <ChevronDown className="hidden h-3.5 w-3.5 shrink-0 opacity-70 lg:block" />
                        </Button>
                      </DropdownMenuTrigger>
                      <DropdownMenuContent align="start" className={cn(dropdownSurfaceClass, "max-h-80 overflow-y-auto")}>
                        <MoveToDropdownItems targets={moveTargets} onMoveTo={singleMoveTo} />
                      </DropdownMenuContent>
                    </DropdownMenu>
                  </div>
                </>
              ) : (
                <>
                  <div className="flex shrink-0 items-center gap-0.5">
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="icon"
                          className="h-9 w-9 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                          aria-label="Archiver"
                          onClick={singleArchive}
                        >
                          <Archive className="h-[18px] w-[18px]" strokeWidth={1.5} />
                        </Button>
                      </TooltipTrigger>
                      <TooltipContent side="bottom" className="text-xs">Archiver</TooltipContent>
                    </Tooltip>
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="icon"
                          className="h-9 w-9 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                          aria-label="Signaler comme spam"
                          onClick={singleSpam}
                        >
                          <ShieldAlert className="h-[18px] w-[18px]" strokeWidth={1.5} />
                        </Button>
                      </TooltipTrigger>
                      <TooltipContent side="bottom" className="text-xs">Signaler comme spam</TooltipContent>
                    </Tooltip>
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="icon"
                          className="h-9 w-9 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                          aria-label="Supprimer"
                          onClick={singleDelete}
                        >
                          <Trash2 className="h-[18px] w-[18px]" strokeWidth={1.5} />
                        </Button>
                      </TooltipTrigger>
                      <TooltipContent side="bottom" className="text-xs">Supprimer</TooltipContent>
                    </Tooltip>
                  </div>

                  <span className="mx-1 h-6 w-px shrink-0 bg-[#dadce0]" aria-hidden />

                  <div className="flex min-w-0 shrink-0 items-center gap-0.5">
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="icon"
                          className="h-9 w-9 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                          aria-label={viewModeIsRead ? "Marquer comme non lu" : "Marquer comme lu"}
                          onClick={singleToggleRead}
                        >
                          {viewModeIsRead ? (
                            <Mail className="h-[18px] w-[18px]" strokeWidth={1.5} />
                          ) : (
                            <MailOpen className="h-[18px] w-[18px]" strokeWidth={1.5} />
                          )}
                        </Button>
                      </TooltipTrigger>
                      <TooltipContent side="bottom" className="text-xs">
                        {viewModeIsRead ? "Marquer comme non lu" : "Marquer comme lu"}
                      </TooltipContent>
                    </Tooltip>

                    <DropdownMenu>
                      <DropdownMenuTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="sm"
                          className="h-9 w-9 shrink-0 gap-1 px-0 text-[#444746] hover:bg-[#f1f3f4] lg:h-9 lg:w-auto lg:px-2"
                          aria-label="Déplacer vers"
                        >
                          <FolderInput className="h-[18px] w-[18px] shrink-0" strokeWidth={1.5} />
                          <span className="hidden max-w-32 truncate lg:inline">
                            Déplacer vers
                          </span>
                          <ChevronDown className="hidden h-3.5 w-3.5 shrink-0 opacity-70 lg:block" />
                        </Button>
                      </DropdownMenuTrigger>
                      <DropdownMenuContent align="start" className={cn(dropdownSurfaceClass, "max-h-80 overflow-y-auto")}>
                        <MoveToDropdownItems targets={moveTargets} onMoveTo={singleMoveTo} />
                      </DropdownMenuContent>
                    </DropdownMenu>
                  </div>
                </>
              )}
            </div>
          </TooltipProvider>
        ) : (
          /* ── LIST MODE TOOLBAR (original) ── */
          <>
            <DropdownMenu
              open={bulkSelectMenuOpen}
              onOpenChange={setBulkSelectMenuOpen}
            >
              <div
                className={cn(
                  "flex items-center overflow-hidden rounded-md border pr-0 transition-[background-color,box-shadow,border-color]",
                  bulkSelectMenuOpen
                    ? "border-[#dadce0] bg-[#f1f3f4] shadow-sm"
                    : "border-transparent"
                )}
              >
                <div className="flex h-9 shrink-0 items-center pl-1 pr-0.5 md:pl-0">
                  <Checkbox
                    checked={selectAllChecked}
                    onCheckedChange={handleSelectAllChange}
                    className="size-4 min-h-4 min-w-4 shrink-0 rounded-[2.5px] border-[1.5px] border-[#c2c2c2] bg-white shadow-none dark:bg-white focus-visible:ring-[#c2c2c2]/30 data-[state=checked]:border-[#1a73e8] data-[state=checked]:bg-[#1a73e8] data-[state=checked]:text-white data-[state=indeterminate]:border-[#1a73e8] data-[state=indeterminate]:bg-[#1a73e8] data-[state=indeterminate]:text-white"
                  />
                </div>
                <DropdownMenuTrigger asChild>
                  <Button
                    type="button"
                    variant="ghost"
                    size="icon"
                    className={cn(
                      "h-9 w-7 shrink-0 rounded-none p-0 text-[#5f6368]",
                      bulkSelectMenuOpen
                        ? "border-l border-[#dadce0] hover:bg-[#e8eaed]"
                        : "hover:bg-[#f1f3f4]"
                    )}
                    aria-label="Options de sélection"
                  >
                    <ChevronDown className="h-4 w-4" />
                  </Button>
                </DropdownMenuTrigger>
              </div>
              <DropdownMenuContent
                align="start"
                sideOffset={4}
                className={cn(dropdownSurfaceClass, "min-w-[180px]")}
              >
                <DropdownMenuItem onSelect={selectMenuAll}>Tous</DropdownMenuItem>
                <DropdownMenuItem onSelect={selectMenuNone}>Aucun</DropdownMenuItem>
                <DropdownMenuItem onSelect={selectMenuRead}>Lus</DropdownMenuItem>
                <DropdownMenuItem onSelect={selectMenuUnread}>Non lus</DropdownMenuItem>
                <DropdownMenuItem onSelect={selectMenuStarred}>Suivis</DropdownMenuItem>
                <DropdownMenuItem onSelect={selectMenuUnstarred}>
                  Non suivis
                </DropdownMenuItem>
              </DropdownMenuContent>
            </DropdownMenu>

            {showBulkToolbar ? (
              <TooltipProvider delayDuration={400}>
                <div className="flex min-w-0 items-center gap-0.5 pl-1">
                  <div className="flex shrink-0 items-center gap-0.5">
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="icon"
                          className="h-9 w-9 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                          aria-label="Archiver"
                          onClick={bulkArchive}
                        >
                          <Archive className="h-[18px] w-[18px]" strokeWidth={1.5} />
                        </Button>
                      </TooltipTrigger>
                      <TooltipContent side="bottom" className="text-xs">
                        Archiver
                      </TooltipContent>
                    </Tooltip>
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="icon"
                          className="h-9 w-9 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                          aria-label="Signaler comme spam"
                          onClick={bulkSpam}
                        >
                          <ShieldAlert className="h-[18px] w-[18px]" strokeWidth={1.5} />
                        </Button>
                      </TooltipTrigger>
                      <TooltipContent side="bottom" className="text-xs">
                        Signaler comme spam
                      </TooltipContent>
                    </Tooltip>
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="icon"
                          className="h-9 w-9 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                          aria-label="Supprimer"
                          onClick={bulkDelete}
                        >
                          <Trash2 className="h-[18px] w-[18px]" strokeWidth={1.5} />
                        </Button>
                      </TooltipTrigger>
                      <TooltipContent side="bottom" className="text-xs">
                        Supprimer
                      </TooltipContent>
                    </Tooltip>
                  </div>

                  <span
                    className="mx-1 h-6 w-px shrink-0 bg-[#dadce0]"
                    aria-hidden
                  />

                  <div className="flex min-w-0 shrink-0 items-center gap-0.5">
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="icon"
                          className="h-9 w-9 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                          aria-label={
                            hasUnreadInSelection
                              ? "Marquer comme lu"
                              : "Marquer comme non lu"
                          }
                          onClick={() =>
                            hasUnreadInSelection ? bulkMarkRead() : bulkMarkUnread()
                          }
                        >
                          {hasUnreadInSelection ? (
                            <MailOpen className="h-[18px] w-[18px]" strokeWidth={1.5} />
                          ) : (
                            <Mail className="h-[18px] w-[18px]" strokeWidth={1.5} />
                          )}
                        </Button>
                      </TooltipTrigger>
                      <TooltipContent side="bottom" className="text-xs">
                        {hasUnreadInSelection
                          ? "Marquer comme lu"
                          : "Marquer comme non lu"}
                      </TooltipContent>
                    </Tooltip>

                    <DropdownMenu>
                      <DropdownMenuTrigger asChild>
                        <Button
                          type="button"
                          variant="ghost"
                          size="sm"
                          className="h-9 w-9 shrink-0 gap-1 px-0 text-[#444746] hover:bg-[#f1f3f4] lg:h-9 lg:w-auto lg:px-2"
                          aria-label="Déplacer vers"
                        >
                          <FolderInput className="h-[18px] w-[18px] shrink-0" strokeWidth={1.5} />
                          <span className="hidden max-w-32 truncate lg:inline">
                            Déplacer vers
                          </span>
                          <ChevronDown className="hidden h-3.5 w-3.5 shrink-0 opacity-70 lg:block" />
                        </Button>
                      </DropdownMenuTrigger>
                      <DropdownMenuContent
                        align="start"
                        className={cn(dropdownSurfaceClass, "max-h-80 overflow-y-auto")}
                      >
                        <MoveToDropdownItems targets={moveTargets} onMoveTo={bulkMoveTo} />
                      </DropdownMenuContent>
                    </DropdownMenu>
                  </div>

                  <span
                    className="mx-1 h-6 w-px shrink-0 bg-[#dadce0]"
                    aria-hidden
                  />

                  <DropdownMenu
                    onOpenChange={(open) => {
                      if (!open) setLabelPickerQuery("")
                    }}
                  >
                    <DropdownMenuTrigger asChild>
                      <Button
                        type="button"
                        variant="ghost"
                        size="icon"
                        className="h-9 w-9 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                        aria-label="Plus d'actions"
                      >
                        <MoreVertical className="h-[18px] w-[18px]" strokeWidth={1.5} />
                      </Button>
                    </DropdownMenuTrigger>
                    <DropdownMenuContent
                      align="start"
                      className={cn(
                        dropdownSurfaceClass,
                        /* Sous-menus Radix restent dans ce nœud : overflow-auto les clippe */
                        "overflow-visible"
                      )}
                    >
                      <DropdownMenuItem>
                        <Clock className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
                        Mettre en attente
                      </DropdownMenuItem>
                      <DropdownMenuItem>
                        <ListTodo className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
                        Ajouter à Tasks
                      </DropdownMenuItem>
                      <DropdownMenuSeparator />
                      <DropdownMenuSub>
                        <DropdownMenuSubTrigger className="[&>svg:last-child]:text-[#5f6368]">
                          <Tag className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
                          Ajouter le libellé
                        </DropdownMenuSubTrigger>
                        <DropdownMenuSubContent
                          className={cn(
                            dropdownSurfaceClass,
                            "z-[100] flex max-h-72 min-w-[260px] flex-col overflow-hidden p-0 py-0"
                          )}
                        >
                          <EmailLabelPickerBlock
                            query={labelPickerQuery}
                            onQueryChange={setLabelPickerQuery}
                            catalogLabels={catalogLabels}
                            Item={DropdownMenuItem}
                            getLabelPresence={(lab) =>
                              getCatalogLabelPresence(bulkTargetIds, lab)
                            }
                            onToggleCatalogLabel={(lab) =>
                              toggleLabelOnEmails(bulkTargetIds, lab)
                            }
                            onCreateLabel={(lab) => {
                              addLabelToEmails(bulkTargetIds, lab)
                              setLabelPickerQuery("")
                            }}
                          />
                        </DropdownMenuSubContent>
                      </DropdownMenuSub>
                      <DropdownMenuItem>
                        <VolumeX className="size-[18px] text-[#5f6368]" strokeWidth={1.5} />
                        Ignorer la conversation
                      </DropdownMenuItem>
                      <DropdownMenuSeparator />
                      <DropdownMenuItem>
                        <SquareArrowOutUpRight
                          className="size-[18px] text-[#5f6368]"
                          strokeWidth={1.5}
                        />
                        Ouvrir dans une nouvelle fenêtre
                      </DropdownMenuItem>
                    </DropdownMenuContent>
                  </DropdownMenu>
                </div>
              </TooltipProvider>
            ) : (
              <>
                <Button
                  type="button"
                  variant="ghost"
                  size="icon"
                  className="hidden h-9 w-9 text-gray-600 sm:inline-flex"
                  aria-label="Rafraîchir"
                  aria-busy={isRefreshing}
                  disabled={isRefreshing}
                  onClick={() => void handleRefreshMessages()}
                >
                  <RefreshCw
                    className={cn(
                      "h-4 w-4",
                      isRefreshing && REFRESH_SPIN_CLASS
                    )}
                  />
                </Button>
                <DropdownMenu>
                  <DropdownMenuTrigger asChild>
                    <Button
                      type="button"
                      variant="ghost"
                      size="icon"
                      className="h-9 w-9 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                      aria-label="Plus d'actions"
                    >
                      <MoreVertical
                        className="h-[18px] w-[18px]"
                        strokeWidth={1.5}
                      />
                    </Button>
                  </DropdownMenuTrigger>
                  <DropdownMenuContent
                    align="start"
                    sideOffset={4}
                    className={cn(dropdownSurfaceClass, "min-w-[260px]")}
                  >
                    <DropdownMenuItem onSelect={markAllInViewAsRead}>
                      <MailOpen
                        className="size-[18px] text-[#5f6368]"
                        strokeWidth={1.5}
                      />
                      Tout marquer comme lu
                    </DropdownMenuItem>
                    <DropdownMenuSeparator />
                    <div
                      className="px-3 py-2 text-sm leading-snug text-[#5f6368] select-none"
                      role="note"
                    >
                      Sélectionnez des messages pour afficher plus d&apos;actions
                    </div>
                  </DropdownMenuContent>
                </DropdownMenu>
              </>
            )}
          </>
        )}

        <div className="flex-1" />

        {/* Pagination — liste (pages) ou vue message (position dans le filtre) */}
        <div
          className={cn(
            "flex shrink-0 items-center gap-2 whitespace-nowrap text-sm text-gray-600",
            !isViewMode && "max-sm:hidden sm:flex"
          )}
        >
          {filteredEmails.length === 0 ? (
            <span>Aucun résultat</span>
          ) : isViewMode ? (
            <span className="hidden sm:inline">
              {openMailIndex >= 0 ? openMailIndex + 1 : "–"} sur {filteredEmails.length}
            </span>
          ) : (
            <span>
              {(listPage - 1) * LIST_PAGE_SIZE + 1}–
              {Math.min(listPage * LIST_PAGE_SIZE, filteredEmails.length)} sur{" "}
              {filteredEmails.length}
              {totalPages > 1 ? ` · p. ${listPage}/${totalPages}` : null}
            </span>
          )}
          <Tooltip>
            <TooltipTrigger asChild>
              <Button
                variant="ghost"
                size="icon"
                className={cn(
                  "h-9 w-9",
                  isViewMode && openMailIndex > 0
                    ? "text-gray-600"
                    : !isViewMode && listPage > 1
                      ? "text-gray-600"
                      : "text-gray-400"
                )}
                disabled={isViewMode ? openMailIndex <= 0 : listPage <= 1}
                onClick={isViewMode ? goToPrev : goListPrevPage}
                aria-label={isViewMode ? "Plus récent" : "Page précédente"}
              >
                <ChevronLeft className="h-4 w-4" />
              </Button>
            </TooltipTrigger>
            <TooltipContent side="bottom" className="text-xs">
              {isViewMode ? "Plus récent" : "Page précédente"}
            </TooltipContent>
          </Tooltip>
          <Tooltip>
            <TooltipTrigger asChild>
              <Button
                variant="ghost"
                size="icon"
                className={cn(
                  "h-9 w-9",
                  isViewMode && openMailIndex < filteredEmails.length - 1
                    ? "text-gray-600"
                    : !isViewMode && listPage < totalPages
                      ? "text-gray-600"
                      : "text-gray-400"
                )}
                disabled={
                  isViewMode
                    ? openMailIndex >= filteredEmails.length - 1
                    : listPage >= totalPages
                }
                onClick={isViewMode ? goToNext : goListNextPage}
                aria-label={isViewMode ? "Plus ancien" : "Page suivante"}
              >
                <ChevronRight className="h-4 w-4" />
              </Button>
            </TooltipTrigger>
            <TooltipContent side="bottom" className="text-xs">
              {isViewMode ? "Plus ancien" : "Page suivante"}
            </TooltipContent>
          </Tooltip>
        </div>
      </div>

      {selectedFolder === "inbox" && (
        <div className="relative z-10 w-full shrink-0 bg-white after:pointer-events-none after:absolute after:inset-x-0 after:bottom-0 after:z-0 after:h-px after:bg-[#dadce0]">
          {!isViewMode && (
            <div
              className="grid w-full max-w-[1260px] min-w-0"
              style={{
                gridTemplateColumns: `repeat(${categoryTabs.length}, minmax(0, 1fr))`,
              }}
            >
              {categoryTabs.map((tab) => {
                const isActive = inboxTab === tab.id
                const isPrimaryTab = tab.id === "primary"
                const unseen = unseenInTabById[tab.id] ?? 0
                const senderLine = tabUnseenSenderLineById[tab.id] ?? ""
                const showMeta =
                  !isPrimaryTab && !isActive && unseen > 0
                const showSenderLine = showMeta && Boolean(senderLine)
                const isExpandedTabMeta = showSenderLine
                return (
                  <button
                    key={tab.id}
                    type="button"
                    onClick={() => handleCategoryInboxTabClick(tab.id)}
                    className={cn(
                      "relative z-[1] flex min-w-0 w-full cursor-pointer overflow-hidden transition-colors",
                      "max-sm:min-h-10 max-sm:items-center max-sm:justify-center",
                      "sm:min-h-14",
                      "sm:items-center sm:py-2 sm:text-left",
                      isActive && "shadow-[inset_0_-3px_0_0_#0b57d0]",
                      !isActive && "hover:bg-[#f1f3f4]"
                    )}
                  >
                    <div className="flex h-10 w-full items-center justify-center sm:hidden">
                      <div className="relative inline-flex shrink-0">
                        <tab.icon
                          strokeWidth={CATEGORY_TAB_ICON_STROKE}
                          className={cn(
                            "h-4 w-4 shrink-0",
                            isActive ? "text-[#0b57d0]" : "text-[#5f6368]"
                          )}
                        />
                        {showMeta && unseen > 0 && tab.badgeTone ? (
                          <span
                            className={categoryBadgeDotClass(tab.badgeTone)}
                            aria-hidden
                          />
                        ) : null}
                      </div>
                    </div>

                    <div className="hidden min-w-0 flex-1 items-center gap-2 mx-2 sm:mx-3 sm:flex">
                      <tab.icon
                        strokeWidth={CATEGORY_TAB_ICON_STROKE}
                        className={cn(
                          "h-4 w-4 shrink-0 self-center",
                          isActive ? "text-[#0b57d0]" : "text-[#5f6368]"
                        )}
                      />
                      <div className="flex min-w-0 w-0 flex-1 flex-col gap-px">
                        <div
                          className={cn(
                            "flex min-w-0 items-center gap-1.5",
                            isExpandedTabMeta && "min-h-5"
                          )}
                        >
                          <span
                            className={cn(
                              "min-w-0 flex-1 truncate text-[13px] font-semibold leading-tight",
                              isActive ? "text-[#0b57d0]" : "text-[#3c4043]"
                            )}
                          >
                            {tab.label}
                          </span>
                          {showMeta && unseen > 0 && tab.badgeTone ? (
                            <span className={categoryBadgeClass(tab.badgeTone)}>
                              {unseen}
                              <span className="hidden md:inline">
                                {" "}
                                {unseen === 1 ? "nouveau" : "nouveaux"}
                              </span>
                            </span>
                          ) : null}
                        </div>
                        {isExpandedTabMeta ? (
                          <span className="block min-h-4 min-w-0 truncate text-[11px] leading-snug text-[#5f6368]">
                            {senderLine}
                          </span>
                        ) : null}
                      </div>
                    </div>
                  </button>
                )
              })}
            </div>
          )}
        </div>
      )}

      <div
        ref={listViewportRef}
        className={cn(mainScrollClass, "relative overscroll-y-none max-sm:pb-16")}
      >
      {!isViewMode && (
        <div
          className="pointer-events-none absolute inset-x-0 top-0 z-10 flex items-center justify-center pt-2 sm:hidden"
          style={{ height: PULL_HOLD_HEIGHT }}
          aria-hidden
        >
          <RefreshCw
            ref={pullIconRef}
            className={cn(
              "h-5 w-5 text-[#5f6368]",
              isRefreshing && REFRESH_SPIN_CLASS
            )}
            style={{ opacity: 0 }}
          />
        </div>
      )}
      <div
        ref={pullContentRef}
        className={cn(
          !isViewMode && "flex min-h-full flex-col max-sm:[transform:translateZ(0)]"
        )}
      >
      {isViewMode && openEmail ? (
        /* ── EMAIL VIEW ── */
        <EmailView
          email={openEmail}
          onToggleStar={toggleStar}
          isStarred={starredEmails.includes(openEmail.id) || openEmail.starred}
          onNavigateToLabel={handleNavigateToLabel}
          onNotSpam={openEmail.spam === true ? singleNotSpam : undefined}
          labelBgByText={listRowLabelBgByTextLower}
          emailLabelToSidebarFolderId={sidebarNav.emailLabelToSidebarFolderId}
          getNavItemPrefs={sidebarNav.getNavItemPrefs}
          showLabelChip={(lab) => {
            if (LABEL_PICKER_EXCLUDE.has(lab)) return true
            const fid = sidebarNav.emailLabelToSidebarFolderId[lab]
            if (!fid) return true
            return sidebarNav.getNavItemPrefs(fid).messages !== "hide"
          }}
        />
      ) : (
        <TooltipProvider delayDuration={400}>
        <>
          {selectedFolder === "scheduled" && (
            <div className="flex shrink-0 items-start gap-3 border-b border-[#eceff1] bg-[#f8f9fa] px-4 py-3">
              <Clock
                className="h-5 w-5 shrink-0 text-[#5f6368]"
                strokeWidth={1.5}
                aria-hidden
              />
              <p className="text-sm leading-snug text-[#3c4043]">
                Les messages de la liste «&nbsp;Envois programmés&nbsp;» seront envoyés à l&apos;heure prévue pour chacun d&apos;eux.
              </p>
            </div>
          )}
          {filteredEmails.length === 0 ? (
            selectedFolder === "scheduled" ? (
              <div className="flex min-h-[220px] flex-col items-center justify-center px-4 py-12 text-center">
                <p className="text-sm text-[#5f6368]">Aucun message planifié.</p>
              </div>
            ) : (
              <Empty className="min-h-[240px] flex-1 border-0 bg-white py-10 shadow-none">
                <EmptyHeader className="max-w-md">
                  <EmptyMedia
                    variant="icon"
                    className="mb-1 border-0 bg-[#f1f3f4] text-[#5f6368] [&_svg]:size-6"
                  >
                    <Mail className="size-6" strokeWidth={1.5} aria-hidden />
                  </EmptyMedia>
                  <EmptyTitle className="text-[15px] font-medium text-[#3c4043]">
                    Aucun message
                  </EmptyTitle>
                  <EmptyDescription className="text-[13px] text-[#5f6368]">
                    {selectedFolder === "inbox" ? (
                      <>
                        Aucun message dans l&apos;onglet{" "}
                        <span className="font-medium text-[#3c4043]">
                          {inboxCategoryTabLabel}
                        </span>{" "}
                        de la boîte de réception.
                      </>
                    ) : (
                      <>
                        Aucun message dans{" "}
                        <span className="font-medium text-[#3c4043]">
                          {getMailNavFolderLabel(selectedFolder, sidebarNav.folderIdToLabel)}
                        </span>
                        .
                      </>
                    )}
                  </EmptyDescription>
                </EmptyHeader>
              </Empty>
            )
          ) : (
          <div className="divide-y divide-[#eceff1]">
            {listEmails.map((email) => {
              const isStarred = starredEmails.includes(email.id) || email.starred
              const isImportant = importantEmails.includes(email.id) || email.important
              const isSpam = email.spam === true
              const isDraft = email.labels?.includes("drafts") === true
              const hasThreadReplyDraft =
                savedThreadReplyDrafts[email.id] !== undefined
              const showDraftBadge = isDraft || hasThreadReplyDraft
              const isRead =
                readOverrides[email.id] !== undefined ? readOverrides[email.id]! : email.read
              const senderHoverEmail = resolveSenderEmail(email.sender, email.senderEmail)
              const senderForSearch = email.sender.replace(/\s+/g, " ").trim()
              const isSelected = selectedEmails.includes(email.id)
              const hasInvitation = email.hasInvitation === true
              const parsedInvitation =
                listRowExtras.invitationById.get(email.id) ?? null
              const attachmentList =
                listRowExtras.attachmentsById.get(email.id) ?? []
              const isScheduled = email.labels?.includes("scheduled") === true
              const contextTargetIds = contextMenuTargetIdsForRow(
                email.id,
                selectedEmails,
                selectedFolder,
                allEmails
              )
              const allContextTargetsScheduled =
                contextTargetIds.length > 0 &&
                contextTargetIds.every((id) =>
                  listMailIndex.scheduledIds.has(id)
                )
              const scheduledCtxAnyUnread =
                allContextTargetsScheduled &&
                contextTargetIds.some((id) => {
                  const em = listMailIndex.emailById.get(id)
                  if (!em) return false
                  return !(readOverrides[id] ?? em.read)
                })
              const isRescheduleOpenThisRow =
                rescheduleTarget?.id === email.id
              const spamRowHoverNoArchive = selectedFolder === "spam"
              const snoozedFolderRow = selectedFolder === "snoozed"

              return (
              <ContextMenu
                key={email.id}
                modal={false}
                onOpenChange={(open) => {
                  if (open) {
                    rowContextMenuOpenedAtRef.current = Date.now()
                    setSelectedEmails((prev) => {
                      const next = contextMenuTargetIdsForRow(
                        email.id,
                        prev,
                        selectedFolder,
                        allEmails
                      )
                      contextMenuTargetIdsRef.current = [...next]
                      return next
                    })
                  } else {
                    setLabelPickerQuery("")
                  }
                }}
              >
                <ContextMenuTrigger asChild>
              <div
                data-email-row-id={email.id}
                draggable={!isXs}
                onDragStart={isXs ? undefined : (e) => startRowDrag(email.id, e)}
                onClick={() => {
                  if (readXsMatches() && mobileSelectionMode) {
                    toggleSelect(email.id)
                    lastSelectionAnchorIdRef.current = email.id
                    return
                  }
                  handleRowActivate(email)
                }}
                className={cn(
                  "group relative z-0 w-full cursor-pointer pl-3 pr-2 py-2 transition-[background-color,box-shadow] duration-[50ms] ease-out md:flex md:items-start md:gap-2 md:px-2 md:py-1.5",
                  isSelected
                    ? "bg-[#e8f0fe]"
                    : isRead
                      ? "bg-[#f5f5f5]"
                      : "bg-white",
                  "hover:z-1 hover:shadow-[inset_1px_0_0_#d2d5da,inset_-1px_0_0_#d2d5da,0_4px_10px_-3px_rgba(60,64,67,.16),0_2px_5px_0_rgba(60,64,67,.09)]"
                )}
              >
                {/* Compact < md */}
                <div
                  className={cn(
                    "flex w-full min-w-0 flex-col gap-0.5 md:hidden",
                    mobileSelectionMode &&
                      "max-sm:flex-row max-sm:items-center max-sm:gap-2"
                  )}
                >
                  {mobileSelectionMode && (
                    <div
                      className="flex shrink-0 self-center sm:hidden"
                      onClick={(e) => e.stopPropagation()}
                      onClickCapture={(e) => handleRowCheckboxClickCapture(email.id, e)}
                    >
                      <Checkbox
                        className={listRowCheckboxClass(true)}
                        checked={isSelected}
                        onCheckedChange={() => {
                          toggleSelect(email.id)
                          lastSelectionAnchorIdRef.current = email.id
                        }}
                      />
                    </div>
                  )}
                  <div
                    className={cn(
                      "flex min-w-0 flex-1 flex-col gap-0.5",
                      mobileSelectionMode && "max-sm:pointer-events-none"
                    )}
                  >
                  <div className="flex w-full min-w-0 items-center gap-2">
                    <div
                      className="hidden shrink-0 items-center sm:flex"
                      onClick={(e) => e.stopPropagation()}
                      onClickCapture={(e) => handleRowCheckboxClickCapture(email.id, e)}
                    >
                      <Checkbox
                        className={listRowCheckboxClass(false)}
                        checked={isSelected}
                        onCheckedChange={() => {
                          toggleSelect(email.id)
                          lastSelectionAnchorIdRef.current = email.id
                        }}
                      />
                    </div>
                    <div className="flex min-w-0 flex-1 items-center justify-between gap-2">
                      <div className="flex min-w-0 flex-1 items-center gap-1">
                        <button
                          type="button"
                          onClick={(e) => {
                            e.stopPropagation()
                            toggleImportant(email.id)
                          }}
                          className={cn(
                            "flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-full",
                            isSpam
                              ? "text-[#d93025] hover:bg-[#d93025]/10 hover:text-[#b3261e]"
                              : "text-[#c2c2c2] hover:bg-black/4 hover:text-[#5f6368]"
                          )}
                          aria-label={
                            isSpam
                              ? "Marqué comme spam"
                              : isImportant
                                ? "Retirer important"
                                : "Marquer important"
                          }
                        >
                          <Icon
                            icon={importantSignalIcon(isSpam, isImportant)}
                            className={cn(
                              "size-4 shrink-0",
                              isSpam && "text-[#d93025]",
                              !isSpam &&
                                (isImportant ? "text-[#f4cc70]" : "text-[#c2c2c2]")
                            )}
                            aria-hidden
                          />
                        </button>
                        {isScheduled && (
                          <span
                            className="flex h-7 w-6 shrink-0 items-center justify-center text-[#5f6368]"
                            aria-hidden
                          >
                            <Send className="size-3.5" strokeWidth={2} />
                          </span>
                        )}
                    {isScheduled ? (
                      <span
                        className={cn(
                          "min-w-0 truncate text-sm",
                          !isRead ? "font-semibold text-gray-900" : "font-normal text-gray-700"
                        )}
                      >
                        À : {email.scheduledToName ?? email.sender}
                      </span>
                    ) : (
                    <ContactHoverCard displayName={email.sender} email={senderHoverEmail}>
                      <span
                        className={cn(
                          "min-w-0 truncate text-sm",
                          !isRead ? "font-semibold text-gray-900" : "font-normal text-gray-700"
                        )}
                      >
                        {showDraftBadge && (
                          <span className="font-medium text-[#d93025]">Brouillon </span>
                        )}
                        {email.sender}
                      </span>
                    </ContactHoverCard>
                    )}
                        {email.participantCount != null && email.participantCount > 1 && (
                          <span className="shrink-0 text-sm font-normal text-gray-500">
                            {email.participantCount}
                          </span>
                        )}
                      </div>
                      <div className="flex shrink-0 items-center gap-1">
                        {(parsedInvitation || hasInvitation) && (
                          <Icon
                            icon={
                              parsedInvitation
                                ? VIDEO_CONFERENCE_LOGOS[
                                    parsedInvitation.conferenceProvider
                                  ]
                                : "mdi:calendar"
                            }
                            className="size-4 shrink-0 text-[#5f6368]"
                            aria-label={
                              parsedInvitation
                                ? "Invitation visioconférence"
                                : "Invitation calendrier"
                            }
                          />
                        )}
                        {attachmentList.length > 0 && (
                          <Paperclip
                            className="size-4 shrink-0 text-[#5f6368]"
                            strokeWidth={1.75}
                            aria-label="Pièces jointes"
                          />
                        )}
                        <span
                          className={cn(
                            "shrink-0 text-sm font-semibold tabular-nums tracking-tight",
                            !isRead ? "text-gray-900" : "text-gray-700"
                          )}
                        >
                          {isScheduled
                            ? formatScheduledDateTimeDisplay(email.scheduledSendAt)
                            : email.date}
                        </span>
                      </div>
                    </div>
                  </div>

                  <div className={cn("flex min-w-0 flex-wrap items-center gap-1 sm:pl-6")}>
                      {email.tag && (
                        <span className="shrink-0 rounded bg-gray-200 px-1.5 py-0.5 text-xs text-gray-600 opacity-[0.92]">
                          {email.tag}
                        </span>
                      )}
                      <MailLabelPillStrip
                        variant="list"
                        labels={email.labels}
                        labelBgByText={listRowLabelBgByTextLower}
                        emailLabelToSidebarFolderId={sidebarNav.emailLabelToSidebarFolderId}
                        getNavItemPrefs={sidebarNav.getNavItemPrefs}
                        onLabelNavigate={handleNavigateToLabel}
                        currentFolderId={selectedFolder}
                        folderTree={sidebarNav.folderTree}
                      />
                      <span
                        className={cn(
                          "min-w-0 flex-1 text-sm leading-snug line-clamp-1",
                          !isRead ? "font-semibold text-gray-900" : "font-semibold text-[#202124]"
                        )}
                      >
                        {email.subject}
                      </span>
                    </div>

                    <div className={cn("flex min-w-0 items-start gap-1.5 sm:pl-6")}>
                      <p className="min-w-0 flex-1 text-sm leading-snug text-[#5f6368] line-clamp-1">
                        {email.preview}
                      </p>
                      <button
                        type="button"
                        onClick={(e) => {
                          e.stopPropagation()
                          toggleStar(email.id)
                        }}
                        className="mt-0.5 flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-full text-[#c2c2c2] hover:bg-black/4 hover:text-[#5f6368]"
                        aria-label={isStarred ? "Retirer des favoris" : "Marquer comme favori"}
                      >
                        <Star
                          strokeWidth={isStarred ? 0 : 1.25}
                          className={cn(
                            "size-4",
                            isStarred
                              ? "fill-[#f4cc70] stroke-none text-[#f4cc70]"
                              : "fill-transparent stroke-[#c2c2c2]"
                          )}
                        />
                      </button>
                    </div>
                  </div>
                </div>

                {/* Desktop >= md */}
                <div className="hidden w-full items-start gap-2 md:flex">
                <div className="flex shrink-0 items-center gap-2">
                  <div
                    className="flex shrink-0"
                    onClick={(e) => e.stopPropagation()}
                    onClickCapture={(e) => handleRowCheckboxClickCapture(email.id, e)}
                  >
                    <Checkbox
                      className="size-4 min-h-4 min-w-4 shrink-0 rounded-[2.5px] border-[1.5px] border-[#c2c2c2] bg-transparent shadow-none dark:bg-transparent focus-visible:ring-[#c2c2c2]/30 data-[state=checked]:border-[#1a73e8] data-[state=checked]:bg-[#1a73e8] data-[state=checked]:text-white"
                      checked={isSelected}
                      onCheckedChange={() => {
                        toggleSelect(email.id)
                        lastSelectionAnchorIdRef.current = email.id
                      }}
                    />
                  </div>

                  <div className="flex items-center gap-0">
                    <button
                      type="button"
                      onClick={(e) => {
                        e.stopPropagation()
                        toggleStar(email.id)
                      }}
                      className="flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-full text-[#c2c2c2] hover:bg-black/4 hover:text-[#5f6368]"
                      aria-label={isStarred ? "Retirer des favoris" : "Marquer comme favori"}
                    >
                      <Star
                        strokeWidth={isStarred ? 0 : 1.25}
                        className={cn(
                          "size-4",
                          isStarred
                            ? "fill-[#f4cc70] stroke-none text-[#f4cc70]"
                            : "fill-transparent stroke-[#c2c2c2]"
                        )}
                      />
                    </button>

                    <button
                      type="button"
                      onClick={(e) => {
                        e.stopPropagation()
                        toggleImportant(email.id)
                      }}
                      className={cn(
                        "flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-full",
                        isSpam
                          ? "text-[#d93025] hover:bg-[#d93025]/10 hover:text-[#b3261e]"
                          : "text-[#c2c2c2] hover:bg-black/4 hover:text-[#5f6368]"
                      )}
                      aria-label={
                        isSpam
                          ? "Marqué comme spam"
                          : isImportant
                            ? "Retirer important"
                            : "Marquer important"
                      }
                    >
                      <Icon
                        icon={importantSignalIcon(isSpam, isImportant)}
                        className={cn(
                          "size-4 shrink-0",
                          isSpam && "text-[#d93025]",
                          !isSpam &&
                            (isImportant ? "text-[#f4cc70]" : "text-[#c2c2c2]")
                        )}
                        aria-hidden
                      />
                    </button>
                    {isScheduled && (
                      <span
                        className="flex h-7 w-6 shrink-0 items-center justify-center text-[#5f6368]"
                        aria-hidden
                      >
                        <Send className="size-3.5" strokeWidth={2} />
                      </span>
                    )}
                  </div>
                </div>

                <div
                  className={cn(
                    "w-44 shrink-0 truncate pl-2 lg:w-40",
                    attachmentList.length === 0 ? "pt-px" : "pt-0"
                  )}
                >
                  {isScheduled ? (
                    <span
                      className={cn(
                        "text-sm",
                        !isRead ? "font-semibold text-gray-900" : "text-gray-700"
                      )}
                    >
                      À : {email.scheduledToName ?? email.sender}
                    </span>
                  ) : (
                  <ContactHoverCard displayName={email.sender} email={senderHoverEmail}>
                    <span className={cn(
                      "text-sm",
                      !isRead ? "font-semibold text-gray-900" : "text-gray-700"
                    )}>
                      {showDraftBadge && (
                        <span className="font-medium text-[#d93025]">Brouillon </span>
                      )}
                      {email.sender}
                    </span>
                  </ContactHoverCard>
                  )}
                  {email.participantCount && email.participantCount > 1 && (
                    <span className="text-sm text-gray-500 ml-1">{email.participantCount}</span>
                  )}
                </div>

                <div className="flex min-w-0 flex-1 flex-col justify-start gap-0.5 px-2 pb-0.5">
                  <div
                    className={cn(
                      "flex min-w-0 items-center gap-1",
                      attachmentList.length === 0 ? "pt-1" : "pt-0.5"
                    )}
                  >
                    {email.tag && (
                      <span className="shrink-0 rounded bg-gray-200 px-1.5 py-0.5 text-xs text-gray-600 opacity-[0.92]">
                        {email.tag}
                      </span>
                    )}
                    <MailLabelPillStrip
                      variant="list"
                      labels={email.labels}
                      labelBgByText={listRowLabelBgByTextLower}
                      emailLabelToSidebarFolderId={sidebarNav.emailLabelToSidebarFolderId}
                      getNavItemPrefs={sidebarNav.getNavItemPrefs}
                      onLabelNavigate={handleNavigateToLabel}
                      currentFolderId={selectedFolder}
                      folderTree={sidebarNav.folderTree}
                    />
                    <span
                      className={cn(
                        "min-w-0 shrink truncate text-sm",
                        !isRead ? "font-semibold text-gray-900" : "font-normal text-[#3c4043]"
                      )}
                    >
                      {email.subject}
                    </span>
                    <span className="min-w-0 flex-1 truncate text-sm text-gray-500">{email.preview}</span>
                  </div>
                  {attachmentList.length > 0 && (
                    <EmailListAttachmentRow emailId={email.id} attachments={attachmentList} />
                  )}
                </div>

                <div
                  className={cn(
                    "flex shrink-0 flex-col items-end gap-1 self-start pr-2 text-right md:max-w-[150px] md:min-w-0",
                    attachmentList.length === 0 ? "pt-1" : "pt-0.5"
                  )}
                >
                  {isScheduled ? (
                    <div className="relative flex w-full min-w-0 shrink-0 items-center justify-end">
                      <span
                        className={cn(
                          "block max-w-full truncate text-sm font-semibold tabular-nums text-[#c65308]",
                          "transition-opacity duration-[50ms] ease-out",
                          isRescheduleOpenThisRow
                            ? "opacity-0"
                            : "opacity-100 group-hover:opacity-0"
                        )}
                      >
                        {formatScheduledDateTimeDisplay(email.scheduledSendAt)}
                      </span>
                      <div
                        className={cn(
                          "pointer-events-none absolute right-0 top-1/2 z-[1] flex w-max -translate-y-1/2 flex-nowrap items-center gap-0.5 rounded-md py-0.5 pl-1 opacity-0 transition-opacity duration-[50ms] ease-out",
                          listRowQuickHoverTrayToneClass(isSelected, isRead),
                          isRescheduleOpenThisRow
                            ? "pointer-events-auto opacity-100"
                            : "group-hover:pointer-events-auto group-hover:opacity-100"
                        )}
                      >
                        {!spamRowHoverNoArchive && (
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <Button
                              type="button"
                              variant="ghost"
                              size="icon"
                              className="h-8 w-8 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                              aria-label="Archiver"
                              onClick={(e) => {
                                e.stopPropagation()
                                void requestArchiveScheduled(email.id)
                              }}
                            >
                              <Archive className="h-[18px] w-[18px]" strokeWidth={1.5} />
                            </Button>
                          </TooltipTrigger>
                          <TooltipContent side="bottom" className="text-xs">
                            Archiver
                          </TooltipContent>
                        </Tooltip>
                        )}
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <Button
                              type="button"
                              variant="ghost"
                              size="icon"
                              className="h-8 w-8 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                              aria-label="Supprimer"
                              onClick={(e) => {
                                e.stopPropagation()
                                void requestDeleteScheduled(email.id)
                              }}
                            >
                              <Trash2 className="h-[18px] w-[18px]" strokeWidth={1.5} />
                            </Button>
                          </TooltipTrigger>
                          <TooltipContent side="bottom" className="text-xs">
                            Supprimer
                          </TooltipContent>
                        </Tooltip>
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <Button
                              type="button"
                              variant="ghost"
                              size="icon"
                              className="h-8 w-8 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                              aria-label={isRead ? "Marquer comme non lu" : "Marquer comme lu"}
                              onClick={(e) => {
                                e.stopPropagation()
                                const next = !isRead
                                setReadOverrides((prev) => ({ ...prev, [email.id]: next }))
                                void requestToggleReadScheduled(email.id, next)
                              }}
                            >
                              {isRead ? (
                                <Mail className="h-[18px] w-[18px]" strokeWidth={1.5} />
                              ) : (
                                <MailOpen className="h-[18px] w-[18px]" strokeWidth={1.5} />
                              )}
                            </Button>
                          </TooltipTrigger>
                          <TooltipContent side="bottom" className="text-xs">
                            {isRead ? "Marquer comme non lu" : "Marquer comme lu"}
                          </TooltipContent>
                        </Tooltip>
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <Button
                              type="button"
                              variant="ghost"
                              size="icon"
                              className="h-8 w-8 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                              aria-label="Mettre en attente"
                              onClick={(e) => {
                                e.stopPropagation()
                                void requestSnoozeScheduled(email.id)
                              }}
                            >
                              <Clock className="h-[18px] w-[18px]" strokeWidth={1.5} />
                            </Button>
                          </TooltipTrigger>
                          <TooltipContent side="bottom" className="text-xs">
                            Mettre en attente
                          </TooltipContent>
                        </Tooltip>
                        <Popover
                          open={
                            rescheduleTarget?.id === email.id &&
                            rescheduleTarget.panelOpen
                          }
                          onOpenChange={(open) => {
                            if (open) {
                              const pending =
                                rescheduleDismissTimeoutsRef.current.get(
                                  email.id
                                )
                              if (pending) {
                                clearTimeout(pending)
                                rescheduleDismissTimeoutsRef.current.delete(
                                  email.id
                                )
                              }
                              setRescheduleTarget({
                                id: email.id,
                                value: scheduledIsoToDatetimeLocalValue(
                                  email.scheduledSendAt
                                ),
                                panelOpen: true,
                              })
                            } else {
                              setRescheduleTarget((prev) =>
                                prev?.id === email.id
                                  ? { ...prev, panelOpen: false }
                                  : prev
                              )
                              scheduleReschedulePopoverDismiss(email.id)
                            }
                          }}
                        >
                          <Tooltip>
                            <TooltipTrigger asChild>
                              <PopoverTrigger asChild>
                                <Button
                                  type="button"
                                  variant="ghost"
                                  size="icon"
                                  className="h-8 w-8 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                                  aria-label="Reprogrammer"
                                  onClick={(e) => e.stopPropagation()}
                                >
                                  <CalendarClock
                                    className="h-[18px] w-[18px]"
                                    strokeWidth={1.5}
                                  />
                                </Button>
                              </PopoverTrigger>
                            </TooltipTrigger>
                            <TooltipContent side="bottom" className="text-xs">
                              Reprogrammer
                            </TooltipContent>
                          </Tooltip>
                          <PopoverContent
                            className="w-[min(100vw-2rem,280px)] p-3"
                            align="end"
                            side="bottom"
                            sideOffset={6}
                            collisionPadding={12}
                            onClick={(e) => e.stopPropagation()}
                          >
                            <p className="mb-2 text-xs font-medium text-[#3c4043]">
                              Nouvelle date d&apos;envoi
                            </p>
                            <input
                              type="datetime-local"
                              className="mb-3 w-full rounded border border-[#dadce0] px-2 py-1.5 text-sm text-[#3c4043]"
                              value={
                                rescheduleTarget?.id === email.id
                                  ? rescheduleTarget.value
                                  : ""
                              }
                              onChange={(e) =>
                                setRescheduleTarget((prev) =>
                                  prev?.id === email.id
                                    ? {
                                        ...prev,
                                        value: e.target.value,
                                        panelOpen: true,
                                      }
                                    : prev
                                )
                              }
                            />
                            <div className="flex justify-end gap-2">
                              <Button
                                type="button"
                                variant="outline"
                                size="sm"
                                className="h-8 text-xs"
                                onClick={() => {
                                  setRescheduleTarget((prev) =>
                                    prev?.id === email.id
                                      ? { ...prev, panelOpen: false }
                                      : prev
                                  )
                                  scheduleReschedulePopoverDismiss(email.id)
                                }}
                              >
                                Annuler
                              </Button>
                              <Button
                                type="button"
                                size="sm"
                                className="h-8 text-xs"
                                onClick={() => {
                                  if (rescheduleTarget?.id !== email.id) return
                                  const iso = parseDatetimeLocalToIso(
                                    rescheduleTarget.value
                                  )
                                  if (!iso) return
                                  void requestRescheduleScheduled(email.id, iso)
                                  setRescheduleTarget((prev) =>
                                    prev?.id === email.id
                                      ? { ...prev, panelOpen: false }
                                      : prev
                                  )
                                  scheduleReschedulePopoverDismiss(email.id)
                                }}
                              >
                                Valider
                              </Button>
                            </div>
                          </PopoverContent>
                        </Popover>
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <Button
                              type="button"
                              variant="ghost"
                              size="icon"
                              className="h-8 w-8 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                              aria-label="Modifier le mail"
                              onClick={(e) => {
                                e.stopPropagation()
                                void handleEditScheduledMail(email.id)
                              }}
                            >
                              <Pencil
                                className="h-[18px] w-[18px]"
                                strokeWidth={1.5}
                              />
                            </Button>
                          </TooltipTrigger>
                          <TooltipContent side="bottom" className="text-xs">
                            Modifier le mail
                          </TooltipContent>
                        </Tooltip>
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <Button
                              type="button"
                              variant="ghost"
                              size="icon"
                              className="h-8 w-8 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                              aria-label="Envoyer maintenant"
                              onClick={(e) => {
                                e.stopPropagation()
                                void requestSendScheduledNow(email.id)
                              }}
                            >
                              <Send
                                className="h-[18px] w-[18px]"
                                strokeWidth={1.5}
                              />
                            </Button>
                          </TooltipTrigger>
                          <TooltipContent side="bottom" className="text-xs">
                            Envoyer maintenant
                          </TooltipContent>
                        </Tooltip>
                      </div>
                    </div>
                  ) : (
                    <div className="relative flex w-full min-w-0 shrink-0 items-center justify-end">
                      <div
                        className={cn(
                          "flex min-w-0 max-w-full items-center justify-end gap-1.5 overflow-hidden",
                          "transition-opacity duration-[50ms] ease-out",
                          "group-hover:opacity-0"
                        )}
                      >
                        {(parsedInvitation || hasInvitation) && (
                          <Icon
                            icon={
                              parsedInvitation
                                ? VIDEO_CONFERENCE_LOGOS[
                                    parsedInvitation.conferenceProvider
                                  ]
                                : "mdi:calendar"
                            }
                            className="size-[18px] shrink-0 text-[#5f6368]"
                            aria-label={
                              parsedInvitation
                                ? "Invitation visioconférence"
                                : "Invitation calendrier"
                            }
                          />
                        )}
                        <span
                          className={cn(
                            "min-w-0 truncate text-sm tabular-nums",
                            !isRead ? "font-semibold text-gray-900" : "text-gray-600"
                          )}
                        >
                          {email.date}
                        </span>
                      </div>
                      <div
                        className={cn(
                          "pointer-events-none absolute right-0 top-1/2 z-[1] flex w-max -translate-y-1/2 flex-nowrap items-center gap-0.5 rounded-md py-0.5 pl-1 opacity-0 transition-opacity duration-[50ms] ease-out",
                          listRowQuickHoverTrayToneClass(isSelected, isRead),
                          "group-hover:pointer-events-auto group-hover:opacity-100"
                        )}
                      >
                        {!spamRowHoverNoArchive && (
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <Button
                              type="button"
                              variant="ghost"
                              size="icon"
                              className="h-8 w-8 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                              aria-label="Archiver"
                              onClick={(e) => {
                                e.stopPropagation()
                                mailActions.hideEmail(email.id)
                                closeViewIfShowingEmail(email.id)
                              }}
                            >
                              <Archive className="h-[18px] w-[18px]" strokeWidth={1.5} />
                            </Button>
                          </TooltipTrigger>
                          <TooltipContent side="bottom" className="text-xs">
                            Archiver
                          </TooltipContent>
                        </Tooltip>
                        )}
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <Button
                              type="button"
                              variant="ghost"
                              size="icon"
                              className="h-8 w-8 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                              aria-label="Supprimer"
                              onClick={(e) => {
                                e.stopPropagation()
                                mailActions.hideEmail(email.id)
                                closeViewIfShowingEmail(email.id)
                              }}
                            >
                              <Trash2 className="h-[18px] w-[18px]" strokeWidth={1.5} />
                            </Button>
                          </TooltipTrigger>
                          <TooltipContent side="bottom" className="text-xs">
                            Supprimer
                          </TooltipContent>
                        </Tooltip>
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <Button
                              type="button"
                              variant="ghost"
                              size="icon"
                              className="h-8 w-8 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                              aria-label={isRead ? "Marquer comme non lu" : "Marquer comme lu"}
                              onClick={(e) => {
                                e.stopPropagation()
                                const next = !isRead
                                setReadOverrides((prev) => ({ ...prev, [email.id]: next }))
                              }}
                            >
                              {isRead ? (
                                <Mail className="h-[18px] w-[18px]" strokeWidth={1.5} />
                              ) : (
                                <MailOpen className="h-[18px] w-[18px]" strokeWidth={1.5} />
                              )}
                            </Button>
                          </TooltipTrigger>
                          <TooltipContent side="bottom" className="text-xs">
                            {isRead ? "Marquer comme non lu" : "Marquer comme lu"}
                          </TooltipContent>
                        </Tooltip>
                        {spamRowHoverNoArchive && (
                          <Tooltip>
                            <TooltipTrigger asChild>
                              <Button
                                type="button"
                                variant="ghost"
                                size="icon"
                                className="h-8 w-8 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                                aria-label="Déplacer vers la boîte de réception"
                                onClick={(e) => {
                                  e.stopPropagation()
                                  mailActions.markNotSpam(email.id)
                                  onSelectFolder?.("inbox")
                                  closeViewIfShowingEmail(email.id)
                                }}
                              >
                                <InboxIcon
                                  className="h-[18px] w-[18px]"
                                  strokeWidth={1.5}
                                />
                              </Button>
                            </TooltipTrigger>
                            <TooltipContent side="bottom" className="text-xs">
                              Boîte de réception
                            </TooltipContent>
                          </Tooltip>
                        )}
                        {!spamRowHoverNoArchive &&
                          (snoozedFolderRow ? (
                          <Tooltip>
                            <TooltipTrigger asChild>
                              <Button
                                type="button"
                                variant="ghost"
                                size="icon"
                                className="h-8 w-8 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                                aria-label={
                                  email.id.startsWith("snz-")
                                    ? "Déplacer vers la boîte de réception"
                                    : "Remettre dans les mails planifiés"
                                }
                                onClick={(e) => {
                                  e.stopPropagation()
                                  restoreSnoozedRowToMailbox(email)
                                }}
                              >
                                <InboxIcon
                                  className="h-[18px] w-[18px]"
                                  strokeWidth={1.5}
                                />
                              </Button>
                            </TooltipTrigger>
                            <TooltipContent side="bottom" className="text-xs">
                              {email.id.startsWith("snz-")
                                ? "Boîte de réception"
                                : "Planifiés"}
                            </TooltipContent>
                          </Tooltip>
                        ) : (
                          <Tooltip>
                            <TooltipTrigger asChild>
                              <Button
                                type="button"
                                variant="ghost"
                                size="icon"
                                className="h-8 w-8 shrink-0 text-[#444746] hover:bg-[#f1f3f4]"
                                aria-label="Mettre en attente"
                                onClick={(e) => {
                                  e.stopPropagation()
                                  void requestSnoozeMailboxEmail(email)
                                  if (email.labels?.includes("snoozed")) return
                                  mailActions.hideEmail(email.id)
                                  closeViewIfShowingEmail(email.id)
                                }}
                              >
                                <Clock className="h-[18px] w-[18px]" strokeWidth={1.5} />
                              </Button>
                            </TooltipTrigger>
                            <TooltipContent side="bottom" className="text-xs">
                              Mettre en attente
                            </TooltipContent>
                          </Tooltip>
                        ))}
                      </div>
                    </div>
                  )}
                </div>
                </div>
              </div>
                </ContextMenuTrigger>

                <ContextMenuContent
                  onCloseAutoFocus={(e) => e.preventDefault()}
                  onPointerDownOutside={(event) => {
                    const native = event.detail.originalEvent
                    if (
                      native.pointerType === "mouse" &&
                      native.button === 2 &&
                      Date.now() - rowContextMenuOpenedAtRef.current < 450
                    ) {
                      event.preventDefault()
                    }
                  }}
                  className={cn(
                    "min-w-[280px] overflow-visible rounded-lg border border-[#dadce0] bg-white p-0 py-1 text-[#3c4043] shadow-lg",
                    "[&_[data-slot=context-menu-item]]:gap-3 [&_[data-slot=context-menu-item]]:rounded-none [&_[data-slot=context-menu-item]]:px-3 [&_[data-slot=context-menu-item]]:py-2 [&_[data-slot=context-menu-item]]:text-sm",
                    "[&_[data-slot=context-menu-item]:focus]:bg-[#f1f3f4] [&_[data-slot=context-menu-item]:focus]:text-[#3c4043]",
                    "[&_[data-slot=context-menu-sub-trigger]]:gap-3 [&_[data-slot=context-menu-sub-trigger]]:rounded-none [&_[data-slot=context-menu-sub-trigger]]:px-3 [&_[data-slot=context-menu-sub-trigger]]:py-2 [&_[data-slot=context-menu-sub-trigger]]:text-sm",
                    "[&_[data-slot=context-menu-sub-trigger]:focus]:bg-[#f1f3f4] [&_[data-slot=context-menu-sub-trigger]:focus]:text-[#3c4043]",
                    "[&_[data-slot=context-menu-separator]]:mx-0 [&_[data-slot=context-menu-separator]]:my-1 [&_[data-slot=context-menu-separator]]:h-px [&_[data-slot=context-menu-separator]]:bg-[#eceff1]",
                    "[&_[data-slot=context-menu-sub-content]]:min-w-[200px] [&_[data-slot=context-menu-sub-content]]:rounded-lg [&_[data-slot=context-menu-sub-content]]:border [&_[data-slot=context-menu-sub-content]]:border-[#dadce0] [&_[data-slot=context-menu-sub-content]]:bg-white [&_[data-slot=context-menu-sub-content]]:shadow-lg"
                  )}
                >
                  {allContextTargetsScheduled ? (
                    <>
                      <ContextMenuItem
                        onSelect={() => {
                          const ids = [...contextMenuTargetIdsRef.current]
                          void Promise.all(
                            ids.map((id) => requestArchiveScheduled(id))
                          )
                        }}
                      >
                        <Archive
                          strokeWidth={1.5}
                          className="size-[18px] text-[#5f6368]"
                        />
                        Archiver
                      </ContextMenuItem>
                      <ContextMenuItem
                        onSelect={() => {
                          const ids = [...contextMenuTargetIdsRef.current]
                          void Promise.all(
                            ids.map((id) => requestDeleteScheduled(id))
                          )
                        }}
                      >
                        <Trash2
                          strokeWidth={1.5}
                          className="size-[18px] text-[#5f6368]"
                        />
                        Supprimer
                      </ContextMenuItem>
                      <ContextMenuItem
                        onSelect={() => {
                          const ids = [...contextMenuTargetIdsRef.current]
                          const markRead = scheduledCtxAnyUnread
                          setReadOverrides((prev) => {
                            const next = { ...prev }
                            for (const id of ids) next[id] = markRead
                            return next
                          })
                          void Promise.all(
                            ids.map((id) =>
                              requestToggleReadScheduled(id, markRead)
                            )
                          )
                        }}
                      >
                        {scheduledCtxAnyUnread ? (
                          <Mail
                            strokeWidth={1.5}
                            className="size-[18px] text-[#5f6368]"
                          />
                        ) : (
                          <MailOpen
                            strokeWidth={1.5}
                            className="size-[18px] text-[#5f6368]"
                          />
                        )}
                        {scheduledCtxAnyUnread
                          ? "Marquer comme lu"
                          : "Marquer comme non lu"}
                      </ContextMenuItem>
                      <ContextMenuItem
                        onSelect={() => {
                          const ids = [...contextMenuTargetIdsRef.current]
                          void Promise.all(
                            ids.map((id) => requestSnoozeScheduled(id))
                          )
                        }}
                      >
                        <Clock
                          strokeWidth={1.5}
                          className="size-[18px] text-[#5f6368]"
                        />
                        Mettre en attente
                      </ContextMenuItem>
                      <ContextMenuSeparator />
                      <ContextMenuSub
                        onOpenChange={(subOpen) => {
                          if (!subOpen) return
                          const ids = contextMenuTargetIdsRef.current
                          const first = allEmails.find((e) => e.id === ids[0])
                          setCmScheduledRescheduleValue(
                            scheduledIsoToDatetimeLocalValue(
                              first?.scheduledSendAt
                            )
                          )
                        }}
                      >
                        <ContextMenuSubTrigger className="[&>svg:last-child]:text-[#5f6368]">
                          <CalendarClock
                            strokeWidth={1.5}
                            className="size-[18px] text-[#5f6368]"
                          />
                          Reprogrammer
                        </ContextMenuSubTrigger>
                        <ContextMenuSubContent
                          className={cn(
                            "min-w-[288px] rounded-lg border border-[#dadce0] bg-white px-4 py-3.5 text-[#3c4043] shadow-lg"
                          )}
                        >
                          <div
                            className="flex flex-col gap-3.5"
                            onPointerDown={(e) => e.stopPropagation()}
                          >
                            <p className="text-xs font-medium leading-snug text-[#3c4043]">
                              Nouvelle date d&apos;envoi
                              {contextTargetIds.length > 1
                                ? ` (${contextTargetIds.length} messages)`
                                : null}
                            </p>
                            <input
                              type="datetime-local"
                              className="w-full rounded border border-[#dadce0] px-2.5 py-1.5 text-sm text-[#3c4043]"
                              value={cmScheduledRescheduleValue}
                              onChange={(e) =>
                                setCmScheduledRescheduleValue(e.target.value)
                              }
                              onPointerDown={(e) => e.stopPropagation()}
                            />
                            <button
                              type="button"
                              className="rounded bg-[#0b57d0] px-3 py-1.5 text-xs font-medium text-white hover:bg-[#0842a0]"
                              onPointerDown={(e) => {
                                e.stopPropagation()
                                e.preventDefault()
                              }}
                              onClick={(e) => {
                                e.stopPropagation()
                                const iso = parseDatetimeLocalToIso(
                                  cmScheduledRescheduleValue
                                )
                                if (!iso) return
                                const ids = [
                                  ...contextMenuTargetIdsRef.current,
                                ]
                                void Promise.all(
                                  ids.map((id) =>
                                    requestRescheduleScheduled(id, iso)
                                  )
                                )
                              }}
                            >
                              Valider
                            </button>
                          </div>
                        </ContextMenuSubContent>
                      </ContextMenuSub>
                      <ContextMenuItem
                        disabled={contextTargetIds.length > 1}
                        onSelect={() => {
                          if (contextTargetIds.length !== 1) return
                          void handleEditScheduledMail(contextTargetIds[0]!)
                        }}
                      >
                        <Pencil
                          strokeWidth={1.5}
                          className="size-[18px] text-[#5f6368]"
                        />
                        Modifier le mail
                      </ContextMenuItem>
                      <ContextMenuItem
                        onSelect={() => {
                          const ids = [...contextMenuTargetIdsRef.current]
                          void Promise.all(
                            ids.map((id) => requestSendScheduledNow(id))
                          )
                        }}
                      >
                        <Send
                          strokeWidth={1.5}
                          className="size-[18px] text-[#5f6368]"
                        />
                        Envoyer maintenant
                      </ContextMenuItem>
                    </>
                  ) : (
                    <>
                  <ContextMenuItem>
                    <Reply strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                    Répondre
                  </ContextMenuItem>
                  <ContextMenuItem>
                    <ReplyAll strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                    Répondre à tous
                  </ContextMenuItem>
                  <ContextMenuItem>
                    <Forward strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                    Transférer
                  </ContextMenuItem>
                  <ContextMenuItem>
                    <Paperclip strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                    Transférer en tant que pièce jointe
                  </ContextMenuItem>

                  <ContextMenuSeparator />

                  <ContextMenuItem>
                    <Archive strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                    Archiver
                  </ContextMenuItem>
                  <ContextMenuItem>
                    <Trash2 strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                    Supprimer
                  </ContextMenuItem>
                  <ContextMenuItem
                    onSelect={() => {
                      const newRead = !isRead
                      const ids = contextMenuTargetIdsRef.current
                      setReadOverrides((prev) => {
                        const next = { ...prev }
                        for (const id of ids) {
                          next[id] = newRead
                        }
                        return next
                      })
                    }}
                  >
                    {!isRead ? (
                      <Mail strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                    ) : (
                      <MailOpen strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                    )}
                    {isRead ? "Marquer comme non lu" : "Marquer comme lu"}
                  </ContextMenuItem>
                  <ContextMenuItem>
                    <Clock strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                    Mettre en attente
                  </ContextMenuItem>
                  <ContextMenuItem>
                    <ListTodo strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                    Ajouter à Tasks
                  </ContextMenuItem>

                  <ContextMenuSeparator />

                  <ContextMenuSub>
                    <ContextMenuSubTrigger className="[&>svg:last-child]:text-[#5f6368]">
                      <FolderInput strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                      Déplacer vers
                    </ContextMenuSubTrigger>
                    <ContextMenuSubContent
                      className={cn(
                        "max-h-80 min-w-[200px] overflow-y-auto rounded-lg border border-[#dadce0] bg-white p-0 py-1 text-[#3c4043] shadow-lg",
                        "[&_[data-slot=context-menu-item]]:gap-3 [&_[data-slot=context-menu-item]]:rounded-none [&_[data-slot=context-menu-item]]:px-3 [&_[data-slot=context-menu-item]]:py-2 [&_[data-slot=context-menu-item]]:text-sm",
                        "[&_[data-slot=context-menu-item]:focus]:bg-[#f1f3f4]"
                      )}
                    >
                      <MoveToContextMenuItems
                        targets={moveTargets}
                        onMoveTo={(targetId) => {
                          moveEmailsToTarget(contextTargetIds, targetId)
                          if (targetId !== "inbox") {
                            setSelectedEmails((prev) => prev.filter((id) => !contextTargetIds.includes(id)))
                          }
                        }}
                      />
                    </ContextMenuSubContent>
                  </ContextMenuSub>

                  <ContextMenuSub>
                    <ContextMenuSubTrigger className="[&>svg:last-child]:text-[#5f6368]">
                      <Tag strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                      Ajouter le libellé
                    </ContextMenuSubTrigger>
                    <ContextMenuSubContent
                      className={cn(
                        "z-[100] flex max-h-72 min-w-[260px] flex-col overflow-hidden rounded-lg border border-[#dadce0] bg-white p-0 py-0 text-[#3c4043] shadow-lg",
                        "[&_[data-slot=context-menu-item]]:gap-3 [&_[data-slot=context-menu-item]]:rounded-none [&_[data-slot=context-menu-item]]:px-3 [&_[data-slot=context-menu-item]]:py-2 [&_[data-slot=context-menu-item]]:text-sm",
                        "[&_[data-slot=context-menu-item]:focus]:bg-[#f1f3f4]"
                      )}
                    >
                      <EmailLabelPickerBlock
                        query={labelPickerQuery}
                        onQueryChange={setLabelPickerQuery}
                        catalogLabels={catalogLabels}
                        Item={ContextMenuItem}
                        getLabelPresence={(lab) =>
                          getCatalogLabelPresence(contextTargetIds, lab)
                        }
                        onToggleCatalogLabel={(lab) =>
                          toggleLabelOnEmails(contextTargetIds, lab)
                        }
                        onCreateLabel={(lab) => {
                          addLabelToEmails(contextTargetIds, lab)
                          setLabelPickerQuery("")
                        }}
                      />
                    </ContextMenuSubContent>
                  </ContextMenuSub>

                  <ContextMenuItem>
                    <VolumeX strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                    Ignorer la conversation
                  </ContextMenuItem>

                  <ContextMenuSeparator />

                  <ContextMenuItem title={`Recherche : ${senderForSearch}`}>
                    <Search strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                    <span className="min-w-0 truncate">
                      Rech. e-mails de {senderForSearch}
                    </span>
                  </ContextMenuItem>

                  <ContextMenuSeparator />

                  <ContextMenuItem>
                    <SquareArrowOutUpRight strokeWidth={1.5} className="size-[18px] text-[#5f6368]" />
                    Ouvrir dans une nouvelle fenêtre
                  </ContextMenuItem>
                    </>
                  )}
                </ContextMenuContent>
              </ContextMenu>
              )
            })}
          </div>
          )}
        </>
        </TooltipProvider>
      )}
      {!isViewMode ? (
        <div className="sticky bottom-0 left-0 z-20 mt-auto hidden w-fit max-w-full shrink-0 pt-2 sm:flex">
          <MailFolderStackIndicator
            currentKey={mailNavVisitKey(selectedFolder, inboxTab)}
            folderTree={sidebarNav.folderTree}
            folderIdToLabel={sidebarNav.folderIdToLabel}
          />
        </div>
      ) : null}
      </div>
      </div>
    </div>
  )
}
