{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "subscription-churn-analytics",
  "title": "Subscription Churn Analytics",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/subscription-churn-analytics/SubscriptionChurnAnalytics.vue",
      "content": "<script setup lang=\"ts\">\nimport { ref } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport {\n  AlertCircle,\n  ArrowDownRight,\n  ArrowUpRight,\n  Calendar,\n  CheckCircle2,\n  DollarSign,\n  Download,\n  PhoneCall,\n  RefreshCw,\n  RotateCcw,\n  TrendingDown,\n  TrendingUp,\n  UserMinus,\n  UserPlus,\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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { Separator } from '@/components/ui/separator'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\n\ninterface Props {\n  class?: HTMLAttributes['class']\n}\n\nconst props = defineProps<Props>()\n\nconst selectedRange = ref('90d')\n\nconst primaryMetrics = [\n  {\n    id: 'net-mrr',\n    label: 'Net MRR Growth',\n    value: '+$12,480',\n    unit: '/ mo',\n    badge: '+8.4%',\n    badgeVariant: 'success' as const,\n    badgeIcon: TrendingUp,\n    description: 'Gross additions outpacing cancellations by 6.8x',\n  },\n  {\n    id: 'user-churn',\n    label: 'User Churn Rate',\n    value: '1.8%',\n    unit: '/ mo',\n    badge: 'Below 2% benchmark',\n    badgeVariant: 'success' as const,\n    badgeIcon: CheckCircle2,\n    description: 'Logo churn down 0.4% from previous quarter',\n  },\n  {\n    id: 'revenue-churn',\n    label: 'Revenue Churn Rate',\n    value: '0.9%',\n    unit: '/ mo',\n    badge: 'Negative Net Churn',\n    badgeVariant: 'outline' as const,\n    badgeIcon: TrendingDown,\n    description: 'Expansion ($6,450) exceeds total churn ($2,170)',\n  },\n  {\n    id: 'ltv',\n    label: 'Customer Lifetime Value',\n    value: '$4,850.00',\n    unit: '',\n    badge: 'CAC Payback 4.2 mo',\n    badgeVariant: 'secondary' as const,\n    badgeIcon: DollarSign,\n    description: '3.4x LTV to CAC ratio across active cohort',\n  },\n]\n\nconst mrrWaterfall = [\n  {\n    id: 'new',\n    label: 'New Subscriptions',\n    amount: '+$8,200.00',\n    impact: 'positive' as const,\n    share: '52.9%',\n    count: '38 new accounts',\n    colorClass: 'text-success',\n    badgeClass: 'bg-success/10 text-success border-success/20',\n    barClass: 'bg-success',\n    icon: UserPlus,\n  },\n  {\n    id: 'expansion',\n    label: 'Expansion / Upgrades',\n    amount: '+$6,450.00',\n    impact: 'positive' as const,\n    share: '41.6%',\n    count: '24 accounts expanded',\n    colorClass: 'text-success',\n    badgeClass: 'bg-success/10 text-success border-success/20',\n    barClass: 'bg-success/80',\n    icon: ArrowUpRight,\n  },\n  {\n    id: 'contraction',\n    label: 'Contraction / Downgrades',\n    amount: '-$1,120.00',\n    impact: 'warning' as const,\n    share: '7.2%',\n    count: '9 tier downgrades',\n    colorClass: 'text-warning',\n    badgeClass: 'bg-warning/10 text-warning border-warning/20',\n    barClass: 'bg-warning',\n    icon: ArrowDownRight,\n  },\n  {\n    id: 'churn',\n    label: 'Churn / Cancellations',\n    amount: '-$1,050.00',\n    impact: 'negative' as const,\n    share: '6.8%',\n    count: '7 accounts lost',\n    colorClass: 'text-destructive',\n    badgeClass: 'bg-destructive/10 text-destructive border-destructive/20',\n    barClass: 'bg-destructive',\n    icon: UserMinus,\n  },\n  {\n    id: 'reactivations',\n    label: 'Reactivations',\n    amount: '+$850.00',\n    impact: 'info' as const,\n    share: '5.5%',\n    count: '4 win-back returns',\n    colorClass: 'text-info',\n    badgeClass: 'bg-info/10 text-info border-info/20',\n    barClass: 'bg-info bg-info',\n    icon: RefreshCw,\n  },\n]\n\nconst churnReasons = [\n  {\n    id: 'competitor',\n    reason: 'Switched to competitor',\n    category: 'Product Fit / Competition',\n    share: 38,\n    lostArr: '-$24,800.00',\n    accounts: 19,\n    trend: 'Increasing',\n    trendDelta: '+12% QoQ',\n    trendVariant: 'destructive' as const,\n  },\n  {\n    id: 'budget',\n    reason: 'Budget constraints',\n    category: 'Economic / Spend Freeze',\n    share: 28,\n    lostArr: '-$18,300.00',\n    accounts: 14,\n    trend: 'Decreasing',\n    trendDelta: '-8% QoQ',\n    trendVariant: 'success' as const,\n  },\n  {\n    id: 'missing-sso',\n    reason: 'Missing feature: SAML SSO',\n    category: 'Security / Compliance',\n    share: 21,\n    lostArr: '-$13,750.00',\n    accounts: 8,\n    trend: 'Decreasing',\n    trendDelta: '-15% QoQ',\n    trendVariant: 'success' as const,\n  },\n  {\n    id: 'project-ended',\n    reason: 'Project ended',\n    category: 'Seasonal / Lifecycle',\n    share: 13,\n    lostArr: '-$8,500.00',\n    accounts: 6,\n    trend: 'Increasing',\n    trendDelta: '+4% QoQ',\n    trendVariant: 'warning' as const,\n  },\n]\n\nconst quickActions = [\n  {\n    id: 'winback',\n    title: 'Trigger Discount Win-Back Campaign',\n    description: 'Dispatch automated 20% annual renewal incentives to 25 accounts canceled within the last 45 days.',\n    impactBadge: 'Est. $4,800 MRR recovered',\n    buttonText: 'Trigger Win-Back',\n    buttonVariant: 'default' as const,\n    icon: RotateCcw,\n  },\n  {\n    id: 'interviews',\n    title: 'Schedule Exit Discovery Interviews',\n    description:\n      'Book 15-minute product alignment calls with churned enterprise accounts ($10k+ ARR) for feature feedback.',\n    impactBadge: '3 enterprise accounts flagged',\n    buttonText: 'Schedule Interviews',\n    buttonVariant: 'outline' as const,\n    icon: PhoneCall,\n  },\n  {\n    id: 'health-alerts',\n    title: 'Configure Churn Risk Telemetry Alerts',\n    description: 'Automate high-priority notifications when weekly active seat engagement drops below 40% threshold.',\n    impactBadge: '12 accounts in risk zone',\n    buttonText: 'Configure Triggers',\n    buttonVariant: 'outline' as const,\n    icon: AlertCircle,\n  },\n]\n</script>\n\n<template>\n  <div data-uipkge data-slot=\"subscription-churn-analytics\" :class=\"cn('w-full space-y-6', props.class)\">\n    <!-- Header Section -->\n    <div class=\"flex flex-col gap-4 md:flex-row md:items-center md:justify-between\">\n      <div class=\"space-y-1\">\n        <div class=\"flex items-center gap-2\">\n          <h2 class=\"text-foreground text-xl font-bold tracking-tight sm:text-2xl\">\n            Subscription Churn &amp; MRR Analytics\n          </h2>\n          <Badge variant=\"outline\" class=\"border-border text-muted-foreground hidden font-mono text-xs sm:inline-flex\">\n            SaaS Metrics\n          </Badge>\n        </div>\n        <p class=\"text-muted-foreground text-sm\">\n          Track recurring revenue dynamics, logo retention cohorts, and cancellation root causes.\n        </p>\n      </div>\n\n      <div class=\"flex flex-wrap items-center gap-3\">\n        <div class=\"w-44\">\n          <Select v-model=\"selectedRange\">\n            <SelectTrigger size=\"sm\" class=\"w-full\">\n              <Calendar class=\"text-muted-foreground mr-1 size-3.5\" aria-hidden=\"true\" />\n              <SelectValue placeholder=\"Select period\" />\n            </SelectTrigger>\n            <SelectContent>\n              <SelectItem value=\"30d\">Last 30 Days</SelectItem>\n              <SelectItem value=\"90d\">Last 90 Days</SelectItem>\n              <SelectItem value=\"12m\">Last 12 Months</SelectItem>\n              <SelectItem value=\"ytd\">Year to Date</SelectItem>\n            </SelectContent>\n          </Select>\n        </div>\n\n        <Button aria-label=\"Download attachment\" size=\"sm\" variant=\"outline\" class=\"gap-2 shadow-xs\">\n          <Download class=\"text-muted-foreground size-4\" aria-hidden=\"true\" />\n          <span>Export Retention Report</span>\n        </Button>\n      </div>\n    </div>\n\n    <!-- 4 Primary SaaS Metrics Cards -->\n    <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n      <Card\n        v-for=\"metric in primaryMetrics\"\n        :key=\"metric.id\"\n        class=\"border-border bg-card hover:border-border/80 shadow-xs transition-colors\"\n      >\n        <CardHeader class=\"pb-2\">\n          <div class=\"flex items-center justify-between gap-2\">\n            <CardTitle class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">\n              {{ metric.label }}\n            </CardTitle>\n            <Badge :variant=\"metric.badgeVariant\" class=\"gap-1 font-medium tabular-nums\">\n              <component :is=\"metric.badgeIcon\" class=\"size-3\" aria-hidden=\"true\" />\n              <span>{{ metric.badge }}</span>\n            </Badge>\n          </div>\n        </CardHeader>\n        <CardContent class=\"space-y-1 pb-4\">\n          <div class=\"flex items-baseline gap-1\">\n            <span class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums sm:text-3xl\">\n              {{ metric.value }}\n            </span>\n            <span v-if=\"metric.unit\" class=\"text-muted-foreground text-xs font-normal\">\n              {{ metric.unit }}\n            </span>\n          </div>\n          <p class=\"text-muted-foreground text-xs leading-relaxed\">\n            {{ metric.description }}\n          </p>\n        </CardContent>\n      </Card>\n    </div>\n\n    <!-- MRR Movement Waterfall Breakdown Card -->\n    <Card class=\"border-border bg-card shadow-xs\">\n      <CardHeader class=\"pb-4\">\n        <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n          <div>\n            <div class=\"flex items-center gap-2\">\n              <CardTitle class=\"text-foreground text-base font-semibold\"> MRR Movement Waterfall Breakdown </CardTitle>\n              <Badge variant=\"outline\" class=\"border-border bg-muted/30 text-xs font-medium\"> ChartMogul Bridge </Badge>\n            </div>\n            <CardDescription class=\"mt-1 text-xs\">\n              Decomposition of new customer revenue, expansion, contractions, logo churn, and reactivations.\n            </CardDescription>\n          </div>\n          <div\n            class=\"border-border/80 bg-muted/20 flex items-center gap-2 self-start rounded-lg border px-3 py-1.5 sm:self-auto\"\n          >\n            <span class=\"text-muted-foreground text-xs font-medium\">Net MRR Change:</span>\n            <span class=\"text-success text-sm font-bold tabular-nums\">+$13,330.00</span>\n            <Badge variant=\"success\" class=\"ml-1 text-xs\"> +9.3% </Badge>\n          </div>\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"space-y-6\">\n        <!-- Visual Waterfall Proportional Bar -->\n        <div class=\"space-y-2\">\n          <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n            <span>Starting MRR: <strong class=\"text-foreground font-semibold tabular-nums\">$142,500.00</strong></span>\n            <span>Ending MRR: <strong class=\"text-foreground font-semibold tabular-nums\">$155,830.00</strong></span>\n          </div>\n          <div class=\"bg-muted/60 flex h-3 w-full overflow-hidden rounded-full p-0.5 shadow-inner\">\n            <div\n              class=\"bg-success h-full rounded-l-full transition-[width] duration-300\"\n              style=\"width: 48%\"\n              title=\"New Subscriptions (+$8,200.00)\"\n            />\n            <div\n              class=\"bg-success/90 h-full transition-[width] duration-300\"\n              style=\"width: 38%\"\n              title=\"Expansion (+$6,450.00)\"\n            />\n            <div\n              class=\"bg-info h-full transition-[width] duration-300\"\n              style=\"width: 5%\"\n              title=\"Reactivations (+$850.00)\"\n            />\n            <div\n              class=\"bg-warning h-full transition-[width] duration-300\"\n              style=\"width: 5%\"\n              title=\"Contraction (-$1,120.00)\"\n            />\n            <div\n              class=\"bg-destructive h-full rounded-r-full transition-[width] duration-300\"\n              style=\"width: 4%\"\n              title=\"Churn (-$1,050.00)\"\n            />\n          </div>\n          <div class=\"text-muted-foreground flex flex-wrap items-center justify-between gap-2 pt-1 text-xs\">\n            <div class=\"flex items-center gap-1.5\">\n              <span class=\"bg-success inline-block size-2 rounded-full\" />\n              <span>New (+$8.2k)</span>\n            </div>\n            <div class=\"flex items-center gap-1.5\">\n              <span class=\"bg-success inline-block size-2 rounded-full\" />\n              <span>Expansion (+$6.45k)</span>\n            </div>\n            <div class=\"flex items-center gap-1.5\">\n              <span class=\"bg-info inline-block size-2 rounded-full\" />\n              <span>Reactivation (+$850)</span>\n            </div>\n            <div class=\"flex items-center gap-1.5\">\n              <span class=\"bg-warning inline-block size-2 rounded-full\" />\n              <span>Contraction (-$1.12k)</span>\n            </div>\n            <div class=\"flex items-center gap-1.5\">\n              <span class=\"bg-destructive inline-block size-2 rounded-full\" />\n              <span>Churn (-$1.05k)</span>\n            </div>\n          </div>\n        </div>\n\n        <Separator class=\"border-border\" />\n\n        <!-- Detailed Waterfall Grid -->\n        <div class=\"grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3\">\n          <div\n            v-for=\"item in mrrWaterfall\"\n            :key=\"item.id\"\n            class=\"border-border bg-card/60 hover:bg-muted/20 flex items-start justify-between rounded-lg border p-3.5 shadow-xs transition-colors\"\n          >\n            <div class=\"flex items-start gap-3\">\n              <div\n                class=\"border-border flex size-9 shrink-0 items-center justify-center rounded-md border shadow-xs\"\n                :class=\"item.badgeClass\"\n              >\n                <component :is=\"item.icon\" class=\"size-4\" aria-hidden=\"true\" />\n              </div>\n              <div class=\"space-y-0.5\">\n                <p class=\"text-foreground text-xs font-semibold\">{{ item.label }}</p>\n                <p class=\"text-muted-foreground text-xs\">{{ item.count }}</p>\n              </div>\n            </div>\n            <div class=\"text-right\">\n              <p class=\"text-sm font-bold tabular-nums\" :class=\"item.colorClass\">\n                {{ item.amount }}\n              </p>\n              <span class=\"text-muted-foreground text-xs tabular-nums\"> {{ item.share }} gross </span>\n            </div>\n          </div>\n\n          <!-- Net Summary Tile -->\n          <div\n            class=\"border-success/30 bg-success/5 flex items-start justify-between rounded-lg border p-3.5 shadow-xs\"\n          >\n            <div class=\"flex items-start gap-3\">\n              <div\n                class=\"border-success/30 bg-success/15 text-success flex size-9 shrink-0 items-center justify-center rounded-md border shadow-xs\"\n              >\n                <TrendingUp class=\"size-4\" aria-hidden=\"true\" />\n              </div>\n              <div class=\"space-y-0.5\">\n                <p class=\"text-foreground text-xs font-semibold\">Net MRR Movement</p>\n                <p class=\"text-muted-foreground text-xs\">All streams combined</p>\n              </div>\n            </div>\n            <div class=\"text-right\">\n              <p class=\"text-success text-sm font-bold tabular-nums\">+$13,330.00</p>\n              <Badge variant=\"success\" class=\"text-xs tabular-nums\"> Net Positive </Badge>\n            </div>\n          </div>\n        </div>\n      </CardContent>\n    </Card>\n\n    <!-- Churn Reason Distribution Table -->\n    <Card class=\"border-border bg-card shadow-xs\">\n      <CardHeader class=\"pb-3\">\n        <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n          <div>\n            <CardTitle class=\"text-foreground text-base font-semibold\">\n              Churn Reason Distribution &amp; Lost ARR Attribution\n            </CardTitle>\n            <CardDescription class=\"mt-1 text-xs\">\n              Primary cancellation drivers captured via post-cancellation exit surveys and customer success logs.\n            </CardDescription>\n          </div>\n          <div class=\"flex items-center gap-2\">\n            <span class=\"text-muted-foreground text-xs\">Total Lost ARR:</span>\n            <span class=\"text-destructive text-sm font-bold tabular-nums\">-$65,350.00</span>\n          </div>\n        </div>\n      </CardHeader>\n      <CardContent class=\"p-0\">\n        <div class=\"overflow-x-auto\">\n          <Table>\n            <TableHeader class=\"bg-muted/40\">\n              <TableRow class=\"border-border hover:bg-transparent\">\n                <TableHead class=\"text-foreground text-xs font-semibold\">Cancellation Reason</TableHead>\n                <TableHead class=\"text-foreground text-xs font-semibold\">Distribution Share</TableHead>\n                <TableHead class=\"text-foreground text-right text-xs font-semibold\">Lost ARR ($)</TableHead>\n                <TableHead class=\"text-foreground text-right text-xs font-semibold\">Impacted Accounts</TableHead>\n                <TableHead class=\"text-foreground text-right text-xs font-semibold\">Quarterly Trend</TableHead>\n              </TableRow>\n            </TableHeader>\n            <TableBody>\n              <TableRow\n                v-for=\"row in churnReasons\"\n                :key=\"row.id\"\n                class=\"border-border hover:bg-muted/30 transition-colors\"\n              >\n                <TableCell class=\"py-3.5\">\n                  <div class=\"text-foreground text-sm font-medium\">{{ row.reason }}</div>\n                  <div class=\"text-muted-foreground text-xs\">{{ row.category }}</div>\n                </TableCell>\n                <TableCell class=\"min-w-[180px] py-3.5\">\n                  <div class=\"space-y-1.5\">\n                    <div class=\"flex items-center justify-between text-xs\">\n                      <span class=\"text-foreground font-medium tabular-nums\">{{ row.share }}%</span>\n                      <span class=\"text-muted-foreground text-xs\">of total churn</span>\n                    </div>\n                    <Progress :model-value=\"row.share\" class=\"bg-muted h-1.5\" />\n                  </div>\n                </TableCell>\n                <TableCell class=\"text-foreground py-3.5 text-right text-sm font-semibold tabular-nums\">\n                  {{ row.lostArr }}\n                </TableCell>\n                <TableCell class=\"text-muted-foreground py-3.5 text-right text-xs tabular-nums\">\n                  <span class=\"text-foreground font-medium\">{{ row.accounts }}</span> accounts\n                </TableCell>\n                <TableCell class=\"py-3.5 text-right\">\n                  <Badge :variant=\"row.trendVariant\" class=\"gap-1 text-xs font-medium tabular-nums\">\n                    <span>{{ row.trend === 'Increasing' ? '↑' : '↓' }}</span>\n                    <span>{{ row.trend }}</span>\n                    <span class=\"opacity-75\">({{ row.trendDelta }})</span>\n                  </Badge>\n                </TableCell>\n              </TableRow>\n            </TableBody>\n          </Table>\n        </div>\n      </CardContent>\n    </Card>\n\n    <!-- Churn Prevention Quick Actions -->\n    <Card class=\"border-border bg-card shadow-xs\">\n      <CardHeader class=\"pb-3\">\n        <div class=\"flex items-center gap-2\">\n          <CardTitle class=\"text-foreground text-base font-semibold\">\n            Churn Prevention &amp; Win-Back Quick Actions\n          </CardTitle>\n          <Badge variant=\"secondary\" class=\"text-xs\"> Playbooks </Badge>\n        </div>\n        <CardDescription class=\"text-xs\">\n          High-leverage intervention workflows to stem revenue loss and re-engage churned customer cohorts.\n        </CardDescription>\n      </CardHeader>\n      <CardContent>\n        <div class=\"grid grid-cols-1 gap-4 md:grid-cols-3\">\n          <div\n            v-for=\"action in quickActions\"\n            :key=\"action.id\"\n            class=\"border-border bg-card/60 hover:border-border/80 hover:bg-muted/10 flex flex-col justify-between rounded-lg border p-4 shadow-xs transition-colors\"\n          >\n            <div class=\"space-y-3\">\n              <div class=\"flex items-center justify-between\">\n                <div\n                  class=\"border-border bg-muted/40 text-foreground flex size-9 items-center justify-center rounded-md border shadow-xs\"\n                >\n                  <component :is=\"action.icon\" class=\"size-4\" aria-hidden=\"true\" />\n                </div>\n                <Badge variant=\"outline\" class=\"border-border text-muted-foreground font-mono text-xs\">\n                  {{ action.impactBadge }}\n                </Badge>\n              </div>\n              <div class=\"space-y-1\">\n                <h4 class=\"text-foreground text-sm leading-snug font-semibold\">\n                  {{ action.title }}\n                </h4>\n                <p class=\"text-muted-foreground text-xs leading-relaxed\">\n                  {{ action.description }}\n                </p>\n              </div>\n            </div>\n\n            <div class=\"mt-4 pt-2\">\n              <Button :variant=\"action.buttonVariant\" size=\"sm\" class=\"w-full gap-2 shadow-xs\">\n                <component :is=\"action.icon\" class=\"size-3.5\" aria-hidden=\"true\" />\n                <span>{{ action.buttonText }}</span>\n              </Button>\n            </div>\n          </div>\n        </div>\n      </CardContent>\n    </Card>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/SubscriptionChurnAnalytics.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/select.json",
    "https://uipkge.dev/r/vue/separator.json",
    "https://uipkge.dev/r/vue/table.json"
  ],
  "description": "ChartMogul and Baremetrics style SaaS subscription churn and MRR analytics dashboard. Features 4 key SaaS metrics cards (Net MRR growth, logo churn rate, net revenue churn, and LTV/CAC), an MRR movement waterfall decomposition bridge, a churn reasons distribution table with lost ARR attribution and trend indicators, and automated churn prevention playbook quick actions.",
  "categories": [
    "analytics",
    "fintech",
    "dashboard"
  ]
}