{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "smart-inbox-triage",
  "title": "Smart Inbox Triage",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/smart-inbox-triage/SmartInboxTriage.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport {\n  Archive,\n  ArrowDown,\n  ArrowUp,\n  AtSign,\n  Check,\n  CheckCircle2,\n  Clock,\n  Command as CommandIcon,\n  FileText,\n  Forward,\n  Mail,\n  Paperclip,\n  Reply,\n  ReplyAll,\n  Search,\n  Send,\n  Smile,\n  Star,\n  Undo2,\n  X,\n} from 'lucide-vue-next'\nimport { Avatar, AvatarFallback } from '@/components/ui/avatar'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Separator } from '@/components/ui/separator'\nimport { cn } from '@/lib/utils'\n\nexport type InboxCategory = 'vip' | 'team' | 'newsletters' | 'archived'\n\nexport interface EmailMessage {\n  id: string\n  sender: {\n    name: string\n    email: string\n    initials: string\n  }\n  recipient: string\n  subject: string\n  snippet: string\n  body: string\n  timestamp: string\n  fullDate: string\n  category: 'vip' | 'team' | 'newsletters'\n  categoryLabel: string\n  badgeVariant?: 'default' | 'secondary' | 'outline' | 'info' | 'success' | 'warning'\n  unread: boolean\n  starred: boolean\n  archived: boolean\n  snoozed?: boolean\n  attachment?: {\n    name: string\n    size: string\n    type: string\n  }\n}\n\ninterface Props {\n  initialCategory?: InboxCategory\n  initialSearch?: string\n  initialSelectedId?: string\n  messages?: EmailMessage[]\n  class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  initialCategory: 'vip',\n  initialSearch: '',\n  initialSelectedId: 'msg-1',\n})\n\nconst defaultMessages: EmailMessage[] = [\n  {\n    id: 'msg-1',\n    sender: {\n      name: 'Marcus Vance',\n      email: 'marcus.vance@uipkge.internal',\n      initials: 'MV',\n    },\n    recipient: 'you@uipkge.dev, core-eng@uipkge.dev',\n    subject: 'Architecture Review: Real-time Sync & CRDT Conflict Resolution',\n    snippet: 'I’ve updated the design doc with event-sourcing and CRDT tradeoffs for the multi-region sync engine...',\n    body: `Hey team,\n\nI’ve updated the architecture RFC for the multi-region state synchronization engine. Based on yesterday's benchmark results, we are proceeding with hybrid state-based CRDTs for deterministic document convergence.\n\nKey RFC Highlights:\n• P99 sync latency reduced from 140ms to 24ms across edge worker replicas\n• Deterministic Last-Write-Wins (LWW) resolver for metadata mutations\n• Offline reconciliation buffer with automated exponential retry backoff\n• Zero dependency footprint — pure TypeScript state machines\n\nPlease review the attached technical specification and drop your comments before Thursday's design council.\n\nBest,\nMarcus Vance\nPrincipal Systems Architect`,\n    timestamp: '14:28',\n    fullDate: 'Today at 14:28 PM',\n    category: 'vip',\n    categoryLabel: 'VIP Review',\n    badgeVariant: 'default',\n    unread: true,\n    starred: true,\n    archived: false,\n    attachment: {\n      name: 'sync-engine-rfc-v2.4.pdf',\n      size: '2.4 MB',\n      type: 'PDF',\n    },\n  },\n  {\n    id: 'msg-2',\n    sender: {\n      name: 'Sarah Connor',\n      email: 'sarah.connor@uipkge.internal',\n      initials: 'SC',\n    },\n    recipient: 'you@uipkge.dev, exec@uipkge.dev',\n    subject: 'Q2 OKR Sign-off & Headcount Allocation',\n    snippet: 'Final draft from the leadership offsite. Flagged two key decisions before Wednesday lock...',\n    body: `Hi team,\n\nI’ve compiled the finalized Q2 OKR draft following our executive offsite. There are two strategic items requiring your explicit sign-off before we lock the plan Wednesday EOD:\n\n1. Engineering Headcount: 4 vs. 6 senior backend roles\n2. Multi-cloud deployment schedule: Target June instead of August\n\nPlease review and confirm your alignment so we can present to the board.\n\nThanks,\nSarah Connor\nVP of Engineering`,\n    timestamp: '15:40',\n    fullDate: 'Today at 15:40 PM',\n    category: 'vip',\n    categoryLabel: 'VIP Review',\n    badgeVariant: 'default',\n    unread: true,\n    starred: false,\n    archived: false,\n  },\n  {\n    id: 'msg-3',\n    sender: {\n      name: 'Stripe Merchant Services',\n      email: 'payouts@stripe.com',\n      initials: 'ST',\n    },\n    recipient: 'billing@uipkge.dev',\n    subject: 'Payout Confirmed: $18,420.50 USD',\n    snippet:\n      'Your daily payout for May 18 has been processed and initiated to your linked corporate checking account...',\n    body: `Hello UIPKGE Team,\n\nYour automatic daily payout has been initiated and is on its way to your designated bank account ending in •••• 8842.\n\nTransfer Summary:\n• Gross volume (last 24h): $19,250.00\n• Stripe processing fees: -$829.50\n• Net settled transfer: $18,420.50 USD\n• Estimated arrival: Thursday, May 22, 2026\n\nNo further action is required. You can download your official tax statement and transaction logs directly in the Stripe Merchant Portal.`,\n    timestamp: '12:15',\n    fullDate: 'Today at 12:15 PM',\n    category: 'vip',\n    categoryLabel: 'Finance',\n    badgeVariant: 'success',\n    unread: true,\n    starred: false,\n    archived: false,\n  },\n  {\n    id: 'msg-4',\n    sender: {\n      name: 'GitHub Notifications',\n      email: 'notifications@github.com',\n      initials: 'GH',\n    },\n    recipient: 'you@uipkge.dev',\n    subject: '[PR #412] Merged: feat(tokens): OKLCH color scale & dynamic theme engine',\n    snippet: 'Merged by @uday into main with 4 approvals and all CI checks passing in 42s...',\n    body: `Pull Request #412 has been successfully merged into \\`main\\` by @uday.\n\nBranch: feat/oklch-tokens → main\nApprovals: 4 / 4 (Marcus Vance, Elena Rostova, Devon Patel, Sarah Connor)\nCI Workflow: Build, Typecheck, and Parity Verification passed in 42s.\n\nKey Deliverables:\n• Implemented OKLCH lightness/chroma token scale with WCAG AAA contrast\n• Tailwind v4 @theme inline integration with zero CSS variable bloat\n• 100% test coverage across both Vue and React registry packages\n\nAutomated staging preview is now active at https://staging.uipkge.dev.`,\n    timestamp: '10:45',\n    fullDate: 'Today at 10:45 AM',\n    category: 'team',\n    categoryLabel: 'GitHub',\n    badgeVariant: 'info',\n    unread: false,\n    starred: true,\n    archived: false,\n  },\n  {\n    id: 'msg-5',\n    sender: {\n      name: 'Elena Rostova',\n      email: 'elena.rostova@uipkge.internal',\n      initials: 'ER',\n    },\n    recipient: 'you@uipkge.dev, design-system@uipkge.dev',\n    subject: 'Design Tokens OKLCH Migration Spec & Guidelines',\n    snippet: 'Here is the finalized Figma token mapping and color ramp guide for the new high-contrast theme...',\n    body: `Hi team,\n\nFollowing up on PR #412, I’ve published the companion Figma variables library and developer handoff sheet.\n\nWhat’s included in this release:\n1. Semantic tokens: added \\`--surface-elevated\\` and \\`--sidebar-accent\\`\n2. Focus ring contrast ratios audited across all 14 colorways\n3. Mobile breakpoint typography scale verified with 12px min floor\n4. Tactile micro-transitions mapped to \\`--ease-spring\\` (140ms duration)\n\nPlease review the design system documentation and let me know if any component needs tailored adjustments.\n\nWarmly,\nElena Rostova\nLead Product Designer`,\n    timestamp: '09:12',\n    fullDate: 'Today at 09:12 AM',\n    category: 'team',\n    categoryLabel: 'Design',\n    badgeVariant: 'secondary',\n    unread: false,\n    starred: false,\n    archived: false,\n  },\n  {\n    id: 'msg-6',\n    sender: {\n      name: 'Substack / The Unbundled Engineer',\n      email: 'digest@unbundled.dev',\n      initials: 'SE',\n    },\n    recipient: 'you@uipkge.dev',\n    subject: 'The Unbundled Engineer: Issue #84 — The Rise of Component Registries',\n    snippet:\n      'Why copy-paste component architecture is replacing bloated npm packages across modern frontend engineering...',\n    body: `Welcome to Issue #84 of The Unbundled Engineer.\n\nThis week: Why the component registry model is winning.\n\n\"When you install a traditional monolithic npm UI library, you inherit its dependency tree, its CSS opinions, and its release bottlenecks. When you copy registry source code into your own repository, you gain zero-dependency ownership, effortless code customization, and total UI autonomy.\"\n\nIn this edition:\n• Benchmarking bundle sizes: Registry components vs. Monolithic packages\n• Tactile micro-interactions and keyboard-first inbox triage UX\n• The future of dual-framework design systems (Vue 3.5 & React 19)\n\nRead the full deep-dive on our website.`,\n    timestamp: 'Yesterday',\n    fullDate: 'Yesterday at 17:30 PM',\n    category: 'newsletters',\n    categoryLabel: 'Newsletter',\n    badgeVariant: 'warning',\n    unread: false,\n    starred: false,\n    archived: false,\n  },\n]\n\nconst mails = ref<EmailMessage[]>(props.messages ? JSON.parse(JSON.stringify(props.messages)) : defaultMessages)\nconst activeCategory = ref<InboxCategory>(props.initialCategory)\nconst search = ref(props.initialSearch)\nconst activeId = ref<string>(props.initialSelectedId)\nconst replyMode = ref<'reply' | 'reply-all' | 'forward'>('reply')\nconst replyDraft = ref('')\nconst toastMessage = ref('')\nconst hasUndo = ref(false)\nconst lastArchivedId = ref<string | null>(null)\nconst commandPaletteOpen = ref(false)\nconst commandFilter = ref('')\n\nconst searchInputRef = ref<HTMLInputElement | null>(null)\nconst replyTextareaRef = ref<HTMLTextAreaElement | null>(null)\n\nlet toastTimer: number | undefined\n\nfunction showToast(msg: string, allowUndo = false) {\n  toastMessage.value = msg\n  hasUndo.value = allowUndo\n  if (toastTimer) clearTimeout(toastTimer)\n  toastTimer = window.setTimeout(() => {\n    toastMessage.value = ''\n    hasUndo.value = false\n  }, 4000)\n}\n\nconst vipCount = computed(() => mails.value.filter((m) => !m.archived && m.category === 'vip').length)\nconst teamCount = computed(() => mails.value.filter((m) => !m.archived && m.category === 'team').length)\nconst newslettersCount = computed(() => mails.value.filter((m) => !m.archived && m.category === 'newsletters').length)\nconst archivedCount = computed(() => mails.value.filter((m) => m.archived).length)\nconst remainingCount = computed(() => mails.value.filter((m) => !m.archived).length)\n\nconst categoriesList = computed<Array<{ id: InboxCategory; label: string; count: number }>>(() => [\n  { id: 'vip', label: 'Important & VIP', count: vipCount.value },\n  { id: 'team', label: 'Team & GitHub', count: teamCount.value },\n  { id: 'newsletters', label: 'Newsletters', count: newslettersCount.value },\n  { id: 'archived', label: 'Done / Archived', count: archivedCount.value },\n])\n\nconst visibleMails = computed(() => {\n  const q = search.value.trim().toLowerCase()\n  let list = mails.value.filter((m) => {\n    if (activeCategory.value === 'archived') {\n      return m.archived\n    }\n    return !m.archived && m.category === activeCategory.value\n  })\n\n  if (q) {\n    list = list.filter(\n      (m) =>\n        m.subject.toLowerCase().includes(q) ||\n        m.sender.name.toLowerCase().includes(q) ||\n        m.sender.email.toLowerCase().includes(q) ||\n        m.snippet.toLowerCase().includes(q) ||\n        m.body.toLowerCase().includes(q),\n    )\n  }\n\n  return list\n})\n\nconst activeMail = computed(() => {\n  if (!activeId.value) return visibleMails.value[0] ?? null\n  return mails.value.find((m) => m.id === activeId.value) ?? visibleMails.value[0] ?? null\n})\n\nfunction selectMail(id: string) {\n  activeId.value = id\n  const target = mails.value.find((m) => m.id === id)\n  if (target) {\n    target.unread = false\n  }\n}\n\nfunction selectCategory(cat: InboxCategory) {\n  activeCategory.value = cat\n  nextTick(() => {\n    const first = visibleMails.value[0]\n    if (first) {\n      selectMail(first.id)\n    } else {\n      activeId.value = ''\n    }\n  })\n}\n\nfunction archiveMail(id?: string) {\n  const targetId = id ?? activeMail.value?.id\n  if (!targetId) return\n  const item = mails.value.find((m) => m.id === targetId)\n  if (!item) return\n\n  item.archived = true\n  item.snoozed = false\n  lastArchivedId.value = targetId\n  showToast(`Archived: \"${item.subject}\"`, true)\n\n  nextTick(() => {\n    const next = visibleMails.value[0]\n    activeId.value = next ? next.id : ''\n    if (next) next.unread = false\n  })\n}\n\nfunction snoozeMail(id?: string) {\n  const targetId = id ?? activeMail.value?.id\n  if (!targetId) return\n  const item = mails.value.find((m) => m.id === targetId)\n  if (!item) return\n\n  item.archived = true\n  item.snoozed = true\n  lastArchivedId.value = targetId\n  showToast('Snoozed until tomorrow 08:00 AM', true)\n\n  nextTick(() => {\n    const next = visibleMails.value[0]\n    activeId.value = next ? next.id : ''\n    if (next) next.unread = false\n  })\n}\n\nfunction undoLastAction() {\n  if (!lastArchivedId.value) return\n  const item = mails.value.find((m) => m.id === lastArchivedId.value)\n  if (item) {\n    item.archived = false\n    item.snoozed = false\n    activeCategory.value = item.category\n    activeId.value = item.id\n    showToast(`Restored: \"${item.subject}\"`)\n  }\n  lastArchivedId.value = null\n  hasUndo.value = false\n}\n\nfunction toggleStar(id?: string, e?: Event) {\n  e?.stopPropagation()\n  const targetId = id ?? activeMail.value?.id\n  if (!targetId) return\n  const item = mails.value.find((m) => m.id === targetId)\n  if (item) {\n    item.starred = !item.starred\n  }\n}\n\nfunction navigateNext() {\n  if (visibleMails.value.length === 0) return\n  const currentIndex = visibleMails.value.findIndex((m) => m.id === activeId.value)\n  if (currentIndex === -1 || currentIndex >= visibleMails.value.length - 1) {\n    selectMail(visibleMails.value[0].id)\n  } else {\n    selectMail(visibleMails.value[currentIndex + 1].id)\n  }\n}\n\nfunction navigatePrev() {\n  if (visibleMails.value.length === 0) return\n  const currentIndex = visibleMails.value.findIndex((m) => m.id === activeId.value)\n  if (currentIndex <= 0) {\n    selectMail(visibleMails.value[visibleMails.value.length - 1].id)\n  } else {\n    selectMail(visibleMails.value[currentIndex - 1].id)\n  }\n}\n\nfunction sendReply() {\n  const content = replyDraft.value.trim()\n  if (!content || !activeMail.value) return\n\n  const senderName = activeMail.value.sender.name\n  replyDraft.value = ''\n  showToast(`Reply sent to ${senderName}`)\n}\n\nfunction markAllRead() {\n  mails.value.forEach((m) => {\n    if (activeCategory.value === 'archived' ? m.archived : !m.archived && m.category === activeCategory.value) {\n      m.unread = false\n    }\n  })\n  showToast('Marked all as read')\n}\n\nfunction archiveAllInCategory() {\n  if (activeCategory.value === 'archived') return\n  mails.value.forEach((m) => {\n    if (!m.archived && m.category === activeCategory.value) {\n      m.archived = true\n    }\n  })\n  showToast('All messages in category archived')\n  nextTick(() => {\n    const next = visibleMails.value[0]\n    activeId.value = next ? next.id : ''\n  })\n}\n\nfunction handleGlobalKeydown(e: KeyboardEvent) {\n  const activeEl = document.activeElement\n  const isInputActive =\n    activeEl instanceof HTMLInputElement ||\n    activeEl instanceof HTMLTextAreaElement ||\n    activeEl?.getAttribute('contenteditable') === 'true'\n\n  // Cmd+K / Ctrl+K\n  if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'k') {\n    e.preventDefault()\n    commandPaletteOpen.value = !commandPaletteOpen.value\n    return\n  }\n\n  // Cmd+Z / Ctrl+Z\n  if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === 'z') {\n    e.preventDefault()\n    undoLastAction()\n    return\n  }\n\n  // Cmd+Enter inside reply\n  if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {\n    if (replyDraft.value.trim()) {\n      e.preventDefault()\n      sendReply()\n      return\n    }\n  }\n\n  // Escape\n  if (e.key === 'Escape') {\n    if (commandPaletteOpen.value) {\n      e.preventDefault()\n      commandPaletteOpen.value = false\n      return\n    }\n    if (isInputActive) {\n      ;(activeEl as HTMLElement).blur()\n      return\n    }\n    if (search.value) {\n      search.value = ''\n      return\n    }\n  }\n\n  // If focused on an input element, do not trigger single-key navigation\n  if (isInputActive) return\n\n  switch (e.key.toLowerCase()) {\n    case 'j':\n    case 'arrowdown':\n      e.preventDefault()\n      navigateNext()\n      break\n    case 'k':\n    case 'arrowup':\n      e.preventDefault()\n      navigatePrev()\n      break\n    case 'e':\n      e.preventDefault()\n      archiveMail()\n      break\n    case 'h':\n      e.preventDefault()\n      snoozeMail()\n      break\n    case 'r':\n      e.preventDefault()\n      nextTick(() => {\n        const el = replyTextareaRef.value\n        if (el) {\n          el.focus()\n        }\n      })\n      break\n    case 's':\n      e.preventDefault()\n      toggleStar()\n      break\n    case '/':\n      e.preventDefault()\n      nextTick(() => {\n        const el = searchInputRef.value\n        if (el) {\n          el.focus()\n          el.select()\n        }\n      })\n      break\n    case '1':\n      e.preventDefault()\n      selectCategory('vip')\n      break\n    case '2':\n      e.preventDefault()\n      selectCategory('team')\n      break\n    case '3':\n      e.preventDefault()\n      selectCategory('newsletters')\n      break\n    case '4':\n      e.preventDefault()\n      selectCategory('archived')\n      break\n  }\n}\n\nonMounted(() => {\n  window.addEventListener('keydown', handleGlobalKeydown)\n})\n\nonUnmounted(() => {\n  window.removeEventListener('keydown', handleGlobalKeydown)\n  if (toastTimer) clearTimeout(toastTimer)\n})\n\nwatch(\n  () => props.initialCategory,\n  (newVal) => {\n    if (newVal) activeCategory.value = newVal\n  },\n)\n\nwatch(\n  () => props.initialSearch,\n  (newVal) => {\n    if (typeof newVal === 'string') search.value = newVal\n  },\n)\n\nwatch(\n  () => props.messages,\n  (newVal) => {\n    if (newVal) mails.value = JSON.parse(JSON.stringify(newVal))\n  },\n  { deep: true },\n)\n\nconst commandPaletteItems = [\n  { key: 'E', label: 'Archive active email', action: () => archiveMail() },\n  { key: 'H', label: 'Snooze until tomorrow', action: () => snoozeMail() },\n  {\n    key: 'R',\n    label: 'Reply to sender',\n    action: () => {\n      replyTextareaRef.value?.focus()\n    },\n  },\n  { key: 'S', label: 'Toggle star / priority', action: () => toggleStar() },\n  { key: '1', label: 'Switch to Important & VIP', action: () => selectCategory('vip') },\n  { key: '2', label: 'Switch to Team & GitHub', action: () => selectCategory('team') },\n  { key: '3', label: 'Switch to Newsletters', action: () => selectCategory('newsletters') },\n  { key: '4', label: 'Switch to Done / Archived', action: () => selectCategory('archived') },\n  { key: 'Shift+A', label: 'Mark all as read in current category', action: () => markAllRead() },\n  { key: 'Shift+E', label: 'Archive all in category', action: () => archiveAllInCategory() },\n]\n\nconst filteredCommandPaletteItems = computed(() => {\n  const q = commandFilter.value.trim().toLowerCase()\n  if (!q) return commandPaletteItems\n  return commandPaletteItems.filter((i) => i.label.toLowerCase().includes(q) || i.key.toLowerCase().includes(q))\n})\n\nfunction executeCommand(action: () => void) {\n  action()\n  commandPaletteOpen.value = false\n  commandFilter.value = ''\n}\n</script>\n\n<template>\n  <div\n    data-slot=\"smart-inbox-triage\"\n    :class=\"\n      cn(\n        'bg-card text-card-foreground border-border relative flex flex-col overflow-hidden rounded-xl border shadow-xs',\n        props.class,\n      )\n    \"\n  >\n    <!-- TOP COMMAND BAR -->\n    <header class=\"bg-card/95 border-border/80 border-b px-4 py-3 backdrop-blur-xs\">\n      <div class=\"flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between\">\n        <!-- Left: Inbox Status & Goal Badge -->\n        <div class=\"flex flex-wrap items-center gap-2.5\">\n          <div\n            class=\"bg-primary/10 border-primary/20 text-foreground inline-flex items-center gap-2 rounded-full border px-3 py-1 text-xs font-semibold tracking-tight\"\n          >\n            <span class=\"bg-primary size-2 animate-pulse rounded-full\" />\n            <span>Inbox Zero Goal</span>\n            <span class=\"text-primary font-mono tabular-nums\">\n              {{ remainingCount === 0 ? 'Zero Achieved 🎉' : `${remainingCount} Messages Remaining` }}\n            </span>\n          </div>\n\n          <div\n            class=\"border-border/70 bg-muted/40 text-muted-foreground hidden items-center gap-1.5 rounded-full border px-3 py-1 text-xs xl:inline-flex\"\n          >\n            <span>Shortcuts:</span>\n            <kbd class=\"bg-card border-border/80 text-foreground rounded border px-1.5 py-0.5 font-mono text-xs\">E</kbd>\n            <span>Archive</span>\n            <kbd class=\"bg-card border-border/80 text-foreground rounded border px-1.5 py-0.5 font-mono text-xs\">H</kbd>\n            <span>Snooze</span>\n            <kbd class=\"bg-card border-border/80 text-foreground rounded border px-1.5 py-0.5 font-mono text-xs\">R</kbd>\n            <span>Reply</span>\n            <kbd class=\"bg-card border-border/80 text-foreground rounded border px-1.5 py-0.5 font-mono text-xs\"\n              >J/K</kbd\n            >\n            <span>Navigate</span>\n          </div>\n        </div>\n\n        <!-- Right: Search Bar & Command Key Trigger -->\n        <div class=\"flex items-center gap-2\">\n          <div class=\"relative w-full sm:w-72\">\n            <Search class=\"text-muted-foreground absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2\" />\n            <input\n              ref=\"searchInputRef\"\n              v-model=\"search\"\n              type=\"text\"\n              placeholder=\"Search messages...\"\n              class=\"border-input bg-background text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 h-8 w-full rounded-md border pr-8 pl-8 text-xs shadow-xs focus-visible:ring-2 focus-visible:outline-none\"\n            />\n            <kbd\n              class=\"bg-muted text-muted-foreground border-border/70 absolute top-1/2 right-2 -translate-y-1/2 rounded border px-1 font-mono text-xs\"\n            >\n              /\n            </kbd>\n          </div>\n\n          <Button\n            aria-label=\"Close command palette\"\n            variant=\"outline\"\n            size=\"sm\"\n            class=\"h-8 shrink-0 gap-1.5 px-2.5 text-xs font-medium\"\n            @click=\"commandPaletteOpen = true\"\n          >\n            <CommandIcon class=\"size-3.5\" />\n            <span class=\"hidden sm:inline\">Commands</span>\n            <kbd class=\"bg-muted text-muted-foreground border-border/60 ml-0.5 rounded border px-1 font-mono text-xs\">\n              ⌘K\n            </kbd>\n          </Button>\n        </div>\n      </div>\n\n      <!-- Split Category Tabs Bar -->\n      <div class=\"border-border/40 mt-3 flex items-center justify-between border-t pt-2.5\">\n        <nav class=\"flex flex-wrap items-center gap-1.5\" aria-label=\"Inbox Categories\">\n          <button\n            v-for=\"cat in categoriesList\"\n            :key=\"cat.id\"\n            :class=\"[\n              'inline-flex items-center gap-2 rounded-md px-3 py-1.5 text-xs font-medium transition-colors duration-150',\n              activeCategory === cat.id\n                ? 'bg-primary text-primary-foreground shadow-xs'\n                : 'text-muted-foreground hover:bg-muted/70 hover:text-foreground',\n            ]\"\n            @click=\"selectCategory(cat.id)\"\n          >\n            <span>{{ cat.label }}</span>\n            <span\n              :class=\"[\n                'inline-flex h-4 min-w-4 items-center justify-center rounded-full px-1 font-mono text-xs font-semibold tabular-nums',\n                activeCategory === cat.id\n                  ? 'bg-primary-foreground/20 text-primary-foreground'\n                  : 'bg-muted text-foreground',\n              ]\"\n            >\n              {{ cat.count }}\n            </span>\n          </button>\n        </nav>\n\n        <div class=\"hidden items-center gap-1 sm:flex\">\n          <Button\n            variant=\"ghost\"\n            size=\"sm\"\n            class=\"text-muted-foreground hover:text-foreground h-7 px-2 text-xs\"\n            @click=\"markAllRead\"\n          >\n            <Check class=\"mr-1 size-3\" />\n            Mark read\n          </Button>\n        </div>\n      </div>\n    </header>\n\n    <!-- 2-COLUMN SPLIT PANE -->\n    <div class=\"grid h-[620px] grid-cols-1 md:grid-cols-[384px_1fr]\">\n      <!-- LEFT: EMAIL LIST (w-96) -->\n      <aside class=\"bg-card border-border flex min-w-0 flex-col border-r\">\n        <!-- List Header -->\n        <div class=\"bg-muted/20 border-border/80 flex h-11 shrink-0 items-center justify-between border-b px-3.5\">\n          <div class=\"flex items-center gap-2\">\n            <span class=\"text-muted-foreground text-xs font-semibold tracking-tight uppercase\">\n              {{ categoriesList.find((c) => c.id === activeCategory)?.label }}\n            </span>\n            <Badge variant=\"outline\" class=\"h-4 px-1.5 font-mono text-xs tabular-nums\">\n              {{ visibleMails.length }}\n            </Badge>\n          </div>\n          <span class=\"text-muted-foreground/80 font-mono text-xs\"> [J/K] navigate </span>\n        </div>\n\n        <!-- Scrollable Messages Feed -->\n        <div class=\"list-scroll divide-border/40 flex-1 divide-y overflow-y-auto\">\n          <div\n            v-for=\"mail in visibleMails\"\n            :key=\"mail.id\"\n            :class=\"[\n              'group relative flex cursor-pointer flex-col gap-1 px-4 py-3 text-left transition-colors duration-150',\n              mail.id === activeMail?.id ? 'bg-accent/70 text-accent-foreground' : 'hover:bg-muted/40 text-foreground',\n            ]\"\n            @click=\"selectMail(mail.id)\"\n          >\n            <!-- Active indicator left bar -->\n            <span\n              v-if=\"mail.id === activeMail?.id\"\n              class=\"bg-primary absolute top-2 bottom-2 left-0 w-[3px] rounded-r-full\"\n            />\n\n            <!-- Row 1: Sender avatar, name, time, star -->\n            <div class=\"flex items-center justify-between gap-2\">\n              <div class=\"flex min-w-0 items-center gap-2.5\">\n                <Avatar class=\"size-6 shrink-0 text-xs\">\n                  <AvatarFallback class=\"bg-muted text-xs font-semibold\">\n                    {{ mail.sender.initials }}\n                  </AvatarFallback>\n                </Avatar>\n                <p\n                  :class=\"[\n                    'truncate text-xs',\n                    mail.unread ? 'text-foreground font-semibold' : 'text-foreground/80 font-medium',\n                  ]\"\n                >\n                  {{ mail.sender.name }}\n                </p>\n              </div>\n\n              <div class=\"flex shrink-0 items-center gap-1.5\">\n                <span class=\"text-muted-foreground font-mono text-xs tabular-nums\">\n                  {{ mail.timestamp }}\n                </span>\n                <button\n                  type=\"button\"\n                  :class=\"[\n                    'hover:text-warning inline-flex size-6 items-center justify-center rounded transition-colors',\n                    mail.starred ? 'text-warning' : 'text-muted-foreground/40 hover:text-muted-foreground',\n                  ]\"\n                  :title=\"mail.starred ? 'Unstar message' : 'Star message'\"\n                  @click=\"toggleStar(mail.id, $event)\"\n                >\n                  <Star :class=\"['size-3.5', mail.starred ? 'fill-warning' : '']\" />\n                </button>\n              </div>\n            </div>\n\n            <!-- Row 2: Subject line with unread bullet -->\n            <div class=\"mt-0.5 flex items-center gap-1.5\">\n              <span v-if=\"mail.unread\" class=\"bg-primary size-1.5 shrink-0 rounded-full\" />\n              <p\n                :class=\"[\n                  'truncate text-xs tracking-tight',\n                  mail.unread ? 'text-foreground font-semibold' : 'text-foreground/90 font-medium',\n                ]\"\n              >\n                {{ mail.subject }}\n              </p>\n            </div>\n\n            <!-- Row 3: 1-line snippet -->\n            <p class=\"text-muted-foreground line-clamp-1 text-xs leading-relaxed\">\n              {{ mail.snippet }}\n            </p>\n\n            <!-- Row 4: Category badge and attachment -->\n            <div class=\"mt-1 flex items-center justify-between gap-2\">\n              <Badge :variant=\"mail.badgeVariant ?? 'secondary'\" class=\"h-4.5 px-1.5 text-xs font-medium\">\n                {{ mail.categoryLabel }}\n              </Badge>\n\n              <div v-if=\"mail.attachment\" class=\"text-muted-foreground flex items-center gap-1 text-xs\">\n                <Paperclip class=\"size-3\" />\n                <span>{{ mail.attachment.type }}</span>\n              </div>\n            </div>\n          </div>\n\n          <!-- Empty State -->\n          <div\n            v-if=\"visibleMails.length === 0\"\n            class=\"flex flex-col items-center justify-center px-6 py-20 text-center\"\n          >\n            <div class=\"bg-muted/80 text-muted-foreground mb-3 flex size-12 items-center justify-center rounded-full\">\n              <CheckCircle2 class=\"text-primary size-6\" />\n            </div>\n            <p class=\"text-foreground text-sm font-semibold\">Inbox Zero Achieved</p>\n            <p class=\"text-muted-foreground mt-1 max-w-[220px] text-xs\">\n              No emails in {{ categoriesList.find((c) => c.id === activeCategory)?.label }}. You are completely caught\n              up!\n            </p>\n            <Button\n              v-if=\"activeCategory !== 'archived'\"\n              variant=\"outline\"\n              size=\"sm\"\n              class=\"mt-4 h-7 text-xs\"\n              @click=\"selectCategory('archived')\"\n            >\n              View Archived\n            </Button>\n          </div>\n        </div>\n      </aside>\n\n      <!-- RIGHT: SELECTED EMAIL READER & QUICK ACTION -->\n      <main class=\"bg-background flex min-w-0 flex-col overflow-hidden\">\n        <template v-if=\"activeMail\">\n          <!-- Top Action Bar -->\n          <div\n            class=\"bg-card/80 border-border flex h-11 shrink-0 items-center justify-between gap-2 overflow-x-auto border-b px-4 backdrop-blur-xs\"\n          >\n            <div class=\"flex items-center gap-1\">\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"h-7 gap-1 px-2.5 text-xs font-medium shadow-xs\"\n                @click=\"archiveMail(activeMail.id)\"\n              >\n                <Archive class=\"size-3.5\" />\n                <span>Archive</span>\n                <kbd\n                  class=\"bg-muted text-muted-foreground border-border/80 ml-0.5 rounded border px-1 font-mono text-xs\"\n                  >E</kbd\n                >\n              </Button>\n\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"h-7 gap-1 px-2.5 text-xs font-medium shadow-xs\"\n                @click=\"snoozeMail(activeMail.id)\"\n              >\n                <Clock class=\"size-3.5\" />\n                <span>Snooze</span>\n                <kbd\n                  class=\"bg-muted text-muted-foreground border-border/80 ml-0.5 rounded border px-1 font-mono text-xs\"\n                  >H</kbd\n                >\n              </Button>\n\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"h-7 gap-1 px-2.5 text-xs font-medium shadow-xs\"\n                @click=\"replyTextareaRef?.focus()\"\n              >\n                <Reply class=\"size-3.5\" />\n                <span>Reply</span>\n                <kbd\n                  class=\"bg-muted text-muted-foreground border-border/80 ml-0.5 rounded border px-1 font-mono text-xs\"\n                  >R</kbd\n                >\n              </Button>\n\n              <Button\n                variant=\"ghost\"\n                size=\"icon\"\n                class=\"size-7\"\n                :title=\"activeMail.starred ? 'Unstar' : 'Star'\"\n                @click=\"toggleStar(activeMail.id)\"\n                aria-label=\"Action\"\n              >\n                <Star :class=\"['size-4', activeMail.starred ? 'fill-warning text-warning' : 'text-muted-foreground']\" />\n              </Button>\n            </div>\n\n            <!-- Reader Navigation buttons -->\n            <div class=\"flex items-center gap-1\">\n              <Button\n                variant=\"ghost\"\n                size=\"icon\"\n                class=\"text-muted-foreground size-7\"\n                title=\"Previous (K)\"\n                @click=\"navigatePrev\"\n                aria-label=\"Action\"\n              >\n                <ArrowUp class=\"size-3.5\" />\n              </Button>\n              <Button\n                variant=\"ghost\"\n                size=\"icon\"\n                class=\"text-muted-foreground size-7\"\n                title=\"Next (J)\"\n                @click=\"navigateNext\"\n                aria-label=\"Action\"\n              >\n                <ArrowDown class=\"size-3.5\" />\n              </Button>\n            </div>\n          </div>\n\n          <!-- Toast Feedback Notification Banner -->\n          <div\n            v-if=\"toastMessage\"\n            class=\"bg-primary text-primary-foreground flex items-center justify-between px-4 py-2 text-xs font-medium shadow-xs transition-colors\"\n          >\n            <div class=\"flex items-center gap-2\">\n              <Check class=\"size-3.5\" />\n              <span>{{ toastMessage }}</span>\n            </div>\n            <button\n              v-if=\"hasUndo\"\n              class=\"bg-primary-foreground/20 hover:bg-primary-foreground/30 inline-flex items-center gap-1 rounded px-2 py-0.5 text-xs font-semibold transition-colors\"\n              @click=\"undoLastAction\"\n            >\n              <Undo2 class=\"size-3\" />\n              <span>Undo (⌘Z)</span>\n            </button>\n          </div>\n\n          <!-- Reader Scroll Area -->\n          <div class=\"reader-scroll flex-1 overflow-y-auto px-6 py-5\">\n            <!-- Subject Title -->\n            <div class=\"flex items-start justify-between gap-4\">\n              <h1 class=\"text-foreground text-lg font-bold tracking-tight sm:text-xl lg:text-2xl\">\n                {{ activeMail.subject }}\n              </h1>\n              <Badge :variant=\"activeMail.badgeVariant ?? 'default'\" class=\"shrink-0 text-xs\">\n                {{ activeMail.categoryLabel }}\n              </Badge>\n            </div>\n\n            <!-- Sender & Recipient Information Card -->\n            <div class=\"border-border/80 bg-muted/20 mt-4 flex items-start gap-3 rounded-lg border p-3.5\">\n              <Avatar class=\"size-9 shrink-0\">\n                <AvatarFallback class=\"bg-primary/10 text-primary text-xs font-bold\">\n                  {{ activeMail.sender.initials }}\n                </AvatarFallback>\n              </Avatar>\n\n              <div class=\"min-w-0 flex-1\">\n                <div class=\"flex flex-wrap items-baseline justify-between gap-x-2\">\n                  <p class=\"text-foreground min-w-0 truncate text-sm font-semibold\">\n                    {{ activeMail.sender.name }}\n                    <span class=\"text-muted-foreground text-xs font-normal\">&lt;{{ activeMail.sender.email }}&gt;</span>\n                  </p>\n                  <span class=\"text-muted-foreground font-mono text-xs tabular-nums\">\n                    {{ activeMail.fullDate }}\n                  </span>\n                </div>\n                <p class=\"text-muted-foreground mt-0.5 text-xs\">\n                  to <span class=\"text-foreground/80 font-medium\">{{ activeMail.recipient }}</span>\n                </p>\n              </div>\n            </div>\n\n            <Separator class=\"my-5\" />\n\n            <!-- Email Body Content -->\n            <article class=\"text-foreground/90 space-y-4 text-sm leading-relaxed whitespace-pre-wrap\">\n              {{ activeMail.body }}\n            </article>\n\n            <!-- Attachment Tile -->\n            <div v-if=\"activeMail.attachment\" class=\"mt-6\">\n              <p class=\"text-muted-foreground mb-2 text-xs font-semibold tracking-wider uppercase\">Attachment</p>\n              <div\n                class=\"border-border/80 bg-card hover:bg-muted/30 flex max-w-sm items-center justify-between gap-3 rounded-lg border p-3 shadow-xs\"\n              >\n                <div class=\"flex items-center gap-3\">\n                  <div class=\"bg-info/10 text-info flex size-9 items-center justify-center rounded-md\">\n                    <FileText class=\"size-4\" />\n                  </div>\n                  <div>\n                    <p class=\"text-foreground text-xs font-semibold\">{{ activeMail.attachment.name }}</p>\n                    <p class=\"text-muted-foreground font-mono text-xs\">\n                      {{ activeMail.attachment.size }} · {{ activeMail.attachment.type }}\n                    </p>\n                  </div>\n                </div>\n                <Button aria-label=\"Download attachment\" variant=\"outline\" size=\"sm\" class=\"h-7 px-2 text-xs\"\n                  >Download</Button\n                >\n              </div>\n            </div>\n          </div>\n\n          <!-- Quick Reply Composer -->\n          <div class=\"border-border bg-card border-t p-3.5\">\n            <div class=\"mb-2 flex items-center justify-between\">\n              <!-- Mode pills -->\n              <div class=\"flex items-center gap-1\">\n                <button\n                  type=\"button\"\n                  :class=\"[\n                    'inline-flex items-center gap-1 rounded-md px-2.5 py-1 text-xs font-medium transition-colors',\n                    replyMode === 'reply'\n                      ? 'bg-primary/10 text-primary font-semibold'\n                      : 'text-muted-foreground hover:bg-muted',\n                  ]\"\n                  @click=\"replyMode = 'reply'\"\n                >\n                  <Reply class=\"size-3\" />\n                  Reply\n                </button>\n                <button\n                  type=\"button\"\n                  :class=\"[\n                    'inline-flex items-center gap-1 rounded-md px-2.5 py-1 text-xs font-medium transition-colors',\n                    replyMode === 'reply-all'\n                      ? 'bg-primary/10 text-primary font-semibold'\n                      : 'text-muted-foreground hover:bg-muted',\n                  ]\"\n                  @click=\"replyMode = 'reply-all'\"\n                >\n                  <ReplyAll class=\"size-3\" />\n                  Reply all\n                </button>\n                <button\n                  type=\"button\"\n                  :class=\"[\n                    'inline-flex items-center gap-1 rounded-md px-2.5 py-1 text-xs font-medium transition-colors',\n                    replyMode === 'forward'\n                      ? 'bg-primary/10 text-primary font-semibold'\n                      : 'text-muted-foreground hover:bg-muted',\n                  ]\"\n                  @click=\"replyMode = 'forward'\"\n                >\n                  <Forward class=\"size-3\" />\n                  Forward\n                </button>\n              </div>\n\n              <span class=\"text-muted-foreground hidden min-w-0 truncate font-mono text-xs lg:inline\">\n                To: {{ activeMail.sender.email }}\n              </span>\n            </div>\n\n            <!-- Composer Input Box -->\n            <div\n              class=\"border-input bg-background focus-within:border-ring focus-within:ring-ring/50 relative flex flex-col rounded-lg border shadow-xs focus-within:ring-2\"\n            >\n              <textarea\n                ref=\"replyTextareaRef\"\n                v-model=\"replyDraft\"\n                rows=\"2\"\n                :placeholder=\"`Write a reply to ${activeMail.sender.name}... (⌘↵ to send)`\"\n                class=\"placeholder:text-muted-foreground w-full resize-none bg-transparent px-3 py-2 text-xs leading-relaxed outline-none\"\n              />\n\n              <div class=\"border-border/40 flex items-center justify-between border-t px-2 py-1.5\">\n                <div class=\"flex items-center gap-0.5\">\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    class=\"text-muted-foreground hover:text-foreground size-7\"\n                    aria-label=\"Attach file\"\n                  >\n                    <Paperclip class=\"size-3.5\" />\n                  </Button>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    class=\"text-muted-foreground hover:text-foreground size-7\"\n                    aria-label=\"Add emoji\"\n                  >\n                    <Smile class=\"size-3.5\" />\n                  </Button>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    class=\"text-muted-foreground hover:text-foreground size-7\"\n                    aria-label=\"Mention someone\"\n                  >\n                    <AtSign class=\"size-3.5\" />\n                  </Button>\n                </div>\n\n                <div class=\"flex items-center gap-2\">\n                  <kbd\n                    class=\"bg-muted text-muted-foreground border-border/70 hidden rounded border px-1.5 py-0.5 font-mono text-xs sm:inline-flex\"\n                  >\n                    ⌘↵\n                  </kbd>\n                  <Button\n                    size=\"sm\"\n                    class=\"h-7 gap-1 px-3 text-xs font-semibold shadow-xs\"\n                    :disabled=\"!replyDraft.trim()\"\n                    @click=\"sendReply\"\n                  >\n                    <span>Send</span>\n                    <Send class=\"size-3\" />\n                  </Button>\n                </div>\n              </div>\n            </div>\n          </div>\n        </template>\n\n        <!-- No Email Selected Placeholder -->\n        <div v-else class=\"flex flex-1 flex-col items-center justify-center p-8 text-center\">\n          <div class=\"bg-muted/60 text-muted-foreground mb-3 flex size-14 items-center justify-center rounded-full\">\n            <Mail class=\"size-7\" />\n          </div>\n          <p class=\"text-foreground text-sm font-semibold\">No message selected</p>\n          <p class=\"text-muted-foreground mt-1 max-w-sm text-xs\">\n            Select an email from the list or use J/K to navigate through your triage queue.\n          </p>\n        </div>\n      </main>\n    </div>\n\n    <!-- COMMAND PALETTE MODAL (⌘K) -->\n    <div\n      v-if=\"commandPaletteOpen\"\n      class=\"bg-background/80 fixed inset-0 z-50 flex items-center justify-center p-4 backdrop-blur-xs\"\n      @click.self=\"commandPaletteOpen = false\"\n    >\n      <div\n        class=\"bg-card text-card-foreground border-border animate-in fade-in-0 zoom-in-95 w-full max-w-lg overflow-hidden rounded-xl border shadow-xl\"\n      >\n        <div class=\"border-border flex items-center border-b px-3 py-2.5\">\n          <CommandIcon class=\"text-muted-foreground mr-2 size-4\" />\n          <input\n            v-model=\"commandFilter\"\n            type=\"text\"\n            placeholder=\"Type a command or shortcut...\"\n            class=\"placeholder:text-muted-foreground w-full bg-transparent text-xs outline-none\"\n            autofocus\n          />\n          <button\n            aria-label=\"Close command palette\"\n            class=\"text-muted-foreground hover:text-foreground ml-2 rounded p-1\"\n            @click=\"commandPaletteOpen = false\"\n          >\n            <X class=\"size-4\" />\n          </button>\n        </div>\n\n        <div class=\"max-h-72 overflow-y-auto p-2\">\n          <p class=\"text-muted-foreground px-2 py-1 text-xs font-semibold tracking-wider uppercase\">\n            High Velocity Actions\n          </p>\n          <button\n            v-for=\"item in filteredCommandPaletteItems\"\n            :key=\"item.key\"\n            class=\"hover:bg-muted/70 flex w-full items-center justify-between rounded-md px-2.5 py-1.5 text-left text-xs transition-colors\"\n            @click=\"executeCommand(item.action)\"\n          >\n            <span>{{ item.label }}</span>\n            <kbd class=\"bg-muted text-muted-foreground border-border/80 rounded border px-1.5 py-0.5 font-mono text-xs\">\n              {{ item.key }}\n            </kbd>\n          </button>\n        </div>\n\n        <div\n          class=\"bg-muted/40 border-border text-muted-foreground flex items-center justify-between border-t px-3 py-2 text-xs\"\n        >\n          <span>Use <strong>Esc</strong> to close</span>\n          <span>Superhuman Mode Active</span>\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n\n<style scoped>\n.list-scroll::-webkit-scrollbar,\n.reader-scroll::-webkit-scrollbar {\n  width: 5px;\n}\n.list-scroll::-webkit-scrollbar-thumb,\n.reader-scroll::-webkit-scrollbar-thumb {\n  background: var(--border);\n  border-radius: 4px;\n}\n</style>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/SmartInboxTriage.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/avatar.json",
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/separator.json"
  ],
  "description": "Superhuman-style high-velocity email inbox triage command center with keyboard shortcuts, split category tabs (VIP, Team & GitHub, Newsletters, Archived), dual-pane split reader, fast triage actions (Archive, Snooze, Star, Quick Reply), and command palette.",
  "categories": [
    "communication",
    "productivity",
    "layout"
  ]
}