{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "inbox",
  "title": "Inbox",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-svelte/blocks/inbox/Inbox.svelte",
      "content": "<script lang=\"ts\">\n  import type { Component } from 'svelte'\n  import {\n    AlertOctagon,\n    Archive,\n    ArrowLeft,\n    ArrowRight,\n    AtSign,\n    Bookmark,\n    FileText,\n    Forward,\n    Inbox as InboxIcon,\n    MoreVertical,\n    Paperclip,\n    Pencil,\n    Reply,\n    ReplyAll,\n    Search,\n    Send,\n    Smile,\n    Star,\n    Tag,\n    Trash2,\n  } from '@lucide/svelte'\n  import { Avatar, AvatarFallback } from '$lib/components/ui/avatar'\n  import { Button } from '$lib/components/ui/button'\n  import { Input } from '$lib/components/ui/input'\n  import { Textarea } from '$lib/components/ui/textarea'\n\n  type ReplyMode = 'reply' | 'reply-all' | 'forward'\n\n  type FolderId = 'inbox' | 'starred' | 'sent' | 'drafts' | 'spam' | 'trash'\n\n  interface Folder {\n    id: FolderId\n    label: string\n    icon: Component\n  }\n\n  interface LabelTag {\n    id: string\n    label: string\n    color: string\n  }\n\n  interface Mail {\n    id: string\n    folder: FolderId\n    from: { name: string; email: string; initials: string }\n    to: string\n    subject: string\n    preview: string\n    body: string\n    receivedAt: Date\n    read: boolean\n    starred: boolean\n    hasAttachment: boolean\n    labels: string[]\n  }\n\n  const folders: Folder[] = [\n    { id: 'inbox', label: 'Inbox', icon: InboxIcon },\n    { id: 'starred', label: 'Starred', icon: Star },\n    { id: 'sent', label: 'Sent', icon: Send },\n    { id: 'drafts', label: 'Drafts', icon: FileText },\n    { id: 'spam', label: 'Spam', icon: AlertOctagon },\n    { id: 'trash', label: 'Trash', icon: Trash2 },\n  ]\n\n  const labels: LabelTag[] = [\n    { id: 'work', label: 'Work', color: 'bg-primary' },\n    { id: 'personal', label: 'Personal', color: 'bg-success' },\n    { id: 'finance', label: 'Finance', color: 'bg-info' },\n    { id: 'travel', label: 'Travel', color: 'bg-warning' },\n  ]\n\n  const now = new Date()\n  const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate())\n  const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000)\n\n  let mails = $state<Mail[]>([\n    {\n      id: 'e1',\n      folder: 'inbox',\n      from: { name: 'Sarah Connor', email: 'sarah@acme.com', initials: 'SC' },\n      to: 'you@acme.com',\n      subject: 'Q2 OKR draft — your sign-off needed',\n      preview:\n        'Pulled together the Q2 OKR draft from the leadership offsite. I have flagged the two areas where we need…',\n      body: `Hi,\\n\\nPulled together the Q2 OKR draft from the leadership offsite. I have flagged the two areas where we need your call before we lock it:\\n\\n• Hiring plan: 4 vs 6 ENG roles (page 3)\\n• EU rollout timing: April vs June (page 7)\\n\\nGoing to share with the rest of the leadership team Wednesday EOD, so anything from you by Tuesday is great.\\n\\nThanks,\\nSarah`,\n      receivedAt: new Date(now.getTime() - 18 * 60 * 1000),\n      read: false,\n      starred: true,\n      hasAttachment: true,\n      labels: ['work'],\n    },\n    {\n      id: 'e2',\n      folder: 'inbox',\n      from: { name: 'Marcus Rivera', email: 'marcus@acme.com', initials: 'MR' },\n      to: 'you@acme.com',\n      subject: 'Re: Dashboard review tomorrow',\n      preview:\n        'Yes! Pushing to 10:30 so we can join from the standup. I will own the slides and pull the latest kanban metrics.',\n      body: `Yes! Pushing to 10:30 so we can join from the standup. I will own the slides and pull the latest kanban metrics.\\n\\nFew things I want to cover:\\n  - Throughput delta vs last sprint\\n  - The two stories we de-scoped\\n  - Q2 capacity ask\\n\\nSee you tomorrow,\\nMarcus`,\n      receivedAt: new Date(now.getTime() - 95 * 60 * 1000),\n      read: false,\n      starred: false,\n      hasAttachment: false,\n      labels: ['work'],\n    },\n    {\n      id: 'e3',\n      folder: 'inbox',\n      from: { name: 'Stripe', email: 'receipts@stripe.com', initials: 'St' },\n      to: 'you@acme.com',\n      subject: 'Your invoice from Acme Inc. — $1,290.00',\n      preview:\n        'Thanks for using Stripe. Your invoice for the period Mar 1 – Mar 31 is attached. Total due: $1,290.00…',\n      body: 'Thanks for using Stripe. Your invoice for the period Mar 1 – Mar 31 is attached. Total due: $1,290.00.',\n      receivedAt: new Date(now.getTime() - 4 * 60 * 60 * 1000),\n      read: true,\n      starred: false,\n      hasAttachment: true,\n      labels: ['finance'],\n    },\n    {\n      id: 'e4',\n      folder: 'inbox',\n      from: { name: 'Linear', email: 'no-reply@linear.app', initials: 'Li' },\n      to: 'you@acme.com',\n      subject: 'Weekly summary: 14 issues closed, 22 opened',\n      preview:\n        'Good news — the team closed 14 issues this week, up 3 from last week. Top contributors: Marcus, Priya, Devon.',\n      body: 'Good news — the team closed 14 issues this week, up 3 from last week. Top contributors: Marcus, Priya, Devon.',\n      receivedAt: new Date(now.getTime() - 9 * 60 * 60 * 1000),\n      read: true,\n      starred: false,\n      hasAttachment: false,\n      labels: ['work'],\n    },\n    {\n      id: 'e5',\n      folder: 'inbox',\n      from: { name: 'Priya Shah', email: 'priya@acme.com', initials: 'PS' },\n      to: 'you@acme.com',\n      subject: 'Color tokens are live in staging',\n      preview:\n        'Pushed the new OKLCH token set to staging. All chart colors, success/warning/info, sidebar variants. Take a look…',\n      body: 'Pushed the new OKLCH token set to staging. All chart colors, success/warning/info, sidebar variants. Take a look when you have a sec.',\n      receivedAt: yesterday,\n      read: true,\n      starred: true,\n      hasAttachment: false,\n      labels: ['work'],\n    },\n    {\n      id: 'e6',\n      folder: 'inbox',\n      from: { name: 'United Airlines', email: 'reservations@united.com', initials: 'UA' },\n      to: 'you@acme.com',\n      subject: 'Your itinerary: SFO → LHR, departing Apr 12',\n      preview: 'Your reservation is confirmed. Check-in opens 24h before departure. Booking reference: 7HQ4P2.',\n      body: 'Your reservation is confirmed. Check-in opens 24h before departure. Booking reference: 7HQ4P2.',\n      receivedAt: new Date(now.getTime() - 38 * 60 * 60 * 1000),\n      read: true,\n      starred: false,\n      hasAttachment: true,\n      labels: ['travel'],\n    },\n    {\n      id: 'e7',\n      folder: 'inbox',\n      from: { name: 'Mom', email: 'mom@family.net', initials: 'M' },\n      to: 'you@acme.com',\n      subject: 'Sunday lunch?',\n      preview: 'Are you free for lunch this Sunday? Dad is making his lasagne. Let me know!',\n      body: 'Are you free for lunch this Sunday? Dad is making his lasagne. Let me know!',\n      receivedAt: new Date(now.getTime() - 55 * 60 * 60 * 1000),\n      read: true,\n      starred: false,\n      hasAttachment: false,\n      labels: ['personal'],\n    },\n  ])\n\n  let activeFolder = $state<FolderId>('inbox')\n  let activeLabel = $state<string | null>(null)\n  let activeId = $state<string>('e1')\n  let search = $state('')\n  let replyMode = $state<ReplyMode>('reply')\n  let replyDraft = $state('')\n  let justSent = $state(false)\n\n  function folderCount(id: FolderId): number {\n    if (id === 'starred') return mails.filter((m) => m.starred && m.folder !== 'trash').length\n    return mails.filter((m) => m.folder === id).length\n  }\n\n  function unreadCount(id: FolderId): number {\n    if (id === 'starred') return mails.filter((m) => m.starred && !m.read && m.folder !== 'trash').length\n    return mails.filter((m) => m.folder === id && !m.read).length\n  }\n\n  const labelCounts = $derived(\n    labels.reduce<Record<string, number>>((acc, l) => {\n      acc[l.id] = mails.filter((m) => m.labels.includes(l.id)).length\n      return acc\n    }, {}),\n  )\n\n  const visibleMails = $derived.by(() => {\n    const q = search.trim().toLowerCase()\n    let list = mails.filter((m) => {\n      if (activeLabel) return m.labels.includes(activeLabel)\n      if (activeFolder === 'starred') return m.starred && m.folder !== 'trash'\n      return m.folder === activeFolder\n    })\n    if (q) {\n      list = list.filter(\n        (m) =>\n          m.subject.toLowerCase().includes(q) ||\n          m.from.name.toLowerCase().includes(q) ||\n          m.preview.toLowerCase().includes(q),\n      )\n    }\n    return [...list].sort((a, b) => b.receivedAt.getTime() - a.receivedAt.getTime())\n  })\n\n  const activeMail = $derived(mails.find((m) => m.id === activeId) ?? null)\n\n  function selectMail(id: string) {\n    activeId = id\n    const m = mails.find((m) => m.id === id)\n    if (m) m.read = true\n  }\n\n  function selectFolder(id: FolderId) {\n    activeFolder = id\n    activeLabel = null\n    const first = visibleMails[0]\n    if (first) activeId = first.id\n  }\n\n  function selectLabel(id: string) {\n    activeLabel = id\n    const first = visibleMails[0]\n    if (first) activeId = first.id\n  }\n\n  function toggleStar(id: string, e?: Event) {\n    e?.stopPropagation()\n    const m = mails.find((m) => m.id === id)\n    if (m) m.starred = !m.starred\n  }\n\n  function archive(id: string) {\n    mails = mails.filter((m) => m.id !== id)\n    const next = visibleMails[0]\n    if (next) activeId = next.id\n  }\n\n  function formatMailTime(d: Date): string {\n    if (d >= todayStart) return d.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })\n    if (d.toDateString() === yesterday.toDateString()) return 'Yesterday'\n    const diffDays = Math.floor((now.getTime() - d.getTime()) / (24 * 60 * 60 * 1000))\n    if (diffDays < 7) return d.toLocaleDateString(undefined, { weekday: 'short' })\n    return d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })\n  }\n\n  function formatFullTime(d: Date): string {\n    return d.toLocaleString(undefined, {\n      weekday: 'short',\n      month: 'short',\n      day: 'numeric',\n      hour: 'numeric',\n      minute: '2-digit',\n    })\n  }\n\n  function labelMeta(id: string): LabelTag | undefined {\n    return labels.find((l) => l.id === id)\n  }\n\n  const replyRecipient = $derived.by(() => {\n    const m = activeMail\n    if (!m) return ''\n    if (replyMode === 'forward') return ''\n    return m.from.name + ' <' + m.from.email + '>'\n  })\n\n  const replyPlaceholder = $derived(\n    replyMode === 'forward' ? 'Add a note before forwarding' : 'Write a reply',\n  )\n\n  const sendDisabled = $derived(!replyDraft.trim() || (replyMode === 'forward' && false))\n\n  function setReplyMode(mode: ReplyMode) {\n    replyMode = mode\n    justSent = false\n  }\n\n  function sendReply() {\n    const body = replyDraft.trim()\n    if (!body) return\n    replyDraft = ''\n    justSent = true\n    window.setTimeout(() => {\n      justSent = false\n    }, 1800)\n  }\n\n  function onReplyKey(e: KeyboardEvent) {\n    if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n      e.preventDefault()\n      sendReply()\n    }\n  }\n\n  // Switching messages resets the composer. (Runs once on mount too, where it\n  // is a harmless no-op over the empty initial draft.)\n  $effect(() => {\n    void activeId\n    replyDraft = ''\n    replyMode = 'reply'\n    justSent = false\n  })\n</script>\n\n<div\n  data-slot=\"inbox\"\n  class=\"bg-card text-card-foreground grid h-[42.5rem] w-full grid-cols-[220px_340px_1fr] overflow-hidden rounded-xl border shadow-sm\"\n>\n  <aside class=\"bg-muted/30 flex min-w-0 flex-col border-r\">\n    <div class=\"flex h-14 shrink-0 items-center border-b px-3\">\n      <Button class=\"h-9 w-full justify-start gap-2 rounded-lg\" size=\"sm\">\n        <Pencil class=\"size-4\" />\n        Compose\n      </Button>\n    </div>\n    <nav class=\"flex-1 space-y-1 overflow-y-auto px-3 pt-3 pb-3\">\n      <p class=\"text-muted-foreground px-2 pb-1 text-xs font-semibold tracking-widest uppercase\">Folders</p>\n      {#each folders as f (f.id)}\n        {@const FolderIcon = f.icon}\n        <button\n          class=\"flex w-full items-center justify-between gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors {activeFolder ===\n            f.id && !activeLabel\n            ? 'bg-primary/10 text-primary font-medium'\n            : 'hover:bg-muted/60 text-foreground/80'}\"\n          onclick={() => selectFolder(f.id)}\n        >\n          <span class=\"flex min-w-0 items-center gap-2\">\n            <FolderIcon class=\"size-4 shrink-0\" />\n            <span class=\"truncate\">{f.label}</span>\n          </span>\n          {#if unreadCount(f.id) > 0}\n            <span class=\"text-muted-foreground shrink-0 text-xs tabular-nums\">\n              {unreadCount(f.id)}\n            </span>\n          {/if}\n        </button>\n      {/each}\n\n      <p class=\"text-muted-foreground mt-4 px-2 pb-1 text-xs font-semibold tracking-widest uppercase\">Labels</p>\n      {#each labels as l (l.id)}\n        <button\n          class=\"flex w-full items-center justify-between gap-2 rounded-md px-2 py-1.5 text-left text-sm transition-colors {activeLabel ===\n          l.id\n            ? 'bg-primary/10 text-primary font-medium'\n            : 'hover:bg-muted/60 text-foreground/80'}\"\n          onclick={() => selectLabel(l.id)}\n        >\n          <span class=\"flex min-w-0 items-center gap-2\">\n            <span class=\"size-2.5 shrink-0 rounded-full {l.color}\"></span>\n            <span class=\"truncate\">{l.label}</span>\n          </span>\n          <span class=\"text-muted-foreground shrink-0 text-xs tabular-nums\">\n            {labelCounts[l.id] ?? 0}\n          </span>\n        </button>\n      {/each}\n    </nav>\n  </aside>\n\n  <section class=\"bg-background flex min-w-0 flex-col border-r\">\n    <div class=\"flex h-14 shrink-0 items-center gap-2 border-b px-3\">\n      <div class=\"relative flex-1\">\n        <Search class=\"text-muted-foreground absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2\" />\n        <Input bind:value={search} placeholder=\"Search mail\" class=\"h-8 rounded-lg pl-8 text-xs\" />\n      </div>\n      <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Filter\">\n        <Tag class=\"size-4\" />\n      </Button>\n    </div>\n    <div class=\"flex items-center justify-between px-4 pt-3 pb-2\">\n      <h2 class=\"text-sm font-semibold tracking-tight capitalize\">\n        {activeLabel ? labelMeta(activeLabel)?.label : activeFolder}\n      </h2>\n      <span class=\"text-muted-foreground text-xs tabular-nums\">\n        {visibleMails.length} message{visibleMails.length === 1 ? '' : 's'}\n      </span>\n    </div>\n    <div class=\"list-scroll flex-1 overflow-y-auto pb-3\">\n      {#each visibleMails as m (m.id)}\n        <button\n          class=\"group relative w-full px-4 py-3 text-left transition-colors {m.id === activeId\n            ? 'bg-primary/5'\n            : 'hover:bg-muted/60'}\"\n          onclick={() => selectMail(m.id)}\n        >\n          {#if m.id === activeId}\n            <span class=\"bg-primary absolute top-2 bottom-2 left-0 w-[3px] rounded-r-full\"></span>\n          {/if}\n          <div class=\"flex items-start gap-3\">\n            <Avatar class=\"mt-0.5 size-8 shrink-0\">\n              <AvatarFallback class=\"text-xs\">{m.from.initials}</AvatarFallback>\n            </Avatar>\n            <div class=\"min-w-0 flex-1\">\n              <div class=\"flex items-center justify-between gap-2\">\n                <p class=\"truncate text-sm {m.read ? 'font-medium' : 'font-semibold'}\">\n                  {m.from.name}\n                </p>\n                <span class=\"text-muted-foreground shrink-0 text-xs tabular-nums\">\n                  {formatMailTime(m.receivedAt)}\n                </span>\n              </div>\n              <p class=\"mt-0.5 truncate text-xs {m.read ? 'text-foreground/80' : 'font-semibold'}\">\n                {m.subject}\n              </p>\n              <p class=\"text-muted-foreground mt-0.5 line-clamp-2 text-xs leading-relaxed\">\n                {m.preview}\n              </p>\n              <div class=\"mt-1.5 flex items-center gap-1.5\">\n                {#each m.labels as lid (lid)}\n                  <span\n                    class=\"text-muted-foreground bg-muted inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 text-xs\"\n                  >\n                    <span class=\"size-1.5 rounded-full {labelMeta(lid)?.color}\"></span>\n                    {labelMeta(lid)?.label}\n                  </span>\n                {/each}\n                {#if m.hasAttachment}\n                  <Paperclip class=\"text-muted-foreground size-3\" />\n                {/if}\n                {#if !m.read}\n                  <span class=\"bg-primary ml-auto size-1.5 shrink-0 rounded-full\"></span>\n                {/if}\n              </div>\n            </div>\n            <span\n              role=\"button\"\n              tabindex=\"0\"\n              class=\"text-muted-foreground hover:text-warning inline-flex shrink-0 cursor-pointer items-center justify-center transition-colors\"\n              title={m.starred ? 'Unstar' : 'Star'}\n              onclick={(e) => toggleStar(m.id, e)}\n              onkeydown={(e) => {\n                if (e.key === 'Enter' || e.key === ' ') {\n                  e.preventDefault()\n                  toggleStar(m.id, e)\n                }\n              }}\n            >\n              <Star class=\"size-3.5 {m.starred ? 'fill-warning text-warning' : ''}\" />\n            </span>\n          </div>\n        </button>\n      {/each}\n\n      {#if visibleMails.length === 0}\n        <div class=\"flex flex-col items-center justify-center px-6 py-16 text-center\">\n          <div class=\"bg-muted mb-3 rounded-full p-3\">\n            <InboxIcon class=\"text-muted-foreground size-5\" />\n          </div>\n          <p class=\"text-sm font-medium\">Nothing here</p>\n          <p class=\"text-muted-foreground mt-0.5 text-xs\">No messages match the current filter.</p>\n        </div>\n      {/if}\n    </div>\n  </section>\n\n  <section class=\"bg-background flex min-w-0 flex-col\">\n    {#if activeMail}\n      {@const mail = activeMail}\n      <div class=\"flex h-14 shrink-0 items-center justify-between gap-2 border-b px-4\">\n        <div class=\"flex items-center gap-1\">\n          <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Back\">\n            <ArrowLeft class=\"size-4\" />\n          </Button>\n          <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Archive\" onclick={() => archive(mail.id)}>\n            <Archive class=\"size-4\" />\n          </Button>\n          <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Delete\">\n            <Trash2 class=\"size-4\" />\n          </Button>\n          <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Save\">\n            <Bookmark class=\"size-4\" />\n          </Button>\n        </div>\n        <div class=\"flex items-center gap-1\">\n          <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Reply\">\n            <Reply class=\"size-4\" />\n          </Button>\n          <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Reply all\">\n            <ReplyAll class=\"size-4\" />\n          </Button>\n          <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"Forward\">\n            <Forward class=\"size-4\" />\n          </Button>\n          <Button variant=\"ghost\" size=\"icon\" class=\"size-8\" aria-label=\"More options\">\n            <MoreVertical class=\"size-4\" />\n          </Button>\n        </div>\n      </div>\n\n      <div class=\"reader-scroll flex-1 overflow-y-auto\">\n        <div class=\"px-6 pt-5 pb-3\">\n          <h1 class=\"text-foreground text-xl leading-tight font-semibold tracking-tight\">\n            {mail.subject}\n          </h1>\n          <div class=\"mt-2 flex flex-wrap items-center gap-2\">\n            {#each mail.labels as lid (lid)}\n              <span\n                class=\"text-foreground/70 bg-muted inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs\"\n              >\n                <span class=\"size-1.5 rounded-full {labelMeta(lid)?.color}\"></span>\n                {labelMeta(lid)?.label}\n              </span>\n            {/each}\n          </div>\n        </div>\n\n        <div class=\"flex items-start gap-3 px-6 pb-4\">\n          <Avatar class=\"size-10\">\n            <AvatarFallback>{mail.from.initials}</AvatarFallback>\n          </Avatar>\n          <div class=\"min-w-0 flex-1\">\n            <div class=\"flex flex-wrap items-baseline gap-x-2\">\n              <p class=\"text-sm font-semibold\">{mail.from.name}</p>\n              <p class=\"text-muted-foreground text-xs\">&lt;{mail.from.email}&gt;</p>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">to {mail.to}</p>\n          </div>\n          <div class=\"text-muted-foreground flex shrink-0 items-center gap-2 text-xs\">\n            <span>{formatFullTime(mail.receivedAt)}</span>\n            <button\n              class=\"hover:text-warning transition-colors\"\n              title={mail.starred ? 'Unstar' : 'Star'}\n              onclick={() => toggleStar(mail.id)}\n            >\n              <Star class=\"size-4 {mail.starred ? 'fill-warning text-warning' : ''}\" />\n            </button>\n          </div>\n        </div>\n\n        <article class=\"text-foreground/90 px-6 pb-6 text-sm leading-relaxed whitespace-pre-wrap\">\n          {mail.body}\n        </article>\n\n        {#if mail.hasAttachment}\n          <div class=\"px-6 pb-6\">\n            <div class=\"bg-muted/40 flex items-center gap-3 rounded-lg border px-3 py-2.5\">\n              <div class=\"bg-info/10 text-info flex size-8 items-center justify-center rounded-md\">\n                <FileText class=\"size-4\" />\n              </div>\n              <div class=\"min-w-0 flex-1\">\n                <p class=\"truncate text-xs font-medium\">attachment.pdf</p>\n                <p class=\"text-muted-foreground text-xs\">142 KB · PDF</p>\n              </div>\n              <Button aria-label=\"Download attachment\" variant=\"ghost\" size=\"sm\" class=\"h-7 text-xs\">Download</Button>\n            </div>\n          </div>\n        {/if}\n      </div>\n\n      <div class=\"bg-muted/20 border-t px-4 pt-3 pb-3\">\n        <div class=\"mb-2 flex items-center gap-1\">\n          <button\n            class=\"inline-flex h-7 items-center gap-1.5 rounded-md px-2 text-xs font-medium transition-colors {replyMode ===\n            'reply'\n              ? 'bg-background text-foreground border-input/60 border shadow-sm'\n              : 'text-muted-foreground hover:bg-background/60 hover:text-foreground'}\"\n            onclick={() => setReplyMode('reply')}\n          >\n            <Reply class=\"size-3.5\" />\n            Reply\n          </button>\n          <button\n            class=\"inline-flex h-7 items-center gap-1.5 rounded-md px-2 text-xs font-medium transition-colors {replyMode ===\n            'reply-all'\n              ? 'bg-background text-foreground border-input/60 border shadow-sm'\n              : 'text-muted-foreground hover:bg-background/60 hover:text-foreground'}\"\n            onclick={() => setReplyMode('reply-all')}\n          >\n            <ReplyAll class=\"size-3.5\" />\n            Reply all\n          </button>\n          <button\n            class=\"inline-flex h-7 items-center gap-1.5 rounded-md px-2 text-xs font-medium transition-colors {replyMode ===\n            'forward'\n              ? 'bg-background text-foreground border-input/60 border shadow-sm'\n              : 'text-muted-foreground hover:bg-background/60 hover:text-foreground'}\"\n            onclick={() => setReplyMode('forward')}\n          >\n            <Forward class=\"size-3.5\" />\n            Forward\n          </button>\n        </div>\n        <div\n          class=\"bg-background border-input/60 focus-within:border-primary/40 focus-within:ring-primary/10 group flex flex-col overflow-hidden rounded-2xl border shadow-sm transition-colors duration-150 focus-within:shadow-md focus-within:ring-4\"\n        >\n          {#if replyRecipient}\n            <p class=\"border-input/40 text-muted-foreground border-b px-4 pt-2.5 pb-2 text-xs\">\n              <span class=\"text-foreground/70 font-medium\">To:</span>\n              {replyRecipient}\n            </p>\n          {/if}\n          <Textarea\n            bind:value={replyDraft}\n            placeholder={replyPlaceholder}\n            rows=\"1\"\n            class=\"placeholder:text-muted-foreground/70 max-h-40 min-h-[2.75rem] resize-none border-0 bg-transparent px-4 pt-3 pb-1 text-sm leading-relaxed shadow-none focus-visible:ring-0\"\n            onkeydown={onReplyKey}\n          />\n          <div class=\"flex items-center justify-between gap-2 px-2 pb-2\">\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-8\"\n                aria-label=\"Attach file\"\n              >\n                <Paperclip class=\"size-4\" />\n              </Button>\n              <Button\n                variant=\"ghost\"\n                size=\"icon\"\n                class=\"text-muted-foreground hover:text-foreground size-8\"\n                aria-label=\"Emoji\"\n              >\n                <Smile class=\"size-4\" />\n              </Button>\n              <Button\n                variant=\"ghost\"\n                size=\"icon\"\n                class=\"text-muted-foreground hover:text-foreground size-8\"\n                aria-label=\"Mention\"\n              >\n                <AtSign class=\"size-4\" />\n              </Button>\n            </div>\n            <div class=\"flex items-center gap-2\">\n              <kbd\n                class=\"bg-muted text-muted-foreground hidden h-5 items-center gap-0.5 rounded border px-1.5 font-mono text-xs sm:inline-flex\"\n              >\n                <span>⌘</span><span>↵</span>\n              </kbd>\n              <Button\n                class=\"h-8 gap-1.5 rounded-lg px-3 text-xs font-medium\"\n                disabled={sendDisabled}\n                aria-label=\"Send\"\n                onclick={sendReply}\n              >\n                Send\n                <ArrowRight class=\"size-3.5\" />\n              </Button>\n            </div>\n          </div>\n        </div>\n        {#if justSent}\n          <p class=\"text-success mt-2 text-center text-xs font-medium\">Reply sent</p>\n        {/if}\n      </div>\n    {:else}\n      <div class=\"flex flex-1 items-center justify-center\">\n        <div class=\"text-center\">\n          <div class=\"bg-muted mx-auto mb-3 size-12 rounded-full p-3\">\n            <InboxIcon class=\"text-muted-foreground size-6\" />\n          </div>\n          <p class=\"text-sm font-medium\">No message selected</p>\n          <p class=\"text-muted-foreground mt-1 text-xs\">Pick a message from the list to read it here.</p>\n        </div>\n      </div>\n    {/if}\n  </section>\n</div>\n\n<style>\n  /* Thin overlay scrollbars. Scrollbar pseudo-elements can't be Tailwind\n     utilities, so they live here. */\n  .list-scroll::-webkit-scrollbar,\n  .reader-scroll::-webkit-scrollbar {\n    width: 6px;\n  }\n  .list-scroll::-webkit-scrollbar-thumb,\n  .reader-scroll::-webkit-scrollbar-thumb {\n    background: var(--border);\n    border-radius: 3px;\n  }\n</style>\n",
      "type": "registry:block",
      "target": "~/src/lib/components/blocks/inbox/Inbox.svelte"
    }
  ],
  "dependencies": [
    "@lucide/svelte"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/svelte/avatar.json",
    "https://uipkge.dev/r/svelte/button.json",
    "https://uipkge.dev/r/svelte/input.json",
    "https://uipkge.dev/r/svelte/textarea.json"
  ],
  "description": "Three-pane mail surface. Left rail: Compose button, folders (Inbox/Starred/Sent/Drafts/Spam/Trash) with unread counts, colour-coded labels with totals. Middle: searchable message list with sender, subject, preview, labels, attachment glyphs, star toggle, smart timestamps. Right: reader pane with subject, from/to, body, attachment chip, reply/forward/archive actions. Stateful demo — swap `mails` for your data source.",
  "categories": [
    "communication",
    "layout"
  ]
}