{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "features-numbered-grid",
  "title": "Features — Numbered Grid",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/features-numbered-grid/features-numbered-grid.component.ts",
      "content": "// Six-cell feature grid drawn with one-pixel dividers instead of cards, each cell led\n// by a monospace ordinal, an icon, a title, and two lines of supporting copy.\n// Port of the React block 1:1 — ordinals derive from index, so order is the source.\nimport { ChangeDetectionStrategy, Component, Input } from '@angular/core'\nimport {\n  ArrowRight,\n  Boxes,\n  Clock,\n  GitBranch,\n  Lock,\n  LucideAngularModule,\n  Receipt,\n  Signal,\n  type LucideIconData,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\n\nexport interface NumberedFeature {\n  icon: LucideIconData\n  title: string\n  body: string\n}\n\nconst defaultFeatures: NumberedFeature[] = [\n  {\n    icon: GitBranch,\n    title: 'Definitions under review',\n    body: 'Metrics live in the repo. Changing one opens a pull request with a diff, an owner, and a revert path.',\n  },\n  {\n    icon: Lock,\n    title: 'Access at query time',\n    body: 'Scope resolves from your identity provider on every query, so a shared link cannot outrun permissions.',\n  },\n  {\n    icon: Clock,\n    title: 'Freshness you choose',\n    body: 'Materialise the hot aggregates on a schedule; let everything else fall through to the warehouse.',\n  },\n  {\n    icon: Receipt,\n    title: 'Cost ceilings per team',\n    body: 'Query budgets are enforced where the query runs, not reconciled from an invoice a month later.',\n  },\n  {\n    icon: Signal,\n    title: 'Drift alerting',\n    body: 'Threshold and anomaly alerts fire against certified metrics, so nobody debates the trigger.',\n  },\n  {\n    icon: Boxes,\n    title: 'Embedding without forks',\n    body: 'Signed, scoped URLs render the same dashboards inside your product with the viewer’s own permissions.',\n  },\n]\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-features-numbered-grid, [ui-features-numbered-grid]',\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: [LucideAngularModule, UiBadgeComponent, UiButtonComponent],\n  template: `\n    <section data-slot=\"features-numbered-grid\" [class]=\"rootClass\">\n      <div class=\"mx-auto max-w-6xl px-6 py-20 lg:py-28\">\n        <div class=\"flex flex-wrap items-end justify-between gap-6\">\n          <div class=\"max-w-2xl\">\n            <span ui-badge variant=\"secondary\">How it holds up</span>\n            <h2 class=\"mt-4 text-3xl font-semibold tracking-tight sm:text-4xl\">Six decisions, in order of impact</h2>\n          </div>\n          <button ui-button variant=\"outline\">\n            Read the architecture notes\n            <lucide-icon [img]=\"ArrowRight\" class=\"ml-2 size-4\" aria-hidden=\"true\" />\n          </button>\n        </div>\n\n        <!-- gap-px over a border-coloured ground draws hairline rules between\n             cells, so the grid reads as one table rather than six floating cards. -->\n        <div\n          class=\"bg-border border-border mt-10 grid gap-px overflow-hidden rounded-xl border sm:grid-cols-2 lg:grid-cols-3\"\n        >\n          @for (feature of features; track feature.title; let i = $index) {\n            <article class=\"bg-background p-6\">\n              <div class=\"flex items-center gap-3\">\n                <span class=\"text-muted-foreground/70 font-mono text-xs\">{{ ordinal(i) }}</span>\n                <lucide-icon [img]=\"feature.icon\" class=\"text-muted-foreground size-4\" aria-hidden=\"true\" />\n              </div>\n              <h3 class=\"mt-4 text-base font-semibold\">{{ feature.title }}</h3>\n              <p class=\"text-muted-foreground mt-2 text-sm leading-relaxed\">{{ feature.body }}</p>\n            </article>\n          }\n        </div>\n      </div>\n    </section>\n  `,\n})\nexport class UiFeaturesNumberedGridComponent {\n  protected readonly ArrowRight = ArrowRight\n\n  @Input() features: NumberedFeature[] = defaultFeatures.map((f) => ({ ...f }))\n  @Input('class') className?: string\n\n  get rootClass(): string {\n    return cn('bg-background', this.className)\n  }\n\n  ordinal(index: number): string {\n    return String(index + 1).padStart(2, '0')\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/features-numbered-grid/features-numbered-grid.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/features-numbered-grid/index.ts",
      "content": "export { UiFeaturesNumberedGridComponent, type NumberedFeature } from './features-numbered-grid.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/features-numbered-grid/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json"
  ],
  "description": "Six-cell feature grid drawn with one-pixel dividers instead of cards, each cell led by a monospace ordinal, an icon, a title, and two lines of supporting copy.",
  "categories": [
    "marketing"
  ]
}