{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "personal-finance-budget",
  "title": "Personal Finance Budget",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/personal-finance-budget/PersonalFinanceBudget.vue",
      "content": "<script setup lang=\"ts\">\nimport { type HTMLAttributes } from 'vue'\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-vue-next'\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\nconst props = defineProps<{\n  class?: HTMLAttributes['class']\n}>()\n\ninterface EnvelopeCategory {\n  id: string\n  name: string\n  icon: any\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: any\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</script>\n\n<template>\n  <div data-slot=\"personal-finance-budget\" :class=\"cn('mx-auto w-full max-w-6xl space-y-6', props.class)\">\n    <!-- Header -->\n    <div class=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n      <div class=\"space-y-1.5\">\n        <div class=\"flex flex-wrap items-center gap-2.5\">\n          <h1 class=\"text-foreground text-2xl font-bold tracking-tight sm:text-3xl\">Monthly Zero-Based Budget</h1>\n          <div\n            class=\"bg-muted text-foreground border-border flex items-center gap-1 rounded-md border px-2 py-0.5 text-xs font-semibold\"\n          >\n            <Calendar class=\"text-muted-foreground size-3.5\" />\n            <span>August 2026</span>\n          </div>\n        </div>\n        <div class=\"flex flex-wrap items-center gap-2 pt-0.5\">\n          <div\n            class=\"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          >\n            <CheckCircle2 class=\"size-3.5 shrink-0\" />\n            <span\n              >To be Budgeted: <strong class=\"font-semibold tabular-nums\">$0.00</strong> · Every dollar assigned!</span\n            >\n          </div>\n          <span class=\"text-muted-foreground hidden text-xs sm:inline\">Zero-Based Envelope Method</span>\n        </div>\n      </div>\n\n      <div class=\"flex items-center gap-2\">\n        <Button variant=\"outline\" size=\"sm\" class=\"gap-1.5 shadow-xs\">\n          <FolderPlus class=\"text-muted-foreground size-4\" />\n          <span>Add Category</span>\n        </Button>\n        <Button size=\"sm\" class=\"gap-1.5 shadow-xs\">\n          <Plus class=\"size-4\" />\n          <span>Add Expense</span>\n        </Button>\n      </div>\n    </div>\n\n    <!-- 4 Primary Overview Cards -->\n    <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n      <!-- Card 1: Total Monthly Income -->\n      <Card class=\"flex flex-col justify-between shadow-xs\">\n        <CardHeader class=\"pb-2\">\n          <div class=\"flex items-center justify-between gap-2\">\n            <div class=\"flex items-center gap-2\">\n              <div\n                class=\"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                aria-hidden=\"true\"\n              >\n                <Wallet class=\"size-4\" />\n              </div>\n              <CardTitle class=\"text-muted-foreground text-xs font-medium\">Total Monthly Income</CardTitle>\n            </div>\n            <Badge variant=\"success\" class=\"text-xs\">100% Assigned</Badge>\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-2\">\n          <div>\n            <div class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">$8,500.00</div>\n            <p class=\"text-muted-foreground mt-0.5 text-xs\">2 Inflow streams (Salary & Freelance)</p>\n          </div>\n          <div class=\"border-border/60 text-muted-foreground flex items-center justify-between border-t pt-2 text-xs\">\n            <span>Unassigned Pool</span>\n            <span class=\"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 class=\"flex flex-col justify-between shadow-xs\">\n        <CardHeader class=\"pb-2\">\n          <div class=\"flex items-center justify-between gap-2\">\n            <div class=\"flex items-center gap-2\">\n              <div\n                class=\"bg-muted text-muted-foreground border-border flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs\"\n                aria-hidden=\"true\"\n              >\n                <CreditCard class=\"size-4\" />\n              </div>\n              <CardTitle class=\"text-muted-foreground text-xs font-medium\">Budgeted & Spent</CardTitle>\n            </div>\n            <Badge variant=\"warning\" class=\"text-xs tabular-nums\">80.5% Spent</Badge>\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-2\">\n          <div>\n            <div class=\"flex items-baseline gap-1 text-2xl font-bold tracking-tight\">\n              <span class=\"text-foreground tabular-nums\">$6,840.00</span>\n              <span class=\"text-muted-foreground text-xs font-normal tabular-nums\">/ $8,500.00</span>\n            </div>\n            <div class=\"mt-2 space-y-1\">\n              <Progress :model-value=\"80.5\" class=\"[&_[data-slot=progress-indicator]]:bg-warning h-2\" />\n            </div>\n          </div>\n          <div class=\"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 class=\"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 class=\"flex flex-col justify-between shadow-xs\">\n        <CardHeader class=\"pb-2\">\n          <div class=\"flex items-center justify-between gap-2\">\n            <div class=\"flex items-center gap-2\">\n              <div\n                class=\"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                aria-hidden=\"true\"\n              >\n                <PiggyBank class=\"size-4\" />\n              </div>\n              <CardTitle class=\"text-muted-foreground text-xs font-medium\">Savings Allocated</CardTitle>\n            </div>\n            <Badge variant=\"success\" class=\"text-xs tabular-nums\">19.5% Rate</Badge>\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-2\">\n          <div>\n            <div class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">$1,660.00</div>\n            <div class=\"mt-2 space-y-1\">\n              <Progress :model-value=\"89.3\" class=\"[&_[data-slot=progress-indicator]]:bg-success h-2\" />\n            </div>\n          </div>\n          <div class=\"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 class=\"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 class=\"flex flex-col justify-between shadow-xs\">\n        <CardHeader class=\"pb-2\">\n          <div class=\"flex items-center justify-between gap-2\">\n            <div class=\"flex items-center gap-2\">\n              <div\n                class=\"bg-muted text-muted-foreground border-border flex size-8 shrink-0 items-center justify-center rounded-lg border shadow-xs\"\n                aria-hidden=\"true\"\n              >\n                <Clock class=\"size-4\" />\n              </div>\n              <CardTitle class=\"text-muted-foreground text-xs font-medium\">Month Pace</CardTitle>\n            </div>\n            <Badge variant=\"outline\" class=\"text-xs font-normal tabular-nums\">Day 21 of 31</Badge>\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-2\">\n          <div>\n            <div class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">10 Days left</div>\n            <div class=\"mt-2 space-y-1\">\n              <Progress :model-value=\"67.7\" class=\"h-2\" />\n            </div>\n          </div>\n          <div class=\"border-border/60 text-muted-foreground flex items-center justify-between border-t pt-2 text-xs\">\n            <span>Cycle Elapsed</span>\n            <span class=\"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 class=\"space-y-6\">\n      <Card v-for=\"section in sections\" :key=\"section.id\" class=\"overflow-hidden shadow-xs\">\n        <CardHeader class=\"bg-muted/20 border-border border-b py-4\">\n          <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n            <div class=\"space-y-0.5\">\n              <div class=\"flex items-center gap-2\">\n                <component :is=\"section.icon\" class=\"text-muted-foreground size-4 shrink-0\" />\n                <CardTitle class=\"text-base font-semibold\">{{ section.title }}</CardTitle>\n              </div>\n              <CardDescription class=\"text-xs\">\n                {{ section.description }}\n              </CardDescription>\n            </div>\n            <div class=\"flex items-center gap-3 text-xs\">\n              <div class=\"bg-background border-border flex items-center gap-2 rounded-md border px-3 py-1.5 shadow-2xs\">\n                <span class=\"text-muted-foreground\">Subtotal:</span>\n                <span class=\"text-foreground font-semibold tabular-nums\">{{ formatCurrency(section.totalSpent) }}</span>\n                <span class=\"text-muted-foreground\">/</span>\n                <span class=\"text-muted-foreground font-medium tabular-nums\">{{\n                  formatCurrency(section.totalBudgeted)\n                }}</span>\n              </div>\n            </div>\n          </div>\n        </CardHeader>\n\n        <CardContent class=\"p-0\">\n          <div class=\"overflow-x-auto\">\n            <Table>\n              <TableHeader>\n                <TableRow class=\"hover:bg-transparent\">\n                  <TableHead class=\"min-w-[240px] text-xs font-semibold\">Envelope Category</TableHead>\n                  <TableHead class=\"text-right text-xs font-semibold\">{{\n                    section.id === 'savings-investments' ? 'Monthly Target' : 'Budgeted'\n                  }}</TableHead>\n                  <TableHead class=\"text-right text-xs font-semibold\">{{\n                    section.id === 'savings-investments' ? 'Funded to Date' : 'Spent to Date'\n                  }}</TableHead>\n                  <TableHead class=\"text-right text-xs font-semibold\">{{\n                    section.id === 'savings-investments' ? 'Remaining to Goal' : 'Available Balance'\n                  }}</TableHead>\n                  <TableHead class=\"min-w-[180px] text-xs font-semibold\">Progress & Pace</TableHead>\n                  <TableHead class=\"w-[110px] text-right text-xs font-semibold\">Status</TableHead>\n                </TableRow>\n              </TableHeader>\n              <TableBody>\n                <TableRow v-for=\"cat in section.categories\" :key=\"cat.id\" class=\"hover:bg-muted/40 transition-colors\">\n                  <!-- Envelope Category & Note -->\n                  <TableCell class=\"py-3.5\">\n                    <div class=\"flex items-start gap-3\">\n                      <div\n                        class=\"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                        aria-hidden=\"true\"\n                      >\n                        <component :is=\"cat.icon\" class=\"size-4\" />\n                      </div>\n                      <div class=\"space-y-0.5\">\n                        <p class=\"text-foreground text-xs font-semibold\">{{ cat.name }}</p>\n                        <p class=\"text-muted-foreground text-xs\">{{ cat.note }}</p>\n                      </div>\n                    </div>\n                  </TableCell>\n\n                  <!-- Budgeted Amount -->\n                  <TableCell class=\"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 class=\"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 class=\"py-3.5 text-right text-xs\">\n                    <span\n                      :class=\"[\n                        'font-bold tabular-nums',\n                        cat.budgeted - cat.spent === 0\n                          ? 'text-muted-foreground'\n                          : cat.status === 'warning'\n                            ? 'text-warning'\n                            : 'text-success',\n                      ]\"\n                    >\n                      {{ formatCurrency(cat.budgeted - cat.spent) }}\n                    </span>\n                  </TableCell>\n\n                  <!-- Progress Bar & Percentage -->\n                  <TableCell class=\"py-3.5\">\n                    <div class=\"space-y-1.5\">\n                      <div class=\"flex items-center justify-between text-xs\">\n                        <span class=\"text-muted-foreground tabular-nums\">\n                          {{ Math.round((cat.spent / cat.budgeted) * 100) }}% {{ cat.isSavings ? 'funded' : 'used' }}\n                        </span>\n                        <span class=\"text-muted-foreground text-xs tabular-nums\">\n                          {{ formatCurrency(cat.spent) }}\n                        </span>\n                      </div>\n                      <Progress\n                        :model-value=\"Math.min(100, Math.round((cat.spent / cat.budgeted) * 100))\"\n                        :class=\"cn('h-1.5', getProgressColor(cat.status))\"\n                      />\n                    </div>\n                  </TableCell>\n\n                  <!-- Status Badge -->\n                  <TableCell class=\"py-3.5 text-right\">\n                    <Badge :variant=\"getBadgeVariant(cat.status)\" class=\"text-xs\">\n                      {{ cat.statusLabel }}\n                    </Badge>\n                  </TableCell>\n                </TableRow>\n              </TableBody>\n            </Table>\n          </div>\n        </CardContent>\n      </Card>\n    </div>\n\n    <!-- Zero-Based Budgeting Philosophy & Rules Card -->\n    <Card class=\"bg-muted/20 border-border p-4 shadow-xs\">\n      <div class=\"flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n        <div class=\"flex items-start gap-3\">\n          <div\n            class=\"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            aria-hidden=\"true\"\n          >\n            <CheckCircle2 class=\"size-4\" />\n          </div>\n          <div class=\"space-y-0.5\">\n            <h4 class=\"text-foreground text-xs font-semibold\">Zero-Based Allocation Completed</h4>\n            <p class=\"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 class=\"flex shrink-0 items-center gap-2\">\n          <Badge variant=\"outline\" class=\"text-xs font-normal\"> Next Payday: Sep 1, 2026 </Badge>\n        </div>\n      </div>\n    </Card>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/PersonalFinanceBudget.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/progress.json",
    "https://uipkge.dev/r/vue/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"
  ]
}