{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "feature-alternating-rows",
  "title": "Feature Deep-Dive — Alternating Rows",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-svelte/blocks/feature-alternating-rows/FeatureAlternatingRows.svelte",
      "content": "<script lang=\"ts\" module>\n  import type { Component } from 'svelte'\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.\n  export interface FeatureRow {\n    eyebrow: string\n    icon: Component\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</script>\n\n<script lang=\"ts\">\n  import { ArrowRight, Check, GitBranch, ShieldCheck, Zap } from '@lucide/svelte'\n  import { Badge } from '$lib/components/ui/badge'\n  import { Button } from '$lib/components/ui/button'\n  import { Card, CardContent } from '$lib/components/ui/card'\n  import { Separator } from '$lib/components/ui/separator'\n\n  const rows: FeatureRow[] = [\n    {\n      eyebrow: 'Versioning',\n      icon: GitBranch,\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      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      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  function toneClass(tone: 'add' | 'remove' | 'same') {\n    return tone === 'add' ? 'text-success' : tone === 'remove' ? 'text-destructive' : 'text-muted-foreground'\n  }\n</script>\n\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      <Badge variant=\"secondary\">Platform</Badge>\n      <h2 class=\"mt-4 text-3xl font-semibold tracking-tight sm:text-4xl\">Built like infrastructure, not a widget</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      {#each rows as row (row.title)}\n        {@const Icon = row.icon}\n        <div class=\"grid items-center gap-10 lg:grid-cols-2 lg:gap-16\">\n          <div class:lg:order-2={row.reverse}>\n            <div class=\"text-muted-foreground flex items-center gap-2\">\n              <Icon class=\"size-4\" aria-hidden=\"true\" />\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              {#each row.points as point (point)}\n                <li class=\"flex items-start gap-2.5 text-sm\">\n                  <Check class=\"text-primary mt-0.5 size-4 shrink-0\" aria-hidden=\"true\" />\n                  <span>{point}</span>\n                </li>\n              {/each}\n            </ul>\n            <Button variant=\"link\" class=\"mt-5 h-auto p-0\">\n              {row.link}\n              <ArrowRight class=\"ml-1.5 size-3.5\" aria-hidden=\"true\" />\n            </Button>\n          </div>\n\n          <Card class={row.reverse ? 'lg:order-1' : ''}>\n            <CardContent 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              <!-- Diff preview -->\n              {#if row.preview.lines}\n                <div class=\"space-y-1 p-4 font-mono text-xs\">\n                  {#each row.preview.lines as line (line.text)}\n                    <p class={toneClass(line.tone)}>\n                      {line.text}\n                    </p>\n                  {/each}\n                </div>\n                <!-- Access preview -->\n              {:else if row.preview.rules}\n                <div class=\"divide-border divide-y\">\n                  {#each row.preview.rules as rule (rule.scope)}\n                    <div class=\"flex items-center justify-between gap-4 px-4 py-3\">\n                      <span class=\"font-mono text-xs\">{rule.scope}</span>\n                      <Badge variant={rule.allowed ? 'secondary' : 'outline'}>{rule.value}</Badge>\n                    </div>\n                  {/each}\n                </div>\n                <!-- Freshness preview -->\n              {:else}\n                <div class=\"p-4\">\n                  <ul class=\"space-y-3\">\n                    {#each (row.preview.stats ?? []) as stat (stat.name)}\n                      <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                        <Separator class=\"mt-3\" />\n                      </li>\n                    {/each}\n                  </ul>\n                </div>\n              {/if}\n            </CardContent>\n          </Card>\n        </div>\n      {/each}\n    </div>\n  </div>\n</section>\n",
      "type": "registry:block",
      "target": "~/src/lib/components/blocks/feature-alternating-rows/FeatureAlternatingRows.svelte"
    }
  ],
  "dependencies": [
    "@lucide/svelte"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/svelte/badge.json",
    "https://uipkge.dev/r/svelte/button.json",
    "https://uipkge.dev/r/svelte/card.json",
    "https://uipkge.dev/r/svelte/separator.json"
  ],
  "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"
  ]
}