{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "features-2x2-spotlight",
  "title": "Features — 2×2 Spotlight",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/features-2x2-spotlight/features-2x2-spotlight.component.ts",
      "content": "// Four large feature panels in a two-by-two grid, each with a generous illustration\n// slot built from primitives, a headline, supporting copy, and a quiet inline link.\n// Port of the React block 1:1 — same four panels, same lineage/access/budget/release\n// illustration slots, same copy.\nimport { ChangeDetectionStrategy, Component, Input } from '@angular/core'\nimport { ArrowRight, LucideAngularModule } from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport { UiCardComponent, UiCardContentComponent } from '@/ui/card/card.component'\nimport { UiProgressComponent } from '@/ui/progress/progress.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\n\nexport interface SpotlightPanel {\n  eyebrow: string\n  title: string\n  body: string\n  link: string\n  kind: 'lineage' | 'access' | 'budget' | 'release'\n}\n\nconst defaultPanels: SpotlightPanel[] = [\n  {\n    eyebrow: 'Modelling',\n    title: 'One definition, every surface',\n    body: 'Dashboards, exports, and the API all resolve the same certified metric, so the number cannot disagree with itself.',\n    link: 'See the metric layer',\n    kind: 'lineage',\n  },\n  {\n    eyebrow: 'Governance',\n    title: 'Permissions you can prove',\n    body: 'Scope resolves per query from your identity provider, and every evaluation lands in an exportable audit trail.',\n    link: 'Read the access model',\n    kind: 'access',\n  },\n  {\n    eyebrow: 'Performance',\n    title: 'Budgeted, not throttled',\n    body: 'Each team gets a query budget enforced at run time, with materialised aggregates carrying the frequent load.',\n    link: 'See the caching rules',\n    kind: 'budget',\n  },\n  {\n    eyebrow: 'Delivery',\n    title: 'Ship without a redeploy',\n    body: 'Publishing a definition change rolls out to every consumer immediately, and reverting is the same one click.',\n    link: 'How releases work',\n    kind: 'release',\n  },\n]\n\nconst lineage = ['warehouse.orders', 'metrics.revenue_net', 'dashboard.exec_summary']\n\nconst access = [\n  { label: 'EMEA analyst', value: 'Region-scoped' },\n  { label: 'Finance lead', value: 'Full ledger' },\n  { label: 'Contractor', value: 'No payroll' },\n]\n\nconst budgets = [\n  { team: 'Finance', used: 62 },\n  { team: 'RevOps', used: 38 },\n  { team: 'Product', used: 81 },\n]\n\nconst releases = [\n  { version: 'v128', note: 'revenue_net → trailing 28d' },\n  { version: 'v127', note: 'added margin_by_channel' },\n]\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-features-2x2-spotlight, [ui-features-2x2-spotlight]',\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    UiProgressComponent,\n    UiSeparatorComponent,\n  ],\n  template: `\n    <section data-slot=\"features-2x2-spotlight\" [class]=\"rootClass\">\n      <div class=\"mx-auto max-w-6xl px-6 py-20 lg:py-28\">\n        <div class=\"max-w-2xl\">\n          <span ui-badge variant=\"secondary\">Platform</span>\n          <h2 class=\"mt-4 text-3xl font-semibold tracking-tight sm:text-4xl\">Four things it does properly</h2>\n          <p class=\"text-muted-foreground mt-3 text-lg\">\n            Each panel is a mechanism, not a promise — the illustration is the real shape of the feature.\n          </p>\n        </div>\n\n        <div class=\"mt-12 grid gap-5 md:grid-cols-2\">\n          @for (panel of panels; track panel.title) {\n            <div ui-card class=\"group overflow-hidden\">\n              <div ui-card-content class=\"flex h-full flex-col p-0\">\n                <!-- Illustration slot: built from primitives so it themes with the\n                     page instead of shipping a baked screenshot. -->\n                <div class=\"bg-muted/40 border-border border-b p-6\">\n                  @if (panel.kind === 'lineage') {\n                    <div class=\"space-y-2\">\n                      @for (node of lineage; track node; let i = $index) {\n                        <div\n                          class=\"border-border bg-card rounded-md border px-3 py-2 font-mono text-xs\"\n                          [class.ml-8]=\"i === lineage.length - 1\"\n                          [class.ml-4]=\"i === 1\"\n                        >\n                          {{ node }}\n                        </div>\n                      }\n                    </div>\n                  } @else if (panel.kind === 'access') {\n                    <div class=\"divide-border border-border bg-card divide-y rounded-md border\">\n                      @for (row of access; track row.label) {\n                        <div class=\"flex items-center justify-between gap-3 px-3 py-2\">\n                          <span class=\"text-xs font-medium\">{{ row.label }}</span>\n                          <span class=\"text-muted-foreground font-mono text-xs\">{{ row.value }}</span>\n                        </div>\n                      }\n                    </div>\n                  } @else if (panel.kind === 'budget') {\n                    <div class=\"space-y-3\">\n                      @for (row of budgets; track row.team) {\n                        <div>\n                          <div class=\"flex items-baseline justify-between gap-3\">\n                            <span class=\"text-xs font-medium\">{{ row.team }}</span>\n                            <span class=\"text-muted-foreground font-mono text-xs\">{{ row.used }}%</span>\n                          </div>\n                          <div\n                            ui-progress\n                            [value]=\"row.used\"\n                            [aria-label]=\"row.team + ' budget used'\"\n                            class=\"mt-1.5 h-1.5\"\n                          ></div>\n                        </div>\n                      }\n                    </div>\n                  } @else {\n                    <div class=\"space-y-3\">\n                      @for (release of releases; track release.version) {\n                        <div class=\"flex items-baseline gap-3\">\n                          <span class=\"text-primary font-mono text-xs\">{{ release.version }}</span>\n                          <span class=\"text-muted-foreground min-w-0 truncate text-xs\">{{ release.note }}</span>\n                        </div>\n                      }\n                      <ui-separator />\n                      <p class=\"text-muted-foreground text-xs\">Rolled out to 41 consumers, no redeploy.</p>\n                    </div>\n                  }\n                </div>\n\n                <div class=\"flex flex-1 flex-col p-6\">\n                  <p class=\"text-muted-foreground font-mono text-xs tracking-[0.14em] uppercase\">\n                    {{ panel.eyebrow }}\n                  </p>\n                  <h3 class=\"mt-2 text-lg font-semibold tracking-tight\">{{ panel.title }}</h3>\n                  <p class=\"text-muted-foreground mt-2 text-sm leading-relaxed\">{{ panel.body }}</p>\n                  <button ui-button variant=\"link\" class=\"mt-auto h-auto justify-start p-0 pt-4 text-sm\">\n                    {{ panel.link }}\n                    <lucide-icon\n                      [img]=\"ArrowRight\"\n                      class=\"ml-1.5 size-3.5 transition-transform group-hover:translate-x-0.5\"\n                      aria-hidden=\"true\"\n                    />\n                  </button>\n                </div>\n              </div>\n            </div>\n          }\n        </div>\n      </div>\n    </section>\n  `,\n})\nexport class UiFeatures2x2SpotlightComponent {\n  protected readonly ArrowRight = ArrowRight\n  protected readonly lineage = lineage\n  protected readonly access = access\n  protected readonly budgets = budgets\n  protected readonly releases = releases\n\n  @Input() panels: SpotlightPanel[] = defaultPanels.map((p) => ({ ...p }))\n  @Input('class') className?: string\n\n  get rootClass(): string {\n    return cn('bg-background', this.className)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/features-2x2-spotlight/features-2x2-spotlight.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/features-2x2-spotlight/index.ts",
      "content": "export { UiFeatures2x2SpotlightComponent, type SpotlightPanel } from './features-2x2-spotlight.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/features-2x2-spotlight/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/progress.json",
    "https://uipkge.dev/r/angular/separator.json"
  ],
  "description": "Four large feature panels in a two-by-two grid, each with a generous illustration slot built from primitives, a headline, supporting copy, and a quiet inline link.",
  "categories": [
    "marketing"
  ]
}