{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "case-study",
  "title": "Case Study",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/case-study/CaseStudyFeaturedStory.tsx",
      "content": "'use client'\n\nimport { ArrowRight, Quote } from 'lucide-react'\nimport { Avatar, AvatarFallback } from '@/components/ui/avatar'\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'\n\nconst results = [\n  { value: '5 days', label: 'off the monthly close' },\n  { value: '11 → 1', label: 'reconciliation spreadsheets' },\n  { value: '340', label: 'certified metrics published' },\n  { value: '6 weeks', label: 'kickoff to full hand-over' },\n]\n\nconst facts = [\n  { term: 'Industry', detail: 'Freight forwarding' },\n  { term: 'Size', detail: '1,200 staff · 18 countries' },\n  { term: 'Stack', detail: 'Snowflake · dbt · Okta' },\n  { term: 'Live since', detail: 'Q1 2026' },\n]\n\nexport function CaseStudyFeaturedStory() {\n  return (\n    <section data-slot=\"case-study-featured-story\" className=\"bg-background\">\n      <div className=\"mx-auto max-w-6xl px-6 py-20 lg:py-28\">\n        <div className=\"grid gap-12 lg:grid-cols-[1.4fr_1fr] lg:gap-16\">\n          <article>\n            <Badge variant=\"secondary\">Case study</Badge>\n            <h2 className=\"mt-4 text-3xl font-semibold tracking-tight text-balance sm:text-4xl\">\n              How Northwind Logistics closed the books five days early\n            </h2>\n\n            <div className=\"mt-8 space-y-8\">\n              <div>\n                <h3 className=\"text-muted-foreground font-mono text-xs tracking-[0.14em] uppercase\">The challenge</h3>\n                <p className=\"mt-2.5 leading-relaxed\">\n                  Month-end ran on eleven spreadsheets maintained by four people across three time zones. Every close\n                  opened with a reconciliation pass nobody had budgeted for, and restatements were tracked in email.\n                </p>\n              </div>\n\n              <div>\n                <h3 className=\"text-muted-foreground font-mono text-xs tracking-[0.14em] uppercase\">The approach</h3>\n                <p className=\"mt-2.5 leading-relaxed\">\n                  We mirrored the warehouse schema, rebuilt revenue and margin as versioned definitions, and reconciled\n                  them against the prior four quarters before anything was published. A single regional team piloted the\n                  first close; the rest of finance moved over two weeks later.\n                </p>\n              </div>\n\n              <div>\n                <h3 className=\"text-muted-foreground font-mono text-xs tracking-[0.14em] uppercase\">The result</h3>\n                <p className=\"mt-2.5 leading-relaxed\">\n                  Close now starts from a reconciled position. Restatements open a reviewable change instead of a\n                  thread, and the audit pack is generated from the same history.\n                </p>\n              </div>\n            </div>\n\n            <figure className=\"border-border mt-10 border-l-2 pl-6\">\n              <Quote className=\"text-muted-foreground/60 size-5\" aria-hidden=\"true\" />\n              <blockquote className=\"mt-3 text-lg leading-snug font-medium text-balance\">\n                We stopped arguing about whose number was right and started arguing about what to do next. That is the\n                whole change, and it was worth the six weeks.\n              </blockquote>\n              <figcaption className=\"mt-5 flex items-center gap-3\">\n                <Avatar className=\"size-9\">\n                  <AvatarFallback className=\"text-xs\">EW</AvatarFallback>\n                </Avatar>\n                <div>\n                  <p className=\"text-sm font-medium\">Erin Walsh</p>\n                  <p className=\"text-muted-foreground text-xs\">VP Finance, Northwind Logistics</p>\n                </div>\n              </figcaption>\n            </figure>\n\n            <Button className=\"mt-10\">\n              Read the full story\n              <ArrowRight className=\"ml-2 size-4\" aria-hidden=\"true\" />\n            </Button>\n          </article>\n\n          {/* Sticky results panel: keeps the numbers in view while the narrative scrolls. */}\n          <aside className=\"lg:sticky lg:top-24 lg:self-start\">\n            <Card>\n              <CardContent className=\"p-6\">\n                <h3 className=\"text-muted-foreground font-mono text-xs tracking-[0.14em] uppercase\">Results</h3>\n                <dl className=\"mt-5 grid grid-cols-2 gap-x-4 gap-y-6\">\n                  {results.map((result) => (\n                    <div key={result.label}>\n                      <dt className=\"sr-only\">{result.label}</dt>\n                      <dd>\n                        <span className=\"font-display block text-2xl font-bold tracking-tight\">{result.value}</span>\n                        <span className=\"text-muted-foreground mt-1 block text-xs leading-snug\">{result.label}</span>\n                      </dd>\n                    </div>\n                  ))}\n                </dl>\n\n                <Separator className=\"my-6\" />\n\n                <dl className=\"space-y-3\">\n                  {facts.map((fact) => (\n                    <div key={fact.term} className=\"flex items-baseline justify-between gap-4 text-sm\">\n                      <dt className=\"text-muted-foreground\">{fact.term}</dt>\n                      <dd className=\"text-right font-medium\">{fact.detail}</dd>\n                    </div>\n                  ))}\n                </dl>\n              </CardContent>\n            </Card>\n          </aside>\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/case-study/CaseStudyFeaturedStory.tsx"
    },
    {
      "path": "packages/registry-react/blocks/case-study/CaseStudyFilterableList.tsx",
      "content": "'use client'\n\nimport { Fragment, useMemo, useState } from 'react'\nimport { ArrowUpRight } from 'lucide-react'\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 { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group'\n\nconst studies = [\n  {\n    company: 'Northwind Logistics',\n    industry: 'Logistics',\n    result: '5 days off the monthly close',\n    stack: 'Snowflake · dbt · Okta',\n    readTime: '8 min',\n  },\n  {\n    company: 'Halden Health',\n    industry: 'Healthcare',\n    result: '71% fewer ad-hoc data requests',\n    stack: 'BigQuery · Airflow',\n    readTime: '6 min',\n  },\n  {\n    company: 'Verity Retail Group',\n    industry: 'Retail',\n    result: '2.4pp tighter forecast band',\n    stack: 'Redshift · dbt',\n    readTime: '7 min',\n  },\n  {\n    company: 'Calder Manufacturing',\n    industry: 'Manufacturing',\n    result: '11 spreadsheets retired',\n    stack: 'Postgres · Dagster',\n    readTime: '5 min',\n  },\n  {\n    company: 'Ridgeway Freight',\n    industry: 'Logistics',\n    result: 'Per-shipment landed cost',\n    stack: 'Snowflake · Fivetran',\n    readTime: '9 min',\n  },\n  {\n    company: 'Ashford Clinics',\n    industry: 'Healthcare',\n    result: 'PHI-scoped self-serve reporting',\n    stack: 'BigQuery · Entra ID',\n    readTime: '6 min',\n  },\n]\n\nconst ALL = 'All'\nconst industries = [ALL, ...new Set(studies.map((study) => study.industry))]\n\nexport function CaseStudyFilterableList() {\n  const [active, setActive] = useState(ALL)\n  const visible = useMemo(\n    () => (active === ALL ? studies : studies.filter((study) => study.industry === active)),\n    [active],\n  )\n\n  return (\n    <section data-slot=\"case-study-filterable-list\" className=\"bg-background\">\n      <div className=\"mx-auto max-w-4xl px-6 py-20 lg:py-28\">\n        <div className=\"flex flex-wrap items-end justify-between gap-6\">\n          <div>\n            <Badge variant=\"secondary\">Customer stories</Badge>\n            <h2 className=\"mt-4 text-3xl font-semibold tracking-tight sm:text-4xl\">Read one close to your own</h2>\n          </div>\n\n          <ToggleGroup\n            value={active}\n            type=\"single\"\n            variant=\"outline\"\n            size=\"sm\"\n            className=\"flex-nowrap overflow-x-auto\"\n            aria-label=\"Filter case studies by industry\"\n            // Single-select emits '' when the pressed chip is pressed again;\n            // fall back to ALL so the list is never empty by accident.\n            onValueChange={(value: string) => setActive(value || ALL)}\n          >\n            {industries.map((industry) => (\n              <ToggleGroupItem key={industry} value={industry}>\n                {industry}\n              </ToggleGroupItem>\n            ))}\n          </ToggleGroup>\n        </div>\n\n        <Card className=\"mt-8\">\n          <CardContent className=\"p-2\">\n            {!visible.length ? (\n              <div className=\"px-4 py-16 text-center\">\n                <p className=\"text-sm font-medium\">No stories in that industry yet.</p>\n                <Button variant=\"outline\" size=\"sm\" className=\"mt-4\" onClick={() => setActive(ALL)}>\n                  Show all\n                </Button>\n              </div>\n            ) : (\n              <ul>\n                {visible.map((study, index) => (\n                  <Fragment key={study.company}>\n                    <li>\n                      <a\n                        href=\"#\"\n                        className=\"hover:bg-muted focus-visible:ring-ring group flex items-center gap-4 rounded-lg p-4 transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n                      >\n                        <div className=\"min-w-0 flex-1\">\n                          <div className=\"flex flex-wrap items-center gap-2\">\n                            <p className=\"text-sm font-semibold\">{study.company}</p>\n                            <Badge variant=\"outline\">{study.industry}</Badge>\n                          </div>\n                          <p className=\"mt-1 text-sm\">{study.result}</p>\n                          <p className=\"text-muted-foreground mt-1 font-mono text-xs\">{study.stack}</p>\n                        </div>\n                        <span className=\"text-muted-foreground shrink-0 text-xs\">{study.readTime}</span>\n                        <ArrowUpRight\n                          className=\"text-muted-foreground size-4 shrink-0 transition-transform group-hover:translate-x-0.5 group-hover:-translate-y-0.5\"\n                          aria-hidden=\"true\"\n                        />\n                      </a>\n                    </li>\n                    {index < visible.length - 1 && <Separator />}\n                  </Fragment>\n                ))}\n              </ul>\n            )}\n          </CardContent>\n        </Card>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/case-study/CaseStudyFilterableList.tsx"
    },
    {
      "path": "packages/registry-react/blocks/case-study/CaseStudyMetricCards.tsx",
      "content": "'use client'\n\nimport { ArrowUpRight } from 'lucide-react'\nimport { Avatar, AvatarFallback } from '@/components/ui/avatar'\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'\n\nconst studies = [\n  {\n    metric: '5 days',\n    metricLabel: 'off the monthly close',\n    company: 'Northwind Logistics',\n    industry: 'Freight forwarding · 1,200 staff',\n    outcome: 'Replaced eleven reconciliation spreadsheets with one certified revenue model.',\n    quote: 'We stopped arguing about whose number was right and started arguing about what to do next.',\n    author: { name: 'Erin Walsh', role: 'VP Finance', initials: 'EW' },\n  },\n  {\n    metric: '71%',\n    metricLabel: 'fewer ad-hoc data requests',\n    company: 'Halden Health',\n    industry: 'Provider network · 40 clinics',\n    outcome: 'Clinic leads self-serve their own quality metrics without filing a ticket.',\n    quote: 'The analytics team went from a request queue to actually building things again.',\n    author: { name: 'Daniel Brooks', role: 'Head of Analytics', initials: 'DB' },\n  },\n  {\n    metric: '2.4pp',\n    metricLabel: 'tighter forecast accuracy',\n    company: 'Verity Retail Group',\n    industry: 'Omnichannel retail · 310 stores',\n    outcome: 'Sales and finance now forecast off the same pipeline definition, snapshotted weekly.',\n    quote: 'Forecast review stopped opening with twenty minutes of reconciling two decks.',\n    author: { name: 'Priya Raman', role: 'RevOps Director', initials: 'PR' },\n  },\n]\n\nexport function CaseStudyMetricCards() {\n  return (\n    <section data-slot=\"case-study-metric-cards\" className=\"bg-background\">\n      <div className=\"mx-auto max-w-6xl px-6 py-20 lg:py-28\">\n        <div className=\"flex flex-wrap items-end justify-between gap-6\">\n          <div className=\"max-w-2xl\">\n            <Badge variant=\"secondary\">Customer results</Badge>\n            <h2 className=\"mt-4 text-3xl font-semibold tracking-tight sm:text-4xl\">What changed after the rollout</h2>\n            <p className=\"text-muted-foreground mt-3 text-lg\">\n              Three teams, measured against their own numbers from the quarter before.\n            </p>\n          </div>\n          <Button variant=\"outline\">All case studies</Button>\n        </div>\n\n        <div className=\"mt-10 grid gap-4 md:grid-cols-3\">\n          {studies.map((study) => (\n            <Card key={study.company} className=\"group\">\n              <CardContent className=\"flex h-full flex-col p-6\">\n                {/* Metric leads: it is the only part that survives a skim. */}\n                <p className=\"font-display text-4xl font-bold tracking-tight\">{study.metric}</p>\n                <p className=\"text-muted-foreground mt-1 text-sm\">{study.metricLabel}</p>\n\n                <Separator className=\"my-5\" />\n\n                <p className=\"text-sm font-semibold\">{study.company}</p>\n                <p className=\"text-muted-foreground mt-0.5 text-xs\">{study.industry}</p>\n                <p className=\"mt-4 text-sm leading-relaxed\">{study.outcome}</p>\n\n                <blockquote className=\"border-border text-muted-foreground mt-5 border-l-2 pl-4 text-sm italic\">\n                  “{study.quote}”\n                </blockquote>\n\n                <div className=\"mt-auto flex items-center gap-3 pt-6\">\n                  <Avatar className=\"size-8\">\n                    <AvatarFallback className=\"text-xs\">{study.author.initials}</AvatarFallback>\n                  </Avatar>\n                  <div className=\"min-w-0\">\n                    <p className=\"truncate text-sm font-medium\">{study.author.name}</p>\n                    <p className=\"text-muted-foreground truncate text-xs\">{study.author.role}</p>\n                  </div>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon\"\n                    className=\"ml-auto\"\n                    aria-label={`Read the ${study.company} case study`}\n                  >\n                    <ArrowUpRight\n                      className=\"size-4 transition-transform group-hover:translate-x-0.5 group-hover:-translate-y-0.5\"\n                      aria-hidden=\"true\"\n                    />\n                  </Button>\n                </div>\n              </CardContent>\n            </Card>\n          ))}\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/case-study/CaseStudyMetricCards.tsx"
    },
    {
      "path": "packages/registry-react/blocks/case-study/CaseStudyMetricComparison.tsx",
      "content": "'use client'\n\nimport { ArrowRight, TrendingDown, TrendingUp } from 'lucide-react'\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 { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\n\n// `better` records which direction is good, so the delta colour never has to be\n// hard-coded per row — a falling close time is good, falling accuracy is not.\nconst metrics = [\n  { name: 'Days to close', before: '9.4', after: '4.2', delta: '−55%', better: 'down' },\n  { name: 'Ad-hoc data requests / month', before: '212', after: '61', delta: '−71%', better: 'down' },\n  { name: 'Certified metrics published', before: '0', after: '340', delta: '+340', better: 'up' },\n  { name: 'Forecast accuracy band', before: '±6.1pp', after: '±3.7pp', delta: '−2.4pp', better: 'down' },\n]\n\nexport function CaseStudyMetricComparison() {\n  return (\n    <section data-slot=\"case-study-metric-comparison\" className=\"bg-background\">\n      <div className=\"mx-auto max-w-4xl px-6 py-20 lg:py-28\">\n        <Badge variant=\"secondary\">Northwind Logistics</Badge>\n        <h2 className=\"mt-4 text-3xl font-semibold tracking-tight text-balance sm:text-4xl\">\n          Two quarters either side of the rollout\n        </h2>\n        <p className=\"text-muted-foreground mt-3 text-lg\">\n          Their numbers, their definitions, measured the same way before and after. Nothing normalised.\n        </p>\n\n        <Card className=\"mt-8\">\n          <CardContent className=\"p-0\">\n            <Table>\n              <TableHeader>\n                <TableRow>\n                  <TableHead>Metric</TableHead>\n                  <TableHead className=\"text-right\">Q4 2025</TableHead>\n                  <TableHead className=\"text-right\">Q2 2026</TableHead>\n                  <TableHead className=\"text-right\">Change</TableHead>\n                </TableRow>\n              </TableHeader>\n              <TableBody>\n                {metrics.map((metric) => {\n                  const Trend = metric.better === 'down' ? TrendingDown : TrendingUp\n                  return (\n                    <TableRow key={metric.name}>\n                      <TableCell className=\"font-medium\">{metric.name}</TableCell>\n                      <TableCell className=\"text-muted-foreground text-right font-mono text-sm\">\n                        {metric.before}\n                      </TableCell>\n                      <TableCell className=\"text-right font-mono text-sm font-semibold\">{metric.after}</TableCell>\n                      <TableCell className=\"text-right\">\n                        <span className=\"text-success inline-flex items-center gap-1.5 font-mono text-sm\">\n                          <Trend className=\"size-3.5\" aria-hidden=\"true\" />\n                          {metric.delta}\n                        </span>\n                      </TableCell>\n                    </TableRow>\n                  )\n                })}\n              </TableBody>\n            </Table>\n\n            <Separator />\n\n            <p className=\"text-muted-foreground px-6 py-4 text-xs leading-relaxed\">\n              Measured from their own close calendar and ticket queue. The rollout completed between the two quarters;\n              no headcount was added or removed in finance during the period.\n            </p>\n          </CardContent>\n        </Card>\n\n        <Button className=\"mt-8\">\n          Read how they did it\n          <ArrowRight className=\"ml-2 size-4\" aria-hidden=\"true\" />\n        </Button>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/case-study/CaseStudyMetricComparison.tsx"
    },
    {
      "path": "packages/registry-react/blocks/case-study/CaseStudyResultsStrip.tsx",
      "content": "'use client'\n\nimport { ArrowRight } from 'lucide-react'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Separator } from '@/components/ui/separator'\n\n// One result per customer. A second number halves the weight of the first.\nconst results = [\n  { wordmark: 'Northwind', metric: '5 days', label: 'off the monthly close' },\n  { wordmark: 'Halden', metric: '71%', label: 'fewer ad-hoc requests' },\n  { wordmark: 'Verity', metric: '2.4pp', label: 'tighter forecast band' },\n  { wordmark: 'Calder', metric: '11 → 1', label: 'reporting spreadsheets' },\n]\n\nexport function CaseStudyResultsStrip() {\n  return (\n    <section data-slot=\"case-study-results-strip\" className=\"border-border bg-card border-y\">\n      <div className=\"mx-auto max-w-6xl px-6 py-10\">\n        <div className=\"flex flex-wrap items-center justify-between gap-4\">\n          <Badge variant=\"secondary\">Proven</Badge>\n          <Button variant=\"link\" className=\"h-auto p-0 text-sm\">\n            All case studies\n            <ArrowRight className=\"ml-1.5 size-3.5\" aria-hidden=\"true\" />\n          </Button>\n        </div>\n\n        <div className=\"mt-6 grid gap-6 sm:grid-cols-2 lg:grid-cols-4 lg:gap-0\">\n          {results.map((result, index) => (\n            <div key={result.wordmark} className=\"relative lg:px-6 lg:first:pl-0\">\n              <p className=\"text-sm font-semibold tracking-[0.18em] uppercase\">{result.wordmark}</p>\n              <p className=\"font-display mt-3 text-3xl font-bold tracking-tight\">{result.metric}</p>\n              <p className=\"text-muted-foreground mt-1 text-sm\">{result.label}</p>\n\n              {index < results.length - 1 && (\n                <Separator orientation=\"vertical\" className=\"absolute top-0 right-0 hidden h-full lg:block\" />\n              )}\n            </div>\n          ))}\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/case-study/CaseStudyResultsStrip.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/avatar.json",
    "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/separator.json",
    "https://uipkge.dev/r/react/table.json",
    "https://uipkge.dev/r/react/toggle-group.json"
  ],
  "description": "Customer-proof set pairing a featured split story with a sticky results panel, a filterable story index, three-up metric cards, a before-and-after metric comparison table, and a compact results strip.",
  "categories": [
    "marketing"
  ]
}