"use client"

import {
  Inbox,
  Star,
  Clock,
  ClockArrowUp,
  Send,
  FileText,
  Tag,
  ChevronDown,
  GripVertical,
  Pencil,
  Plus,
  Bot,
  Folder,
  MoreVertical,
  Newspaper,
  LayoutGrid,
  Rss,
  Mail,
  ShieldAlert,
  Check,
  Trash2,
} from "lucide-react"
import { cn, formatCount } from "@/lib/utils"
import { useIsXs } from "@/hooks/use-xs"
import { readTouchNavMatches, useTouchNav } from "@/hooks/use-touch-nav"
import {
  useState,
  useRef,
  useEffect,
  useMemo,
  useCallback,
  type ReactNode,
  type CSSProperties,
} from "react"
import { useEmailDropTarget } from "@/lib/drag-context"
import {
  readSidebarNavDragData,
  resolveNavDropPlacement,
  setSidebarNavDragData,
  type SidebarNavDragPayload,
  type SidebarNavDropPlacement,
} from "@/lib/sidebar-nav-dnd"
import { useComposeActions } from "@/lib/compose-context"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuSub,
  DropdownMenuSubContent,
  DropdownMenuSubTrigger,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { type FolderTreeNode, isSystemNavLabelId, SYSTEM_NAV_LABEL_DEFAULTS } from "@/lib/sidebar-nav-data"
import { folderMoveParentOptions, useSidebarNav } from "@/lib/sidebar-nav-context"
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog"
import { Label } from "@/components/ui/label"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import { Icon, addCollection } from "@iconify/react"
import { icons as mdiIcons } from "@iconify-json/mdi"
import {
  FOLDER_SECTION_ICON,
  folderTreeNavIconName,
  navFolderIconColorFromBgClass,
} from "@/lib/folder-nav-icons"
import { UltiMailLogo } from "@/components/ultimail-logo"
import {
  SidebarNavOptionsSheet,
  SidebarNavSheetAction,
  SidebarNavSheetCheckOption,
  SidebarNavSheetColorPicker,
  SidebarNavSheetDivider,
  SidebarNavSheetSectionLabel,
} from "@/components/gmail/sidebar-nav-options-sheet"
import { useSidebarTouchOptionsMenu } from "@/components/gmail/use-sidebar-touch-options"

addCollection(mdiIcons)
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"
import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuLabel,
  ContextMenuSeparator,
  ContextMenuSub,
  ContextMenuSubContent,
  ContextMenuSubTrigger,
  ContextMenuTrigger,
} from "@/components/ui/context-menu"

/** Retourne les ids des parents à ouvrir pour afficher `targetId`, ou null. */
function ancestorFolderIdsForTarget(
  nodes: FolderTreeNode[],
  targetId: string,
  chain: string[] = []
): string[] | null {
  for (const n of nodes) {
    if (n.id === targetId) return chain
    if (n.children?.length) {
      const found = ancestorFolderIdsForTarget(n.children, targetId, [...chain, n.id])
      if (found) return found
    }
  }
  return null
}

function folderSubtreeContainsId(node: FolderTreeNode, targetId: string): boolean {
  if (node.id === targetId) return true
  return node.children?.some((c) => folderSubtreeContainsId(c, targetId)) ?? false
}

interface SidebarProps {
  selectedFolder: string
  onSelectFolder: (folder: string) => void
  collapsed: boolean
  /** Nombre de messages non lus par id de ligne (boîte, catégorie, dossier, libellé). */
  folderUnreadCounts?: Record<string, number>
  /** md+ split pane: mobile-style branding, no header compose. */
  splitView?: boolean
}

const mainItems = [
  { id: "inbox", label: "Boîte de réception", icon: Inbox },
  { id: "starred", label: "Messages suivis", icon: Star },
  { id: "snoozed", label: "En attente", icon: Clock },
  { id: "important", label: "Important", icon: Tag },
  { id: "sent", label: "Messages envoyés", icon: Send },
  { id: "drafts", label: "Brouillons", icon: FileText },
  { id: "scheduled", label: "Planifié", icon: ClockArrowUp },
  { id: "spam", label: "Indésirables", icon: ShieldAlert },
  { id: "trash", label: "Corbeille", icon: Trash2 },
]

/** Catégories système affichées sous « Plus » uniquement. */
const CATEGORY_IDS_IN_PLUS_ONLY = new Set<string>(["mises-a-jour", "finance"])

const SYSTEM_NAV_LABEL_ORDER = SYSTEM_NAV_LABEL_DEFAULTS.map((r) => r.id)

function sortSystemLabelRows(rows: { id: string }[]): { id: string; label: string; icon?: string }[] {
  const copy = [...rows]
  copy.sort(
    (a, b) =>
      SYSTEM_NAV_LABEL_ORDER.indexOf(a.id) - SYSTEM_NAV_LABEL_ORDER.indexOf(b.id)
  )
  return copy as { id: string; label: string; icon?: string }[]
}

/** Liens secondaires sous la liste (jusqu’à Gérer les abonnements). */
const sidebarSecondaryActions = [
  { id: "customize-inbox", label: "Personnaliser la zone de réception", icon: LayoutGrid },
  { id: "manage-sections", label: "Gérer les sections", icon: Newspaper },
  { id: "manage-news", label: "Gérer les actualités", icon: Rss },
  { id: "manage-subscriptions", label: "Gérer les abonnements", icon: Mail },
] as const

const hasPlusOnlyExtras =
  SYSTEM_NAV_LABEL_DEFAULTS.some((c) => CATEGORY_IDS_IN_PLUS_ONLY.has(c.id)) ||
  sidebarSecondaryActions.length > 0

/** Pastilles sous-menu « Couleur du libellé » (démo UI). */
const LABEL_MENU_COLOR_SWATCHES = [
  "bg-gray-500",
  "bg-red-400",
  "bg-orange-400",
  "bg-amber-500",
  "bg-yellow-400",
  "bg-lime-500",
  "bg-emerald-500",
  "bg-teal-500",
  "bg-blue-500",
  "bg-indigo-500",
  "bg-purple-500",
  "bg-pink-500",
] as const

function LabelMenuOptionWithCheck({
  checked,
  onPick,
  children,
}: {
  checked: boolean
  onPick: () => void
  children: ReactNode
}) {
  return (
    <DropdownMenuItem
      onClick={(e) => {
        e.stopPropagation()
        onPick()
      }}
      className="mx-1 flex cursor-pointer items-center justify-between gap-3 px-3 py-2 text-sm text-gray-800 focus:bg-gray-100"
    >
      <span className="min-w-0 flex-1 text-left">{children}</span>
      <span
        className="flex size-4 shrink-0 items-center justify-center"
        aria-hidden={!checked}
      >
        {checked ? (
          <Check className="size-4 text-gray-900" strokeWidth={2} aria-hidden />
        ) : null}
      </span>
    </DropdownMenuItem>
  )
}

function ContextLabelMenuOptionWithCheck({
  checked,
  onPick,
  children,
}: {
  checked: boolean
  onPick: () => void
  children: ReactNode
}) {
  return (
    <ContextMenuItem
      onClick={() => onPick()}
      className="mx-1 flex cursor-pointer items-center justify-between gap-3 px-3 py-2 text-sm"
    >
      <span className="min-w-0 flex-1 text-left">{children}</span>
      <span
        className="flex size-4 shrink-0 items-center justify-center"
        aria-hidden={!checked}
      >
        {checked ? (
          <Check className="size-4 text-gray-900" strokeWidth={2} aria-hidden />
        ) : null}
      </span>
    </ContextMenuItem>
  )
}

function folderParentSelectOptions(tree: FolderTreeNode[]): {
  value: string
  label: string
}[] {
  const out: { value: string; label: string }[] = [
    { value: "__root__", label: "Racine" },
  ]
  const walk = (nodes: FolderTreeNode[], depth: number) => {
    for (const n of nodes) {
      out.push({
        value: n.id,
        label: `${"\u2003".repeat(depth * 2)}${n.label}`,
      })
      if (n.children?.length) walk(n.children, depth + 1)
    }
  }
  walk(tree, 0)
  return out
}

type CategoryNavSourceItem = {
  id: string
  label: string
  icon?: string
}

/** Pill à droite seulement quand le fond d’accent est visible (évite frange sur fond neutre). */
function navRowRoundedWhenActive(active: boolean) {
  return active ? "rounded-r-full" : "rounded-r-none hover:rounded-r-full"
}

/** Pastille non-lus : point jaune + ping en haut à droite du picto. */
function SidebarNavIconUnreadDot({ show }: { show: boolean }) {
  if (!show) return null
  return (
    <>
      <span
        className="pointer-events-none absolute -right-0.5 -top-0.5 size-2 rounded-full bg-yellow-400 opacity-75 motion-reduce:animate-none animate-ping"
        aria-hidden
      />
      <span
        className="pointer-events-none absolute -right-0.5 -top-0.5 size-2 rounded-full bg-yellow-400"
        aria-hidden
      />
    </>
  )
}

function SidebarNavIconSlot({
  showUnreadDot,
  children,
}: {
  showUnreadDot?: boolean
  children: ReactNode
}) {
  return (
    <span className="relative flex h-5 w-5 shrink-0 items-center justify-center">
      {children}
      <SidebarNavIconUnreadDot show={!!showUnreadDot} />
    </span>
  )
}

/** Mark an element as the nav drag source (opacity via CSS). */
function markNavDragSource(el: HTMLElement | null) {
  el?.setAttribute("data-nav-drag-source", "true")
}
function unmarkNavDragSource(el: HTMLElement | null) {
  el?.removeAttribute("data-nav-drag-source")
}
/** Mark / unmark a drop indicator via data attribute (CSS driven). */
function setNavDropIndicator(
  el: HTMLElement | null,
  placement: SidebarNavDropPlacement | null,
) {
  if (!el) return
  if (placement) {
    el.setAttribute("data-nav-drop", placement)
  } else {
    el.removeAttribute("data-nav-drop")
  }
}

function navRowActivate(
  e: React.KeyboardEvent,
  action: () => void
) {
  if (e.key === "Enter" || e.key === " ") {
    e.preventDefault()
    action()
  }
}

function FolderTreeNavIcon({
  hasChildren,
  open,
  colorBgClass,
  className,
  style,
}: {
  hasChildren: boolean
  open: boolean
  colorBgClass: string
  className?: string
  style?: CSSProperties
}) {
  return (
    <Icon
      icon={folderTreeNavIconName(hasChildren, open)}
      className={cn("h-5 w-5 shrink-0", className)}
      style={{ color: navFolderIconColorFromBgClass(colorBgClass), ...style }}
      aria-hidden
    />
  )
}

function SidebarNavDragHandle({
  label,
  onDragStart,
  onDragEnd,
}: {
  label: string
  onDragStart: (e: React.DragEvent<HTMLSpanElement>) => void
  onDragEnd: () => void
}) {
  return (
    <span
      draggable
      title={`Réorganiser : ${label}`}
      aria-label={`Réorganiser : ${label}`}
      onDragStart={onDragStart}
      onDragEnd={onDragEnd}
      onClick={(e) => e.stopPropagation()}
      onMouseDown={(e) => e.stopPropagation()}
      className="pointer-events-none absolute left-0 top-1/2 z-10 flex h-8 w-4 -translate-y-1/2 cursor-grab items-center justify-center text-gray-400 opacity-0 transition-opacity hover:opacity-100 active:cursor-grabbing group-hover/folderrow:pointer-events-auto group-hover/folderrow:opacity-100 group-hover/labelrow:pointer-events-auto group-hover/labelrow:opacity-100"
    >
      <GripVertical className="h-3.5 w-3.5" aria-hidden />
    </span>
  )
}

