{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "personal-finance-budget",
  "title": "Personal Finance Budget",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/personal-finance-budget/PersonalFinanceBudget.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport {\n  Calendar,\n  CheckCircle2,\n  Clock,\n  CreditCard,\n  Film,\n  FolderPlus,\n  HeartPulse,\n  Home,\n  Laptop,\n  PiggyBank,\n  Plane,\n  Plus,\n  ShieldCheck,\n  ShoppingCart,\n  TrendingUp,\n  UtensilsCrossed,\n  Wallet,\n  Zap,\n} from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Progress } from '@/components/ui/progress'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\n\ninterface EnvelopeCategory {\n  id: string\n  name: string\n  icon: React.ElementType\n  budgeted: number\n  spent: number\n  note: string\n  status: 'healthy' | 'warning' | 'completed' | 'on-track'\n  statusLabel: string\n  isSavings?: boolean\n}\n\ninterface EnvelopeSection {\n  id: string\n  title: string\n  description: string\n  icon: React.ElementType\n  totalBudgeted: number\n  totalSpent: number\n  categories: EnvelopeCategory[]\n}\n\nconst sections: EnvelopeSection[] = [\n  {\n    id: 'immediate-obligations',\n    title: 'Immediate Obligations',\n    description: 'Non-negotiable fixed living expenses and essential monthly bills.',\n    icon: Home,\n    totalBudgeted: 3750,\n    totalSpent: 3550,\n    categories: [\n      {\n        id: 'cat-housing',\n        name: 'Housing & Rent',\n        icon: Home,\n        budgeted: 2400,\n        spent: 2400,\n        note: 'Mortgage, HOA fee & insurance · Auto-paid Aug 1',\n        status: 'completed',\n        statusLabel: 'Paid in Full',\n      },\n      {\n        id: 'cat-utilities',\n        name: 'Utilities & Internet',\n        icon: Zap,\n        budgeted: 350,\n        spent: 320,\n        note: 'Electric ($185), Water ($75), Fiber ($60)',\n        status: 'healthy',\n        statusLabel: 'Healthy',\n      },\n      {\n        id: 'cat-groceries',\n        name: 'Groceries & Household',\n        icon: ShoppingCart,\n        budgeted: 800,\n        spent: 650,\n        note: 'Trader Joe’s & weekly produce · $15.00/day left',\n        status: 'healthy',\n        statusLabel: 'Healthy',\n      },\n      {\n        id: 'cat-health',\n        name: 'Health & Medical',\n        icon: HeartPulse,\n        budgeted: 200,\n        spent: 180,\n        note: 'Prescription copays & health membership',\n        status: 'healthy',\n        statusLabel: 'Healthy',\n      },\n    ],\n  },\n  {\n    id: 'lifestyle-discretionary',\n    title: 'Lifestyle & Discretionary',\n    description: 'Variable lifestyle choices, dining, entertainment, and digital subscriptions.',\n    icon: UtensilsCrossed,\n    totalBudgeted: 700,\n    totalSpent: 625,\n    categories: [\n      {\n        id: 'cat-dining',\n        name: 'Dining Out & Cafes',\n        icon: UtensilsCrossed,\n        budgeted: 400,\n        spent: 380,\n        note: 'Restaurants, coffee & takeout · $20.00 left for 10 days',\n        status: 'warning',\n        statusLabel: 'Near Limit',\n      },\n      {\n        id: 'cat-entertainment',\n        name: 'Entertainment & Leisure',\n        icon: Film,\n        budgeted: 200,\n        spent: 150,\n        note: 'Cinema tickets, gaming pass & weekend outings',\n        status: 'healthy',\n        statusLabel: 'Healthy',\n      },\n      {\n        id: 'cat-tech',\n        name: 'Tech & Subscriptions',\n        icon: Laptop,\n        budgeted: 100,\n        spent: 95,\n        note: 'iCloud, Spotify, GitHub Pro, ChatGPT Plus',\n        status: 'warning',\n        statusLabel: 'Near Limit',\n      },\n    ],\n  },\n  {\n    id: 'savings-investments',\n    title: 'Savings Goals & Investments',\n    description: 'Dedicated wealth accumulation, emergency reserve, and planned sinking funds.',\n    icon: PiggyBank,\n    totalBudgeted: 1583,\n    totalSpent: 1483,\n    categories: [\n      {\n        id: 'cat-emergency',\n        name: 'Emergency Fund',\n        icon: ShieldCheck,\n        budgeted: 500,\n        spent: 500,\n        note: 'High-yield cash reserve · Total balance: $18,500.00',\n        status: 'completed',\n        statusLabel: 'Goal Met',\n        isSavings: true,\n      },\n      {\n        id: 'cat-roth',\n        name: 'Roth IRA Contribution',\n        icon: TrendingUp,\n        budgeted: 583,\n        spent: 583,\n        note: 'Broad-market index ETF · 2026 cap pacing ($7,000/yr)',\n        status: 'completed',\n        statusLabel: 'Maxed Monthly',\n        isSavings: true,\n      },\n      {\n        id: 'cat-vacation',\n        name: 'Vacation & Travel Fund',\n        icon: Plane,\n        budgeted: 500,\n        spent: 400,\n        note: 'Tokyo autumn trip 2027 · $3,400.00 of $5,000.00 goal',\n        status: 'on-track',\n        statusLabel: '80% Funded',\n        isSavings: true,\n      },\n    ],\n  },\n]\n\nfunction formatCurrency(amount: number): string {\n  return `$${amount.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`\n}\n\nfunction getProgressColor(status: EnvelopeCategory['status']): string {\n  if (status === 'warning') {\n    return '[&_[data-slot=progress-indicator]]:bg-warning'\n  }\n  if (status === 'completed' || status === 'healthy' || status === 'on-track') {\n    return '[&_[data-slot=progress-indicator]]:bg-success'\n  }\n  return '[&_[data-slot=progress-indicator]]:bg-primary'\n}\n\nfunction getBadgeVariant(status: EnvelopeCategory['status']) {\n  if (status === 'warning') return 'warning'\n  if (status === 'completed' || status === 'healthy' || status === 'on-track') return 'success'\n  return 'outline'\n}\n\nexport function PersonalFinanceBudget({ className }: { className?: string }) {\n  return (\n    <div data-slot=\"personal-finance-budget\" className={cn('mx-auto w-full max-w-6xl space-y-6', className)}>\n      {/* Header */}\n      <div className=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n        <div className=\"space-y-1.5\">\n          <div className=\"flex flex-wrap items-center gap-2.5\">\n            <h1 className=\"text-foreground text-2xl font-bold tracking-tight sm:text-3xl\">Monthly Zero-Based Budget</h1>\n            <div className=\"bg-muted text-foreground border-border flex items-center gap-1 rounded-md border px-2 py-0.5 text-xs font-semibold\">\n              <Calendar className=\"text-muted-foreground size-3.5\" />\n              <span>August 2026</span>\n            </div>\n          </div>\n          <div className=\"flex flex-wrap items-center gap-2 pt-0.5\">\n            <div className=\"border-success/20 bg-success/10 text-success inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-xs font-medium\">\n              <CheckCircle2 className=\"size-3.5 shrink-0\" />\n              <span>\n                To be Budgeted: <strong className=\"font-semibold tabular-nums\">$0.00</strong> · Every dollar assigned!\n              </span>\n            </div>\n            <span className=\"text-muted-foreground hidden text-xs sm:inline\">Zero-Based Envelope Method</span>\n          </div>\n        </div>\n\n        <div className=\"flex items-center gap-2\">\n          <Button variant=\"outline\" size=\"sm\" className=\"gap-1.5 shadow-xs\">\n            <FolderPlus className=\"text-muted-foreground size-4\" />\n            <span>Add Category</span>\n          </Button>\n          <Button size=\"sm\" className=\"gap-1.5 shadow-xs\">\n            <Plus className=\"size-4\" />\n            <span>Add Expense</span>\n          </Button>\n        </div>\n      </div>\n\n      {/* 4 Primary Overview Cards */}\n      <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n        {/* Card 1: Total Monthly Income */}\n        <Card className=\"flex flex-col justify-between shadow-xs\">\n          <CardHeader className=\"pb-2\">\n            <div className=\"flex items-center justify-between gap-2\">\n              <div className=\"flex items-center gap-2\">\n                <div\n                  aria-hidden=\"true\"\n                  className=\"border-success/20 bg-success/10 text-success text-success flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs\"\n                >\n                  <Wallet className=\"size-4\" />\n                </div>\n                <CardTitle className=\"text-muted-foreground text-xs font-medium\">Total Monthly Income</CardTitle>\n              </div>\n              <Badge variant=\"success\" className=\"text-xs\">\n                100% Assigned\n              </Badge>\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-2\">\n            <div>\n              <div className=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">$8,500.00</div>\n              <p className=\"text-muted-foreground mt-0.5 text-xs\">2 Inflow streams (Salary & Freelance)</p>\n            </div>\n            <div className=\"border-border/60 text-muted-foreground flex items-center justify-between border-t pt-2 text-xs\">\n              <span>Unassigned Pool</span>\n              <span className=\"text-success text-success font-semibold tabular-nums\">$0.00</span>\n            </div>\n          </CardContent>\n        </Card>\n\n        {/* Card 2: Total Budgeted & Spent */}\n        <Card className=\"flex flex-col justify-between shadow-xs\">\n          <CardHeader className=\"pb-2\">\n            <div className=\"flex items-center justify-between gap-2\">\n              <div className=\"flex items-center gap-2\">\n                <div\n                  aria-hidden=\"true\"\n                  className=\"bg-muted text-muted-foreground border-border flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs\"\n                >\n                  <CreditCard className=\"size-4\" />\n                </div>\n                <CardTitle className=\"text-muted-foreground text-xs font-medium\">Budgeted & Spent</CardTitle>\n              </div>\n              <Badge variant=\"warning\" className=\"text-xs tabular-nums\">\n                80.5% Spent\n              </Badge>\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-2\">\n            <div>\n              <div className=\"flex items-baseline gap-1 text-2xl font-bold tracking-tight\">\n                <span className=\"text-foreground tabular-nums\">$6,840.00</span>\n                <span className=\"text-muted-foreground text-xs font-normal tabular-nums\">/ $8,500.00</span>\n              </div>\n              <div className=\"mt-2 space-y-1\">\n                <Progress value={80.5} className=\"[&_[data-slot=progress-indicator]]:bg-warning h-2\" />\n              </div>\n            </div>\n            <div className=\"border-border/60 text-muted-foreground flex items-center justify-between border-t pt-2 text-xs\">\n              <span>Remaining in Envelopes</span>\n              <span className=\"text-foreground font-medium tabular-nums\">$1,660.00</span>\n            </div>\n          </CardContent>\n        </Card>\n\n        {/* Card 3: Total Savings Allocated */}\n        <Card className=\"flex flex-col justify-between shadow-xs\">\n          <CardHeader className=\"pb-2\">\n            <div className=\"flex items-center justify-between gap-2\">\n              <div className=\"flex items-center gap-2\">\n                <div\n                  aria-hidden=\"true\"\n                  className=\"border-success/20 bg-success/10 text-success text-success flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs\"\n                >\n                  <PiggyBank className=\"size-4\" />\n                </div>\n                <CardTitle className=\"text-muted-foreground text-xs font-medium\">Savings Allocated</CardTitle>\n              </div>\n              <Badge variant=\"success\" className=\"text-xs tabular-nums\">\n                19.5% Rate\n              </Badge>\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-2\">\n            <div>\n              <div className=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">$1,660.00</div>\n              <div className=\"mt-2 space-y-1\">\n                <Progress value={89.3} className=\"[&_[data-slot=progress-indicator]]:bg-success h-2\" />\n              </div>\n            </div>\n            <div className=\"border-border/60 text-muted-foreground flex items-center justify-between border-t pt-2 text-xs\">\n              <span>Funded to Date</span>\n              <span className=\"text-success text-success font-semibold tabular-nums\">$1,483.00 (89.3%)</span>\n            </div>\n          </CardContent>\n        </Card>\n\n        {/* Card 4: Days Remaining in Month */}\n        <Card className=\"flex flex-col justify-between shadow-xs\">\n          <CardHeader className=\"pb-2\">\n            <div className=\"flex items-center justify-between gap-2\">\n              <div className=\"flex items-center gap-2\">\n                <div\n                  aria-hidden=\"true\"\n                  className=\"bg-muted text-muted-foreground border-border flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs\"\n                >\n                  <Clock className=\"size-4\" />\n                </div>\n                <CardTitle className=\"text-muted-foreground text-xs font-medium\">Month Pace</CardTitle>\n              </div>\n              <Badge variant=\"outline\" className=\"text-xs font-normal tabular-nums\">\n                Day 21 of 31\n              </Badge>\n            </div>\n          </CardHeader>\n          <CardContent className=\"space-y-2\">\n            <div>\n              <div className=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">10 Days left</div>\n              <div className=\"mt-2 space-y-1\">\n                <Progress value={67.7} className=\"h-2\" />\n              </div>\n            </div>\n            <div className=\"border-border/60 text-muted-foreground flex items-center justify-between border-t pt-2 text-xs\">\n              <span>Cycle Elapsed</span>\n              <span className=\"text-foreground font-medium tabular-nums\">67.7% of month</span>\n            </div>\n          </CardContent>\n        </Card>\n      </div>\n\n      {/* Envelope Categories List Grouped by Section */}\n      <div className=\"space-y-6\">\n        {sections.map((section) => {\n          const SectionIcon = section.icon\n          return (\n            <Card key={section.id} className=\"overflow-hidden shadow-xs\">\n              <CardHeader className=\"bg-muted/20 border-border border-b py-4\">\n                <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n                  <div className=\"space-y-0.5\">\n                    <div className=\"flex items-center gap-2\">\n                      <SectionIcon className=\"text-muted-foreground size-4 shrink-0\" />\n                      <CardTitle className=\"text-base font-semibold\">{section.title}</CardTitle>\n                    </div>\n                    <CardDescription className=\"text-xs\">{section.description}</CardDescription>\n                  </div>\n                  <div className=\"flex items-center gap-3 text-xs\">\n                    <div className=\"bg-background border-border flex items-center gap-2 rounded-md border px-3 py-1.5 shadow-2xs\">\n                      <span className=\"text-muted-foreground\">Subtotal:</span>\n                      <span className=\"text-foreground font-semibold tabular-nums\">\n                        {formatCurrency(section.totalSpent)}\n                      </span>\n                      <span className=\"text-muted-foreground\">/</span>\n                      <span className=\"text-muted-foreground font-medium tabular-nums\">\n                        {formatCurrency(section.totalBudgeted)}\n                      </span>\n                    </div>\n                  </div>\n                </div>\n              </CardHeader>\n\n              <CardContent className=\"p-0\">\n                <div className=\"overflow-x-auto\">\n                  <Table>\n                    <TableHeader>\n                      <TableRow className=\"hover:bg-transparent\">\n                        <TableHead className=\"min-w-[240px] text-xs font-semibold\">Envelope Category</TableHead>\n                        <TableHead className=\"text-right text-xs font-semibold\">\n                          {section.id === 'savings-investments' ? 'Monthly Target' : 'Budgeted'}\n                        </TableHead>\n                        <TableHead className=\"text-right text-xs font-semibold\">\n                          {section.id === 'savings-investments' ? 'Funded to Date' : 'Spent to Date'}\n                        </TableHead>\n                        <TableHead className=\"text-right text-xs font-semibold\">\n                          {section.id === 'savings-investments' ? 'Remaining to Goal' : 'Available Balance'}\n                        </TableHead>\n                        <TableHead className=\"min-w-[180px] text-xs font-semibold\">Progress & Pace</TableHead>\n                        <TableHead className=\"w-[110px] text-right text-xs font-semibold\">Status</TableHead>\n                      </TableRow>\n                    </TableHeader>\n                    <TableBody>\n                      {section.categories.map((cat) => {\n                        const CatIcon = cat.icon\n                        const remaining = cat.budgeted - cat.spent\n                        const percent = Math.min(100, Math.round((cat.spent / cat.budgeted) * 100))\n\n                        return (\n                          <TableRow key={cat.id} className=\"hover:bg-muted/40 transition-colors\">\n                            {/* Envelope Category & Note */}\n                            <TableCell className=\"py-3.5\">\n                              <div className=\"flex items-start gap-3\">\n                                <div\n                                  aria-hidden=\"true\"\n                                  className=\"bg-muted text-muted-foreground border-border mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs\"\n                                >\n                                  <CatIcon className=\"size-4\" />\n                                </div>\n                                <div className=\"space-y-0.5\">\n                                  <p className=\"text-foreground text-xs font-semibold\">{cat.name}</p>\n                                  <p className=\"text-muted-foreground text-xs\">{cat.note}</p>\n                                </div>\n                              </div>\n                            </TableCell>\n\n                            {/* Budgeted Amount */}\n                            <TableCell className=\"text-foreground py-3.5 text-right text-xs font-medium tabular-nums\">\n                              {formatCurrency(cat.budgeted)}\n                            </TableCell>\n\n                            {/* Spent to Date */}\n                            <TableCell className=\"text-foreground py-3.5 text-right text-xs font-medium tabular-nums\">\n                              {formatCurrency(cat.spent)}\n                            </TableCell>\n\n                            {/* Remaining Balance */}\n                            <TableCell className=\"py-3.5 text-right text-xs\">\n                              <span\n                                className={cn(\n                                  'font-bold tabular-nums',\n                                  remaining === 0\n                                    ? 'text-muted-foreground'\n                                    : cat.status === 'warning'\n                                      ? 'text-warning'\n                                      : 'text-success',\n                                )}\n                              >\n                                {formatCurrency(remaining)}\n                              </span>\n                            </TableCell>\n\n                            {/* Progress Bar & Percentage */}\n                            <TableCell className=\"py-3.5\">\n                              <div className=\"space-y-1.5\">\n                                <div className=\"flex items-center justify-between text-xs\">\n                                  <span className=\"text-muted-foreground tabular-nums\">\n                                    {percent}% {cat.isSavings ? 'funded' : 'used'}\n                                  </span>\n                                  <span className=\"text-muted-foreground text-xs tabular-nums\">\n                                    {formatCurrency(cat.spent)}\n                                  </span>\n                                </div>\n                                <Progress value={percent} className={cn('h-1.5', getProgressColor(cat.status))} />\n                              </div>\n                            </TableCell>\n\n                            {/* Status Badge */}\n                            <TableCell className=\"py-3.5 text-right\">\n                              <Badge variant={getBadgeVariant(cat.status)} className=\"text-xs\">\n                                {cat.statusLabel}\n                              </Badge>\n                            </TableCell>\n                          </TableRow>\n                        )\n                      })}\n                    </TableBody>\n                  </Table>\n                </div>\n              </CardContent>\n            </Card>\n          )\n        })}\n      </div>\n\n      {/* Zero-Based Budgeting Philosophy & Rules Card */}\n      <Card className=\"bg-muted/20 border-border p-4 shadow-xs\">\n        <div className=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n          <div className=\"flex items-start gap-3\">\n            <div\n              aria-hidden=\"true\"\n              className=\"border-success/20 bg-success/10 text-success text-success mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs\"\n            >\n              <CheckCircle2 className=\"size-4\" />\n            </div>\n            <div className=\"space-y-0.5\">\n              <h4 className=\"text-foreground text-xs font-semibold\">Zero-Based Allocation Completed</h4>\n              <p className=\"text-muted-foreground text-xs\">\n                Every dollar of your $8,500.00 income is accounted for: $4,450.00 living expenses + $1,583.00 savings\n                goals + $2,467.00 scheduled buffer = $0.00 unassigned.\n              </p>\n            </div>\n          </div>\n          <div className=\"flex shrink-0 items-center gap-2\">\n            <Badge variant=\"outline\" className=\"text-xs font-normal\">\n              Next Payday: Sep 1, 2026\n            </Badge>\n          </div>\n        </div>\n      </Card>\n    </div>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/PersonalFinanceBudget.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/card.json",
    "https://uipkge.dev/r/react/progress.json",
    "https://uipkge.dev/r/react/table.json"
  ],
  "description": "YNAB and Copilot-style zero-based monthly budget planner: envelope category budgeting, monthly pacing metrics, real-time spending progress by envelope, color-coded health indicators, and savings goal trackers.",
  "categories": [
    "finance",
    "dashboard",
    "app"
  ]
}