{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "roi-calculator-inputs",
  "title": "ROI — Calculator",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/roi-calculator-inputs/RoiCalculatorInputs.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, reactive } from 'vue'\nimport { ArrowRight } from 'lucide-vue-next'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent } from '@/components/ui/card'\nimport { Separator } from '@/components/ui/separator'\nimport { Slider } from '@/components/ui/slider'\n\n// One reactive model keyed by input id. Refs nested inside a computed array do\n// not unwrap in the template, so v-model against them silently fails to write.\nconst model = reactive<Record<string, number[]>>({\n  analysts: [6],\n  days: [9],\n  rate: [520],\n})\n\n// Stating the model beneath the number is what stops this reading as a toy.\n// Every figure below is derived from the three inputs and nothing else.\nconst DAYS_SAVED_SHARE = 0.55\nconst CLOSES_PER_YEAR = 12\n\nconst inputs = [\n  { id: 'analysts', label: 'People involved in close', min: 1, max: 40, step: 1, format: (v: number) => `${v}` },\n  { id: 'days', label: 'Days the close takes today', min: 2, max: 20, step: 1, format: (v: number) => `${v} days` },\n  { id: 'rate', label: 'Fully-loaded day rate', min: 200, max: 1200, step: 20, format: (v: number) => `£${v}` },\n]\n\nconst daysSaved = computed(() => Math.round(model.days[0] * DAYS_SAVED_SHARE * 10) / 10)\nconst annualSaving = computed(() => Math.round(daysSaved.value * CLOSES_PER_YEAR * model.analysts[0] * model.rate[0]))\nconst formatted = computed(() => `£${annualSaving.value.toLocaleString('en-GB')}`)\n</script>\n\n<template>\n  <section data-slot=\"roi-calculator-inputs\" class=\"bg-background\">\n    <div class=\"mx-auto max-w-4xl px-6 py-20 lg:py-28\">\n      <div class=\"max-w-2xl\">\n        <Badge variant=\"secondary\">Estimate</Badge>\n        <h2 class=\"mt-4 text-3xl font-semibold tracking-tight sm:text-4xl\">What the close currently costs you</h2>\n        <p class=\"text-muted-foreground mt-3 text-lg\">\n          Three inputs, one arithmetic model, stated in full underneath. Adjust anything that looks wrong.\n        </p>\n      </div>\n\n      <Card class=\"mt-10\">\n        <CardContent class=\"grid gap-8 p-6 sm:grid-cols-[1.2fr_1fr] sm:p-8\">\n          <div class=\"space-y-6\">\n            <div v-for=\"input in inputs\" :key=\"input.id\">\n              <div class=\"flex items-baseline justify-between gap-4\">\n                <label :for=\"input.id\" class=\"text-sm font-medium\">{{ input.label }}</label>\n                <span class=\"font-mono text-sm tabular-nums\">{{ input.format(model[input.id][0]) }}</span>\n              </div>\n              <Slider\n                :id=\"input.id\"\n                v-model=\"model[input.id]\"\n                :min=\"input.min\"\n                :max=\"input.max\"\n                :step=\"input.step\"\n                class=\"mt-3\"\n                :aria-label=\"input.label\"\n              />\n            </div>\n          </div>\n\n          <div class=\"border-border bg-muted/30 flex flex-col justify-center rounded-lg border p-6 text-center\">\n            <p class=\"text-muted-foreground text-xs tracking-wide uppercase\">Estimated annual saving</p>\n            <p class=\"font-display mt-2 text-4xl font-bold tracking-tight tabular-nums\">{{ formatted }}</p>\n            <p class=\"text-muted-foreground mt-2 text-xs\">\n              {{ daysSaved }} days saved per close, {{ CLOSES_PER_YEAR }} closes a year\n            </p>\n            <Button class=\"mt-5\">\n              Check it against your numbers\n              <ArrowRight class=\"ml-2 size-4\" aria-hidden=\"true\" />\n            </Button>\n          </div>\n        </CardContent>\n\n        <Separator />\n\n        <div class=\"px-6 py-4 sm:px-8\">\n          <p class=\"text-muted-foreground text-xs leading-relaxed\">\n            <span class=\"font-medium\">The model. </span>\n            Saving = days saved × closes per year × people × day rate, where days saved assumes\n            {{ Math.round(DAYS_SAVED_SHARE * 100) }}% of close time is reconciliation that certified definitions remove.\n            That share is the median across 240 rollouts; yours will differ, and the figure is only as good as that\n            assumption.\n          </p>\n        </div>\n      </Card>\n    </div>\n  </section>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/RoiCalculatorInputs.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/separator.json",
    "https://uipkge.dev/r/vue/slider.json"
  ],
  "description": "Input-driven ROI estimate where team size, close days, and analyst rate drive a computed saving, with the assumptions stated beneath the figure.",
  "categories": [
    "marketing"
  ]
}