{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "feature-alternating-rows",
  "title": "Feature Deep-Dive — Alternating Rows",
  "type": "registry:block",
  "description": "Classic zig-zag feature deep-dive: three full-width rows alternating copy and visual, each with an eyebrow, headline, checklist, inline link, and a bordered preview panel built from real primitives.",
  "categories": [
    "marketing"
  ],
  "files": [
    {
      "path": "packages/elements-lit/src/blocks/feature-alternating-rows/feature-alternating-rows.ts",
      "content": "import { LitElement, css, html, nothing } from 'lit'\nimport { ArrowRight, Check, GitBranch, ShieldCheck, Zap, type IconNode } from 'lucide'\nimport { tailwind } from '../../lib/styles'\nimport { ThemeController } from '../../lib/theme'\nimport { icon } from '../../lib/icon'\n// Side-effect imports: register the composed elements for standalone use\n// (consumers who install only this block still get working primitives).\nimport '../../components/badge/badge'\nimport '../../components/button/button'\n\n// Explicit shape: the three preview panels are structurally different, so the\n// optional keys keep the union from collapsing when the template narrows.\ninterface FeatureRow {\n  eyebrow: string\n  icon: IconNode\n  iconName: string\n  title: string\n  body: string\n  points: string[]\n  link: string\n  reverse: boolean\n  preview: {\n    label: string\n    lines?: { text: string; tone: 'add' | 'remove' | 'same' }[]\n    rules?: { scope: string; value: string; allowed: boolean }[]\n    stats?: { name: string; detail: string }[]\n  }\n}\n\nconst rows: FeatureRow[] = [\n  {\n    eyebrow: 'Versioning',\n    icon: GitBranch,\n    iconName: 'git-branch',\n    title: 'Every change is a reviewable diff',\n    body: 'Dashboards, metrics, and permissions are stored as plain files. Changes open a pull request instead of silently overwriting production.',\n    points: ['Branch per change', 'Review before publish', 'One-click revert'],\n    link: 'How version control works',\n    reverse: false,\n    preview: {\n      label: 'metrics/revenue.yml',\n      lines: [\n        { text: '+ window: trailing_28d', tone: 'add' },\n        { text: '- window: trailing_30d', tone: 'remove' },\n        { text: '  owner: finance-analytics', tone: 'same' },\n      ],\n    },\n  },\n  {\n    eyebrow: 'Access',\n    icon: ShieldCheck,\n    iconName: 'shield-check',\n    title: 'Permissions that follow the row, not the dashboard',\n    body: 'Scope is evaluated at query time from your identity provider, so a shared link never leaks a region or account the viewer cannot see.',\n    points: ['Row-level filters', 'SCIM group sync', 'Audited every query'],\n    link: 'Read the access model',\n    reverse: true,\n    preview: {\n      label: 'Effective access — EMEA analyst',\n      rules: [\n        { scope: 'region', value: 'EMEA only', allowed: true },\n        { scope: 'revenue.net', value: 'Visible', allowed: true },\n        { scope: 'payroll.*', value: 'Blocked', allowed: false },\n      ],\n    },\n  },\n  {\n    eyebrow: 'Performance',\n    icon: Zap,\n    iconName: 'zap',\n    title: 'Cached where it matters, fresh where it counts',\n    body: 'Hot aggregates are materialised on a schedule you control. Everything else falls through to the warehouse so the number is never stale by accident.',\n    points: ['Per-metric freshness', 'Warehouse pass-through', 'Cost ceiling per team'],\n    link: 'See the caching rules',\n    reverse: false,\n    preview: {\n      label: 'Freshness',\n      stats: [\n        { name: 'Revenue rollup', detail: 'materialised · 5 min' },\n        { name: 'Pipeline by stage', detail: 'materialised · 1 hr' },\n        { name: 'Raw event search', detail: 'live query' },\n      ],\n    },\n  },\n]\n\n/**\n * <uip-feature-alternating-rows> — the registry FeatureAlternatingRows block\n * as a web component.\n *\n * Class strings are React's FeatureAlternatingRows verbatim. No props, no\n * state, no callbacks — a static zig-zag. Card and separator chrome stay\n * plain divs carrying the registry part classes (see the login-01 block).\n */\nexport class UipFeatureAlternatingRows extends LitElement {\n  static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true }\n  // :host display can't be a utility class (the host has no template of its own).\n  static styles = [tailwind, css`:host { display: block; }`]\n\n  constructor() {\n    super()\n    new ThemeController(this)\n  }\n\n  connectedCallback() {\n    super.connectedCallback()\n    this.setAttribute('data-uipkge', '')\n    this.setAttribute('data-slot', 'feature-alternating-rows')\n  }\n\n  render() {\n    return html`\n      <section data-slot=\"feature-alternating-rows\" class=\"bg-background\">\n        <div class=\"mx-auto max-w-6xl px-6 py-20 lg:py-28\">\n          <div class=\"max-w-2xl\">\n            <uip-badge variant=\"secondary\">Platform</uip-badge>\n            <h2 class=\"mt-4 text-3xl font-semibold tracking-tight sm:text-4xl\">\n              Built like infrastructure, not a widget\n            </h2>\n            <p class=\"text-muted-foreground mt-3 text-lg\">\n              Three decisions that stop a reporting layer from rotting after the first quarter.\n            </p>\n          </div>\n\n          <div class=\"mt-16 space-y-16 lg:space-y-24\">\n            ${rows.map(\n              (row) => html`<div class=\"grid items-center gap-10 lg:grid-cols-2 lg:gap-16\">\n                <div class=${row.reverse ? 'lg:order-2' : ''}>\n                  <div class=\"text-muted-foreground flex items-center gap-2\">\n                    ${icon(row.icon, row.iconName, 'size-4')}\n                    <span class=\"font-mono text-xs tracking-[0.14em] uppercase\">${row.eyebrow}</span>\n                  </div>\n                  <h3 class=\"mt-4 text-2xl font-semibold tracking-tight\">${row.title}</h3>\n                  <p class=\"text-muted-foreground mt-3 leading-relaxed\">${row.body}</p>\n                  <ul class=\"mt-6 space-y-2.5\">\n                    ${row.points.map(\n                      (point) => html`<li class=\"flex items-start gap-2.5 text-sm\">\n                        ${icon(Check, 'check', 'text-primary mt-0.5 size-4 shrink-0')}\n                        <span>${point}</span>\n                      </li>`,\n                    )}\n                  </ul>\n                  <uip-button\n                    variant=\"link\"\n                    class=\"mt-5 h-auto p-0 [&::part(base)]:h-auto [&::part(base)]:p-0\"\n                  >\n                    ${row.link} ${icon(ArrowRight, 'arrow-right', 'ml-1.5 size-3.5')}\n                  </uip-button>\n                </div>\n\n                <div\n                  data-uipkge=\"\"\n                  data-slot=\"card\"\n                  class=${row.reverse\n                    ? 'bg-card text-card-foreground rounded-xl border border-border shadow-sm transition-colors duration-150 overflow-hidden lg:order-1'\n                    : 'bg-card text-card-foreground rounded-xl border border-border shadow-sm transition-colors duration-150 overflow-hidden'}\n                >\n                  <div data-uipkge=\"\" data-slot=\"card-content\" class=\"p-0\">\n                    <div class=\"border-border text-muted-foreground border-b px-4 py-2.5 font-mono text-xs\">\n                      ${row.preview.label}\n                    </div>\n\n                    ${row.preview.lines\n                      ? html`<div class=\"space-y-1 p-4 font-mono text-xs\">\n                          ${row.preview.lines.map(\n                            (line) => html`<p\n                              class=${line.tone === 'add'\n                                ? 'text-success'\n                                : line.tone === 'remove'\n                                  ? 'text-destructive'\n                                  : 'text-muted-foreground'}\n                            >\n                              ${line.text}\n                            </p>`,\n                          )}\n                        </div>`\n                      : nothing}\n\n                    ${row.preview.rules\n                      ? html`<div class=\"divide-border divide-y\">\n                          ${row.preview.rules.map(\n                            (rule) => html`<div class=\"flex items-center justify-between gap-4 px-4 py-3\">\n                              <span class=\"font-mono text-xs\">${rule.scope}</span>\n                              <uip-badge variant=${rule.allowed ? 'secondary' : 'outline'}>${rule.value}</uip-badge>\n                            </div>`,\n                          )}\n                        </div>`\n                      : nothing}\n\n                    ${row.preview.stats\n                      ? html`<div class=\"p-4\">\n                          <ul class=\"space-y-3\">\n                            ${row.preview.stats.map(\n                              (stat) => html`<li>\n                                <div class=\"flex items-baseline justify-between gap-4\">\n                                  <span class=\"text-sm font-medium\">${stat.name}</span>\n                                  <span class=\"text-muted-foreground font-mono text-xs\">${stat.detail}</span>\n                                </div>\n                                <div\n                                  data-uipkge=\"\"\n                                  data-slot=\"separator\"\n                                  data-orientation=\"horizontal\"\n                                  role=\"none\"\n                                  class=\"bg-border shrink-0 h-px w-full mt-3\"\n                                ></div>\n                              </li>`,\n                            )}\n                          </ul>\n                        </div>`\n                      : nothing}\n                  </div>\n                </div>\n              </div>`,\n            )}\n          </div>\n        </div>\n      </section>\n    `\n  }\n}\n\ncustomElements.get('uip-feature-alternating-rows') ||\n  customElements.define('uip-feature-alternating-rows', UipFeatureAlternatingRows)\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'uip-feature-alternating-rows': UipFeatureAlternatingRows\n  }\n}\n",
      "type": "registry:file",
      "target": "src/uip/blocks/feature-alternating-rows/feature-alternating-rows.ts"
    }
  ],
  "dependencies": [
    "lit",
    "lucide"
  ],
  "registryDependencies": [
    "https://uipkge.dev/r/lit/badge.json",
    "https://uipkge.dev/r/lit/button.json",
    "https://uipkge.dev/r/lit/lit-core.json"
  ]
}