const OVERFLOW_COUNT_HOVER_HIDE = {
  folderrow: "group-hover/folderrow:opacity-0",
  labelrow: "group-hover/labelrow:opacity-0",
  catnav: "group-hover/catnav:opacity-0",
} as const

const OVERFLOW_MENU_HOVER_SHOW = {
  folderrow:
    "group-hover/folderrow:opacity-100 group-has-[button:focus-visible]/folderrow:opacity-100",
  labelrow:
    "group-hover/labelrow:opacity-100 group-has-[button:focus-visible]/labelrow:opacity-100",
  catnav:
    "group-hover/catnav:opacity-100 group-has-[button:focus-visible]/catnav:opacity-100",
} as const

/** Colonne droite : compteur et ⋮ partagent le même emplacement (style Gmail). */
function SidebarOverflowColumn({
  unread,
  menuOpen,
  hoverGroup,
  isSelected,
  hasUnread,
  className,
  showMenuButton = true,
  children,
}: {
  unread: number
  menuOpen: boolean
  hoverGroup: "folderrow" | "labelrow" | "catnav"
  isSelected?: boolean
  hasUnread?: boolean
  className?: string
  showMenuButton?: boolean
  children?: ReactNode
}) {
  if (!showMenuButton) {
    if (unread <= 0) return null
    return (
      <div className={cn("relative h-8 w-8 shrink-0", className)}>
        <span
          className={cn(
            "flex h-full items-center justify-center text-xs tabular-nums leading-none",
            isSelected && "font-medium",
            hasUnread && !isSelected && "font-semibold"
          )}
        >
          {formatCount(unread)}
        </span>
      </div>
    )
  }

  return (
    <div className={cn("relative h-8 w-8 shrink-0", className)}>
      {unread > 0 && (
        <span
          className={cn(
            "pointer-events-none absolute inset-0 flex items-center justify-center text-xs tabular-nums leading-none transition-opacity duration-150",
            isSelected && "font-medium",
            hasUnread && !isSelected && "font-semibold",
            menuOpen ? "opacity-0" : OVERFLOW_COUNT_HOVER_HIDE[hoverGroup]
          )}
        >
          {formatCount(unread)}
        </span>
      )}
      <div
        className={cn(
          "absolute inset-0 flex items-center justify-center opacity-0 transition-opacity duration-150",
          menuOpen ? "opacity-100" : OVERFLOW_MENU_HOVER_SHOW[hoverGroup]
        )}
      >
        {children}
      </div>
    </div>
  )
}

const sidebarOverflowMenuButtonClass =
  "flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-full text-gray-600 outline-none hover:bg-black/8 focus-visible:ring-2 focus-visible:ring-ring/50"

function CategoryNavRow({
  item,
  isSelected,
  isExpanded,
  unreadCount,
  onSelectFolder,
  onDisableNavLabel,
  onEnableNavLabel,
  touchNav,
  variant = "listed",
}: {
  item: CategoryNavSourceItem
  isSelected: boolean
  isExpanded: boolean
  unreadCount: number
  onSelectFolder: (id: string) => void
  onDisableNavLabel: (id: string) => void
  onEnableNavLabel: (id: string) => void
  touchNav: boolean
  variant?: "listed" | "hidden"
}) {
  const { isOver, dropHandlers } = useEmailDropTarget(item.id, item.label)
  const [menuOpen, setMenuOpen] = useState(false)
  const menuTriggerRef = useRef<HTMLButtonElement>(null)
  const isHiddenRow = variant === "hidden"
  const showCategoryMenu = isSystemNavLabelId(item.id) && isExpanded
  const hasUnread = unreadCount > 0
  const touchMenuEnabled = touchNav && (isHiddenRow || showCategoryMenu)
  const { sheetOpen, setSheetOpen, touchRowProps, touchRowClassName, closeSheet } =
    useSidebarTouchOptionsMenu(touchMenuEnabled)

  const handleMenuOpenChange = (open: boolean) => {
    setMenuOpen(open)
    if (!open) {
      queueMicrotask(() => menuTriggerRef.current?.blur())
    }
  }

  const rowHoverHeld =
    !isHiddenRow && !isSelected && !isOver && (menuOpen || sheetOpen)

  const rowIcon = item.icon ? (
    <Icon
      icon={item.icon}
      className={cn(
        "h-5 w-5 shrink-0",
        isHiddenRow && "opacity-70",
        hasUnread && !isSelected && !isHiddenRow && "text-gray-900"
      )}
      aria-hidden
    />
  ) : (
    <Folder
      className={cn(
        "h-5 w-5 shrink-0",
        isHiddenRow && "opacity-70",
        hasUnread && !isSelected && !isHiddenRow && "text-gray-900"
      )}
      aria-hidden
    />
  )

  if (isHiddenRow) {
    return (
      <>
        <div
          {...dropHandlers}
          {...touchRowProps}
          className={cn(
            "flex h-8 w-full min-w-0 shrink-0 items-center pl-6 pr-2 text-gray-500 transition-colors",
            isOver ? "rounded-r-full" : "rounded-r-none",
            isOver && "bg-yellow-100 text-gray-900",
            touchRowClassName
          )}
        >
          <button
            type="button"
            onClick={() => onSelectFolder(item.id)}
            className="flex h-8 min-w-0 flex-1 items-center gap-4 rounded-r-none py-0 pr-1 text-left outline-none hover:rounded-r-full hover:bg-gray-50"
          >
            {rowIcon}
            <div className="flex min-w-0 flex-1 items-baseline gap-4">
              <span
                className={cn(
                  "min-w-0 flex-1 truncate text-sm leading-5",
                  hasUnread && "font-semibold text-gray-900"
                )}
              >
                {item.label}
              </span>
              {unreadCount > 0 && (
                <span
                  className={cn(
                    "shrink-0 text-xs tabular-nums leading-none text-gray-700",
                    hasUnread && "font-semibold"
                  )}
                >
                  {formatCount(unreadCount)}
                </span>
              )}
            </div>
          </button>
          {!touchNav && (
            <DropdownMenu open={menuOpen} onOpenChange={handleMenuOpenChange}>
              <DropdownMenuTrigger asChild>
                <button
                  ref={menuTriggerRef}
                  type="button"
                  className={sidebarOverflowMenuButtonClass}
                  aria-label={`Options pour ${item.label}`}
                  onClick={(e) => e.stopPropagation()}
                >
                  <MoreVertical className="h-4 w-4" />
                </button>
              </DropdownMenuTrigger>
              <DropdownMenuContent align="end" className="min-w-40">
                <DropdownMenuItem
                  onClick={() => {
                    onEnableNavLabel(item.id)
                    setMenuOpen(false)
                  }}
                >
                  Réactiver le libellé
                </DropdownMenuItem>
              </DropdownMenuContent>
            </DropdownMenu>
          )}
        </div>
        {touchNav && (
          <SidebarNavOptionsSheet
            open={sheetOpen}
            onOpenChange={setSheetOpen}
            title={item.label}
          >
            <SidebarNavSheetAction
              onClick={() => {
                onEnableNavLabel(item.id)
                closeSheet()
              }}
            >
              Réactiver le libellé
            </SidebarNavSheetAction>
          </SidebarNavOptionsSheet>
        )}
      </>
    )
  }

  return (
    <>
    <div
      {...dropHandlers}
      {...touchRowProps}
      className={cn(
        "group/catnav flex h-8 w-full min-w-0 shrink-0 cursor-pointer items-center pl-6 pr-2 transition-colors",
        navRowRoundedWhenActive(isSelected || isOver || rowHoverHeld),
        isSelected
          ? "bg-[#d3e3fd] text-gray-900 font-medium"
          : isOver
            ? "bg-yellow-100 text-gray-900"
            : rowHoverHeld
              ? "bg-gray-100 text-gray-900"
              : hasUnread
                ? "text-gray-900 hover:bg-gray-100"
                : "text-gray-700 hover:bg-gray-100",
        touchRowClassName
      )}
    >
      <button
        type="button"
        onClick={() => onSelectFolder(item.id)}
        title={!isExpanded ? item.label : undefined}
        className={cn(
          "flex h-8 min-w-0 flex-1 cursor-pointer items-center gap-4 py-0 text-left outline-none",
          showCategoryMenu ? "pr-1" : "pr-3"
        )}
      >
        <SidebarNavIconSlot showUnreadDot={hasUnread}>
          {rowIcon}
        </SidebarNavIconSlot>
        {isExpanded && (
          <div className="flex min-w-0 flex-1 items-baseline gap-4">
            <span
              className={cn(
                "min-w-0 flex-1 truncate text-sm leading-5",
                hasUnread && !isSelected && "font-semibold text-gray-900"
              )}
            >
              {item.label}
            </span>
            {!showCategoryMenu && unreadCount > 0 && (
              <span
                className={cn(
                  "shrink-0 text-xs tabular-nums leading-none",
                  isSelected && "font-medium",
                  hasUnread && !isSelected && "font-semibold"
                )}
              >
                {formatCount(unreadCount)}
              </span>
            )}
          </div>
        )}
      </button>
      {showCategoryMenu && (
        <SidebarOverflowColumn
          unread={unreadCount}
          menuOpen={menuOpen || sheetOpen}
          hoverGroup="catnav"
          isSelected={isSelected}
          hasUnread={hasUnread}
          className="mr-[-7px]"
          showMenuButton={!touchNav}
        >
          {!touchNav && (
            <DropdownMenu open={menuOpen} onOpenChange={handleMenuOpenChange}>
              <DropdownMenuTrigger asChild>
                <button
                  ref={menuTriggerRef}
                  type="button"
                  className={cn(sidebarOverflowMenuButtonClass, isSelected && "text-gray-900")}
                  aria-label={`Options pour ${item.label}`}
                  onClick={(e) => {
                    e.stopPropagation()
                  }}
                >
                  <MoreVertical className="h-4 w-4" />
                </button>
              </DropdownMenuTrigger>
              <DropdownMenuContent align="end" className="min-w-40">
                <DropdownMenuItem disabled className="text-gray-400">
                  Afficher
                </DropdownMenuItem>
                <DropdownMenuItem
                  onClick={() => {
                    onDisableNavLabel(item.id)
                    setMenuOpen(false)
                  }}
                >
                  Désactiver le libellé
                </DropdownMenuItem>
              </DropdownMenuContent>
            </DropdownMenu>
          )}
        </SidebarOverflowColumn>
      )}
    </div>
    {touchNav && showCategoryMenu && (
      <SidebarNavOptionsSheet
        open={sheetOpen}
        onOpenChange={setSheetOpen}
        title={item.label}
      >
        <div className="px-4 py-3 text-sm text-[#9aa0a6]">Afficher</div>
        <SidebarNavSheetAction
          onClick={() => {
            onDisableNavLabel(item.id)
            closeSheet()
          }}
        >
          Désactiver le libellé
        </SidebarNavSheetAction>
      </SidebarNavOptionsSheet>
    )}
    </>
  )
}

