{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "how-it-works-timeline",
  "title": "How It Works — Vertical Timeline",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/how-it-works-timeline/how-it-works-timeline.component.ts",
      "content": "// Vertical numbered timeline with a continuous rail, per-stage status badge, outcome\n// bullets, and a paired detail card — for onboarding or implementation narratives that\n// need more room than a three-up row. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, Input } from '@angular/core'\nimport { Check, Clock, LucideAngularModule } from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\nimport {\n  UiTimelineComponent,\n  UiTimelineContentComponent,\n  UiTimelineDescriptionComponent,\n  UiTimelineHeaderComponent,\n  UiTimelineItemComponent,\n  UiTimelineMediaComponent,\n  UiTimelineTitleComponent,\n} from '@/ui/timeline/timeline.component'\n\nexport interface TimelineStage {\n  title: string\n  status: string\n  done: boolean\n  body: string\n  outcomes: string[]\n}\n\nconst stages: TimelineStage[] = [\n  {\n    title: 'Kickoff & access',\n    status: 'Week 1',\n    done: true,\n    body: 'A shared channel, a named engineer, and read-only credentials. Nothing is provisioned until scope is signed off.',\n    outcomes: ['Workspace provisioned', 'SSO connected', 'Data contract agreed'],\n  },\n  {\n    title: 'Model your data',\n    status: 'Week 2',\n    done: true,\n    body: 'We mirror your warehouse schema and reconcile it against last quarter’s numbers before anything is published.',\n    outcomes: ['Schema mirrored', 'Historical backfill', 'Reconciliation signed off'],\n  },\n  {\n    title: 'Pilot with one team',\n    status: 'Week 3–4',\n    done: false,\n    body: 'A single team runs their real reporting cycle on it. We fix what they hit before anyone else sees it.',\n    outcomes: ['Pilot cohort live', 'Feedback loop open', 'Runbook drafted'],\n  },\n  {\n    title: 'Roll out & hand over',\n    status: 'Week 5',\n    done: false,\n    body: 'Permissions, alerting, and the runbook move to your team. Support stays on call through the first close.',\n    outcomes: ['Org-wide access', 'Alerting configured', 'Ownership transferred'],\n  },\n]\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-how-it-works-timeline, [ui-how-it-works-timeline]',\n  standalone: true,\n  // React renders the root <section> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiSeparatorComponent,\n    UiTimelineComponent,\n    UiTimelineContentComponent,\n    UiTimelineDescriptionComponent,\n    UiTimelineHeaderComponent,\n    UiTimelineItemComponent,\n    UiTimelineMediaComponent,\n    UiTimelineTitleComponent,\n  ],\n  template: `\n    <section data-slot=\"how-it-works-timeline\" [class]=\"rootClass\">\n      <div class=\"mx-auto max-w-5xl px-6 py-20 lg:py-28\">\n        <div class=\"max-w-2xl\">\n          <span ui-badge variant=\"secondary\">Implementation</span>\n          <h2 class=\"mt-4 text-3xl font-semibold tracking-tight sm:text-4xl\">\n            From kickoff to hand-over in five weeks\n          </h2>\n          <p class=\"text-muted-foreground mt-3 text-lg\">\n            The same plan we run for every rollout. No phase starts before the one above it is signed off.\n          </p>\n        </div>\n\n        <ui-timeline class=\"mt-14\" density=\"comfortable\">\n          @for (stage of allStages; track stage.title; let index = $index) {\n            <ui-timeline-item [status]=\"stage.done ? 'success' : 'default'\">\n              <ui-timeline-media variant=\"outline\" [status]=\"stage.done ? 'success' : 'muted'\">\n                @if (stage.done) {\n                  <lucide-icon [img]=\"Check\" class=\"size-4\" aria-hidden=\"true\" />\n                } @else {\n                  <span class=\"font-mono text-xs font-semibold\">{{ pad(index + 1) }}</span>\n                }\n              </ui-timeline-media>\n\n              <ui-timeline-content>\n                <ui-timeline-header>\n                  <ui-timeline-title as=\"h3\" class=\"text-base font-semibold\">{{ stage.title }}</ui-timeline-title>\n                  <span ui-badge [variant]=\"stage.done ? 'secondary' : 'outline'\" class=\"gap-1.5 font-normal\">\n                    <lucide-icon [img]=\"Clock\" class=\"size-3\" aria-hidden=\"true\" />\n                    {{ stage.status }}\n                  </span>\n                </ui-timeline-header>\n\n                <ui-timeline-description class=\"mt-2 max-w-prose leading-relaxed\">\n                  {{ stage.body }}\n                </ui-timeline-description>\n\n                <div ui-card class=\"mt-4\">\n                  <div ui-card-header class=\"pb-3\">\n                    <h4 ui-card-title class=\"text-muted-foreground text-xs font-medium tracking-wide uppercase\">\n                      What you have at the end\n                    </h4>\n                  </div>\n                  <div ui-card-content>\n                    <ul class=\"grid gap-2 sm:grid-cols-3\">\n                      @for (outcome of stage.outcomes; track outcome) {\n                        <li class=\"text-foreground flex items-start gap-2 text-sm\">\n                          <lucide-icon [img]=\"Check\" class=\"text-primary mt-0.5 size-3.5 shrink-0\" aria-hidden=\"true\" />\n                          <span>{{ outcome }}</span>\n                        </li>\n                      }\n                    </ul>\n                  </div>\n                </div>\n              </ui-timeline-content>\n            </ui-timeline-item>\n          }\n        </ui-timeline>\n\n        <ui-separator />\n        <div class=\"mt-8 flex flex-wrap items-center gap-4\">\n          <button ui-button>Book an implementation call</button>\n          <button ui-button variant=\"ghost\">Download the rollout plan</button>\n        </div>\n      </div>\n    </section>\n  `,\n})\nexport class UiHowItWorksTimelineComponent {\n  protected readonly Check = Check\n  protected readonly Clock = Clock\n  protected readonly allStages = stages\n\n  @Input('class') className?: string\n\n  get rootClass(): string {\n    return cn('bg-background', this.className)\n  }\n\n  pad(n: number): string {\n    return String(n).padStart(2, '0')\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/how-it-works-timeline/how-it-works-timeline.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/how-it-works-timeline/index.ts",
      "content": "export { UiHowItWorksTimelineComponent, type TimelineStage } from './how-it-works-timeline.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/how-it-works-timeline/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/separator.json",
    "https://uipkge.dev/r/angular/timeline.json"
  ],
  "description": "Vertical numbered timeline with a continuous rail, per-stage status badge, outcome bullets, and a paired detail card — for onboarding or implementation narratives that need more room than a three-up row.",
  "categories": [
    "marketing"
  ]
}