{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dashboard-folder",
  "title": "Modern Folder Dashboard",
  "description": "",
  "dependencies": [
    "framer-motion",
    "lucide-react"
  ],
  "files": [
    {
      "path": "registry/default/blocks/Dashboard/dashboard-folde.tsx",
      "content": "\"use client\";\n\nimport React, {\n  useState,\n  useCallback,\n  useMemo,\n  useRef,\n  createContext,\n  useContext,\n} from \"react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport {\n  Home,\n  Folder as FolderIcon,\n  FileText,\n  FileSpreadsheet,\n  FileType,\n  Presentation,\n  Image as ImageIcon,\n  BarChart3,\n  Mail,\n  MailOpen,\n  Workflow,\n  Settings,\n  Bell,\n  Search,\n  SlidersHorizontal,\n  MoreHorizontal,\n  MoreVertical,\n  Share2,\n  ArrowLeft,\n  ChevronDown,\n  ChevronRight,\n  ChevronsRight,\n  ExternalLink,\n  Pin,\n  Inbox,\n  Plus,\n  Trash2,\n  Download,\n  Pencil,\n  Check,\n  Link2,\n  X,\n  ArrowUpDown,\n  Clock,\n  Zap,\n  Sun,\n  Moon,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\nimport { summarizeStorage } from \"@/lib/storage\";\n\n/* ================================================================== */\n/*  Theme (dark mode) context                                          */\n/* ================================================================== */\n/*\n  Uses Tailwind's class-based dark mode strategy: the root wrapper gets a\n  \"dark\" class toggled by React state, and every descendant uses regular\n  `dark:` variants. Make sure tailwind.config has `darkMode: \"class\"`\n  (or, on Tailwind v4, `@custom-variant dark (&:where(.dark, .dark *));`\n  in your CSS) for this to take effect.\n*/\n\nconst ThemeContext = createContext<boolean>(false);\nfunction useIsDark() {\n  return useContext(ThemeContext);\n}\n\n/* ================================================================== */\n/*  Types                                                              */\n/* ================================================================== */\n\ntype FolderVariant = \"neutral\" | \"blue\" | \"black\";\ntype FileKind = \"doc\" | \"sheet\" | \"image\" | \"pdf\" | \"slide\";\ntype TagName = \"Sales\" | \"Marketing\" | \"Analytics\" | \"Product\" | \"Engineering\" | \"Growth\";\ntype NavKey = \"home\" | \"notes\" | \"reports\" | \"emails\" | \"automation\";\ntype SortKey = \"name\" | \"size\" | \"date\";\n\ntype FileItem = {\n  id: string;\n  name: string;\n  kind: FileKind;\n  sizeKb: number;\n  modified: string; // ISO yyyy-mm-dd\n  owner: string;\n};\n\ntype Folder = {\n  id: string;\n  title: string;\n  notesCount: number;\n  sizeKb: number;\n  variant: FolderVariant;\n  tag: TagName;\n  files: FileItem[];\n};\n\ntype Project = {\n  id: string;\n  name: string;\n  folders: Folder[];\n};\n\ntype SelectedItem =\n  | { type: \"folder\"; folder: Folder }\n  | { type: \"file\"; file: FileItem; folderTitle: string; folderTag: TagName }\n  | null;\n\ntype NotificationItem = {\n  id: number;\n  message: string;\n  time: string;\n  unread: boolean;\n  link?: { projectId: string; folderId: string };\n};\n\ntype EmailItem = {\n  id: number;\n  from: string;\n  subject: string;\n  snippet: string;\n  time: string;\n  unread: boolean;\n};\n\ntype AutomationItem = {\n  id: number;\n  name: string;\n  description: string;\n  trigger: string;\n  enabled: boolean;\n};\n\n/* ================================================================== */\n/*  Folder graphic — same flap silhouette + \"cards peeking out\" idea   */\n/* ================================================================== */\n\nconst FLAP_PATH =\n  \"M0 25C0 11.1929 11.1929 0 25 0H136.084C143.044 0 149.689 2.90139 154.42 8.00608L178.08 33.5343C182.811 38.639 189.456 41.5404 196.416 41.5404H296C309.807 41.5404 321 52.7333 321 66.5404V216C321 229.807 309.807 241 296 241H25C11.1929 241 0 229.807 0 216V25Z\";\n\n/* Light theme — soft neutrals + a single blue accent */\ntype FolderPalette = {\n  readonly flapFill: string;\n  readonly flapStroke: string;\n  readonly cardFill: string;\n  readonly cardStroke: string;\n  readonly cardLineFill: string;\n};\n\nconst folderPalettes = {\n  neutral: {\n    flapFill: \"#EFEFF1\",\n    flapStroke: \"#E2E2E6\",\n    cardFill: \"#FFFFFF\",\n    cardStroke: \"#E9E9EC\",\n    cardLineFill: \"#E3E3E7\",\n  },\n  blue: {\n    flapFill: \"#6DBCFE\",\n    flapStroke: \"#94CEFF\",\n    cardFill: \"#FFFFFF\",\n    cardStroke: \"#EAF4FF\",\n    cardLineFill: \"#DCEEFF\",\n  },\n  black: {\n    flapFill: \"#1F2937\",\n    flapStroke: \"#374151\",\n    cardFill: \"#111827\",\n    cardStroke: \"#374151\",\n    cardLineFill: \"#374151\",\n  }\n} as const satisfies Record<FolderVariant, FolderPalette>;\n\n/* Dark theme — kept deliberately monochrome (charcoal / graphite / off-white),\n   with the \"blue\" variant surviving as the one accent, muted to a deep\n   midnight so it still reads as black-and-white-first. The \"black\" variant\n   flips to near-white so it keeps acting as the spotlight tile against a\n   dark canvas. */\nconst folderPalettesDark = {\n  neutral: {\n    flapFill: \"#4B4B4F\",\n    flapStroke: \"#5D5D62\",\n    cardFill: \"#ECECEE\",\n    cardStroke: \"#E5E7EB\",\n    cardLineFill: \"#C7C7CB\",\n  },\n  blue: {\n    flapFill: \"#2B4A6E\",\n    flapStroke: \"#3E6690\",\n    cardFill: \"#ECECEE\",\n    cardStroke: \"#E5E7EB\",\n    cardLineFill: \"#C7C7CB\",\n  },\n  black: {\n    flapFill: \"#F5F5F7\",\n    flapStroke: \"#E4E4E7\",\n    cardFill: \"#FFFFFF\",\n    cardStroke: \"#E5E7EB\",\n    cardLineFill: \"#E2E2E5\",\n  }\n} as const satisfies Record<FolderVariant, FolderPalette>;\n\nconst cardSpring = { type: \"spring\" as const, stiffness: 150, damping: 15 };\n\nfunction MiniCard({ palette }: { palette: FolderPalette }) {\n  const isDark = useIsDark();\n  return (\n    <svg width=\"70\" height=\"92\" viewBox=\"0 0 70 92\" fill=\"none\">\n      <rect width=\"70\" height=\"92\" rx=\"12\" fill={palette.cardFill} stroke={palette.cardStroke} strokeWidth={isDark ? 1.75 : 1} />\n      <rect x=\"9\" y=\"14\" width=\"52\" height=\"6\" rx=\"3\" fill={palette.cardLineFill} />\n      <rect x=\"9\" y=\"28\" width=\"36\" height=\"4\" rx=\"2\" fill={palette.cardLineFill} opacity={0.75} />\n      <rect x=\"9\" y=\"37\" width=\"36\" height=\"4\" rx=\"2\" fill={palette.cardLineFill} opacity={0.75} />\n      <rect x=\"9\" y=\"47\" width=\"28\" height=\"4\" rx=\"2\" fill={palette.cardLineFill} opacity={0.75} />\n    </svg>\n  );\n}\n\nconst FolderGraphic = React.memo(function FolderGraphic({\n  variant = \"neutral\",\n  hovered,\n}: {\n  variant?: FolderVariant;\n  hovered: boolean;\n}) {\n  const isDark = useIsDark();\n  const palette = (isDark ? folderPalettesDark : folderPalettes)[variant];\n  const open = hovered;\n\n  return (\n    <div className=\"relative inline-flex h-[130px] w-[158px] items-end justify-center\">\n      <div className=\"absolute inset-0 flex items-center justify-center pointer-events-none\">\n        <motion.div\n          className=\"absolute\"\n          animate={{ y: open ? -34 : -16, x: 17, rotate: open ? 8 : 4 }}\n          transition={cardSpring}\n        >\n          <MiniCard palette={palette} />\n        </motion.div>\n        <motion.div\n          className=\"absolute\"\n          animate={{ y: open ? -40 : -20, x: 0, rotate: 0 }}\n          transition={cardSpring}\n        >\n          <MiniCard palette={palette} />\n        </motion.div>\n        <motion.div\n          className=\"absolute\"\n          animate={{ y: open ? -34 : -16, x: -17, rotate: open ? -8 : -4 }}\n          transition={cardSpring}\n        >\n          <MiniCard palette={palette} />\n        </motion.div>\n      </div>\n\n      <motion.svg\n        width=\"160\"\n        height=\"120\"\n        viewBox=\"0 0 321 241\"\n        fill=\"none\"\n        className=\"relative\"\n        animate={{ y: open ? 2 : 0 }}\n        transition={cardSpring}\n      >\n        <path d={FLAP_PATH} fill={palette.flapFill} />\n        <path d={FLAP_PATH} fill=\"none\" stroke={palette.flapStroke} />\n      </motion.svg>\n    </div>\n  );\n});\n\n/* ================================================================== */\n/*  Helpers                                                             */\n/* ================================================================== */\n\nfunction formatSize(kb: number) {\n  if (kb >= 1024 * 1024) return `${(kb / (1024 * 1024)).toFixed(1)} GB`;\n  if (kb >= 1024) return `${(kb / 1024).toFixed(1)} MB`;\n  return `${Math.round(kb)} KB`;\n}\n\nconst MONTHS = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\nfunction formatDate(iso: string) {\n  const [y, m, d] = iso.split(\"-\").map(Number);\n  return `${MONTHS[(m ?? 1) - 1]} ${d}, ${y}`;\n}\nfunction todayIso() {\n  const d = new Date();\n  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, \"0\")}-${String(d.getDate()).padStart(2, \"0\")}`;\n}\n\nconst TAG_DOT: Record<TagName, string> = {\n  Sales: \"bg-blue-500\",\n  Marketing: \"bg-neutral-400\",\n  Analytics: \"bg-rose-500\",\n  Product: \"bg-violet-500\",\n  Engineering: \"bg-amber-500\",\n  Growth: \"bg-emerald-500\",\n};\n\nconst KIND_META: Record<FileKind, { icon: React.ComponentType<{ className?: string }>; color: string; bg: string; label: string }> = {\n  doc: { icon: FileText, color: \"text-indigo-500 dark:text-indigo-400\", bg: \"bg-indigo-50 dark:bg-indigo-500/15\", label: \"Document\" },\n  sheet: { icon: FileSpreadsheet, color: \"text-emerald-600 dark:text-emerald-400\", bg: \"bg-emerald-50 dark:bg-emerald-500/15\", label: \"Spreadsheet\" },\n  image: { icon: ImageIcon, color: \"text-pink-500 dark:text-pink-400\", bg: \"bg-pink-50 dark:bg-pink-500/15\", label: \"Image\" },\n  pdf: { icon: FileType, color: \"text-rose-500 dark:text-rose-400\", bg: \"bg-rose-50 dark:bg-rose-500/15\", label: \"PDF\" },\n  slide: { icon: Presentation, color: \"text-orange-500 dark:text-orange-400\", bg: \"bg-orange-50 dark:bg-orange-500/15\", label: \"Slides\" },\n};\n\nfunction sortFolders(folders: Folder[], sortBy: SortKey): Folder[] {\n  const copy = [...folders];\n  copy.sort((a, b) => {\n    if (sortBy === \"name\") return a.title.localeCompare(b.title);\n    if (sortBy === \"size\") return b.sizeKb - a.sizeKb;\n    return 0;\n  });\n  return copy;\n}\n\nfunction sortFiles(files: FileItem[], sortBy: SortKey): FileItem[] {\n  const copy = [...files];\n  copy.sort((a, b) => {\n    if (sortBy === \"name\") return a.name.localeCompare(b.name);\n    if (sortBy === \"size\") return b.sizeKb - a.sizeKb;\n    return b.modified.localeCompare(a.modified);\n  });\n  return copy;\n}\n\n/* ================================================================== */\n/*  Mock data                                                          */\n/* ================================================================== */\n\nlet uid = 1000;\nfunction nextId(prefix: string) {\n  uid += 1;\n  return `${prefix}-${uid}`;\n}\n\nfunction f(name: string, kind: FileKind, sizeKb: number, modified: string, owner: string): FileItem {\n  return { id: nextId(\"file\"), name, kind, sizeKb, modified, owner };\n}\n\nconst INITIAL_PROJECTS: Project[] = [\n  {\n    id: \"bagui\",\n    name: \"Bag Ui\",\n    folders: [\n      {\n        id: \"ux-research\",\n        title: \"UX research\",\n        notesCount: 233,\n        sizeKb: 119706,\n        variant: \"neutral\",\n        tag: \"Product\",\n        files: [\n          f(\"Interview transcript — Maria K.\", \"doc\", 480, \"2024-12-01\", \"Sophia Lane\"),\n          f(\"Interview transcript — Noah P.\", \"doc\", 512, \"2024-12-02\", \"Sophia Lane\"),\n          f(\"Usability test notes\", \"doc\", 210, \"2024-11-28\", \"Lina Voss\"),\n          f(\"Persona board\", \"image\", 3200, \"2024-11-20\", \"Marc Ade\"),\n          f(\"Research plan Q4\", \"pdf\", 640, \"2024-11-15\", \"Sophia Lane\"),\n        ],\n      },\n      {\n        id: \"raw-data\",\n        title: \"Raw data\",\n        notesCount: 39,\n        sizeKb: 184525,\n        variant: \"blue\",\n        tag: \"Analytics\",\n        files: [\n          f(\"Event export — Nov\", \"sheet\", 43008, \"2024-12-01\", \"Theo Kade\"),\n          f(\"Event export — Dec\", \"sheet\", 38912, \"2024-12-05\", \"Theo Kade\"),\n          f(\"Survey responses raw\", \"sheet\", 15360, \"2024-11-30\", \"Nora Bell\"),\n          f(\"Session logs sample\", \"doc\", 1126, \"2024-11-22\", \"Theo Kade\"),\n        ],\n      },\n      {\n        id: \"processed-data\",\n        title: \"Processed data\",\n        notesCount: 21,\n        sizeKb: 23962,\n        variant: \"neutral\",\n        tag: \"Analytics\",\n        files: [\n          f(\"Cohort table Q4\", \"sheet\", 6554, \"2024-12-03\", \"Nora Bell\"),\n          f(\"Cleaned survey set\", \"sheet\", 4915, \"2024-11-30\", \"Nora Bell\"),\n          f(\"Feature matrix v3\", \"sheet\", 3174, \"2024-11-25\", \"Theo Kade\"),\n        ],\n      },\n      {\n        id: \"reports\",\n        title: \"Reports\",\n        notesCount: 17,\n        sizeKb: 501760,\n        variant: \"neutral\",\n        tag: \"Marketing\",\n        files: [\n          f(\"Q4 growth report\", \"pdf\", 2458, \"2024-12-06\", \"Sophia Lane\"),\n          f(\"Board deck — December\", \"slide\", 18432, \"2024-12-04\", \"Marc Ade\"),\n          f(\"Retention deep dive\", \"pdf\", 3994, \"2024-11-18\", \"Nora Bell\"),\n          f(\"Weekly summary #48\", \"doc\", 220, \"2024-11-29\", \"Sophia Lane\"),\n        ],\n      },\n      {\n        id: \"data-visualization\",\n        title: \"Data visualization\",\n        notesCount: 96,\n        sizeKb: 1362790,\n        variant: \"neutral\",\n        tag: \"Analytics\",\n        files: [\n          f(\"Funnel dashboard export\", \"image\", 4710, \"2024-12-02\", \"Marc Ade\"),\n          f(\"Cohort heatmap\", \"image\", 2969, \"2024-11-27\", \"Nora Bell\"),\n          f(\"Revenue trend chart\", \"image\", 1843, \"2024-11-21\", \"Marc Ade\"),\n          f(\"Viz style guide\", \"pdf\", 1229, \"2024-11-10\", \"Lina Voss\"),\n        ],\n      },\n      {\n        id: \"ideas-insights\",\n        title: \"Ideas and Insights\",\n        notesCount: 103,\n        sizeKb: 129331,\n        variant: \"neutral\",\n        tag: \"Product\",\n        files: [\n          f(\"Insight log — November\", \"doc\", 340, \"2024-11-30\", \"Lina Voss\"),\n          f(\"Feature idea backlog\", \"doc\", 290, \"2024-11-26\", \"Marc Ade\"),\n          f(\"Customer quotes bank\", \"doc\", 410, \"2024-11-19\", \"Sophia Lane\"),\n        ],\n      },\n    ],\n  },\n  {\n    id: \"kivu-event\",\n    name: \"Kivu Event\",\n    folders: [\n      {\n        id: \"customer-interviews\",\n        title: \"Customer interviews\",\n        notesCount: 58,\n        sizeKb: 65843,\n        variant: \"neutral\",\n        tag: \"Product\",\n        files: [\n          f(\"Interview — Acme Co.\", \"doc\", 380, \"2024-12-01\", \"Lina Voss\"),\n          f(\"Interview — Nimbus Inc.\", \"doc\", 402, \"2024-11-27\", \"Lina Voss\"),\n          f(\"Synthesis notes\", \"doc\", 260, \"2024-11-24\", \"Sophia Lane\"),\n        ],\n      },\n      {\n        id: \"onboarding-flows\",\n        title: \"Onboarding flows\",\n        notesCount: 24,\n        sizeKb: 39014,\n        variant: \"neutral\",\n        tag: \"Growth\",\n        files: [\n          f(\"Flow diagram v2\", \"image\", 2150, \"2024-11-29\", \"Marc Ade\"),\n          f(\"Drop-off analysis\", \"sheet\", 5530, \"2024-11-22\", \"Theo Kade\"),\n          f(\"Copy audit\", \"doc\", 180, \"2024-11-15\", \"Nora Bell\"),\n        ],\n      },\n      {\n        id: \"growth-experiments\",\n        title: \"Growth experiments\",\n        notesCount: 31,\n        sizeKb: 53862,\n        variant: \"blue\",\n        tag: \"Growth\",\n        files: [\n          f(\"Experiment log Q4\", \"sheet\", 3686, \"2024-12-05\", \"Theo Kade\"),\n          f(\"Pricing test results\", \"pdf\", 1434, \"2024-11-30\", \"Nora Bell\"),\n          f(\"Referral loop notes\", \"doc\", 310, \"2024-11-20\", \"Sophia Lane\"),\n          f(\"Landing page variants\", \"image\", 2765, \"2024-11-12\", \"Marc Ade\"),\n        ],\n      },\n    ],\n  },\n  {\n    id: \"codeai\",\n    name: \"CodeAI\",\n    folders: [\n      {\n        id: \"model-evals\",\n        title: \"Model evals\",\n        notesCount: 47,\n        sizeKb: 215450,\n        variant: \"blue\",\n        tag: \"Engineering\",\n        files: [\n          f(\"Eval suite results v6\", \"sheet\", 8397, \"2024-12-04\", \"Theo Kade\"),\n          f(\"Regression report\", \"pdf\", 1946, \"2024-11-28\", \"Nora Bell\"),\n          f(\"Prompt failure cases\", \"doc\", 340, \"2024-11-21\", \"Lina Voss\"),\n        ],\n      },\n      {\n        id: \"prompt-library\",\n        title: \"Prompt library\",\n        notesCount: 19,\n        sizeKb: 13107,\n        variant: \"neutral\",\n        tag: \"Engineering\",\n        files: [\n          f(\"System prompts v3\", \"doc\", 220, \"2024-12-02\", \"Marc Ade\"),\n          f(\"Few-shot examples\", \"doc\", 190, \"2024-11-25\", \"Sophia Lane\"),\n          f(\"Prompt style guide\", \"pdf\", 640, \"2024-11-10\", \"Lina Voss\"),\n        ],\n      },\n      {\n        id: \"release-notes\",\n        title: \"Release notes\",\n        notesCount: 12,\n        sizeKb: 6246,\n        variant: \"neutral\",\n        tag: \"Engineering\",\n        files: [\n          f(\"v2.4 release notes\", \"doc\", 120, \"2024-12-06\", \"Marc Ade\"),\n          f(\"v2.3 release notes\", \"doc\", 118, \"2024-11-18\", \"Marc Ade\"),\n          f(\"Changelog archive\", \"pdf\", 980, \"2024-10-30\", \"Theo Kade\"),\n        ],\n      },\n    ],\n  },\n];\n\nconst INITIAL_NOTIFICATIONS: NotificationItem[] = [\n  { id: 1, message: \"Marc Ade commented on Q4 growth report\", time: \"5m ago\", unread: true, link: { projectId: \"bagui\", folderId: \"reports\" } },\n  { id: 2, message: \"New file added to Raw data\", time: \"1h ago\", unread: true, link: { projectId: \"bagui\", folderId: \"raw-data\" } },\n  { id: 3, message: \"Theo Kade shared Event export — Dec\", time: \"3h ago\", unread: true, link: { projectId: \"bagui\", folderId: \"raw-data\" } },\n  { id: 4, message: \"Weekly summary #48 is ready\", time: \"Yesterday\", unread: false, link: { projectId: \"bagui\", folderId: \"reports\" } },\n  { id: 5, message: \"You were mentioned in Persona board\", time: \"2d ago\", unread: true, link: { projectId: \"bagui\", folderId: \"ux-research\" } },\n  { id: 6, message: \"New experiment added to Growth experiments\", time: \"2d ago\", unread: false, link: { projectId: \"kivu-event\", folderId: \"growth-experiments\" } },\n];\n\nconst INITIAL_EMAILS: EmailItem[] = [\n  { id: 1, from: \"Notion Digest\", subject: \"Your weekly activity summary\", snippet: \"Here's what happened across bagui Labs this week: 14 new files, 3 comments, and 2 folders updated across the team.\", time: \"9:14 AM\", unread: true },\n  { id: 2, from: \"Marc Ade\", subject: \"Re: Board deck feedback\", snippet: \"Left a few comments on slide 6, mostly about the retention chart. Can we sync before Friday's review?\", time: \"Yesterday\", unread: true },\n  { id: 3, from: \"Linear\", subject: \"3 issues assigned to you\", snippet: \"ENG-482, ENG-491 and ENG-503 are waiting on your review. Two are marked high priority.\", time: \"Yesterday\", unread: false },\n  { id: 4, from: \"Theo Kade\", subject: \"Raw export is ready\", snippet: \"Pushed the December event export to Raw data, let me know if the schema looks right before we process it.\", time: \"Mon\", unread: false },\n  { id: 5, from: \"Stripe\", subject: \"Your invoice is ready\", snippet: \"Your December invoice for the Kintsugi workspace is now available to download from your billing settings.\", time: \"Mon\", unread: false },\n];\n\nconst INITIAL_AUTOMATIONS: AutomationItem[] = [\n  { id: 1, name: \"Weekly report digest\", description: \"Sends a summary of new files every Monday at 9:00 AM.\", trigger: \"Schedule\", enabled: true },\n  { id: 2, name: \"Auto-tag raw uploads\", description: \"Applies the Analytics tag to anything dropped into Raw data.\", trigger: \"File added\", enabled: true },\n  { id: 3, name: \"Slack notify on comment\", description: \"Posts to #bagui-labs whenever a file gets a new comment.\", trigger: \"Comment\", enabled: false },\n  { id: 4, name: \"Archive stale drafts\", description: \"Moves drafts untouched for 30 days into Archive.\", trigger: \"Schedule\", enabled: false },\n  { id: 5, name: \"Sync to data warehouse\", description: \"Pushes processed sheets to the analytics warehouse nightly.\", trigger: \"Schedule\", enabled: true },\n];\n\nconst SECONDARY_NAV: { key: NavKey; icon: React.ComponentType<{ className?: string }>; label: string }[] = [\n  { key: \"notes\", icon: FileText, label: \"Notes\" },\n  { key: \"reports\", icon: BarChart3, label: \"Reports\" },\n  { key: \"emails\", icon: Mail, label: \"Emails\" },\n  { key: \"automation\", icon: Workflow, label: \"Automation\" },\n];\n\nconst PROJECT_TABS = [\n  { id: \"kivu-event\", label: \"Kivu Event\" },\n  { id: \"codeai\", label: \"CodeAI\" },\n  { id: \"bagui\", label: \"Bag Ui\" },\n];\n\nconst CURRENT_USER = \"Anelka Bag\";\n\n/* ================================================================== */\n/*  Small atoms                                                        */\n/* ================================================================== */\n\nfunction AppLogo() {\n  const isDark = useIsDark();\n  return (\n    <img\n      src={isDark ? \"/logoW.png\" : \"/logo.png\"}\n      alt=\"BagUi\"\n      className=\"h-6 w-6 shrink-0 object-contain\"\n    />\n  );\n}\n\nfunction Avatar({ seed, src, className }: { seed: string; src?: string; className?: string }) {\n  return (\n    <img\n      src={src ?? `https://api.dicebear.com/9.x/notionists/svg?seed=${encodeURIComponent(seed)}&backgroundColor=b6e3f4`}\n      alt={seed}\n      className={cn(\"shrink-0 rounded-full bg-neutral-100 object-cover dark:bg-neutral-800 dark:ring-1 dark:ring-neutral-800\", className)}\n    />\n  );\n}\n\nfunction Switch({ checked, onChange, label }: { checked: boolean; onChange: () => void; label?: string }) {\n  return (\n    <button\n      role=\"switch\"\n      aria-checked={checked}\n      aria-label={label}\n      onClick={onChange}\n      className={cn(\n        \"relative h-6 w-11 shrink-0 rounded-full transition-colors duration-200 cursor-pointer\",\n        checked ? \"bg-neutral-900 dark:bg-neutral-100\" : \"bg-neutral-200 dark:bg-neutral-800\"\n      )}\n    >\n      <motion.span\n        className={cn(\n          \"absolute top-0.5 left-0.5 h-5 w-5 rounded-full shadow-sm\",\n          checked ? \"bg-white dark:bg-neutral-900\" : \"bg-white dark:bg-neutral-400\"\n        )}\n        animate={{ x: checked ? 20 : 0 }}\n        transition={{ type: \"spring\", stiffness: 500, damping: 32 }}\n      />\n    </button>\n  );\n}\n\nfunction TagChip({\n  tag,\n  active,\n  onClick,\n}: {\n  tag: TagName;\n  active?: boolean;\n  onClick?: () => void;\n}) {\n  return (\n    <button\n      onClick={onClick}\n      className={cn(\n        \"inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-[12px] transition-colors\",\n        active\n          ? \"border-neutral-900 bg-neutral-900 text-white dark:border-neutral-100 dark:bg-neutral-100 dark:text-neutral-900\"\n          : \"border-neutral-200 bg-neutral-50 text-neutral-600 hover:bg-neutral-100 dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-400 dark:hover:bg-neutral-800\"\n      )}\n    >\n      <span className={cn(\"h-1.5 w-1.5 rounded-full\", active ? \"bg-white dark:bg-neutral-900\" : TAG_DOT[tag])} />\n      {tag}\n    </button>\n  );\n}\n\nfunction ToastStack({ toasts }: { toasts: { id: number; message: string }[] }) {\n  return (\n    <div className=\"pointer-events-none fixed bottom-5 right-5 z-[100] flex flex-col items-end gap-2\">\n      <AnimatePresence>\n        {toasts.map((t) => (\n          <motion.div\n            key={t.id}\n            initial={{ opacity: 0, y: 12, scale: 0.95 }}\n            animate={{ opacity: 1, y: 0, scale: 1 }}\n            exit={{ opacity: 0, scale: 0.95, transition: { duration: 0.15 } }}\n            transition={{ type: \"spring\", stiffness: 400, damping: 30 }}\n            className=\"pointer-events-auto flex items-center gap-2 rounded-xl bg-neutral-900 px-4 py-2.5 text-[13px] font-medium text-white shadow-lg dark:bg-neutral-50 dark:text-neutral-900 dark:shadow-black/50\"\n          >\n            <Check className=\"h-3.5 w-3.5 text-emerald-400 dark:text-emerald-600\" />\n            {t.message}\n          </motion.div>\n        ))}\n      </AnimatePresence>\n    </div>\n  );\n}\n\n/* Generic dropdown shell: backdrop + animated panel */\nfunction Dropdown({\n  open,\n  onClose,\n  anchorClassName,\n  children,\n}: {\n  open: boolean;\n  onClose: () => void;\n  anchorClassName: string;\n  children: React.ReactNode;\n}) {\n  if (!open) return null;\n  return (\n    <>\n      <div className=\"fixed inset-0 z-40 cursor-pointer\" onClick={onClose} />\n      <motion.div\n        initial={{ opacity: 0, y: -6, scale: 0.98 }}\n        animate={{ opacity: 1, y: 0, scale: 1 }}\n        exit={{ opacity: 0, y: -6, scale: 0.98 }}\n        transition={{ duration: 0.14 }}\n        className={cn(\n          \"absolute z-50 rounded-xl border border-neutral-200 bg-white shadow-xl dark:border-neutral-800 dark:bg-neutral-900 dark:shadow-black/50\",\n          anchorClassName\n        )}\n      >\n        {children}\n      </motion.div>\n    </>\n  );\n}\n\n/* ================================================================== */\n/*  Theme toggle                                                       */\n/* ================================================================== */\n\nfunction ThemeToggle({\n  isDark,\n  onToggle,\n  collapsed,\n}: {\n  isDark: boolean;\n  onToggle: () => void;\n  collapsed?: boolean;\n}) {\n  return (\n    <button\n      onClick={onToggle}\n      title={collapsed ? (isDark ? \"Switch to light mode\" : \"Switch to dark mode\") : undefined}\n      className={cn(\n        \"relative flex w-full cursor-pointer items-center gap-2.5 rounded-lg px-2.5 py-[7px] text-[13.5px] text-neutral-500 transition-colors hover:bg-neutral-50 hover:text-neutral-800 dark:text-neutral-500 dark:hover:bg-neutral-900 dark:hover:text-neutral-200\",\n        collapsed && \"justify-center px-0\"\n      )}\n    >\n      <span className=\"relative flex h-[15px] w-[15px] shrink-0 items-center justify-center overflow-hidden\">\n        <AnimatePresence initial={false} mode=\"wait\">\n          {isDark ? (\n            <motion.span\n              key=\"moon\"\n              initial={{ opacity: 0, rotate: -70, scale: 0.5 }}\n              animate={{ opacity: 1, rotate: 0, scale: 1 }}\n              exit={{ opacity: 0, rotate: 70, scale: 0.5 }}\n              transition={{ duration: 0.22, ease: \"easeOut\" }}\n              className=\"absolute inset-0 flex items-center justify-center\"\n            >\n              <Moon className=\"h-[15px] w-[15px]\" />\n            </motion.span>\n          ) : (\n            <motion.span\n              key=\"sun\"\n              initial={{ opacity: 0, rotate: 70, scale: 0.5 }}\n              animate={{ opacity: 1, rotate: 0, scale: 1 }}\n              exit={{ opacity: 0, rotate: -70, scale: 0.5 }}\n              transition={{ duration: 0.22, ease: \"easeOut\" }}\n              className=\"absolute inset-0 flex items-center justify-center\"\n            >\n              <Sun className=\"h-[15px] w-[15px]\" />\n            </motion.span>\n          )}\n        </AnimatePresence>\n      </span>\n      {!collapsed && <span className=\"flex-1 truncate text-left\">{isDark ? \"Dark mode\" : \"Light mode\"}</span>}\n      {!collapsed && (\n        <span\n          className={cn(\n            \"relative h-5 w-9 shrink-0 rounded-full transition-colors duration-200 cursor-pointer\",\n            isDark ? \"bg-neutral-100\" : \"bg-neutral-200\"\n          )}\n        >\n          <motion.span\n            className={cn(\"absolute top-0.5 left-0.5 h-4 w-4 rounded-full shadow-sm\", isDark ? \"bg-neutral-900\" : \"bg-white\")}\n            animate={{ x: isDark ? 16 : 0 }}\n            transition={{ type: \"spring\", stiffness: 500, damping: 32 }}\n          />\n        </span>\n      )}\n    </button>\n  );\n}\n\n/* ================================================================== */\n/*  Nav item                                                            */\n/* ================================================================== */\n\nconst NavItem = React.memo(function NavItem({\n  icon: Icon,\n  label,\n  active,\n  collapsed,\n  onClick,\n  badge,\n}: {\n  icon: React.ComponentType<{ className?: string }>;\n  label: string;\n  active?: boolean;\n  collapsed?: boolean;\n  onClick?: () => void;\n  badge?: number;\n}) {\n  return (\n    <button\n      onClick={onClick}\n      title={collapsed ? label : undefined}\n      className={cn(\n        \"relative flex w-full cursor-pointer items-center gap-2.5 rounded-lg px-2.5 py-[7px] text-[13.5px] transition-colors\",\n        collapsed && \"justify-center px-0\",\n        active\n          ? \"bg-neutral-100 font-medium text-neutral-900 dark:bg-neutral-800 dark:text-neutral-50\"\n          : \"text-neutral-500 hover:bg-neutral-50 hover:text-neutral-800 dark:text-neutral-500 dark:hover:bg-neutral-900 dark:hover:text-neutral-200\"\n      )}\n    >\n      <Icon className=\"h-[15px] w-[15px] shrink-0\" />\n      {!collapsed && <span className=\"flex-1 truncate text-left\">{label}</span>}\n      {!!badge && badge > 0 && (\n        <span\n          className={cn(\n            \"rounded-full bg-rose-500 px-[6px] py-[1px] text-[10px] font-medium text-white\",\n            collapsed && \"absolute -right-0.5 -top-0.5\"\n          )}\n        >\n          {badge}\n        </span>\n      )}\n    </button>\n  );\n});\n\n/* ================================================================== */\n/*  Sidebar                                                             */\n/* ================================================================== */\n\nfunction Sidebar({\n  collapsed,\n  onToggleCollapsed,\n  projects,\n  activeProjectId,\n  onSelectProject,\n  projectsExpanded,\n  onToggleProjectsExpanded,\n  activeNav,\n  onGoHome,\n  onGoNav,\n  notifications,\n  notificationsOpen,\n  onToggleNotifications,\n  onMarkAllRead,\n  onNotificationClick,\n  unreadCount,\n  isDark,\n  onToggleDark,\n}: {\n  collapsed: boolean;\n  onToggleCollapsed: () => void;\n  projects: Project[];\n  activeProjectId: string;\n  onSelectProject: (id: string) => void;\n  projectsExpanded: boolean;\n  onToggleProjectsExpanded: () => void;\n  activeNav: NavKey | null;\n  onGoHome: () => void;\n  onGoNav: (key: NavKey) => void;\n  notifications: NotificationItem[];\n  notificationsOpen: boolean;\n  onToggleNotifications: () => void;\n  onMarkAllRead: () => void;\n  onNotificationClick: (n: NotificationItem) => void;\n  unreadCount: number;\n  isDark: boolean;\n  onToggleDark: () => void;\n}) {\n  return (\n    <motion.aside\n      animate={{ width: collapsed ? 68 : 212 }}\n      transition={{ type: \"spring\", stiffness: 300, damping: 30 }}\n      className=\"relative flex h-full shrink-0 flex-col overflow-hidden border-r border-neutral-200 bg-white px-3 py-4 dark:border-neutral-800 dark:bg-[#0C0C0E]\"\n    >\n      <div className={cn(\"flex items-center pb-5\", collapsed ? \"justify-center\" : \"justify-between px-1\")}>\n        {!collapsed && (\n          <div className=\"flex items-center gap-2\">\n            <AppLogo />\n            <div className=\"flex min-w-0 flex-col leading-tight\">\n              <span className=\"whitespace-nowrap text-[16px] font-semibold text-neutral-900 dark:text-neutral-50\">BagUi</span>\n              <p className=\"whitespace-nowrap text-[11px] text-neutral-400 dark:text-neutral-600 mt-1\">Open Source Ui Blocks</p>\n            </div>\n          </div>\n        )}\n        {collapsed && <AppLogo />}\n        {!collapsed && (\n          <button\n            onClick={onToggleCollapsed}\n            className=\"flex h-6 w-6 items-center justify-center rounded-md text-neutral-400 hover:bg-neutral-100 hover:text-neutral-600 dark:text-neutral-600 dark:hover:bg-neutral-800 dark:hover:text-neutral-300 cursor-pointer\"\n          >\n            <ChevronsRight className=\"h-[15px] w-[15px]\" />\n          </button>\n        )}\n      </div>\n\n      {collapsed && (\n        <button\n          onClick={onToggleCollapsed}\n          className=\"absolute right-1.5 top-[18px] flex h-6 w-6 items-center justify-center rounded-md text-neutral-400 hover:bg-neutral-100 hover:text-neutral-600 dark:text-neutral-600 dark:hover:bg-neutral-800 dark:hover:text-neutral-300\"\n        >\n          <ChevronsRight className=\"h-[13px] w-[13px] rotate-180\" />\n        </button>\n      )}\n\n      <nav className=\"flex flex-1 flex-col gap-0.5 overflow-y-auto overflow-x-hidden\">\n        <NavItem icon={Home} label=\"Home\" active={activeNav === \"home\"} collapsed={collapsed} onClick={onGoHome} />\n\n        <button\n          onClick={onToggleProjectsExpanded}\n          className={cn(\n            \"flex w-full cursor-pointer items-center gap-2.5 rounded-lg px-2.5 py-[7px] text-[13.5px] text-neutral-500 hover:bg-neutral-50 dark:text-neutral-500 dark:hover:bg-neutral-900\",\n            collapsed && \"justify-center px-0\"\n          )}\n        >\n          <FolderIcon className=\"h-[15px] w-[15px] shrink-0\" />\n          {!collapsed && (\n            <>\n              <span className=\"flex-1 truncate text-left\">Projects</span>\n              <motion.span animate={{ rotate: projectsExpanded ? 0 : -90 }} transition={{ duration: 0.15 }}>\n                <ChevronDown className=\"h-3.5 w-3.5 text-neutral-400 dark:text-neutral-600\" />\n              </motion.span>\n            </>\n          )}\n        </button>\n\n        <AnimatePresence initial={false}>\n          {projectsExpanded && !collapsed && (\n            <motion.div\n              initial={{ height: 0, opacity: 0 }}\n              animate={{ height: \"auto\", opacity: 1 }}\n              exit={{ height: 0, opacity: 0 }}\n              transition={{ duration: 0.18 }}\n              className=\"ml-[18px] overflow-hidden border-l border-neutral-200 pl-3 dark:border-neutral-800 cursor-pointer\"\n            >\n              <div className=\"flex flex-col gap-0.5 py-0.5\">\n                {projects.map((p) => (\n                  <button\n                    key={p.id}\n                    onClick={() => onSelectProject(p.id)}\n                    className={cn(\n                      \"block w-full truncate rounded-lg px-2.5 py-[7px] text-left text-[13.5px] transition-colors\",\n                      p.id === activeProjectId\n                        ? \"bg-neutral-100 font-medium text-neutral-900 dark:bg-neutral-800 dark:text-neutral-50\"\n                        : \"text-neutral-500 hover:bg-neutral-50 hover:text-neutral-800 dark:text-neutral-500 dark:hover:bg-neutral-900 dark:hover:text-neutral-200\"\n                    )}\n                  >\n                    {p.name}\n                  </button>\n                ))}\n              </div>\n            </motion.div>\n          )}\n        </AnimatePresence>\n\n        <div className=\"my-3 h-px bg-neutral-100 dark:bg-neutral-800\" />\n\n        {SECONDARY_NAV.map((item) => (\n          <NavItem\n            key={item.key}\n            icon={item.icon}\n            label={item.label}\n            active={activeNav === item.key}\n            collapsed={collapsed}\n            onClick={() => onGoNav(item.key)}\n          />\n        ))}\n      </nav>\n\n      <div className=\"flex flex-col gap-0.5 pt-2\">\n        <ThemeToggle isDark={isDark} onToggle={onToggleDark} collapsed={collapsed} />\n        <NavItem icon={Settings} label=\"Settings\" collapsed={collapsed} />\n        <div className=\"relative\">\n          <NavItem\n            icon={Bell}\n            label=\"Notifications\"\n            collapsed={collapsed}\n            badge={unreadCount}\n            onClick={onToggleNotifications}\n          />\n          <AnimatePresence>\n            {notificationsOpen && (\n              <Dropdown open onClose={onToggleNotifications} anchorClassName={collapsed ? \"left-[60px] bottom-0 w-[300px]\" : \"left-1 right-1 bottom-[calc(100%+6px)] w-[260px]\"}>\n                <div className=\"flex items-center justify-between border-b border-neutral-100 px-3.5 py-2.5 dark:border-neutral-800\">\n                  <span className=\"text-[13px] font-medium text-neutral-900 dark:text-neutral-50\">Notifications</span>\n                  <button onClick={onMarkAllRead} className=\"cursor-pointer text-[11.5px] text-neutral-400 hover:text-neutral-700 dark:text-neutral-600 dark:hover:text-neutral-200\">\n                    Mark all read\n                  </button>\n                </div>\n                <div className=\"max-h-[280px] overflow-y-auto py-1\">\n                  {notifications.map((n) => (\n                    <button\n                      key={n.id}\n                      onClick={() => onNotificationClick(n)}\n                      className=\"flex w-full items-start gap-2.5 px-3.5 py-2.5 text-left hover:bg-neutral-50 dark:hover:bg-neutral-800/60\"\n                    >\n                      <span\n                        className={cn(\n                          \"mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full\",\n                          n.unread ? \"bg-blue-500 dark:bg-blue-400\" : \"bg-transparent\"\n                        )}\n                      />\n                      <span className=\"min-w-0 flex-1\">\n                        <span className={cn(\"block text-[12.5px] leading-snug\", n.unread ? \"font-medium text-neutral-900 dark:text-neutral-50\" : \"text-neutral-500 dark:text-neutral-500\")}>\n                          {n.message}\n                        </span>\n                        <span className=\"mt-0.5 block text-[11px] text-neutral-400 dark:text-neutral-600\">{n.time}</span>\n                      </span>\n                    </button>\n                  ))}\n                </div>\n              </Dropdown>\n            )}\n          </AnimatePresence>\n        </div>\n\n        <div className=\"my-3 h-px bg-neutral-100 dark:bg-neutral-800\" />\n\n        <div className={cn(\"flex items-center gap-2.5 rounded-lg px-1.5 py-1.5\", collapsed && \"justify-center px-0\")}>\n          <Avatar seed=\"Anelka Bag\" src=\"/avatar.png\" className=\"h-8 w-8\" />\n          {!collapsed && (\n            <>\n              <div className=\"min-w-0 flex-1\">\n                <p className=\"truncate text-[13px] font-medium text-neutral-900 dark:text-neutral-50\">{CURRENT_USER}</p>\n                <p className=\"truncate text-[12px] text-neutral-400 dark:text-neutral-600\">ceo@bagui.pro</p>\n              </div>\n              <ExternalLink className=\"h-3.5 w-3.5 shrink-0 text-neutral-400 dark:text-neutral-600\" />\n            </>\n          )}\n        </div>\n      </div>\n    </motion.aside>\n  );\n}\n\n/* ================================================================== */\n/*  Top bar                                                             */\n/* ================================================================== */\n\nfunction TopBar({\n  projectName,\n  folderTitle,\n  onBack,\n  onGoProjectRoot,\n  showBack,\n  onShare,\n  shareOpen,\n  onCopyLink,\n}: {\n  projectName: string;\n  folderTitle: string | null;\n  onBack: () => void;\n  onGoProjectRoot: () => void;\n  showBack: boolean;\n  onShare: () => void;\n  shareOpen: boolean;\n  onCopyLink: () => void;\n}) {\n  const [moreOpen, setMoreOpen] = useState(false);\n  return (\n    <div className=\"flex h-[60px] shrink-0 border-b border-neutral-200 bg-white dark:border-neutral-800 dark:bg-[#0C0C0E]\">\n      <div className=\"flex flex-1 items-center justify-between px-6\">\n        <div className=\"flex min-w-0 flex-1 items-center gap-3 text-[13.5px]\">\n          <button\n            onClick={onBack}\n            disabled={!showBack}\n            className={cn(\n              \"flex h-7 w-7 shrink-0 cursor-pointer items-center justify-center rounded-md transition-colors\",\n              showBack\n                ? \"text-neutral-500 hover:bg-neutral-100 dark:text-neutral-500 dark:hover:bg-neutral-800\"\n                : \"text-neutral-200 dark:text-neutral-800\"\n            )}\n          >\n            <ArrowLeft className=\"h-4 w-4\" />\n          </button>\n          <div className=\"flex min-w-0 items-center gap-1.5 text-neutral-400 dark:text-neutral-600\">\n            <button onClick={onGoProjectRoot} className=\"flex shrink-0 cursor-pointer items-center gap-1.5 hover:text-neutral-700 dark:hover:text-neutral-200\">\n              <FolderIcon className=\"h-3.5 w-3.5 shrink-0\" />\n              <span>Projects</span>\n            </button>\n            <ChevronRight className=\"h-3.5 w-3.5 shrink-0\" />\n            <button\n              onClick={onGoProjectRoot}\n              className={cn(\n                \"flex min-w-0 cursor-pointer items-center gap-1.5 hover:text-neutral-700 dark:hover:text-neutral-200\",\n                !folderTitle ? \"shrink-0\" : \"shrink\"\n              )}\n            >\n              <FolderIcon className=\"h-3.5 w-3.5 shrink-0 text-neutral-500 dark:text-neutral-500\" />\n              <span className={cn(\"truncate\", !folderTitle && \"font-medium text-neutral-800 dark:text-neutral-100\")}>{projectName}</span>\n            </button>\n            {folderTitle && (\n              <>\n                <ChevronRight className=\"h-3.5 w-3.5 shrink-0\" />\n                <span className=\"min-w-0 shrink truncate font-medium text-neutral-800 dark:text-neutral-100\">{folderTitle}</span>\n              </>\n            )}\n          </div>\n        </div>\n\n        <div className=\"flex shrink-0 items-center gap-1.5 text-[13.5px] text-neutral-500 dark:text-neutral-400\">\n          <button className=\"flex cursor-pointer items-center gap-1.5 rounded-lg px-2.5 py-1.5 hover:bg-neutral-50 dark:hover:bg-neutral-900\">\n            <Settings className=\"h-[15px] w-[15px]\" />\n            Manage\n          </button>\n          <div className=\"relative\">\n            <button onClick={onShare} className=\"flex cursor-pointer items-center gap-1.5 rounded-lg px-2.5 py-1.5 hover:bg-neutral-50 dark:hover:bg-neutral-900\">\n              <Share2 className=\"h-[15px] w-[15px]\" />\n              Share\n            </button>\n            <AnimatePresence>\n              {shareOpen && (\n                <Dropdown open onClose={onShare} anchorClassName=\"right-0 top-[calc(100%+6px)] w-[280px] p-3\">\n                  <p className=\"mb-2 text-[12.5px] text-neutral-500 dark:text-neutral-400\">Anyone with the link can view this project.</p>\n                  <div className=\"flex items-center gap-2 rounded-lg border border-neutral-200 bg-neutral-50 px-2.5 py-2 dark:border-neutral-800 dark:bg-neutral-950\">\n                    <Link2 className=\"h-3.5 w-3.5 shrink-0 text-neutral-400 dark:text-neutral-600\" />\n                    <span className=\"truncate text-[12px] text-neutral-500 dark:text-neutral-500\">bagui.app/fullscreen/dashboard-folder</span>\n                    <button\n                      onClick={onCopyLink}\n                      className=\"ml-auto shrink-0 rounded-md bg-neutral-900 px-2 py-1 text-[11px] font-medium text-white hover:bg-neutral-800 dark:bg-white dark:text-neutral-900 dark:hover:bg-neutral-200\"\n                    >\n                      Copy\n                    </button>\n                  </div>\n                </Dropdown>\n              )}\n            </AnimatePresence>\n          </div>\n          <div className=\"relative\">\n            <button\n              onClick={() => setMoreOpen((v) => !v)}\n              className=\"flex h-7 w-7 cursor-pointer items-center justify-center rounded-md hover:bg-neutral-100 dark:hover:bg-neutral-800\"\n            >\n              <MoreHorizontal className=\"h-[15px] w-[15px]\" />\n            </button>\n            <AnimatePresence>\n              {moreOpen && (\n                <Dropdown open onClose={() => setMoreOpen(false)} anchorClassName=\"right-0 top-[calc(100%+6px)] w-[190px] py-1.5\">\n                  <button className=\"flex cursor-pointer w-full items-center gap-2.5 px-3.5 py-2 text-left text-[13px] text-neutral-600 hover:bg-neutral-50 dark:text-neutral-400 dark:hover:bg-neutral-800\">\n                    <Pencil className=\"h-3.5 w-3.5\" /> Rename project\n                  </button>\n                  <button className=\"flex cursor-pointer w-full items-center gap-2.5 px-3.5 py-2 text-left text-[13px] text-neutral-600 hover:bg-neutral-50 dark:text-neutral-400 dark:hover:bg-neutral-800\">\n                    <Download className=\"h-3.5 w-3.5\" /> Export all\n                  </button>\n                  <button className=\"flex cursor-pointer w-full items-center gap-2.5 px-3.5 py-2 text-left text-[13px] text-rose-500 hover:bg-rose-50 dark:text-rose-400 dark:hover:bg-rose-500/10\">\n                    <Trash2 className=\"h-3.5 w-3.5\" /> Delete project\n                  </button>\n                </Dropdown>\n              )}\n            </AnimatePresence>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n\n/* ================================================================== */\n/*  Folder tile                                                        */\n/* ================================================================== */\n\nconst FolderTile = React.memo(function FolderTile({\n  folder,\n  onOpen,\n}: {\n  folder: Folder;\n  onOpen: (id: string) => void;\n}) {\n  const [hovered, setHovered] = useState(false);\n  const active = folder.variant === \"black\";\n  return (\n    <motion.div\n      layout\n      initial={{ opacity: 0, y: 10 }}\n      animate={{ opacity: 1, y: 0 }}\n      exit={{ opacity: 0, y: -6, scale: 0.97 }}\n      transition={{ duration: 0.2 }}\n      className=\"group inline-flex w-max flex-col items-center gap-6\"\n    >\n      <motion.button\n        type=\"button\"\n        onClick={() => onOpen(folder.id)}\n        onMouseEnter={() => setHovered(true)}\n        onMouseLeave={() => setHovered(false)}\n        whileHover={{ y: -2 }}\n        whileTap={{ scale: 0.98 }}\n        className=\"inline-flex cursor-pointer rounded-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-900/40 dark:focus-visible:ring-neutral-100/40 mt-4\"\n      >\n        <FolderGraphic variant={folder.variant} hovered={hovered} />\n      </motion.button>\n\n      <div className=\"mt-3 flex w-full max-w-[200px] flex-col gap-1.5\">\n        <div className=\"flex items-center justify-between gap-2\">\n          <h3 className={cn(\"min-w-0 flex-1 truncate text-[15px] font-semibold\", active ? \"text-white\" : \"text-neutral-900 dark:text-neutral-100\")}>\n            {folder.title}\n          </h3>\n          <span\n            className={cn(\n              \"shrink-0 whitespace-nowrap rounded-full px-2 py-0.5 text-[11px] font-medium\",\n              active ? \"bg-white/20 text-white\" : \"bg-neutral-100 text-neutral-500 dark:bg-neutral-800 dark:text-neutral-400\"\n            )}\n          >\n            {folder.tag}\n          </span>\n        </div>\n        <div className=\"flex items-center justify-between gap-2\">\n          <p className={cn(\"min-w-0 flex-1 truncate text-[13px]\", active ? \"text-white/80\" : \"text-neutral-500 dark:text-neutral-500\")}>\n            {folder.notesCount} notes\n          </p>\n          <p className={cn(\"shrink-0 whitespace-nowrap text-[13px]\", active ? \"text-white/70\" : \"text-neutral-400 dark:text-neutral-600\")}>\n            {formatSize(folder.sizeKb)}\n          </p>\n        </div>\n      </div>\n    </motion.div>\n  );\n});\n\n/* ================================================================== */\n/*  File row / card                                                    */\n/* ================================================================== */\n\nconst FileRow = React.memo(function FileRow({\n  file,\n  selected,\n  onSelect,\n  onDelete,\n  onRename,\n  onDownload,\n}: {\n  file: FileItem;\n  selected: boolean;\n  onSelect: (file: FileItem) => void;\n  onDelete: (id: string) => void;\n  onRename: (file: FileItem) => void;\n  onDownload: (file: FileItem) => void;\n}) {\n  const [menuOpen, setMenuOpen] = useState(false);\n  const meta = KIND_META[file.kind];\n  const Icon = meta.icon;\n  return (\n    <motion.div\n      layout\n      initial={{ opacity: 0, y: 6 }}\n      animate={{ opacity: 1, y: 0 }}\n      exit={{ opacity: 0, scale: 0.96, transition: { duration: 0.15 } }}\n      transition={{ duration: 0.18 }}\n      onClick={() => onSelect(file)}\n      className={cn(\n        \"group flex cursor-pointer items-center gap-3 rounded-xl border px-3.5 py-2.5 transition-colors\",\n        selected\n          ? \"border-neutral-900/15 bg-neutral-50 dark:border-neutral-100/15 dark:bg-neutral-900\"\n          : \"border-transparent hover:bg-neutral-50 dark:hover:bg-neutral-900/70\"\n      )}\n    >\n      <span className={cn(\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg\", meta.bg)}>\n        <Icon className={cn(\"h-4 w-4\", meta.color)} />\n      </span>\n      <div className=\"min-w-0 flex-1\">\n        <p className=\"truncate text-[13.5px] font-medium text-neutral-900 dark:text-neutral-50\">{file.name}</p>\n        <p className=\"mt-0.5 truncate text-[12px] text-neutral-400 dark:text-neutral-600\">\n          {meta.label} · {formatSize(file.sizeKb)} · {formatDate(file.modified)}\n        </p>\n      </div>\n      <Avatar seed={file.owner} className=\"h-6 w-6\" />\n      <div className=\"relative\">\n        <button\n          onClick={(e) => {\n            e.stopPropagation();\n            setMenuOpen((v) => !v);\n          }}\n          className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-neutral-400 opacity-0 hover:bg-neutral-200/60 hover:text-neutral-700 group-hover:opacity-100 dark:text-neutral-600 dark:hover:bg-neutral-800 dark:hover:text-neutral-200\"\n        >\n          <MoreVertical className=\"h-4 w-4\" />\n        </button>\n        <AnimatePresence>\n          {menuOpen && (\n            <Dropdown open onClose={() => setMenuOpen(false)} anchorClassName=\"right-0 top-[calc(100%+4px)] w-[170px] py-1.5\">\n              <button\n                onClick={(e) => {\n                  e.stopPropagation();\n                  onRename(file);\n                  setMenuOpen(false);\n                }}\n                className=\"flex w-full items-center gap-2.5 px-3.5 py-2 text-left text-[13px] text-neutral-600 hover:bg-neutral-50 dark:text-neutral-400 dark:hover:bg-neutral-800\"\n              >\n                <Pencil className=\"h-3.5 w-3.5\" /> Rename\n              </button>\n              <button\n                onClick={(e) => {\n                  e.stopPropagation();\n                  onDownload(file);\n                  setMenuOpen(false);\n                }}\n                className=\"flex w-full items-center gap-2.5 px-3.5 py-2 text-left text-[13px] text-neutral-600 hover:bg-neutral-50 dark:text-neutral-400 dark:hover:bg-neutral-800\"\n              >\n                <Download className=\"h-3.5 w-3.5\" /> Download\n              </button>\n              <button\n                onClick={(e) => {\n                  e.stopPropagation();\n                  onDelete(file.id);\n                  setMenuOpen(false);\n                }}\n                className=\"flex w-full items-center gap-2.5 px-3.5 py-2 text-left text-[13px] text-rose-500 hover:bg-rose-50 dark:text-rose-400 dark:hover:bg-rose-500/10\"\n              >\n                <Trash2 className=\"h-3.5 w-3.5\" /> Delete\n              </button>\n            </Dropdown>\n          )}\n        </AnimatePresence>\n      </div>\n    </motion.div>\n  );\n});\n\n/* ================================================================== */\n/*  Search + sort toolbar (shared)                                     */\n/* ================================================================== */\n\nfunction Toolbar({\n  search,\n  onSearch,\n  placeholder,\n  sortBy,\n  onSortChange,\n  onNewDraft,\n  newDraftLabel,\n}: {\n  search: string;\n  onSearch: (v: string) => void;\n  placeholder: string;\n  sortBy: SortKey;\n  onSortChange: (v: SortKey) => void;\n  onNewDraft?: () => void;\n  newDraftLabel?: string;\n}) {\n  const [sortOpen, setSortOpen] = useState(false);\n  const sortLabel: Record<SortKey, string> = { name: \"Name\", size: \"Size\", date: \"Date\" };\n  return (\n    <div className=\"mb-6 flex items-center gap-3\">\n      <div className=\"flex flex-1 items-center gap-2 rounded-xl border border-neutral-200 bg-white px-3.5 py-2.5 dark:border-neutral-800 dark:bg-neutral-900\">\n        <Search className=\"h-[15px] w-[15px] text-neutral-400 dark:text-neutral-600\" />\n        <input\n          value={search}\n          onChange={(e) => onSearch(e.target.value)}\n          placeholder={placeholder}\n          className=\"w-full bg-transparent text-[13.5px] text-neutral-700 placeholder:text-neutral-400 focus:outline-none dark:text-neutral-200 dark:placeholder:text-neutral-600\"\n        />\n        {search && (\n          <button onClick={() => onSearch(\"\")} className=\"cursor-pointer text-neutral-300 hover:text-neutral-500 dark:text-neutral-700 dark:hover:text-neutral-400\">\n            <X className=\"h-3.5 w-3.5\" />\n          </button>\n        )}\n      </div>\n      <div className=\"relative\">\n        <button\n          onClick={() => setSortOpen((v) => !v)}\n          className=\"flex cursor-pointer items-center gap-2 rounded-xl border border-neutral-200 bg-white px-3.5 py-2.5 text-[13.5px] text-neutral-600 hover:bg-neutral-50 dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-400 dark:hover:bg-neutral-800\"\n        >\n          <SlidersHorizontal className=\"h-[15px] w-[15px]\" />\n          {sortLabel[sortBy]}\n        </button>\n        <AnimatePresence>\n          {sortOpen && (\n            <Dropdown open onClose={() => setSortOpen(false)} anchorClassName=\"right-0 top-[calc(100%+6px)] w-[150px] py-1.5\">\n              {(Object.keys(sortLabel) as SortKey[]).map((key) => (\n                <button\n                  key={key}\n                  onClick={() => {\n                    onSortChange(key);\n                    setSortOpen(false);\n                  }}\n                  className={cn(\n                    \"flex w-full items-center gap-2.5 px-3.5 py-2 text-left text-[13px] hover:bg-neutral-50 dark:hover:bg-neutral-800\",\n                    sortBy === key ? \"font-medium text-neutral-900 dark:text-neutral-50\" : \"text-neutral-600 dark:text-neutral-400\"\n                  )}\n                >\n                  <ArrowUpDown className=\"h-3.5 w-3.5\" /> {sortLabel[key]}\n                </button>\n              ))}\n            </Dropdown>\n          )}\n        </AnimatePresence>\n      </div>\n      {onNewDraft && (\n        <button\n          onClick={onNewDraft}\n          className=\"flex cursor-pointer items-center gap-1.5 rounded-full bg-neutral-900 px-4 py-2.5 text-[13.5px] font-medium text-white hover:bg-neutral-800 dark:bg-white dark:text-neutral-900 dark:hover:bg-neutral-200\"\n        >\n          <Plus className=\"h-[15px] w-[15px]\" />\n          {newDraftLabel ?? \"New draft\"}\n        </button>\n      )}\n    </div>\n  );\n}\n\n/* ================================================================== */\n/*  Home view                                                          */\n/* ================================================================== */\n\nfunction HomeView({\n  projectName,\n  folders,\n  search,\n  onSearch,\n  sortBy,\n  onSortChange,\n  tagFilter,\n  onOpenFolder,\n  onNewDraft,\n}: {\n  projectName: string;\n  folders: Folder[];\n  search: string;\n  onSearch: (v: string) => void;\n  sortBy: SortKey;\n  onSortChange: (v: SortKey) => void;\n  tagFilter: TagName | null;\n  onOpenFolder: (id: string) => void;\n  onNewDraft: () => void;\n}) {\n  const visible = useMemo(() => {\n    let list = folders;\n    if (tagFilter) list = list.filter((f) => f.tag === tagFilter);\n    if (search.trim()) {\n      const q = search.trim().toLowerCase();\n      list = list.filter((f) => f.title.toLowerCase().includes(q));\n    }\n    return sortFolders(list, sortBy);\n  }, [folders, search, sortBy, tagFilter]);\n\n  return (\n    <div>\n      <div className=\"mb-6 flex items-center justify-between gap-4\">\n        <h1 className=\"min-w-0 truncate text-[22px] font-semibold text-neutral-900 dark:text-neutral-50 mt-4\">{projectName}</h1>\n      </div>\n\n      <Toolbar\n        search={search}\n        onSearch={onSearch}\n        placeholder=\"Search folders\"\n        sortBy={sortBy}\n        onSortChange={onSortChange}\n        onNewDraft={onNewDraft}\n      />\n\n      {visible.length === 0 ? (\n        <div className=\"flex flex-col items-center justify-center rounded-2xl border border-dashed border-neutral-200 py-20 text-center dark:border-neutral-800\">\n          <FolderIcon className=\"mb-3 h-8 w-8 text-neutral-300 dark:text-neutral-700\" />\n          <p className=\"text-[13.5px] text-neutral-500 dark:text-neutral-500\">Nothing matches your search or filter.</p>\n        </div>\n      ) : (\n        <motion.div layout transition={{ layout: { duration: 0.4, ease: \"easeOut\" } }} className=\"grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 justify-items-center\">\n          <AnimatePresence initial={false} mode=\"popLayout\">\n            {visible.map((folder) => (\n              <FolderTile key={folder.id} folder={folder} onOpen={onOpenFolder} />\n            ))}\n          </AnimatePresence>\n        </motion.div>\n      )}\n    </div>\n  );\n}\n\n/* ================================================================== */\n/*  Folder detail view                                                 */\n/* ================================================================== */\n\nfunction FolderDetailView({\n  folder,\n  search,\n  onSearch,\n  sortBy,\n  onSortChange,\n  selectedFileId,\n  onSelectFile,\n  onDeleteFile,\n  onRenameFile,\n  onDownloadFile,\n  onNewDraft,\n}: {\n  folder: Folder;\n  search: string;\n  onSearch: (v: string) => void;\n  sortBy: SortKey;\n  onSortChange: (v: SortKey) => void;\n  selectedFileId: string | null;\n  onSelectFile: (file: FileItem) => void;\n  onDeleteFile: (id: string) => void;\n  onRenameFile: (file: FileItem) => void;\n  onDownloadFile: (file: FileItem) => void;\n  onNewDraft: () => void;\n}) {\n  const isDark = useIsDark();\n  const palette = (isDark ? folderPalettesDark : folderPalettes)[folder.variant];\n\n  const visible = useMemo(() => {\n    let list = folder.files;\n    if (search.trim()) {\n      const q = search.trim().toLowerCase();\n      list = list.filter((file) => file.name.toLowerCase().includes(q));\n    }\n    return sortFiles(list, sortBy);\n  }, [folder.files, search, sortBy]);\n\n  return (\n    <div>\n      <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div className=\"flex items-center gap-3 min-w-0\">\n          <div className=\"min-w-0\">\n            <div className=\"flex items-center gap-3 min-w-0\">\n              <div className=\"pointer-events-none transform scale-50 origin-center -ml-1\">\n                <FolderGraphic variant={folder.variant} hovered={true} />\n              </div>\n              <div className=\"min-w-0\">\n                <h1 className=\"truncate text-[22px] font-semibold text-neutral-900 dark:text-neutral-50\">{folder.title}</h1>\n                <p className=\"mt-0.5 text-[13px] text-neutral-500 dark:text-neutral-500\">{folder.files.length} files</p>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <div className=\"flex shrink-0 items-center gap-3 text-right\">\n          <span className=\"rounded-full bg-neutral-100 px-3 py-1 text-[12px] font-medium text-neutral-700 dark:bg-neutral-800 dark:text-neutral-300\">\n            {folder.tag}\n          </span>\n          <p className=\"text-[13px] text-neutral-500 dark:text-neutral-500\">{formatSize(folder.sizeKb)}</p>\n        </div>\n      </div>\n\n      <Toolbar\n        search={search}\n        onSearch={onSearch}\n        placeholder={`Search in ${folder.title}`}\n        sortBy={sortBy}\n        onSortChange={onSortChange}\n        onNewDraft={onNewDraft}\n        newDraftLabel=\"Add file\"\n      />\n\n      {visible.length === 0 ? (\n        <div className=\"flex flex-col items-center justify-center rounded-2xl border border-dashed border-neutral-200 py-20 text-center dark:border-neutral-800\">\n          <FileText className=\"mb-3 h-8 w-8 text-neutral-300 dark:text-neutral-700\" />\n          <p className=\"text-[13.5px] text-neutral-500 dark:text-neutral-500\">No files match your search.</p>\n        </div>\n      ) : (\n        <motion.div layout transition={{ layout: { duration: 0.4, ease: \"easeOut\" } }} className=\"grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3\">\n          <AnimatePresence initial={false} mode=\"popLayout\">\n            {visible.map((file) => (\n              <motion.button\n                key={file.id}\n                type=\"button\"\n                layout\n                initial={{ opacity: 0, y: 12 }}\n                animate={{ opacity: 1, y: 0 }}\n                exit={{ opacity: 0, y: -12 }}\n                transition={{ duration: 0.32, ease: \"easeOut\" }}\n                onClick={() => onSelectFile(file)}\n                whileHover={{ y: -2 }}\n                whileTap={{ scale: 0.98 }}\n                className={cn(\n                  \"group flex h-full flex-col justify-between rounded-[24px] border border-neutral-200/80 bg-white p-4 text-left transition hover:-translate-y-1 hover:shadow-[0_12px_40px_-24px_rgba(15,23,42,0.35)] focus:outline-none focus-visible:ring-2 focus-visible:ring-neutral-900/40 dark:border-neutral-800/80 dark:bg-neutral-900 dark:hover:shadow-[0_12px_40px_-24px_rgba(0,0,0,0.8)] dark:focus-visible:ring-neutral-100/30\",\n                  file.id === selectedFileId ? \"border-neutral-900/30 bg-neutral-50 dark:border-neutral-100/20 dark:bg-neutral-800/70\" : \"border-transparent\"\n                )}\n              >\n                <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n                  <div className=\"flex min-w-0 items-start gap-3\">\n                    <div className=\"flex h-14 w-14 flex-shrink-0 items-center justify-center rounded-3xl bg-neutral-50 dark:bg-neutral-950\">\n                      <MiniCard palette={palette} />\n                    </div>\n                    <div className=\"min-w-0\">\n                      <p className=\"truncate text-[15px] font-semibold text-neutral-900 dark:text-neutral-50\">{file.name}</p>\n                      <p className=\"mt-1 text-[12px] text-neutral-500 dark:text-neutral-500\">{formatSize(file.sizeKb)}</p>\n                    </div>\n                  </div>\n                  <span className=\"shrink-0 rounded-full bg-neutral-100 px-3 py-1 text-[11px] font-medium text-neutral-500 whitespace-nowrap dark:bg-neutral-800 dark:text-neutral-400\">{file.kind}</span>\n                </div>\n\n                <div className=\"mt-4 flex flex-col gap-2 text-[12px] text-neutral-500 sm:flex-row sm:items-center sm:justify-between dark:text-neutral-500\">\n                  <span className=\"truncate\">{formatDate(file.modified)}</span>\n                  <span className=\"shrink-0 rounded-full bg-neutral-100 px-2 py-1 text-[11px] font-medium text-neutral-500 dark:bg-neutral-800 dark:text-neutral-400\">{folder.tag}</span>\n                </div>\n              </motion.button>\n            ))}\n          </AnimatePresence>\n        </motion.div>\n      )}\n    </div>\n  );\n}\n\n/* ================================================================== */\n/*  Notes / Reports views (derived from files across the project)      */\n/* ================================================================== */\n\nfunction FlatFileListView({\n  title,\n  emptyLabel,\n  files,\n  search,\n  onSearch,\n  selectedFileId,\n  onSelectFile,\n  onDownloadFile,\n}: {\n  title: string;\n  emptyLabel: string;\n  files: (FileItem & { folderTitle: string })[];\n  search: string;\n  onSearch: (v: string) => void;\n  selectedFileId: string | null;\n  onSelectFile: (file: FileItem, folderTitle: string) => void;\n  onDownloadFile: (file: FileItem) => void;\n}) {\n  const visible = useMemo(() => {\n    if (!search.trim()) return files;\n    const q = search.trim().toLowerCase();\n    return files.filter((f) => f.name.toLowerCase().includes(q) || f.folderTitle.toLowerCase().includes(q));\n  }, [files, search]);\n\n  return (\n    <div>\n      <div className=\"mb-6 flex items-center justify-between\">\n        <h1 className=\"text-[22px] font-semibold text-neutral-900 dark:text-neutral-50\">{title}</h1>\n      </div>\n\n      <div className=\"mb-6 flex items-center gap-2 rounded-xl border border-neutral-200 bg-white px-3.5 py-2.5 dark:border-neutral-800 dark:bg-neutral-900\">\n        <Search className=\"h-[15px] w-[15px] text-neutral-400 dark:text-neutral-600\" />\n        <input\n          value={search}\n          onChange={(e) => onSearch(e.target.value)}\n          placeholder={`Search ${title.toLowerCase()}`}\n          className=\"w-full bg-transparent text-[13.5px] text-neutral-700 placeholder:text-neutral-400 focus:outline-none dark:text-neutral-200 dark:placeholder:text-neutral-600\"\n        />\n      </div>\n\n      {visible.length === 0 ? (\n        <div className=\"flex flex-col items-center justify-center rounded-2xl border border-dashed border-neutral-200 py-20 text-center dark:border-neutral-800\">\n          <p className=\"text-[13.5px] text-neutral-500 dark:text-neutral-500\">{emptyLabel}</p>\n        </div>\n      ) : (\n        <div className=\"flex flex-col gap-1\">\n          {visible.map((file) => {\n            const meta = KIND_META[file.kind];\n            const Icon = meta.icon;\n            const selected = file.id === selectedFileId;\n            return (\n              <motion.div\n                layout\n                key={file.id}\n                onClick={() => onSelectFile(file, file.folderTitle)}\n                className={cn(\n                  \"group flex cursor-pointer items-center gap-3 rounded-xl border px-3.5 py-2.5\",\n                  selected\n                    ? \"border-neutral-900/15 bg-neutral-50 dark:border-neutral-100/15 dark:bg-neutral-900\"\n                    : \"border-transparent hover:bg-neutral-50 dark:hover:bg-neutral-900/70\"\n                )}\n              >\n                <span className={cn(\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg\", meta.bg)}>\n                  <Icon className={cn(\"h-4 w-4\", meta.color)} />\n                </span>\n                <div className=\"min-w-0 flex-1\">\n                  <p className=\"truncate text-[13.5px] font-medium text-neutral-900 dark:text-neutral-50\">{file.name}</p>\n                  <p className=\"mt-0.5 truncate text-[12px] text-neutral-400 dark:text-neutral-600\">\n                    {file.folderTitle} · {formatSize(file.sizeKb)} · {formatDate(file.modified)}\n                  </p>\n                </div>\n                <button\n                  onClick={(e) => {\n                    e.stopPropagation();\n                    onDownloadFile(file);\n                  }}\n                  className=\"flex cursor-pointer h-7 w-7 shrink-0 items-center justify-center rounded-md text-neutral-400 opacity-0 hover:bg-neutral-200/60 hover:text-neutral-700 group-hover:opacity-100 dark:text-neutral-600 dark:hover:bg-neutral-800 dark:hover:text-neutral-200\"\n                >\n                  <Download className=\"h-4 w-4\" />\n                </button>\n              </motion.div>\n            );\n          })}\n        </div>\n      )}\n    </div>\n  );\n}\n\n/* ================================================================== */\n/*  Emails view                                                        */\n/* ================================================================== */\n\nfunction EmailsView({\n  emails,\n  expandedId,\n  onToggleExpand,\n}: {\n  emails: EmailItem[];\n  expandedId: number | null;\n  onToggleExpand: (id: number) => void;\n}) {\n  return (\n    <div>\n      <div className=\"mb-6 flex items-center justify-between\">\n        <h1 className=\"text-[22px] font-semibold text-neutral-900 dark:text-neutral-50\">Emails</h1>\n      </div>\n      <div className=\"flex flex-col gap-1\">\n        {emails.map((email) => {\n          const open = expandedId === email.id;\n          return (\n            <motion.div\n              layout\n              key={email.id}\n              className={cn(\n                \"cursor-pointer overflow-hidden rounded-xl border px-4 py-3\",\n                open\n                  ? \"border-neutral-200 bg-white dark:border-neutral-800 dark:bg-neutral-900\"\n                  : \"border-transparent hover:bg-neutral-50 dark:hover:bg-neutral-900/70\"\n              )}\n              onClick={() => onToggleExpand(email.id)}\n            >\n              <div className=\"flex items-center gap-3\">\n                <span className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-lg bg-blue-50 dark:bg-blue-500/15\">\n                  {email.unread ? (\n                    <Mail className=\"h-4 w-4 text-blue-500 dark:text-blue-400\" />\n                  ) : (\n                    <MailOpen className=\"h-4 w-4 text-neutral-400 dark:text-neutral-600\" />\n                  )}\n                </span>\n                <div className=\"min-w-0 flex-1\">\n                  <div className=\"flex items-center justify-between gap-2\">\n                    <p className={cn(\"truncate text-[13.5px]\", email.unread ? \"font-semibold text-neutral-900 dark:text-neutral-50\" : \"font-medium text-neutral-700 dark:text-neutral-300\")}>\n                      {email.from}\n                    </p>\n                    <span className=\"shrink-0 text-[11.5px] text-neutral-400 dark:text-neutral-600\">{email.time}</span>\n                  </div>\n                  <p className={cn(\"truncate text-[13px]\", email.unread ? \"text-neutral-800 dark:text-neutral-200\" : \"text-neutral-500 dark:text-neutral-500\")}>\n                    {email.subject}\n                  </p>\n                </div>\n              </div>\n              <AnimatePresence initial={false}>\n                {open && (\n                  <motion.div\n                    initial={{ height: 0, opacity: 0 }}\n                    animate={{ height: \"auto\", opacity: 1 }}\n                    exit={{ height: 0, opacity: 0 }}\n                    transition={{ duration: 0.18 }}\n                    className=\"pl-[52px]\"\n                  >\n                    <p className=\"pt-2 text-[13px] leading-relaxed text-neutral-500 dark:text-neutral-500\">{email.snippet}</p>\n                  </motion.div>\n                )}\n              </AnimatePresence>\n            </motion.div>\n          );\n        })}\n      </div>\n    </div>\n  );\n}\n\n/* ================================================================== */\n/*  Automation view                                                    */\n/* ================================================================== */\n\nfunction AutomationView({\n  automations,\n  onToggle,\n}: {\n  automations: AutomationItem[];\n  onToggle: (id: number) => void;\n}) {\n  return (\n    <div>\n      <div className=\"mb-6 flex items-center justify-between\">\n        <h1 className=\"text-[22px] font-semibold text-neutral-900 dark:text-neutral-50\">Automation</h1>\n      </div>\n      <div className=\"flex flex-col gap-2.5\">\n        {automations.map((a) => (\n          <div\n            key={a.id}\n            className={cn(\n              \"flex items-center gap-4 rounded-2xl border p-4 transition-colors\",\n              a.enabled\n                ? \"border-neutral-200 bg-white dark:border-neutral-800 dark:bg-neutral-900\"\n                : \"border-neutral-100 bg-neutral-50/60 dark:border-neutral-900 dark:bg-neutral-950/60\"\n            )}\n          >\n            <span className={cn(\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl\", a.enabled ? \"bg-neutral-900 dark:bg-white\" : \"bg-neutral-200 dark:bg-neutral-800\")}>\n              {a.trigger === \"Schedule\" ? (\n                <Clock className={cn(\"h-[17px] w-[17px]\", a.enabled ? \"text-white dark:text-neutral-900\" : \"text-neutral-400 dark:text-neutral-600\")} />\n              ) : (\n                <Zap className={cn(\"h-[17px] w-[17px]\", a.enabled ? \"text-white dark:text-neutral-900\" : \"text-neutral-400 dark:text-neutral-600\")} />\n              )}\n            </span>\n            <div className=\"min-w-0 flex-1\">\n              <p className=\"text-[13.5px] font-medium text-neutral-900 dark:text-neutral-50\">{a.name}</p>\n              <p className=\"mt-0.5 text-[12.5px] text-neutral-500 dark:text-neutral-500\">{a.description}</p>\n            </div>\n            <span className=\"shrink-0 rounded-full bg-neutral-100 px-2.5 py-1 text-[11px] text-neutral-500 dark:bg-neutral-800 dark:text-neutral-400\">{a.trigger}</span>\n            <Switch checked={a.enabled} onChange={() => onToggle(a.id)} label={a.name} />\n          </div>\n        ))}\n      </div>\n    </div>\n  );\n}\n\n/* ================================================================== */\n/*  Info panel                                                         */\n/* ================================================================== */\n\nfunction StatCard({ label, value, progress, barColor }: { label: string; value: string; progress: number; barColor: string }) {\n  return (\n    <div className=\"rounded-2xl border border-neutral-200 bg-white p-4 dark:border-neutral-800 dark:bg-neutral-900\">\n      <div className=\"flex items-start justify-between\">\n        <span className=\"text-[13px] text-neutral-500 dark:text-neutral-500\">{label}</span>\n        <MoreVertical className=\"h-3.5 w-3.5 text-neutral-300 dark:text-neutral-700\" />\n      </div>\n      <p className=\"mt-1 text-[19px] font-semibold text-neutral-900 dark:text-neutral-50\">{value}</p>\n      <div className=\"mt-3 h-[5px] w-full overflow-hidden rounded-full bg-neutral-100 dark:bg-neutral-800\">\n        <motion.div\n          className={cn(\"h-full rounded-full\", barColor)}\n          initial={{ width: 0 }}\n          animate={{ width: `${progress}%` }}\n          transition={{ duration: 0.5, ease: \"easeOut\" }}\n        />\n      </div>\n    </div>\n  );\n}\n\nfunction InfoPanel({\n  selected,\n  activeTagFilter,\n  onToggleTag,\n  allTags,\n  pinnedFolders,\n  onOpenPinned,\n  storageSummary,\n}: {\n  selected: SelectedItem;\n  activeTagFilter: TagName | null;\n  onToggleTag: (tag: TagName) => void;\n  allTags: TagName[];\n  pinnedFolders: Folder[];\n  onOpenPinned: (id: string) => void;\n  storageSummary: { documentsKb: number; imagesKb: number; totalKb: number };\n}) {\n  const properties = useMemo(() => {\n    if (!selected) return null;\n    if (selected.type === \"folder\") {\n      return [\n        { label: \"Size\", value: formatSize(selected.folder.sizeKb) },\n        { label: \"Files\", value: `${selected.folder.files.length}` },\n        { label: \"Tag\", value: selected.folder.tag },\n      ];\n    }\n    return [\n      { label: \"Size\", value: formatSize(selected.file.sizeKb) },\n      { label: \"Modified\", value: formatDate(selected.file.modified) },\n      { label: \"Owner\", value: selected.file.owner },\n    ];\n  }, [selected]);\n\n  const docProgress = Math.min(100, Math.round((storageSummary.documentsKb / Math.max(storageSummary.totalKb, 1)) * 100));\n  const imageProgress = Math.min(100, Math.round((storageSummary.imagesKb / Math.max(storageSummary.totalKb, 1)) * 100));\n\n  return (\n    <aside className=\"flex w-[248px] shrink-0 flex-col overflow-y-auto border-l border-neutral-200 bg-white px-5 py-6 dark:border-neutral-800 dark:bg-[#0C0C0E]\">\n      <div className=\"flex flex-col gap-3\">\n        <StatCard label=\"Documents\" value={formatSize(storageSummary.documentsKb)} progress={docProgress || 1} barColor=\"bg-blue-500\" />\n        <StatCard label=\"Images\" value={formatSize(storageSummary.imagesKb)} progress={imageProgress || 1} barColor=\"bg-rose-500\" />\n      </div>\n\n      <div className=\"mt-7\">\n        <h4 className=\"mb-2.5 text-[13px] font-medium text-neutral-500 dark:text-neutral-500\">\n          {selected ? (selected.type === \"folder\" ? \"Folder\" : \"File\") : \"Properties\"}\n        </h4>\n        {selected ? (\n          <motion.div\n            key={selected.type === \"folder\" ? selected.folder.id : selected.file.id}\n            initial={{ opacity: 0, y: 4 }}\n            animate={{ opacity: 1, y: 0 }}\n            transition={{ duration: 0.15 }}\n          >\n            <p className=\"mb-2 truncate text-[13.5px] font-medium text-neutral-900 dark:text-neutral-50\">\n              {selected.type === \"folder\" ? selected.folder.title : selected.file.name}\n            </p>\n            <div className=\"flex flex-col gap-2\">\n              {properties!.map((prop) => (\n                <div key={prop.label} className=\"flex items-center justify-between text-[13px]\">\n                  <span className=\"text-neutral-500 dark:text-neutral-500\">{prop.label}</span>\n                  <span className=\"truncate font-medium text-neutral-800 dark:text-neutral-200\">{prop.value}</span>\n                </div>\n              ))}\n            </div>\n          </motion.div>\n        ) : (\n          <p className=\"text-[12.5px] text-neutral-400 dark:text-neutral-600\">Select a folder or file to see its details here.</p>\n        )}\n      </div>\n\n      <div className=\"mt-6\">\n        <h4 className=\"mb-2.5 text-[13px] font-medium text-neutral-500 dark:text-neutral-500\">Tags</h4>\n        <div className=\"flex flex-wrap gap-1.5\">\n          {allTags.map((tag) => (\n            <TagChip key={tag} tag={tag} active={activeTagFilter === tag} onClick={() => onToggleTag(tag)} />\n          ))}\n        </div>\n        {activeTagFilter && <p className=\"mt-2 text-[11.5px] text-neutral-400 dark:text-neutral-600\">Filtering Home by \"{activeTagFilter}\"</p>}\n      </div>\n\n      <div className=\"mt-6\">\n        <h4 className=\"mb-2.5 flex items-center gap-1.5 text-[13px] font-medium text-neutral-500 dark:text-neutral-500\">\n          <Pin className=\"h-3.5 w-3.5\" /> Pinned items\n        </h4>\n        <div className=\"flex flex-col gap-1\">\n          {pinnedFolders.map((folder) => (\n            <button\n              key={folder.id}\n              onClick={() => onOpenPinned(folder.id)}\n              className=\"flex cursor-pointer w-full items-center gap-2 rounded-lg px-1.5 py-1.5 text-left text-[12.5px] text-neutral-600 hover:bg-neutral-50 hover:text-neutral-900 dark:text-neutral-400 dark:hover:bg-neutral-900 dark:hover:text-neutral-100\"\n            >\n              <FolderIcon className=\"h-3.5 w-3.5 shrink-0 text-neutral-400 dark:text-neutral-600\" />\n              <span className=\"min-w-0 flex-1 truncate\">{folder.title}</span>\n            </button>\n          ))}\n        </div>\n      </div>\n\n      <div className=\"mt-auto flex flex-col gap-1 border-t border-neutral-100 pt-4 dark:border-neutral-800\">\n        <button className=\"flex cursor-pointer items-center gap-2.5 rounded-lg px-1.5 py-2 text-[13.5px] text-neutral-500 hover:text-neutral-900 dark:text-neutral-500 dark:hover:text-neutral-100\">\n          <Inbox className=\"h-[15px] w-[15px]\" />\n          Activity\n        </button>\n      </div>\n    </aside>\n  );\n}\n\n/* ================================================================== */\n/*  Root                                                                */\n/* ================================================================== */\n\nexport default function baguiDashboard() {\n  const [projects, setProjects] = useState<Project[]>(INITIAL_PROJECTS);\n  const [activeProjectId, setActiveProjectId] = useState(\"bagui\");\n  const [projectsExpanded, setProjectsExpanded] = useState(true);\n  const [sidebarCollapsed, setSidebarCollapsed] = useState(false);\n\n  const [activeNav, setActiveNav] = useState<NavKey>(\"home\");\n  const [openFolderId, setOpenFolderId] = useState<string | null>(null);\n  const [selectedItem, setSelectedItem] = useState<SelectedItem>(null);\n\n  const [search, setSearch] = useState(\"\");\n  const [sortBy, setSortBy] = useState<SortKey>(\"name\");\n  const [activeTagFilter, setActiveTagFilter] = useState<TagName | null>(null);\n\n  const [notifications, setNotifications] = useState(INITIAL_NOTIFICATIONS);\n  const [notificationsOpen, setNotificationsOpen] = useState(false);\n\n  const [emails, setEmails] = useState(INITIAL_EMAILS);\n  const [expandedEmailId, setExpandedEmailId] = useState<number | null>(null);\n\n  const [automations, setAutomations] = useState(INITIAL_AUTOMATIONS);\n\n  const [shareOpen, setShareOpen] = useState(false);\n  const [toasts, setToasts] = useState<{ id: number; message: string }[]>([]);\n  const toastIdRef = useRef(0);\n\n  const [isDark, setIsDark] = useState(false);\n  const toggleDark = useCallback(() => setIsDark((v) => !v), []);\n\n  const pushToast = useCallback((message: string) => {\n    const id = ++toastIdRef.current;\n    setToasts((prev) => [...prev, { id, message }]);\n    setTimeout(() => {\n      setToasts((prev) => prev.filter((t) => t.id !== id));\n    }, 2600);\n  }, []);\n\n  const activeProject = useMemo(\n    () => projects.find((p) => p.id === activeProjectId)!,\n    [projects, activeProjectId]\n  );\n  const openFolder = useMemo(\n    () => (openFolderId ? activeProject.folders.find((fl) => fl.id === openFolderId) ?? null : null),\n    [activeProject, openFolderId]\n  );\n\n  const unreadCount = useMemo(() => notifications.filter((n) => n.unread).length, [notifications]);\n\n  const allFilesFlat = useMemo(\n    () =>\n      activeProject.folders.flatMap((folder) =>\n        folder.files.map((file) => ({ ...file, folderTitle: folder.title }))\n      ),\n    [activeProject]\n  );\n\n  const updateFolders = useCallback(\n    (projectId: string, updater: (folders: Folder[]) => Folder[]) => {\n      setProjects((prev) =>\n        prev.map((p) => (p.id === projectId ? { ...p, folders: updater(p.folders) } : p))\n      );\n    },\n    []\n  );\n\n  /* ---- navigation ---- */\n\n  const resetViewState = useCallback(() => {\n    setSearch(\"\");\n    setSelectedItem(null);\n  }, []);\n\n  const selectProject = useCallback(\n    (id: string) => {\n      setActiveProjectId(id);\n      setOpenFolderId(null);\n      setActiveNav(\"home\");\n      setActiveTagFilter(null);\n      resetViewState();\n    },\n    [resetViewState]\n  );\n\n  const goHome = useCallback(() => {\n    setActiveNav(\"home\");\n    setOpenFolderId(null);\n    resetViewState();\n  }, [resetViewState]);\n\n  const goNav = useCallback(\n    (key: NavKey) => {\n      setActiveNav(key);\n      setOpenFolderId(null);\n      resetViewState();\n    },\n    [resetViewState]\n  );\n\n  const openFolderById = useCallback(\n    (id: string) => {\n      const folder = activeProject.folders.find((fl) => fl.id === id);\n      setOpenFolderId(id);\n      setSearch(\"\");\n      if (folder) setSelectedItem({ type: \"folder\", folder });\n    },\n    [activeProject]\n  );\n\n  const closeFolder = useCallback(() => {\n    setOpenFolderId(null);\n    resetViewState();\n  }, [resetViewState]);\n\n  /* ---- selection ---- */\n\n  const selectFile = useCallback((file: FileItem, folderTitle: string, folderTag: TagName) => {\n    setSelectedItem({ type: \"file\", file, folderTitle, folderTag });\n  }, []);\n\n  /* ---- file / folder mutations ---- */\n\n  const deleteFile = useCallback(\n    (folderId: string, fileId: string) => {\n      updateFolders(activeProjectId, (folders) =>\n        folders.map((fl) =>\n          fl.id === folderId\n            ? { ...fl, files: fl.files.filter((file) => file.id !== fileId), notesCount: Math.max(0, fl.notesCount - 1) }\n            : fl\n        )\n      );\n      setSelectedItem((prev) => (prev?.type === \"file\" && prev.file.id === fileId ? null : prev));\n      pushToast(\"File deleted\");\n    },\n    [activeProjectId, updateFolders, pushToast]\n  );\n\n  const renameFile = useCallback(\n    (_file: FileItem) => {\n      pushToast(\"Renaming is a demo action — hook this up to your API\");\n    },\n    [pushToast]\n  );\n\n  const downloadFile = useCallback(\n    (file: FileItem) => {\n      pushToast(`Downloading \"${file.name}\"`);\n    },\n    [pushToast]\n  );\n\n  const addDraft = useCallback(() => {\n    const targetFolder = openFolder ?? activeProject.folders[0];\n    if (!targetFolder) return;\n    const draft: FileItem = {\n      id: nextId(\"file\"),\n      name: \"Untitled draft\",\n      kind: \"doc\",\n      sizeKb: 12,\n      modified: todayIso(),\n      owner: CURRENT_USER,\n    };\n    updateFolders(activeProjectId, (folders) =>\n      folders.map((fl) =>\n        fl.id === targetFolder.id ? { ...fl, files: [draft, ...fl.files], notesCount: fl.notesCount + 1 } : fl\n      )\n    );\n    if (!openFolder) {\n      setActiveNav(\"notes\");\n      setOpenFolderId(null);\n    }\n    setSelectedItem({ type: \"file\", file: draft, folderTitle: targetFolder.title, folderTag: targetFolder.tag });\n    pushToast(`Draft added to ${targetFolder.title}`);\n  }, [openFolder, activeProject, activeProjectId, updateFolders, pushToast]);\n\n  /* ---- tags ---- */\n\n  const allTags = useMemo(() => {\n    const set = new Set<TagName>();\n    activeProject.folders.forEach((fl) => set.add(fl.tag));\n    return Array.from(set);\n  }, [activeProject]);\n\n  const toggleTagFilter = useCallback((tag: TagName) => {\n    setActiveTagFilter((prev) => (prev === tag ? null : tag));\n  }, []);\n\n  /* ---- notifications ---- */\n\n  const toggleNotifications = useCallback(() => setNotificationsOpen((v) => !v), []);\n\n  const markAllRead = useCallback(() => {\n    setNotifications((prev) => prev.map((n) => ({ ...n, unread: false })));\n  }, []);\n\n  const handleNotificationClick = useCallback(\n    (n: NotificationItem) => {\n      setNotifications((prev) => prev.map((item) => (item.id === n.id ? { ...item, unread: false } : item)));\n      setNotificationsOpen(false);\n      if (n.link) {\n        if (n.link.projectId !== activeProjectId) setActiveProjectId(n.link.projectId);\n        setActiveNav(\"home\");\n        setOpenFolderId(n.link.folderId);\n        const proj = projects.find((p) => p.id === n.link!.projectId);\n        const folder = proj?.folders.find((fl) => fl.id === n.link!.folderId);\n        if (folder) setSelectedItem({ type: \"folder\", folder });\n        setSearch(\"\");\n      }\n    },\n    [activeProjectId, projects]\n  );\n\n  /* ---- share ---- */\n\n  const toggleShare = useCallback(() => setShareOpen((v) => !v), []);\n  const copyLink = useCallback(() => {\n    if (typeof navigator !== \"undefined\" && navigator.clipboard) {\n      navigator.clipboard.writeText(\"https://www.bagui.app/fullscreen/dashboard-folder\").catch(() => {});\n    }\n    setShareOpen(false);\n    pushToast(\"Link copied to clipboard\");\n  }, [pushToast]);\n\n  /* ---- emails / automation ---- */\n\n  const toggleEmailExpand = useCallback((id: number) => {\n    setEmails((prev) => prev.map((e) => (e.id === id ? { ...e, unread: false } : e)));\n    setExpandedEmailId((prev) => (prev === id ? null : id));\n  }, []);\n\n  const toggleAutomation = useCallback((id: number) => {\n    setAutomations((prev) =>\n      prev.map((a) => {\n        if (a.id !== id) return a;\n        pushToast(`${a.name} ${a.enabled ? \"disabled\" : \"enabled\"}`);\n        return { ...a, enabled: !a.enabled };\n      })\n    );\n  }, [pushToast]);\n\n  const pinnedFolders = useMemo(() => activeProject.folders.slice(0, 3), [activeProject]);\n\n  const storageSummary = useMemo(() => {\n    const files = activeProject.folders.flatMap((folder) => folder.files);\n    return summarizeStorage(files);\n  }, [activeProject]);\n\n  return (\n    <ThemeContext.Provider value={isDark}>\n      <div\n        className={cn(\n          \"flex h-screen w-full overflow-hidden bg-white text-neutral-900 transition-colors duration-300 dark:bg-[#08080A] dark:text-neutral-100\",\n          isDark && \"dark\"\n        )}\n      >\n        <Sidebar\n          collapsed={sidebarCollapsed}\n          onToggleCollapsed={() => setSidebarCollapsed((v) => !v)}\n          projects={PROJECT_TABS.map((t) => ({ id: t.id, name: t.label, folders: [] }))}\n          activeProjectId={activeProjectId}\n          onSelectProject={selectProject}\n          projectsExpanded={projectsExpanded}\n          onToggleProjectsExpanded={() => setProjectsExpanded((v) => !v)}\n          activeNav={openFolderId ? null : activeNav}\n          onGoHome={goHome}\n          onGoNav={goNav}\n          notifications={notifications}\n          notificationsOpen={notificationsOpen}\n          onToggleNotifications={toggleNotifications}\n          onMarkAllRead={markAllRead}\n          onNotificationClick={handleNotificationClick}\n          unreadCount={unreadCount}\n          isDark={isDark}\n          onToggleDark={toggleDark}\n        />\n\n        <div className=\"flex flex-1 flex-col overflow-hidden\">\n          <TopBar\n            projectName={activeProject.name}\n            folderTitle={openFolder ? openFolder.title : null}\n            showBack={!!openFolder}\n            onBack={closeFolder}\n            onGoProjectRoot={closeFolder}\n            onShare={toggleShare}\n            shareOpen={shareOpen}\n            onCopyLink={copyLink}\n          />\n\n          <div className=\"flex flex-1 overflow-hidden\">\n            <div className=\"flex-1 overflow-y-auto bg-[#F8F8F9] px-8 dark:bg-[#08080A]\">\n              <AnimatePresence mode=\"wait\">\n                <motion.div\n                  key={openFolderId ? `folder-${openFolderId}` : `nav-${activeNav}-${activeProjectId}`}\n                  initial={{ opacity: 0, y: 8 }}\n                  animate={{ opacity: 1, y: 0 }}\n                  exit={{ opacity: 0, y: -8 }}\n                  transition={{ duration: 0.18 }}\n                >\n                  {openFolder ? (\n                    <FolderDetailView\n                      folder={openFolder}\n                      search={search}\n                      onSearch={setSearch}\n                      sortBy={sortBy}\n                      onSortChange={setSortBy}\n                      selectedFileId={selectedItem?.type === \"file\" ? selectedItem.file.id : null}\n                      onSelectFile={(file) => selectFile(file, openFolder.title, openFolder.tag)}\n                      onDeleteFile={(id) => deleteFile(openFolder.id, id)}\n                      onRenameFile={renameFile}\n                      onDownloadFile={downloadFile}\n                      onNewDraft={addDraft}\n                    />\n                  ) : activeNav === \"home\" ? (\n                    <HomeView\n                      projectName={activeProject.name}\n                      folders={activeProject.folders}\n                      search={search}\n                      onSearch={setSearch}\n                      sortBy={sortBy}\n                      onSortChange={setSortBy}\n                      tagFilter={activeTagFilter}\n                      onOpenFolder={openFolderById}\n                      onNewDraft={addDraft}\n                    />\n                  ) : activeNav === \"notes\" ? (\n                    <FlatFileListView\n                      title=\"Notes\"\n                      emptyLabel=\"No notes yet.\"\n                      files={allFilesFlat.filter((file) => file.kind === \"doc\")}\n                      search={search}\n                      onSearch={setSearch}\n                      selectedFileId={selectedItem?.type === \"file\" ? selectedItem.file.id : null}\n                      onSelectFile={(file, folderTitle) => {\n                        const folder = activeProject.folders.find((fl) => fl.title === folderTitle);\n                        selectFile(file, folderTitle, folder?.tag ?? \"Product\");\n                      }}\n                      onDownloadFile={downloadFile}\n                    />\n                  ) : activeNav === \"reports\" ? (\n                    <FlatFileListView\n                      title=\"Reports\"\n                      emptyLabel=\"No reports yet.\"\n                      files={allFilesFlat.filter((file) => file.kind === \"pdf\" || file.kind === \"slide\")}\n                      search={search}\n                      onSearch={setSearch}\n                      selectedFileId={selectedItem?.type === \"file\" ? selectedItem.file.id : null}\n                      onSelectFile={(file, folderTitle) => {\n                        const folder = activeProject.folders.find((fl) => fl.title === folderTitle);\n                        selectFile(file, folderTitle, folder?.tag ?? \"Marketing\");\n                      }}\n                      onDownloadFile={downloadFile}\n                    />\n                  ) : activeNav === \"emails\" ? (\n                    <EmailsView emails={emails} expandedId={expandedEmailId} onToggleExpand={toggleEmailExpand} />\n                  ) : (\n                    <AutomationView automations={automations} onToggle={toggleAutomation} />\n                  )}\n                </motion.div>\n              </AnimatePresence>\n            </div>\n\n            <InfoPanel\n              selected={selectedItem}\n              activeTagFilter={activeTagFilter}\n              onToggleTag={toggleTagFilter}\n              allTags={allTags}\n              pinnedFolders={pinnedFolders}\n              storageSummary={storageSummary}\n              onOpenPinned={(id) => {\n                setActiveNav(\"home\");\n                openFolderById(id);\n              }}\n            />\n          </div>\n        </div>\n\n        <ToastStack toasts={toasts} />\n      </div>\n    </ThemeContext.Provider>\n  );\n}",
      "type": "registry:block",
      "target": "components/Dashboard/dashboard-folder.tsx"
    }
  ],
  "type": "registry:block"
}