export function Sidebar({
  selectedFolder,
  onSelectFolder,
  collapsed,
  folderUnreadCounts = {},
  splitView = false,
}: SidebarProps) {
  const { openCompose } = useComposeActions()
  const [hoverExpanded, setHoverExpanded] = useState(false)
  const [navMoreOpen, setNavMoreOpen] = useState(false)
  const [expandedFolderIds, setExpandedFolderIds] = useState<Set<string>>(() => new Set())
  const hoverTimeoutRef = useRef<NodeJS.Timeout | null>(null)
  const sidebarRef = useRef<HTMLElement>(null)
  const touchNav = useTouchNav()
  const isXs = useIsXs()

  const isExpanded = !collapsed || (!touchNav && hoverExpanded)
  const isOverlayOpen = touchNav && !collapsed

  const {
    folderTree,
    labelRows,
    folderIdToLabel,
    addFolder,
    addLabelRowFromSidebar,
    getNavItemPrefs,
    setNavItemSidebarVisibility,
    setNavItemMessageVisibility,
    updateFolderOrLabelColor,
    renameFolderOrLabel,
    removeFolderOrLabelRow,
    moveFolder,
    reorderLabelRows,
    moveFolderRelative,
    addSubfolder,
    addChildLabelRow,
    setLabelRowEnabled,
  } = useSidebarNav()

  const navDragRef = useRef<SidebarNavDragPayload | null>(null)
  const navDragSourceElRef = useRef<HTMLElement | null>(null)
  const navDropTargetElRef = useRef<HTMLElement | null>(null)
  const navDropPlacementRef = useRef<SidebarNavDropPlacement | null>(null)

  const beginNavDrag = useCallback(
    (payload: SidebarNavDragPayload, sourceEl: HTMLElement | null) => {
      navDragRef.current = payload
      navDragSourceElRef.current = sourceEl
      markNavDragSource(sourceEl)
    },
    []
  )

  const clearNavDrag = useCallback(() => {
    unmarkNavDragSource(navDragSourceElRef.current)
    setNavDropIndicator(navDropTargetElRef.current, null)
    navDragRef.current = null
    navDragSourceElRef.current = null
    navDropTargetElRef.current = null
    navDropPlacementRef.current = null
  }, [])

  const updateNavDropTarget = useCallback(
    (el: HTMLElement, placement: SidebarNavDropPlacement) => {
      if (navDropTargetElRef.current !== el) {
        setNavDropIndicator(navDropTargetElRef.current, null)
      }
      navDropTargetElRef.current = el
      navDropPlacementRef.current = placement
      setNavDropIndicator(el, placement)
    },
    []
  )

  const clearNavDropTarget = useCallback((el: HTMLElement) => {
    if (navDropTargetElRef.current === el) {
      setNavDropIndicator(el, null)
      navDropTargetElRef.current = null
      navDropPlacementRef.current = null
    }
  }, [])

  const commitNavDrop = useCallback(
    (
      payload: SidebarNavDragPayload,
      targetId: string,
      placement: SidebarNavDropPlacement,
      targetKind: "label" | "folder"
    ) => {
      clearNavDrag()
      if (payload.id === targetId && placement !== "inside") return
      if (targetKind === "label" && payload.kind === "label") {
        if (placement === "inside") return
        reorderLabelRows(payload.id, targetId, placement)
      } else if (targetKind === "folder" && payload.kind === "folder") {
        moveFolderRelative(payload.id, targetId, placement)
        if (placement === "inside") {
          setExpandedFolderIds((prev) => {
            const next = new Set(prev)
            next.add(targetId)
            return next
          })
        }
      }
    },
    [clearNavDrag, moveFolderRelative, reorderLabelRows]
  )

  const visibleNavLabelRows = useMemo(() => {
    return labelRows.filter((row) => {
      if (row.enabled === false) return false
      if (isSystemNavLabelId(row.id)) return false
      const p = getNavItemPrefs(row.id)
      if (p.sidebar === "hide") return false
      if (
        p.sidebar === "showUnread" &&
        (folderUnreadCounts[row.id] ?? 0) === 0
      ) {
        return false
      }
      return true
    })
  }, [labelRows, getNavItemPrefs, folderUnreadCounts])

  const validNavFolderIds = useMemo(() => {
    const s = new Set<string>()
    for (const i of mainItems) s.add(i.id)
    for (const k of Object.keys(folderIdToLabel)) s.add(k)
    return s
  }, [folderIdToLabel])

  useEffect(() => {
    if (!validNavFolderIds.has(selectedFolder)) {
      onSelectFolder("inbox")
    }
  }, [validNavFolderIds, selectedFolder, onSelectFolder])

  const [folderDialogOpen, setFolderDialogOpen] = useState(false)
  const [labelDialogOpen, setLabelDialogOpen] = useState(false)
  const [newFolderName, setNewFolderName] = useState("")
  const [newFolderParent, setNewFolderParent] = useState("__root__")
  const [newLabelName, setNewLabelName] = useState("")
  const newFolderNameInputRef = useRef<HTMLInputElement>(null)
  const newLabelNameInputRef = useRef<HTMLInputElement>(null)

  const folderParentOptions = useMemo(
    () => folderParentSelectOptions(folderTree),
    [folderTree]
  )

  const { primaryVisibleCategories, plusOnlyVisibleCategories } = useMemo(() => {
    const systemEnabled = sortSystemLabelRows(
      labelRows.filter((r) => r.enabled !== false && isSystemNavLabelId(r.id))
    ).map((r) => ({ id: r.id, label: r.label, icon: r.icon }))
    return {
      primaryVisibleCategories: systemEnabled.filter(
        (c) => !CATEGORY_IDS_IN_PLUS_ONLY.has(c.id)
      ),
      plusOnlyVisibleCategories: systemEnabled.filter((c) =>
        CATEGORY_IDS_IN_PLUS_ONLY.has(c.id)
      ),
    }
  }, [labelRows])

  const disabledSystemNavItems = useMemo(() => {
    return sortSystemLabelRows(
      labelRows.filter((r) => r.enabled === false && isSystemNavLabelId(r.id))
    ).map((r) => ({ id: r.id, label: r.label, icon: r.icon }))
  }, [labelRows])

  const visibleMainItems = useMemo(() => {
    const scheduledTotal = folderUnreadCounts.scheduled ?? 0
    if (scheduledTotal > 0) return mainItems
    return mainItems.filter((item) => item.id !== "scheduled")
  }, [folderUnreadCounts.scheduled])

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

  const handleSubmitNewFolder = () => {
    const name = newFolderName.trim()
    if (!name) return
    const parentId = newFolderParent === "__root__" ? null : newFolderParent
    addFolder(parentId, name)
    setNewFolderName("")
    setFolderDialogOpen(false)
  }

  const handleSubmitNewLabel = () => {
    const name = newLabelName.trim()
    if (!name) return
    addLabelRowFromSidebar(name)
    setNewLabelName("")
    setLabelDialogOpen(false)
  }

  useEffect(() => {
    const row = labelRows.find((r) => r.id === selectedFolder)
    if (row && row.enabled === false) {
      onSelectFolder("inbox")
    }
  }, [labelRows, selectedFolder, onSelectFolder])

  useEffect(() => {
    if (selectedFolder !== "scheduled") return
    if ((folderUnreadCounts.scheduled ?? 0) > 0) return
    onSelectFolder("inbox")
  }, [folderUnreadCounts.scheduled, selectedFolder, onSelectFolder])

  useEffect(() => {
    if (CATEGORY_IDS_IN_PLUS_ONLY.has(selectedFolder) && !navMoreOpen) {
      setNavMoreOpen(true)
    }
  }, [selectedFolder, navMoreOpen])

  useEffect(() => {
    const ancestors = ancestorFolderIdsForTarget(folderTree, selectedFolder)
    if (ancestors?.length) {
      setExpandedFolderIds((prev) => {
        const next = new Set(prev)
        ancestors.forEach((id) => next.add(id))
        return next
      })
    }
  }, [selectedFolder])

  const handleMouseEnter = () => {
    if (readTouchNavMatches()) return
    if (collapsed) {
      hoverTimeoutRef.current = setTimeout(() => {
        setHoverExpanded(true)
      }, 300)
    }
  }

  const handleMouseLeave = () => {
    if (hoverTimeoutRef.current) {
      clearTimeout(hoverTimeoutRef.current)
      hoverTimeoutRef.current = null
    }
    if (readTouchNavMatches()) return
    setHoverExpanded(false)
  }

  useEffect(() => {
    if (touchNav) setHoverExpanded(false)
  }, [touchNav, collapsed])

  useEffect(() => {
    return () => {
      if (hoverTimeoutRef.current) {
        clearTimeout(hoverTimeoutRef.current)
      }
    }
  }, [])

  /** Inset rows from sidebar right edge (padding works with w-full; margin-right often clips under overflow-x-hidden). */
  const navRailInset = "pr-3.5"

  /** pl-6 + demi-largeur icône nav (h-5) → axe à 34px ; picto split (size-9) centré sur cet axe. */
  const splitViewLogoIconClass = "size-9 shrink-0"
  /** Aligné sur la barre split (pt-1 shell + py-2 + recherche h-12) et le bouton menu size-9. */
  const splitViewLogoHeaderClass =
    "box-border min-h-[80px] pt-3 pl-4 pr-3.5 pb-4"

  /** Same row geometry collapsed / expanded / hover so icons never jump (h-8, pl-6 icon column). */
  const NavItem = ({
    item,
    isSelected,
    unreadCount,
  }: {
    item: { id: string; label: string; icon: React.ElementType }
    isSelected: boolean
    unreadCount: number
  }) => {
    const { isOver, dropHandlers } = useEmailDropTarget(item.id, item.label)
    const hasUnread = unreadCount > 0
    return (
      <button
        onClick={() => onSelectFolder(item.id)}
        title={!isExpanded ? item.label : undefined}
        {...dropHandlers}
        className={cn(
          "flex h-8 w-full min-w-0 shrink-0 cursor-pointer items-center gap-4 pl-6 pr-3 transition-colors",
          navRowRoundedWhenActive(isSelected || isOver),
          isSelected
            ? "bg-[#d3e3fd] text-gray-900 font-medium"
            : isOver
              ? "bg-yellow-100 text-gray-900"
              : hasUnread
                ? "text-gray-900 hover:bg-gray-100"
                : "text-gray-700 hover:bg-gray-100"
        )}
      >
        <item.icon
          className={cn(
            "h-5 w-5 shrink-0",
            hasUnread && !isSelected && "text-gray-900"
          )}
        />
        {isExpanded && (
          <div className="flex min-w-0 flex-1 items-baseline gap-4">
            <span
              className={cn(
                "min-w-0 flex-1 truncate text-left text-sm leading-5",
                hasUnread && !isSelected && "font-semibold text-gray-900"
              )}
            >
              {item.label}
            </span>
            {unreadCount > 0 && (
              <span
                className={cn(
                  "shrink-0 text-xs tabular-nums leading-none",
                  isSelected && "font-medium",
                  hasUnread && !isSelected && "font-semibold"
                )}
              >
                {formatCount(unreadCount)}
              </span>
            )}
          </div>
        )}
      </button>
    )
  }

  const FolderRowExpanded = ({
    node,
    depth,
  }: {
    node: FolderTreeNode
    depth: number
  }) => {
    const { isOver, dropHandlers } = useEmailDropTarget(node.id, node.label)
    const hasChildren = !!(node.children?.length)
    const isBranchOpen = expandedFolderIds.has(node.id)
    const dotClass = node.color ?? "bg-gray-400"
    const isSelected = selectedFolder === node.id
    const unread = folderUnreadCounts[node.id] ?? 0
    const hasUnread = unread > 0
    const isStickyBranch = hasChildren && isBranchOpen
    const stickyTopPx = 32 + depth * 32
    const [menuOpen, setMenuOpen] = useState(false)
    const [contextMenuOpen, setContextMenuOpen] = useState(false)
    const menuTriggerRef = useRef<HTMLButtonElement>(null)
    const [renameOpen, setRenameOpen] = useState(false)
    const [renameDraft, setRenameDraft] = useState(node.label)
    const [moveOpen, setMoveOpen] = useState(false)
    const [moveParent, setMoveParent] = useState("__root__")
    const [subfolderOpen, setSubfolderOpen] = useState(false)
    const [subfolderName, setSubfolderName] = useState("")
    const folderRenameInputRef = useRef<HTMLInputElement>(null)
    const subfolderNameInputRef = useRef<HTMLInputElement>(null)
    const { sheetOpen, setSheetOpen, touchRowProps, touchRowClassName, closeSheet } =
      useSidebarTouchOptionsMenu(touchNav && isExpanded)

    useEffect(() => {
      setRenameDraft(node.label)
    }, [node.label])

    const handleMenuOpenChange = (open: boolean) => {
      setMenuOpen(open)
      if (!open) {
        queueMicrotask(() => menuTriggerRef.current?.blur())
      }
    }

    const rowHoverHeld =
      !isSelected && !isOver && (contextMenuOpen || menuOpen || sheetOpen)

    const prefs = getNavItemPrefs(node.id)
    const moveTargets = useMemo(
      () => folderMoveParentOptions(folderTree, node.id),
      [folderTree, node.id]
    )

    const folderMenuSurface =
      "min-w-[240px] border-gray-200 bg-white p-0 py-1.5 shadow-md"

    const colorSub = (
      subKind: "dropdown" | "context"
    ) => {
      const Sub = subKind === "dropdown" ? DropdownMenuSub : ContextMenuSub
      const SubTr =
        subKind === "dropdown" ? DropdownMenuSubTrigger : ContextMenuSubTrigger
      const SubCo =
        subKind === "dropdown" ? DropdownMenuSubContent : ContextMenuSubContent
      return (
        <Sub>
          <SubTr
            className={cn(
              "mx-1 cursor-pointer rounded-sm px-2 py-2 text-gray-800 focus:bg-gray-100 data-[state=open]:bg-gray-100",
              subKind === "context" && "flex items-center gap-2"
            )}
          >
            <span className="flex size-5 shrink-0 items-center justify-center rounded-full border border-gray-300 bg-white">
              <span
                className={cn(
                  "block size-3 rounded-sm border border-black/10",
                  dotClass
                )}
                aria-hidden
              />
            </span>
            <span className="flex-1 text-left text-sm">Couleur du dossier</span>
          </SubTr>
          <SubCo className="min-w-[180px] border-gray-200 bg-white p-2 shadow-md">
            <div className="grid grid-cols-6 gap-1.5">
              {LABEL_MENU_COLOR_SWATCHES.map((sw) => (
                <button
                  key={sw}
                  type="button"
                  title={sw}
                  onClick={() => {
                    updateFolderOrLabelColor(node.id, sw)
                    setMenuOpen(false)
                  }}
                  className={cn(
                    "size-6 rounded-full border border-black/10 outline-none ring-offset-1 hover:ring-2 hover:ring-gray-400 focus-visible:ring-2 focus-visible:ring-gray-500",
                    sw
                  )}
                />
              ))}
            </div>
          </SubCo>
        </Sub>
      )
    }

    const rowClass = cn(
      "group/folderrow relative flex h-8 w-full min-w-0 shrink-0 cursor-default items-center gap-2 pr-3 text-sm transition-colors",
      isSelected || isOver || rowHoverHeld ? "rounded-r-full" : "rounded-r-none",
      isStickyBranch && "sticky border-b border-gray-200/70",
      isStickyBranch && !isSelected && !rowHoverHeld && "bg-app-canvas",
      isSelected && "bg-[#d3e3fd] font-medium text-gray-900",
      !isSelected && hasUnread && "text-gray-900",
      isOver && "bg-yellow-100 text-gray-900",
      rowHoverHeld && "bg-gray-100 text-gray-900",
      touchRowClassName
    )
    const rowStyle: CSSProperties = {
      paddingLeft: 24 + depth * 16,
      ...(isStickyBranch ? { top: stickyTopPx, zIndex: 30 - depth } : {}),
    }

    const overflowMenu = (
      <SidebarOverflowColumn
        unread={unread}
        menuOpen={menuOpen || sheetOpen}
        hoverGroup="folderrow"
        isSelected={isSelected}
        hasUnread={hasUnread}
        className={cn(!isExpanded && "hidden", "mr-[-11px]")}
        showMenuButton={!touchNav}
      >
        {!touchNav && (
        <DropdownMenu open={menuOpen} onOpenChange={handleMenuOpenChange}>
          <DropdownMenuTrigger asChild>
            <button
              ref={menuTriggerRef}
              type="button"
              className={cn(sidebarOverflowMenuButtonClass, isSelected && "text-gray-900")}
              aria-label={`Options pour ${node.label}`}
              onClick={(e) => e.stopPropagation()}
            >
              <MoreVertical className="h-4 w-4" />
            </button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="end" className={folderMenuSurface}>
              {colorSub("dropdown")}
              <DropdownMenuSeparator className="my-1.5 bg-gray-200" />
              <DropdownMenuLabel className="px-3 py-1 text-[11px] font-normal normal-case tracking-normal text-gray-500">
                Dans la liste des dossiers
              </DropdownMenuLabel>
              <LabelMenuOptionWithCheck
                checked={prefs.sidebar === "show"}
                onPick={() => setNavItemSidebarVisibility(node.id, "show")}
              >
                Afficher
              </LabelMenuOptionWithCheck>
              <LabelMenuOptionWithCheck
                checked={prefs.sidebar === "showUnread"}
                onPick={() => setNavItemSidebarVisibility(node.id, "showUnread")}
              >
                Afficher si messages non lus
              </LabelMenuOptionWithCheck>
              <LabelMenuOptionWithCheck
                checked={prefs.sidebar === "hide"}
                onPick={() => setNavItemSidebarVisibility(node.id, "hide")}
              >
                Masquer
              </LabelMenuOptionWithCheck>
              <DropdownMenuSeparator className="my-1.5 bg-gray-200" />
              <DropdownMenuLabel className="px-3 py-1 text-[11px] font-normal normal-case tracking-normal text-gray-500">
                Dans la liste des messages
              </DropdownMenuLabel>
              <LabelMenuOptionWithCheck
                checked={prefs.messages === "show"}
                onPick={() => setNavItemMessageVisibility(node.id, "show")}
              >
                Afficher
              </LabelMenuOptionWithCheck>
              <LabelMenuOptionWithCheck
                checked={prefs.messages === "hide"}
                onPick={() => setNavItemMessageVisibility(node.id, "hide")}
              >
                Masquer
              </LabelMenuOptionWithCheck>
              <DropdownMenuSeparator className="my-1.5 bg-gray-200" />
              <DropdownMenuItem
                className="mx-1 cursor-pointer px-3 py-2 text-sm text-gray-800 focus:bg-gray-100"
                onClick={() => {
                  setRenameDraft(node.label)
                  setRenameOpen(true)
                  setMenuOpen(false)
                }}
              >
                Renommer…
              </DropdownMenuItem>
              <DropdownMenuItem
                className="mx-1 cursor-pointer px-3 py-2 text-sm text-gray-800 focus:bg-gray-100"
                onClick={() => {
                  setMoveParent("__root__")
                  setMoveOpen(true)
                  setMenuOpen(false)
                }}
              >
                Déplacer…
              </DropdownMenuItem>
              <DropdownMenuItem
                className="mx-1 cursor-pointer px-3 py-2 text-sm text-gray-800 focus:bg-gray-100"
                onClick={() => {
                  setSubfolderName("")
                  setSubfolderOpen(true)
                  setMenuOpen(false)
                }}
              >
                Nouveau sous-dossier…
              </DropdownMenuItem>
              <DropdownMenuItem
                variant="destructive"
                className="mx-1 cursor-pointer px-3 py-2 text-sm focus:bg-red-50"
                onClick={() => {
                  removeFolderOrLabelRow(node.id)
                  setMenuOpen(false)
                }}
              >
                Supprimer le dossier
              </DropdownMenuItem>
              </DropdownMenuContent>
        </DropdownMenu>
        )}
      </SidebarOverflowColumn>
    )

    const folderOptionsSheet = touchNav && isExpanded && (
      <SidebarNavOptionsSheet
        open={sheetOpen}
        onOpenChange={setSheetOpen}
        title={node.label}
        colorDotClass={dotClass}
      >
        <SidebarNavSheetColorPicker
          title="Couleur du dossier"
          dotClass={dotClass}
          swatches={LABEL_MENU_COLOR_SWATCHES}
          onPick={(sw) => {
            updateFolderOrLabelColor(node.id, sw)
            closeSheet()
          }}
        />
        <SidebarNavSheetDivider />
        <SidebarNavSheetSectionLabel>Dans la liste des dossiers</SidebarNavSheetSectionLabel>
        <SidebarNavSheetCheckOption
          checked={prefs.sidebar === "show"}
          onPick={() => {
            setNavItemSidebarVisibility(node.id, "show")
            closeSheet()
          }}
        >
          Afficher
        </SidebarNavSheetCheckOption>
        <SidebarNavSheetCheckOption
          checked={prefs.sidebar === "showUnread"}
          onPick={() => {
            setNavItemSidebarVisibility(node.id, "showUnread")
            closeSheet()
          }}
        >
          Afficher si messages non lus
        </SidebarNavSheetCheckOption>
        <SidebarNavSheetCheckOption
          checked={prefs.sidebar === "hide"}
          onPick={() => {
            setNavItemSidebarVisibility(node.id, "hide")
            closeSheet()
          }}
        >
          Masquer
        </SidebarNavSheetCheckOption>
        <SidebarNavSheetDivider />
        <SidebarNavSheetSectionLabel>Dans la liste des messages</SidebarNavSheetSectionLabel>
        <SidebarNavSheetCheckOption
          checked={prefs.messages === "show"}
          onPick={() => {
            setNavItemMessageVisibility(node.id, "show")
            closeSheet()
          }}
        >
          Afficher
        </SidebarNavSheetCheckOption>
        <SidebarNavSheetCheckOption
          checked={prefs.messages === "hide"}
          onPick={() => {
            setNavItemMessageVisibility(node.id, "hide")
            closeSheet()
          }}
        >
          Masquer
        </SidebarNavSheetCheckOption>
        <SidebarNavSheetDivider />
        <SidebarNavSheetAction
          onClick={() => {
            setRenameDraft(node.label)
            setRenameOpen(true)
            closeSheet()
          }}
        >
          Renommer…
        </SidebarNavSheetAction>
        <SidebarNavSheetAction
          onClick={() => {
            setMoveParent("__root__")
            setMoveOpen(true)
            closeSheet()
          }}
        >
          Déplacer…
        </SidebarNavSheetAction>
        <SidebarNavSheetAction
          onClick={() => {
            setSubfolderName("")
            setSubfolderOpen(true)
            closeSheet()
          }}
        >
          Nouveau sous-dossier…
        </SidebarNavSheetAction>
        <SidebarNavSheetAction
          destructive
          onClick={() => {
            removeFolderOrLabelRow(node.id)
            closeSheet()
          }}
        >
          Supprimer le dossier
        </SidebarNavSheetAction>
      </SidebarNavOptionsSheet>
    )

    const onFolderRowDragEnter = (e: React.DragEvent) => {
      const active = navDragRef.current
      if (active?.kind === "folder" && active.id !== node.id) {
        e.preventDefault()
        return
      }
      dropHandlers.onDragEnter(e)
    }

    const onFolderRowDragOver = (e: React.DragEvent) => {
      const active = navDragRef.current
      if (active?.kind === "folder") {
        e.preventDefault()
        e.stopPropagation()
        if (active.id === node.id) return
        const ancestors = ancestorFolderIdsForTarget(folderTree, node.id)
        if (ancestors?.includes(active.id)) return
        e.dataTransfer.dropEffect = "move"
        updateNavDropTarget(
          e.currentTarget as HTMLElement,
          resolveNavDropPlacement(e, true)
        )
        return
      }
      dropHandlers.onDragOver(e)
    }

    const onFolderRowDragLeave = (e: React.DragEvent) => {
      if (navDragRef.current?.kind === "folder") {
        const rt = e.relatedTarget as Node | null
        if (rt && e.currentTarget instanceof Node && e.currentTarget.contains(rt)) return
        clearNavDropTarget(e.currentTarget as HTMLElement)
        return
      }
      dropHandlers.onDragLeave(e)
    }

    const onFolderRowDrop = (e: React.DragEvent) => {
      const payload = readSidebarNavDragData(e, navDragRef.current)
      if (payload?.kind === "folder") {
        e.preventDefault()
        e.stopPropagation()
        const placement = navDropPlacementRef.current ?? resolveNavDropPlacement(e, true)
        commitNavDrop(payload, node.id, placement, "folder")
        return
      }
      dropHandlers.onDrop(e)
    }

    const onFolderDragHandleStart = (e: React.DragEvent<HTMLSpanElement>) => {
      const payload = { kind: "folder" as const, id: node.id }
      setSidebarNavDragData(e, payload)
      const rowEl = (e.currentTarget as HTMLElement).closest("[data-nav-row]") as HTMLElement | null
      beginNavDrag(payload, rowEl)
    }

    const folderRowEl = (
            <div
              data-nav-row
              {...touchRowProps}
              onDragEnter={onFolderRowDragEnter}
              onDragOver={onFolderRowDragOver}
              onDragLeave={onFolderRowDragLeave}
              onDrop={onFolderRowDrop}
              className={rowClass}
              style={rowStyle}
            >
              {isExpanded ? (
                <SidebarNavDragHandle
                  label={node.label}
                  onDragStart={onFolderDragHandleStart}
                  onDragEnd={clearNavDrag}
                />
              ) : null}
              <div
                role="button"
                tabIndex={0}
                onClick={() => onSelectFolder(node.id)}
                onKeyDown={(e) => navRowActivate(e, () => onSelectFolder(node.id))}
                className={cn(
                  "flex h-8 min-w-0 flex-1 cursor-pointer items-center gap-3 py-0 pr-1 text-left transition-colors outline-none focus-visible:ring-2 focus-visible:ring-ring/50",
                  !isSelected &&
                    !isOver &&
                    !rowHoverHeld &&
                    "rounded-r-none hover:rounded-r-full hover:bg-gray-100",
                  rowHoverHeld && !isSelected && !isOver && "rounded-r-full",
                  isSelected
                    ? "text-gray-900"
                    : isOver
                      ? "text-gray-900"
                      : "text-gray-700"
                )}
              >
                {hasChildren ? (
                  <button
                    type="button"
                    draggable={false}
                    className="flex h-5 w-5 shrink-0 cursor-pointer items-center justify-center rounded outline-none hover:bg-black/5 focus-visible:ring-2 focus-visible:ring-ring/50"
                    aria-expanded={isBranchOpen}
                    aria-label={
                      isBranchOpen
                        ? `Replier le dossier ${node.label}`
                        : `Déplier le dossier ${node.label}`
                    }
                    onClick={(e) => {
                      e.preventDefault()
                      e.stopPropagation()
                      toggleFolderExpanded(node.id)
                    }}
                  >
                    <SidebarNavIconSlot showUnreadDot={hasUnread}>
                      <FolderTreeNavIcon
                        hasChildren
                        open={isBranchOpen}
                        colorBgClass={dotClass}
                      />
                    </SidebarNavIconSlot>
                  </button>
                ) : (
                  <SidebarNavIconSlot showUnreadDot={hasUnread}>
                    <FolderTreeNavIcon
                      hasChildren={false}
                      open={false}
                      colorBgClass={dotClass}
                    />
                  </SidebarNavIconSlot>
                )}
                <div className="flex min-w-0 flex-1 items-baseline gap-3">
                  <span className="min-w-0 flex-1 truncate leading-5">
                    <span
                      className={cn(
                        hasUnread && !isSelected && "font-semibold text-gray-900"
                      )}
                    >
                      {node.label}
                    </span>
                  </span>
                </div>
              </div>
              {overflowMenu}
            </div>
    )

    return (
      <>
        {touchNav ? (
          folderRowEl
        ) : (
        <ContextMenu onOpenChange={setContextMenuOpen}>
          <ContextMenuTrigger asChild>{folderRowEl}</ContextMenuTrigger>
          <ContextMenuContent className={folderMenuSurface}>
            {colorSub("context")}
            <ContextMenuSeparator className="my-1.5 bg-gray-200" />
            <ContextMenuLabel className="px-3 py-1 text-[11px] font-normal normal-case tracking-normal text-gray-500">
              Dans la liste des dossiers
            </ContextMenuLabel>
            <ContextLabelMenuOptionWithCheck
              checked={prefs.sidebar === "show"}
              onPick={() => setNavItemSidebarVisibility(node.id, "show")}
            >
              Afficher
            </ContextLabelMenuOptionWithCheck>
            <ContextLabelMenuOptionWithCheck
              checked={prefs.sidebar === "showUnread"}
              onPick={() => setNavItemSidebarVisibility(node.id, "showUnread")}
            >
              Afficher si non lus
            </ContextLabelMenuOptionWithCheck>
            <ContextLabelMenuOptionWithCheck
              checked={prefs.sidebar === "hide"}
              onPick={() => setNavItemSidebarVisibility(node.id, "hide")}
            >
              Masquer
            </ContextLabelMenuOptionWithCheck>
            <ContextMenuSeparator className="my-1.5 bg-gray-200" />
            <ContextMenuLabel className="px-3 py-1 text-[11px] font-normal normal-case tracking-normal text-gray-500">
              Dans la liste des messages
            </ContextMenuLabel>
            <ContextLabelMenuOptionWithCheck
              checked={prefs.messages === "show"}
              onPick={() => setNavItemMessageVisibility(node.id, "show")}
            >
              Afficher
            </ContextLabelMenuOptionWithCheck>
            <ContextLabelMenuOptionWithCheck
              checked={prefs.messages === "hide"}
              onPick={() => setNavItemMessageVisibility(node.id, "hide")}
            >
              Masquer
            </ContextLabelMenuOptionWithCheck>
            <ContextMenuSeparator className="my-1.5 bg-gray-200" />
            <ContextMenuItem
              className="mx-1 cursor-pointer px-3 py-2 text-sm"
              onClick={() => {
                setRenameDraft(node.label)
                setRenameOpen(true)
              }}
            >
              Renommer…
            </ContextMenuItem>
            <ContextMenuItem
              className="mx-1 cursor-pointer px-3 py-2 text-sm"
              onClick={() => {
                setMoveParent("__root__")
                setMoveOpen(true)
              }}
            >
              Déplacer…
            </ContextMenuItem>
            <ContextMenuItem
              className="mx-1 cursor-pointer px-3 py-2 text-sm"
              onClick={() => {
                setSubfolderName("")
                setSubfolderOpen(true)
              }}
            >
              Nouveau sous-dossier…
            </ContextMenuItem>
            <ContextMenuItem
              variant="destructive"
              className="mx-1 cursor-pointer px-3 py-2 text-sm"
              onClick={() => removeFolderOrLabelRow(node.id)}
            >
              Supprimer le dossier
            </ContextMenuItem>
          </ContextMenuContent>
        </ContextMenu>
        )}
        {folderOptionsSheet}

        <Dialog open={renameOpen} onOpenChange={setRenameOpen}>
          <DialogContent
            className="sm:max-w-md"
            showCloseButton
            onOpenAutoFocus={(e) => {
              e.preventDefault()
              window.requestAnimationFrame(() =>
                folderRenameInputRef.current?.focus()
              )
            }}
          >
            <DialogHeader>
              <DialogTitle>Renommer le dossier</DialogTitle>
              <DialogDescription>Nouveau nom pour « {node.label} ».</DialogDescription>
            </DialogHeader>
            <Input
              ref={folderRenameInputRef}
              value={renameDraft}
              onChange={(e) => setRenameDraft(e.target.value)}
              autoComplete="off"
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  e.preventDefault()
                  renameFolderOrLabel(node.id, renameDraft)
                  setRenameOpen(false)
                }
              }}
            />
            <DialogFooter>
              <Button variant="outline" type="button" onClick={() => setRenameOpen(false)}>
                Annuler
              </Button>
              <Button
                type="button"
                onClick={() => {
                  renameFolderOrLabel(node.id, renameDraft)
                  setRenameOpen(false)
                }}
              >
                Enregistrer
              </Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>

        <Dialog open={moveOpen} onOpenChange={setMoveOpen}>
          <DialogContent className="sm:max-w-md" showCloseButton>
            <DialogHeader>
              <DialogTitle>Déplacer le dossier</DialogTitle>
              <DialogDescription>Choisissez le dossier parent.</DialogDescription>
            </DialogHeader>
            <Select value={moveParent} onValueChange={setMoveParent}>
              <SelectTrigger className="w-full min-w-0" size="sm">
                <SelectValue />
              </SelectTrigger>
              <SelectContent position="popper" className="max-h-72">
                {moveTargets.map((o) => (
                  <SelectItem key={o.value} value={o.value}>
                    {o.label}
                  </SelectItem>
                ))}
              </SelectContent>
            </Select>
            <DialogFooter>
              <Button variant="outline" type="button" onClick={() => setMoveOpen(false)}>
                Annuler
              </Button>
              <Button
                type="button"
                onClick={() => {
                  moveFolder(
                    node.id,
                    moveParent === "__root__" ? null : moveParent
                  )
                  setMoveOpen(false)
                }}
              >
                Déplacer
              </Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>

        <Dialog open={subfolderOpen} onOpenChange={setSubfolderOpen}>
          <DialogContent
            className="sm:max-w-md"
            showCloseButton
            onOpenAutoFocus={(e) => {
              e.preventDefault()
              window.requestAnimationFrame(() =>
                subfolderNameInputRef.current?.focus()
              )
            }}
          >
            <DialogHeader>
              <DialogTitle>Nouveau sous-dossier</DialogTitle>
              <DialogDescription>Sous « {node.label} ».</DialogDescription>
            </DialogHeader>
            <Input
              ref={subfolderNameInputRef}
              value={subfolderName}
              onChange={(e) => setSubfolderName(e.target.value)}
              placeholder="Nom du dossier"
              autoComplete="off"
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  e.preventDefault()
                  addSubfolder(node.id, subfolderName)
                  setSubfolderOpen(false)
                }
              }}
            />
            <DialogFooter>
              <Button variant="outline" type="button" onClick={() => setSubfolderOpen(false)}>
                Annuler
              </Button>
              <Button
                type="button"
                onClick={() => {
                  addSubfolder(node.id, subfolderName)
                  setSubfolderOpen(false)
                }}
              >
                Créer
              </Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>
      </>
    )
  }

  const sidebarVisibleFolderNodes = (nodes: FolderTreeNode[]) =>
    nodes.filter((node) => {
      const p = getNavItemPrefs(node.id)
      if (p.sidebar === "hide") return false
      if (
        p.sidebar === "showUnread" &&
        (folderUnreadCounts[node.id] ?? 0) === 0
      ) {
        return false
      }
      return true
    })

  const renderExpandedFolderSubtree = (
    nodes: FolderTreeNode[],
    depth: number
  ): ReactNode =>
    sidebarVisibleFolderNodes(nodes).map((node) => {
        const isBranchOpen = expandedFolderIds.has(node.id)
        const kids = node.children
        return (
          /* Limite le sticky au sous-arbre (évite l’empilement hors contexte). */
          <div key={node.id} className="min-w-0">
            <FolderRowExpanded node={node} depth={depth} />
            {kids?.length && isBranchOpen ? (
              <div className="min-w-0">
                {renderExpandedFolderSubtree(kids, depth + 1)}
              </div>
            ) : null}
          </div>
        )
      })

  const FolderButtonCollapsed = ({ node }: { node: FolderTreeNode }) => {
    const { isOver, dropHandlers } = useEmailDropTarget(node.id, node.label)
    const dotClass = node.color ?? "bg-gray-400"
    const hasChildFolders = !!(node.children?.length)
    const isHighlighted = folderSubtreeContainsId(node, selectedFolder)
    const unread = folderUnreadCounts[node.id] ?? 0
    const hasUnread = unread > 0
    return (
      <button
        type="button"
        title={
          !isExpanded
            ? unread > 0
              ? `${node.label} — ${unread} non lus`
              : node.label
            : undefined
        }
        onClick={() => onSelectFolder(node.id)}
        {...dropHandlers}
        className={cn(
          "relative flex h-8 w-full min-w-0 shrink-0 cursor-pointer items-center gap-4 pl-6 pr-3 text-sm transition-colors",
          navRowRoundedWhenActive(isHighlighted || isOver),
          isHighlighted
            ? "bg-[#d3e3fd] text-gray-900 font-medium"
            : isOver
              ? "bg-yellow-100 text-gray-900"
              : hasUnread
                ? "text-gray-900 hover:bg-gray-100"
                : "text-gray-700 hover:bg-gray-100"
        )}
      >
        <SidebarNavIconSlot showUnreadDot={hasUnread}>
          <FolderTreeNavIcon
            hasChildren={hasChildFolders}
            open={false}
            colorBgClass={dotClass}
          />
        </SidebarNavIconSlot>
      </button>
    )
  }

  /** Rail repliée : mêmes dossiers visibles que lorsque les branches sont dépliées. */
  const renderCollapsedFolderList = (nodes: FolderTreeNode[]): ReactNode => {
    const walk = (list: FolderTreeNode[]): ReactNode[] => {
      const out: ReactNode[] = []
      for (const node of sidebarVisibleFolderNodes(list)) {
        out.push(<FolderButtonCollapsed key={node.id} node={node} />)
        if (node.children?.length && expandedFolderIds.has(node.id)) {
          out.push(...walk(node.children))
        }
      }
      return out
    }
    return walk(nodes)
  }

  const LabelItemRow = ({
    item,
    unreadCount,
    isExpanded: labelRowExpanded,
  }: {
    item: { id: string; label: string; color: string; count?: number }
    unreadCount: number
    isExpanded: boolean
  }) => {
    const { isOver, dropHandlers } = useEmailDropTarget(item.id, item.label)
    const isSelected = selectedFolder === item.id
    const hasUnread = unreadCount > 0
    const [menuOpen, setMenuOpen] = useState(false)
    const [contextMenuOpen, setContextMenuOpen] = useState(false)
    const menuTriggerRef = useRef<HTMLButtonElement>(null)
    const [renameOpen, setRenameOpen] = useState(false)
    const [renameDraft, setRenameDraft] = useState(item.label)
    const [sublabelOpen, setSublabelOpen] = useState(false)
    const [sublabelName, setSublabelName] = useState("")
    const labelRenameInputRef = useRef<HTMLInputElement>(null)
    const sublabelNameInputRef = useRef<HTMLInputElement>(null)
    const canDragLabel = labelRowExpanded && !isSystemNavLabelId(item.id)
    const { sheetOpen, setSheetOpen, touchRowProps, touchRowClassName, closeSheet } =
      useSidebarTouchOptionsMenu(touchNav && labelRowExpanded)

    useEffect(() => {
      setRenameDraft(item.label)
    }, [item.label])

    const handleMenuOpenChange = (open: boolean) => {
      setMenuOpen(open)
      if (!open) {
        queueMicrotask(() => menuTriggerRef.current?.blur())
      }
    }

    const rowHoverHeld =
      !isSelected && !isOver && (contextMenuOpen || menuOpen || sheetOpen)

    const prefs = getNavItemPrefs(item.id)
    const labelDotClass = item.color ?? "bg-gray-400"
    const labelMenuSurface =
      "min-w-[240px] border-gray-200 bg-white p-0 py-1.5 shadow-md"

    const colorSub = (subKind: "dropdown" | "context") => {
      const Sub = subKind === "dropdown" ? DropdownMenuSub : ContextMenuSub
      const SubTr =
        subKind === "dropdown" ? DropdownMenuSubTrigger : ContextMenuSubTrigger
      const SubCo =
        subKind === "dropdown" ? DropdownMenuSubContent : ContextMenuSubContent
      return (
        <Sub>
          <SubTr
            className={cn(
              "mx-1 cursor-pointer rounded-sm px-2 py-2 text-gray-800 focus:bg-gray-100 data-[state=open]:bg-gray-100",
              subKind === "context" && "flex items-center gap-2"
            )}
          >
            <span className="flex size-5 shrink-0 items-center justify-center rounded-full border border-gray-300 bg-white">
              <span
                className={cn(
                  "block size-3 rounded-sm border border-black/10",
                  labelDotClass
                )}
                aria-hidden
              />
            </span>
            <span className="flex-1 text-left text-sm">Couleur du libellé</span>
          </SubTr>
          <SubCo className="min-w-[180px] border-gray-200 bg-white p-2 shadow-md">
            <div className="grid grid-cols-6 gap-1.5">
              {LABEL_MENU_COLOR_SWATCHES.map((sw) => (
                <button
                  key={sw}
                  type="button"
                  title={sw}
                  onClick={() => {
                    updateFolderOrLabelColor(item.id, sw)
                    setMenuOpen(false)
                  }}
                  className={cn(
                    "size-6 rounded-full border border-black/10 outline-none ring-offset-1 hover:ring-2 hover:ring-gray-400 focus-visible:ring-2 focus-visible:ring-gray-500",
                    sw
                  )}
                />
              ))}
            </div>
          </SubCo>
        </Sub>
      )
    }

    const rowClass = cn(
      "group/labelrow relative flex h-8 w-full min-w-0 shrink-0 cursor-default items-center pl-6 pr-2 transition-colors",
      navRowRoundedWhenActive(isSelected || isOver || rowHoverHeld),
      isSelected
        ? "bg-[#d3e3fd] text-gray-900 font-medium"
        : isOver
          ? "bg-yellow-100 text-gray-900"
          : rowHoverHeld
            ? "bg-gray-100 text-gray-900"
            : hasUnread
              ? "text-gray-900 hover:bg-gray-100"
              : "text-gray-700 hover:bg-gray-100",
      touchRowClassName
    )

    const onLabelRowDragEnter = (e: React.DragEvent) => {
      const active = navDragRef.current
      if (active?.kind === "label" && active.id !== item.id) {
        e.preventDefault()
        return
      }
      dropHandlers.onDragEnter(e)
    }

    const onLabelRowDragOver = (e: React.DragEvent) => {
      const active = navDragRef.current
      if (active?.kind === "label") {
        e.preventDefault()
        e.stopPropagation()
        if (active.id === item.id) return
        e.dataTransfer.dropEffect = "move"
        updateNavDropTarget(
          e.currentTarget as HTMLElement,
          resolveNavDropPlacement(e, false)
        )
        return
      }
      dropHandlers.onDragOver(e)
    }

    const onLabelRowDragLeave = (e: React.DragEvent) => {
      if (navDragRef.current?.kind === "label") {
        const rt = e.relatedTarget as Node | null
        if (rt && e.currentTarget instanceof Node && e.currentTarget.contains(rt)) return
        clearNavDropTarget(e.currentTarget as HTMLElement)
        return
      }
      dropHandlers.onDragLeave(e)
    }

    const onLabelRowDrop = (e: React.DragEvent) => {
      const payload = readSidebarNavDragData(e, navDragRef.current)
      if (payload?.kind === "label") {
        e.preventDefault()
        e.stopPropagation()
        const placement = navDropPlacementRef.current ?? resolveNavDropPlacement(e, false)
        if (placement !== "inside") {
          commitNavDrop(payload, item.id, placement, "label")
        } else {
          clearNavDrag()
        }
        return
      }
      dropHandlers.onDrop(e)
    }

    const onLabelDragHandleStart = (e: React.DragEvent<HTMLSpanElement>) => {
      const payload = { kind: "label" as const, id: item.id }
      setSidebarNavDragData(e, payload)
      const rowEl = (e.currentTarget as HTMLElement).closest("[data-nav-row]") as HTMLElement | null
      beginNavDrag(payload, rowEl)
    }

    const overflowMenu = labelRowExpanded ? (
      <SidebarOverflowColumn
        unread={unreadCount}
        menuOpen={menuOpen || sheetOpen}
        hoverGroup="labelrow"
        isSelected={isSelected}
        hasUnread={hasUnread}
        className="mr-[-7px]"
        showMenuButton={!touchNav}
      >
        {!touchNav && (
        <DropdownMenu open={menuOpen} onOpenChange={handleMenuOpenChange}>
          <DropdownMenuTrigger asChild>
            <button
              ref={menuTriggerRef}
              type="button"
              draggable={false}
              className={cn(sidebarOverflowMenuButtonClass, isSelected && "text-gray-900")}
              aria-label={`Options pour ${item.label}`}
              onClick={(e) => e.stopPropagation()}
            >
              <MoreVertical className="h-4 w-4" />
            </button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="end" className={labelMenuSurface}>
              {colorSub("dropdown")}
              <DropdownMenuSeparator className="my-1.5 bg-gray-200" />
              <DropdownMenuLabel className="px-3 py-1 text-[11px] font-normal normal-case tracking-normal text-gray-500">
                Dans la liste des libellés
              </DropdownMenuLabel>
              <LabelMenuOptionWithCheck
                checked={prefs.sidebar === "show"}
                onPick={() => setNavItemSidebarVisibility(item.id, "show")}
              >
                Afficher
              </LabelMenuOptionWithCheck>
              <LabelMenuOptionWithCheck
                checked={prefs.sidebar === "showUnread"}
                onPick={() => setNavItemSidebarVisibility(item.id, "showUnread")}
              >
                Afficher si messages non lus
              </LabelMenuOptionWithCheck>
              <LabelMenuOptionWithCheck
                checked={prefs.sidebar === "hide"}
                onPick={() => setNavItemSidebarVisibility(item.id, "hide")}
              >
                Masquer
              </LabelMenuOptionWithCheck>
              <DropdownMenuSeparator className="my-1.5 bg-gray-200" />
              <DropdownMenuLabel className="px-3 py-1 text-[11px] font-normal normal-case tracking-normal text-gray-500">
                Dans la liste des messages
              </DropdownMenuLabel>
              <LabelMenuOptionWithCheck
                checked={prefs.messages === "show"}
                onPick={() => setNavItemMessageVisibility(item.id, "show")}
              >
                Afficher
              </LabelMenuOptionWithCheck>
              <LabelMenuOptionWithCheck
                checked={prefs.messages === "hide"}
                onPick={() => setNavItemMessageVisibility(item.id, "hide")}
              >
                Masquer
              </LabelMenuOptionWithCheck>
              <DropdownMenuSeparator className="my-1.5 bg-gray-200" />
              <DropdownMenuItem
                className="mx-1 cursor-pointer px-3 py-2 text-sm text-gray-800 focus:bg-gray-100"
                onClick={() => {
                  setRenameDraft(item.label)
                  setRenameOpen(true)
                  setMenuOpen(false)
                }}
              >
                Renommer…
              </DropdownMenuItem>
              <DropdownMenuItem
                variant="destructive"
                className="mx-1 cursor-pointer px-3 py-2 text-sm focus:bg-red-50"
                onClick={() => {
                  removeFolderOrLabelRow(item.id)
                  setMenuOpen(false)
                }}
              >
                Supprimer le libellé
              </DropdownMenuItem>
              <DropdownMenuItem
                className="mx-1 cursor-pointer px-3 py-2 text-sm text-gray-800 focus:bg-gray-100"
                onClick={() => {
                  setSublabelName("")
                  setSublabelOpen(true)
                  setMenuOpen(false)
                }}
              >
                Ajouter un sous-libellé
              </DropdownMenuItem>
            </DropdownMenuContent>
        </DropdownMenu>
        )}
      </SidebarOverflowColumn>
    ) : null

    const labelOptionsSheet = touchNav && labelRowExpanded && (
      <SidebarNavOptionsSheet
        open={sheetOpen}
        onOpenChange={setSheetOpen}
        title={item.label}
        colorDotClass={labelDotClass}
      >
        <SidebarNavSheetColorPicker
          title="Couleur du libellé"
          dotClass={labelDotClass}
          swatches={LABEL_MENU_COLOR_SWATCHES}
          onPick={(sw) => {
            updateFolderOrLabelColor(item.id, sw)
            closeSheet()
          }}
        />
        <SidebarNavSheetDivider />
        <SidebarNavSheetSectionLabel>Dans la liste des libellés</SidebarNavSheetSectionLabel>
        <SidebarNavSheetCheckOption
          checked={prefs.sidebar === "show"}
          onPick={() => {
            setNavItemSidebarVisibility(item.id, "show")
            closeSheet()
          }}
        >
          Afficher
        </SidebarNavSheetCheckOption>
        <SidebarNavSheetCheckOption
          checked={prefs.sidebar === "showUnread"}
          onPick={() => {
            setNavItemSidebarVisibility(item.id, "showUnread")
            closeSheet()
          }}
        >
          Afficher si messages non lus
        </SidebarNavSheetCheckOption>
        <SidebarNavSheetCheckOption
          checked={prefs.sidebar === "hide"}
          onPick={() => {
            setNavItemSidebarVisibility(item.id, "hide")
            closeSheet()
          }}
        >
          Masquer
        </SidebarNavSheetCheckOption>
        <SidebarNavSheetDivider />
        <SidebarNavSheetSectionLabel>Dans la liste des messages</SidebarNavSheetSectionLabel>
        <SidebarNavSheetCheckOption
          checked={prefs.messages === "show"}
          onPick={() => {
            setNavItemMessageVisibility(item.id, "show")
            closeSheet()
          }}
        >
          Afficher
        </SidebarNavSheetCheckOption>
        <SidebarNavSheetCheckOption
          checked={prefs.messages === "hide"}
          onPick={() => {
            setNavItemMessageVisibility(item.id, "hide")
            closeSheet()
          }}
        >
          Masquer
        </SidebarNavSheetCheckOption>
        <SidebarNavSheetDivider />
        <SidebarNavSheetAction
          onClick={() => {
            setRenameDraft(item.label)
            setRenameOpen(true)
            closeSheet()
          }}
        >
          Renommer…
        </SidebarNavSheetAction>
        <SidebarNavSheetAction
          destructive
          onClick={() => {
            removeFolderOrLabelRow(item.id)
            closeSheet()
          }}
        >
          Supprimer le libellé
        </SidebarNavSheetAction>
        <SidebarNavSheetAction
          onClick={() => {
            setSublabelName("")
            setSublabelOpen(true)
            closeSheet()
          }}
        >
          Ajouter un sous-libellé
        </SidebarNavSheetAction>
      </SidebarNavOptionsSheet>
    )

    const labelRowEl = (
            <div
              data-nav-row
              {...touchRowProps}
              onDragEnter={onLabelRowDragEnter}
              onDragOver={onLabelRowDragOver}
              onDragLeave={onLabelRowDragLeave}
              onDrop={onLabelRowDrop}
              className={rowClass}
            >
              {canDragLabel ? (
                <SidebarNavDragHandle
                  label={item.label}
                  onDragStart={onLabelDragHandleStart}
                  onDragEnd={clearNavDrag}
                />
              ) : null}
              <div
                role="button"
                tabIndex={0}
                title={!labelRowExpanded ? item.label : undefined}
                onClick={() => onSelectFolder(item.id)}
                onKeyDown={(e) => navRowActivate(e, () => onSelectFolder(item.id))}
                className={cn(
                  "flex h-8 min-w-0 flex-1 cursor-pointer items-center gap-4 py-0 text-left outline-none focus-visible:ring-2 focus-visible:ring-ring/50",
                  labelRowExpanded ? "pr-1" : "pr-3"
                )}
              >
                <SidebarNavIconSlot showUnreadDot={hasUnread}>
                  <span
                    className={cn("block h-3 w-3 rounded-sm", item.color ?? "bg-gray-400")}
                  />
                </SidebarNavIconSlot>
                {labelRowExpanded && (
                  <span
                    className={cn(
                      "min-w-0 flex-1 truncate text-sm leading-5",
                      hasUnread && !isSelected && "font-semibold text-gray-900"
                    )}
                  >
                    {item.label}
                  </span>
                )}
              </div>
              {overflowMenu}
            </div>
    )

    return (
      <>
        {touchNav ? (
          labelRowEl
        ) : (
        <ContextMenu onOpenChange={setContextMenuOpen}>
          <ContextMenuTrigger asChild>{labelRowEl}</ContextMenuTrigger>
          <ContextMenuContent className={labelMenuSurface}>
            {colorSub("context")}
            <ContextMenuSeparator className="my-1.5 bg-gray-200" />
            <ContextMenuLabel className="px-3 py-1 text-[11px] font-normal normal-case tracking-normal text-gray-500">
              Dans la liste des libellés
            </ContextMenuLabel>
            <ContextLabelMenuOptionWithCheck
              checked={prefs.sidebar === "show"}
              onPick={() => setNavItemSidebarVisibility(item.id, "show")}
            >
              Afficher
            </ContextLabelMenuOptionWithCheck>
            <ContextLabelMenuOptionWithCheck
              checked={prefs.sidebar === "showUnread"}
              onPick={() => setNavItemSidebarVisibility(item.id, "showUnread")}
            >
              Afficher si non lus
            </ContextLabelMenuOptionWithCheck>
            <ContextLabelMenuOptionWithCheck
              checked={prefs.sidebar === "hide"}
              onPick={() => setNavItemSidebarVisibility(item.id, "hide")}
            >
              Masquer
            </ContextLabelMenuOptionWithCheck>
            <ContextMenuSeparator className="my-1.5 bg-gray-200" />
            <ContextMenuLabel className="px-3 py-1 text-[11px] font-normal normal-case tracking-normal text-gray-500">
              Dans la liste des messages
            </ContextMenuLabel>
            <ContextLabelMenuOptionWithCheck
              checked={prefs.messages === "show"}
              onPick={() => setNavItemMessageVisibility(item.id, "show")}
            >
              Afficher
            </ContextLabelMenuOptionWithCheck>
            <ContextLabelMenuOptionWithCheck
              checked={prefs.messages === "hide"}
              onPick={() => setNavItemMessageVisibility(item.id, "hide")}
            >
              Masquer
            </ContextLabelMenuOptionWithCheck>
            <ContextMenuSeparator className="my-1.5 bg-gray-200" />
            <ContextMenuItem
              className="mx-1 cursor-pointer px-3 py-2 text-sm"
              onClick={() => {
                setRenameDraft(item.label)
                setRenameOpen(true)
              }}
            >
              Renommer…
            </ContextMenuItem>
            <ContextMenuItem
              variant="destructive"
              className="mx-1 cursor-pointer px-3 py-2 text-sm"
              onClick={() => removeFolderOrLabelRow(item.id)}
            >
              Supprimer le libellé
            </ContextMenuItem>
            <ContextMenuItem
              className="mx-1 cursor-pointer px-3 py-2 text-sm"
              onClick={() => {
                setSublabelName("")
                setSublabelOpen(true)
              }}
            >
              Ajouter un sous-libellé
            </ContextMenuItem>
          </ContextMenuContent>
        </ContextMenu>
        )}
        {labelOptionsSheet}

        <Dialog open={renameOpen} onOpenChange={setRenameOpen}>
          <DialogContent
            className="sm:max-w-md"
            showCloseButton
            onOpenAutoFocus={(e) => {
              e.preventDefault()
              window.requestAnimationFrame(() =>
                labelRenameInputRef.current?.focus()
              )
            }}
          >
            <DialogHeader>
              <DialogTitle>Renommer le libellé</DialogTitle>
              <DialogDescription>Nouveau nom pour « {item.label} ».</DialogDescription>
            </DialogHeader>
            <Input
              ref={labelRenameInputRef}
              value={renameDraft}
              onChange={(e) => setRenameDraft(e.target.value)}
              autoComplete="off"
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  e.preventDefault()
                  renameFolderOrLabel(item.id, renameDraft)
                  setRenameOpen(false)
                }
              }}
            />
            <DialogFooter>
              <Button variant="outline" type="button" onClick={() => setRenameOpen(false)}>
                Annuler
              </Button>
              <Button
                type="button"
                onClick={() => {
                  renameFolderOrLabel(item.id, renameDraft)
                  setRenameOpen(false)
                }}
              >
                Enregistrer
              </Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>

        <Dialog open={sublabelOpen} onOpenChange={setSublabelOpen}>
          <DialogContent
            className="sm:max-w-md"
            showCloseButton
            onOpenAutoFocus={(e) => {
              e.preventDefault()
              window.requestAnimationFrame(() =>
                sublabelNameInputRef.current?.focus()
              )
            }}
          >
            <DialogHeader>
              <DialogTitle>Sous-libellé</DialogTitle>
              <DialogDescription>
                Sera créé sous « {item.label} » (chemin type Parent/Enfant).
              </DialogDescription>
            </DialogHeader>
            <Input
              ref={sublabelNameInputRef}
              value={sublabelName}
              onChange={(e) => setSublabelName(e.target.value)}
              placeholder="Nom du sous-libellé"
              autoComplete="off"
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  e.preventDefault()
                  addChildLabelRow(item.id, sublabelName)
                  setSublabelOpen(false)
                }
              }}
            />
            <DialogFooter>
              <Button variant="outline" type="button" onClick={() => setSublabelOpen(false)}>
                Annuler
              </Button>
              <Button
                type="button"
                onClick={() => {
                  addChildLabelRow(item.id, sublabelName)
                  setSublabelOpen(false)
                }}
              >
                Créer
              </Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>
      </>
    )
  }

  return (
    <aside
      ref={sidebarRef}
      data-sidebar
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
      className={cn(
        "absolute left-0 top-0 bottom-0 flex flex-col overflow-hidden bg-app-canvas transition-[width,transform] duration-200 z-40 select-none",
        isExpanded ? "w-60" : "w-[68px]",
        !touchNav && hoverExpanded && "shadow-xl border-r border-gray-200",
        isOverlayOpen && "z-50 shadow-xl border-r border-gray-200",
        collapsed && isXs && "-translate-x-full pointer-events-none"
      )}
    >
      <div
        className={cn(
          "flex shrink-0 items-center bg-app-canvas",
          splitView
            ? cn(
                splitViewLogoHeaderClass,
                isExpanded ? "justify-between" : "justify-start"
              )
            : "justify-between px-4 pt-4 pb-4 sm:hidden"
        )}
      >
        {splitView && !isExpanded ? (
          <UltiMailLogo variant="mark" className={splitViewLogoIconClass} />
        ) : (
          <>
            <UltiMailLogo
              className={cn(
                "shrink-0",
                splitView
                  ? "max-w-[140px] gap-4 [&_img]:size-9"
                  : "min-h-8"
              )}
            />
            {(splitView || touchNav) && isExpanded && (
              <Button
                variant="ghost"
                size="icon"
                className="size-9 shrink-0 text-gray-600"
                aria-label="Réglages"
              >
                <Icon icon="mdi:cog" className="size-5 shrink-0" aria-hidden />
              </Button>
            )}
          </>
        )}
      </div>

      <div
        className={cn(
          "hidden shrink-0 bg-app-canvas z-10 pt-1 pb-3 pl-2 sm:flex",
          isExpanded ? "pr-3.5" : "pr-2",
          splitView && "!hidden"
        )}
      >
        <button
          type="button"
          title={!isExpanded ? "Nouveau message" : undefined}
          aria-label={!isExpanded ? "Nouveau message" : undefined}
          onClick={openCompose}
          className={cn(
            "inline-flex h-[52px] min-w-0 shrink-0 cursor-pointer items-center rounded-2xl border border-gray-200 bg-white text-sm font-medium text-gray-700 shadow-sm outline-none transition-[box-shadow,background-color,border-color,color] duration-200 hover:bg-gray-50 hover:text-gray-900 hover:shadow-md focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2 [&_svg]:pointer-events-none [&_svg]:size-5 [&_svg]:shrink-0",
            isExpanded
              ? "w-auto max-w-full justify-start gap-3 self-start pl-4 pr-8"
              : "w-[52px] justify-center px-0 py-0"
          )}
        >
          <Pencil className="size-5 shrink-0" />
          {isExpanded && (
            <span className="min-w-0 truncate text-sm font-medium">
              Nouveau message
            </span>
          )}
        </button>
      </div>

      <div
        className={cn(
          "min-h-0 flex-1 overflow-y-auto overflow-x-hidden",
          "[scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden"
        )}
      >
      {/* Boîte principale + catégories (hors « Plus »), puis Plus / Moins, puis extras. */}
      <nav className={cn("flex min-h-full flex-col", navRailInset)}>
        {visibleMainItems.map((item) => (
          <NavItem
            key={item.id}
            item={item}
            isSelected={selectedFolder === item.id}
            unreadCount={folderUnreadCounts[item.id] ?? 0}
          />
        ))}
        {primaryVisibleCategories.map((item) => (
          <CategoryNavRow
            key={item.id}
            item={item}
            isSelected={selectedFolder === item.id}
            isExpanded={isExpanded}
            unreadCount={folderUnreadCounts[item.id] ?? 0}
            onSelectFolder={onSelectFolder}
            touchNav={touchNav}
            onDisableNavLabel={(id) => setLabelRowEnabled(id, false)}
            onEnableNavLabel={(id) => setLabelRowEnabled(id, true)}
          />
        ))}

        {hasPlusOnlyExtras && (
          <button
            type="button"
            title={!isExpanded ? (navMoreOpen ? "Moins" : "Plus") : undefined}
            aria-expanded={navMoreOpen}
            aria-label={
              !isExpanded
                ? navMoreOpen
                  ? "Moins d’entrées"
                  : "Plus d’entrées"
                : undefined
            }
            onClick={() =>
              setNavMoreOpen((wasOpen) => {
                if (!wasOpen) return true
                if (CATEGORY_IDS_IN_PLUS_ONLY.has(selectedFolder)) {
                  onSelectFolder("inbox")
                  return false
                }
                return false
              })
            }
            className={cn(
              "flex h-8 w-full shrink-0 cursor-pointer items-center gap-4 pl-6 pr-3 text-gray-700 transition-colors hover:bg-gray-100",
              navRowRoundedWhenActive(false)
            )}
          >
            <ChevronDown
              className={cn(
                "h-5 w-5 shrink-0 transition-transform duration-200",
                navMoreOpen && "rotate-180"
              )}
            />
            {isExpanded && (
              <span className="text-sm">{navMoreOpen ? "Moins" : "Plus"}</span>
            )}
          </button>
        )}

        {navMoreOpen && (
          <>
            {plusOnlyVisibleCategories.map((item) => (
              <CategoryNavRow
                key={item.id}
                item={item}
                isSelected={selectedFolder === item.id}
                isExpanded={isExpanded}
                unreadCount={folderUnreadCounts[item.id] ?? 0}
                onSelectFolder={onSelectFolder}
                touchNav={touchNav}
                onDisableNavLabel={(id) => setLabelRowEnabled(id, false)}
                onEnableNavLabel={(id) => setLabelRowEnabled(id, true)}
              />
            ))}
            {isExpanded && (
              <div className="mt-1 flex flex-col gap-px">
                {sidebarSecondaryActions.map((a) => {
                  const ActionIcon = a.icon
                  return (
                    <button
                      key={a.id}
                      type="button"
                      className="flex min-h-8 w-full cursor-pointer items-center gap-2 rounded-md py-1.5 pl-6 pr-3 text-left text-xs text-gray-600 transition-colors hover:bg-gray-50 hover:text-gray-800"
                    >
                      <ActionIcon className="h-3.5 w-3.5 shrink-0 opacity-70" aria-hidden />
                      <span className="min-w-0 leading-snug">{a.label}</span>
                    </button>
                  )
                })}
              </div>
            )}
            {isExpanded && disabledSystemNavItems.length > 0 && (
              <div className="mt-2 pt-2">
                <div className="mb-1 pl-6 pr-3 text-[11px] font-medium uppercase tracking-wide text-gray-500">
                  Désactivées
                </div>
                {disabledSystemNavItems.map((item) => (
                  <CategoryNavRow
                    key={item.id}
                    item={item}
                    isSelected={false}
                    isExpanded={isExpanded}
                    unreadCount={folderUnreadCounts[item.id] ?? 0}
                    onSelectFolder={onSelectFolder}
                    touchNav={touchNav}
                    onDisableNavLabel={(id) => setLabelRowEnabled(id, false)}
                    onEnableNavLabel={(id) => setLabelRowEnabled(id, true)}
                    variant="hidden"
                  />
                ))}
              </div>
            )}
          </>
        )}

        {/* Dossiers (hiérarchie : chevron = replier / déplier uniquement) */}
        <div className="mt-3 pt-1">
          <div
            className="sticky top-0 z-30 flex h-8 w-full min-w-0 shrink-0 items-center gap-2 bg-app-canvas pl-6 pr-3"
            title={!isExpanded ? "Dossiers" : undefined}
          >
            <Icon
              icon={FOLDER_SECTION_ICON}
              className="h-5 w-5 shrink-0 text-gray-600"
              aria-hidden
            />
            {isExpanded && (
              <span className="min-w-0 flex-1 truncate text-left text-sm font-medium text-gray-700">
                Dossiers
              </span>
            )}
            {isExpanded && (
              <button
                type="button"
                className="flex h-5 w-5 shrink-0 cursor-pointer items-center justify-center rounded-full text-gray-500 hover:bg-gray-100 hover:text-gray-700"
                aria-label="Ajouter un dossier"
                title="Ajouter un dossier"
                onClick={() => {
                  setNewFolderParent("__root__")
                  setNewFolderName("")
                  setFolderDialogOpen(true)
                }}
              >
                <Plus className="h-5 w-5 shrink-0" />
              </button>
            )}
          </div>

          {isExpanded
            ? renderExpandedFolderSubtree(folderTree, 0)
            : renderCollapsedFolderList(folderTree)}
        </div>

        {/* Labels */}
        <div className="mt-3 pt-1">
          <div
            className="sticky top-0 z-30 flex h-8 w-full min-w-0 shrink-0 items-center gap-2 bg-app-canvas pl-6 pr-3"
            title={!isExpanded ? "Libellés" : undefined}
          >
            <Icon
              icon="mdi:label-outline"
              className="h-5 w-5 shrink-0 text-gray-600"
              aria-hidden
            />
            {isExpanded && (
              <span className="min-w-0 flex-1 truncate text-left text-sm font-medium text-gray-700">
                Libellés
              </span>
            )}
            {isExpanded && (
              <button
                type="button"
                className="flex h-5 w-5 shrink-0 cursor-pointer items-center justify-center rounded-full text-gray-500 hover:bg-gray-100 hover:text-gray-700"
                aria-label="Ajouter un libellé"
                title="Ajouter un libellé"
                onClick={() => {
                  setNewLabelName("")
                  setLabelDialogOpen(true)
                }}
              >
                <Plus className="h-5 w-5 shrink-0" />
              </button>
            )}
          </div>

          {visibleNavLabelRows.map((item) => (
            <LabelItemRow
              key={item.id}
              item={item}
              unreadCount={folderUnreadCounts[item.id] ?? 0}
              isExpanded={isExpanded}
            />
          ))}
        </div>

        {/* Sortbot */}
        <div
          className={cn(
            "relative z-32 mt-auto bg-app-canvas pt-2",
            "max-sm:pb-16 sm:sticky sm:bottom-0 sm:border-t sm:border-gray-200 sm:pb-3"
          )}
        >
          <button
            type="button"
            title={!isExpanded ? "Sortbot" : undefined}
            className={cn(
              "flex h-8 w-full shrink-0 cursor-pointer items-center gap-4 pl-6 pr-3 text-sm text-gray-700 transition-colors hover:bg-gray-100",
              navRowRoundedWhenActive(false)
            )}
          >
            <Bot className="h-5 w-5 shrink-0 text-gray-600" aria-hidden />
            {isExpanded && <span>Sortbot</span>}
          </button>
        </div>
      </nav>
      </div>

      <Dialog open={folderDialogOpen} onOpenChange={setFolderDialogOpen}>
        <DialogContent
          className="sm:max-w-md"
          showCloseButton
          onOpenAutoFocus={(e) => {
            e.preventDefault()
            window.requestAnimationFrame(() =>
              newFolderNameInputRef.current?.focus()
            )
          }}
        >
          <DialogHeader>
            <DialogTitle>Nouveau dossier</DialogTitle>
            <DialogDescription>
              Choisissez l’emplacement (racine ou dossier parent) puis le nom.
            </DialogDescription>
          </DialogHeader>
          <div className="grid gap-3 py-1">
            <div className="grid gap-2">
              <Label htmlFor="new-folder-parent">Emplacement</Label>
              <Select value={newFolderParent} onValueChange={setNewFolderParent}>
                <SelectTrigger id="new-folder-parent" className="w-full min-w-0" size="sm">
                  <SelectValue placeholder="Parent" />
                </SelectTrigger>
                <SelectContent position="popper" className="max-h-72">
                  {folderParentOptions.map((o) => (
                    <SelectItem key={o.value} value={o.value}>
                      {o.label}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
            </div>
            <div className="grid gap-2">
              <Label htmlFor="new-folder-name">Nom</Label>
              <Input
                id="new-folder-name"
                ref={newFolderNameInputRef}
                value={newFolderName}
                onChange={(e) => setNewFolderName(e.target.value)}
                placeholder="Mon dossier"
                autoComplete="off"
                onKeyDown={(e) => {
                  if (e.key === "Enter") {
                    e.preventDefault()
                    handleSubmitNewFolder()
                  }
                }}
              />
            </div>
          </div>
          <DialogFooter>
            <Button
              variant="outline"
              type="button"
              onClick={() => setFolderDialogOpen(false)}
            >
              Annuler
            </Button>
            <Button type="button" onClick={handleSubmitNewFolder}>
              Créer
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog open={labelDialogOpen} onOpenChange={setLabelDialogOpen}>
        <DialogContent
          className="sm:max-w-md"
          showCloseButton
          onOpenAutoFocus={(e) => {
            e.preventDefault()
            window.requestAnimationFrame(() =>
              newLabelNameInputRef.current?.focus()
            )
          }}
        >
          <DialogHeader>
            <DialogTitle>Nouveau libellé</DialogTitle>
            <DialogDescription>
              Nom affiché dans la barre latérale et utilisé sur les messages.
            </DialogDescription>
          </DialogHeader>
          <div className="grid gap-2 py-1">
            <Label htmlFor="new-label-name">Nom</Label>
            <Input
              id="new-label-name"
              ref={newLabelNameInputRef}
              value={newLabelName}
              onChange={(e) => setNewLabelName(e.target.value)}
              placeholder="Libellé"
              autoComplete="off"
              onKeyDown={(e) => {
                if (e.key === "Enter") {
                  e.preventDefault()
                  handleSubmitNewLabel()
                }
              }}
            />
          </div>
          <DialogFooter>
            <Button
              variant="outline"
              type="button"
              onClick={() => setLabelDialogOpen(false)}
            >
              Annuler
            </Button>
            <Button type="button" onClick={handleSubmitNewLabel}>
              Créer
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </aside>
  )
}
