{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "customer-journey-map",
  "title": "Customer Journey Map",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/customer-journey-map/customer-journey-map.component.ts",
      "content": "import { Component, Input, signal, ChangeDetectionStrategy } from '@angular/core'\nimport {\n  ArrowRight,\n  ArrowUpRight,\n  CheckCircle2,\n  Clock,\n  Compass,\n  CreditCard,\n  Download,\n  HeartHandshake,\n  Lightbulb,\n  LucideAngularModule,\n  MousePointerClick,\n  Rocket,\n  Share2,\n  ShieldAlert,\n  Smile,\n  TrendingUp,\n  Zap,\n  type LucideIconData,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent, type BadgeVariant } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiProgressComponent } from '@/ui/progress/progress.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\n\nexport interface JourneyStage {\n  id: string\n  stageNumber: string\n  title: string\n  subtitle: string\n  icon: LucideIconData\n  volume: string\n  volumeLabel: string\n  volumeChange: string\n  volumeChangeTrend: 'up' | 'down'\n  conversionRate: string\n  conversionLabel: string\n  primaryAction: {\n    icon: LucideIconData\n    text: string\n  }\n  keyMetrics: {\n    label: string\n    value: string\n    detail?: string\n  }[]\n  touchpoints: {\n    name: string\n    channel: string\n    type: 'organic' | 'app' | 'email' | 'billing'\n  }[]\n  sentiment: {\n    score: number\n    maxScore: number\n    label: string\n    icon: LucideIconData\n    progressColor: string\n    gaugeLabel: string\n  }\n  frictionPoint: string\n  opportunity: {\n    experiment: string\n    expectedImpact: string\n  }\n  badgeVariant: Extract<BadgeVariant, 'outline' | 'secondary' | 'default' | 'success' | 'info' | 'warning'>\n}\n\nconst timeframes = [\n  { id: '30d', label: 'Last 30 Days' },\n  { id: '90d', label: 'Last 90 Days' },\n  { id: 'qtd', label: 'Quarter to Date' },\n  { id: 'ytd', label: 'Year to Date' },\n]\n\nconst stages: JourneyStage[] = [\n  {\n    id: 'acquisition',\n    stageNumber: '01',\n    title: 'Acquisition',\n    subtitle: 'Traffic & Inbound Discovery',\n    icon: Compass,\n    volume: '120,000',\n    volumeLabel: 'Unique Visitors',\n    volumeChange: '+14.2%',\n    volumeChangeTrend: 'up',\n    conversionRate: '6.8%',\n    conversionLabel: 'Visitor to Signup',\n    primaryAction: {\n      icon: MousePointerClick,\n      text: 'Browses docs & visits pricing',\n    },\n    keyMetrics: [\n      { label: 'Top Channel', value: 'Organic Search', detail: '48% of volume' },\n      { label: 'Signup Conv.', value: '6.8%', detail: '8,160 accounts' },\n      { label: 'Avg. Bounce', value: '41.2%', detail: '-2.4% vs benchmark' },\n    ],\n    touchpoints: [\n      { name: 'SEO landing pages & technical blog', channel: 'Search', type: 'organic' },\n      { name: 'Interactive sandbox demo playground', channel: 'Web App', type: 'app' },\n      { name: 'Product Hunt launch & GitHub repo', channel: 'Community', type: 'organic' },\n      { name: 'Developer search & social ad campaigns', channel: 'Paid Ads', type: 'organic' },\n    ],\n    sentiment: {\n      score: 8.2,\n      maxScore: 10,\n      label: 'High Intent',\n      icon: Smile,\n      progressColor: 'bg-chart-1',\n      gaugeLabel: '8.2 / 10',\n    },\n    frictionPoint: 'Technical landing page bounce rate spikes on legacy mobile browsers (54%).',\n    opportunity: {\n      experiment: 'Optimize hero headline for developer intent to lift bounce rate by 5%',\n      expectedImpact: '+420 signups/mo',\n    },\n    badgeVariant: 'secondary',\n  },\n  {\n    id: 'activation',\n    stageNumber: '02',\n    title: 'Activation',\n    subtitle: 'Onboarding & First Success',\n    icon: Rocket,\n    volume: '8,160',\n    volumeLabel: 'Signups Onboarded',\n    volumeChange: '+8.6%',\n    volumeChangeTrend: 'up',\n    conversionRate: '78.0%',\n    conversionLabel: 'Reached Aha Milestone',\n    primaryAction: {\n      icon: Zap,\n      text: 'Runs first CLI query & creates project',\n    },\n    keyMetrics: [\n      { label: 'Key Milestone', value: 'Created 1st Project', detail: '78% completed' },\n      { label: 'Time to Value', value: '12 min', detail: 'Median onboarding' },\n      { label: 'Stage Drop-off', value: '22.0%', detail: 'Step 3 invite friction' },\n    ],\n    touchpoints: [\n      { name: 'Automated 4-part welcome email sequence', channel: 'Email', type: 'email' },\n      { name: 'Interactive 3-step setup checklist', channel: 'In-App Modal', type: 'app' },\n      { name: 'Pre-populated template project schemas', channel: 'Workspace', type: 'app' },\n      { name: 'CLI quickstart terminal prompt', channel: 'Developer Tool', type: 'app' },\n    ],\n    sentiment: {\n      score: 8.8,\n      maxScore: 10,\n      label: 'Enthusiastic',\n      icon: Smile,\n      progressColor: 'bg-chart-2',\n      gaugeLabel: '8.8 / 10',\n    },\n    frictionPoint: 'Drop-off occurs during mandatory colleague invite screen before dashboard access.',\n    opportunity: {\n      experiment: 'Add single-sign on prompt to reduce drop-off by 8%',\n      expectedImpact: '+650 activated teams',\n    },\n    badgeVariant: 'info',\n  },\n  {\n    id: 'monetization',\n    stageNumber: '03',\n    title: 'Monetization',\n    subtitle: 'Free to Paid Conversion',\n    icon: CreditCard,\n    volume: '1,420',\n    volumeLabel: 'Paid Customers',\n    volumeChange: '+22.4%',\n    volumeChangeTrend: 'up',\n    conversionRate: '17.4%',\n    conversionLabel: 'Signup to Paid Rate',\n    primaryAction: {\n      icon: TrendingUp,\n      text: 'Selects Team plan & enters credit card',\n    },\n    keyMetrics: [\n      { label: 'Avg. Order Value', value: '$49/mo', detail: 'Blended Team/Pro' },\n      { label: 'Conv. Rate', value: '17.4%', detail: '1,420 total accounts' },\n      { label: 'Gross New MRR', value: '+$69,580', detail: 'Paced above target' },\n    ],\n    touchpoints: [\n      { name: 'Feature gate limit trigger modal', channel: 'In-App', type: 'app' },\n      { name: 'Self-serve pricing comparison drawer', channel: 'Web App', type: 'app' },\n      { name: 'Stripe checkout with annual savings toggle', channel: 'Billing Gateway', type: 'billing' },\n      { name: 'Instant VAT receipt & team tax invoice', channel: 'Automated Email', type: 'email' },\n    ],\n    sentiment: {\n      score: 8.4,\n      maxScore: 10,\n      label: 'ROI Positive',\n      icon: Smile,\n      progressColor: 'bg-chart-3',\n      gaugeLabel: '8.4 / 10',\n    },\n    frictionPoint: '12% checkout abandonment when international VAT verification requires manual review.',\n    opportunity: {\n      experiment: 'Introduce annual billing 20% discount badge in checkout to lift ARPU',\n      expectedImpact: '+$14.2k MRR expansion',\n    },\n    badgeVariant: 'warning',\n  },\n  {\n    id: 'retention',\n    stageNumber: '04',\n    title: 'Retention & Advocacy',\n    subtitle: 'Active Renewals & Expansion',\n    icon: HeartHandshake,\n    volume: '92.0%',\n    volumeLabel: 'Net Retention Rate',\n    volumeChange: '+3.1%',\n    volumeChangeTrend: 'up',\n    conversionRate: '92.0%',\n    conversionLabel: 'Cohort Net Retention',\n    primaryAction: {\n      icon: Share2,\n      text: 'Shares referral link & invites teammates',\n    },\n    keyMetrics: [\n      { label: 'NPS Score', value: '+68', detail: 'Industry world-class' },\n      { label: 'Referral Velocity', value: '1.2 invites', detail: 'Per active user/mo' },\n      { label: 'Monthly Logo Churn', value: '0.8%', detail: 'Negative revenue churn' },\n    ],\n    touchpoints: [\n      { name: 'Automated weekly performance digest', channel: 'Email Digest', type: 'email' },\n      { name: 'Quarterly proactive CSM review email', channel: 'Success Touch', type: 'email' },\n      { name: 'Referral program link inside settings', channel: 'Workspace Settings', type: 'app' },\n      { name: 'Changelog notification & release notes', channel: 'In-App Feed', type: 'app' },\n    ],\n    sentiment: {\n      score: 9.4,\n      maxScore: 10,\n      label: 'Brand Advocates',\n      icon: Smile,\n      progressColor: 'bg-chart-4',\n      gaugeLabel: '9.4 / 10',\n    },\n    frictionPoint: 'Feature discovery lag for advanced multi-region latency controls on growing teams.',\n    opportunity: {\n      experiment: 'Launch one-click workspace invite link to increase referral velocity to 1.8',\n      expectedImpact: '+35% viral coefficient',\n    },\n    badgeVariant: 'success',\n  },\n]\n\nconst overallSummary = {\n  funnelConversion: '1.18%',\n  funnelConversionDetail: '1,420 Paid from 120,000 Visitors',\n  timeToValue: '12 min',\n  timeToValueDetail: 'Median signup to Aha moment',\n  conversionVelocity: '4.2 days',\n  conversionVelocityDetail: 'First touch to paid subscription',\n  netRetention: '92.0%',\n  netRetentionDetail: 'Expansion outpacing churn by 3.8x',\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-customer-journey-map, [ui-customer-journey-map]',\n  standalone: true,\n  // React renders the root <div> 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    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiCardDescriptionComponent,\n    UiCardContentComponent,\n    UiProgressComponent,\n    UiSeparatorComponent,\n  ],\n  template: `\n    <div data-uipkge=\"\" data-slot=\"customer-journey-map\" [class]=\"rootClass\">\n      <!-- Header Section -->\n      <div class=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div class=\"space-y-1\">\n          <div class=\"flex min-w-0 items-center gap-2\">\n            <h2 class=\"text-foreground text-2xl font-bold tracking-tight\">Customer Journey & Growth Lifecycle Map</h2>\n            <span ui-badge variant=\"outline\" class=\"border-primary/30 text-primary bg-primary/5 text-xs font-medium\">\n              Live Lifecycle\n            </span>\n          </div>\n          <p class=\"text-muted-foreground text-sm\">\n            Analyze conversion velocity, friction points, and retention cohorts across user lifecycle stages.\n          </p>\n        </div>\n\n        <!-- Action Toolbar -->\n        <div class=\"flex flex-wrap items-center gap-2\">\n          <div class=\"bg-muted/50 border-border inline-flex items-center rounded-lg border p-1\">\n            @for (tf of timeframes; track tf.id) {\n              <button type=\"button\" [class]=\"timeframeClass(tf.id)\" (click)=\"selectedTimeframe.set(tf.id)\">\n                {{ tf.label }}\n              </button>\n            }\n          </div>\n\n          <button\n            ui-button\n            aria-label=\"Download attachment\"\n            variant=\"outline\"\n            size=\"sm\"\n            class=\"h-8 gap-1.5 text-xs font-medium\"\n            [disabled]=\"isExporting()\"\n            (click)=\"handleExport()\"\n          >\n            @if (!isExporting()) {\n              <lucide-icon [img]=\"Download\" class=\"size-3.5\" aria-hidden=\"true\" />\n            } @else {\n              <lucide-icon [img]=\"CheckCircle2\" class=\"text-success size-3.5\" aria-hidden=\"true\" />\n            }\n            <span>{{ isExporting() ? 'Exported' : 'Export Journey Map' }}</span>\n          </button>\n        </div>\n      </div>\n\n      <!-- Connected Horizontal Funnel Flow Ribbon -->\n      <div class=\"border-border bg-card/60 rounded-xl border p-3 shadow-xs backdrop-blur-xs\">\n        <div class=\"grid grid-cols-1 gap-2 md:grid-cols-7 md:items-center\">\n          <!-- Stage 1 Pill -->\n          <div class=\"bg-muted/40 border-border/60 flex items-center justify-between rounded-lg border px-3 py-2\">\n            <div class=\"flex min-w-0 items-center gap-2\">\n              <div class=\"bg-chart-1/15 text-chart-1 flex size-6 items-center justify-center rounded-md\">\n                <lucide-icon [img]=\"Compass\" class=\"size-3.5\" aria-hidden=\"true\" />\n              </div>\n              <div>\n                <p class=\"text-foreground text-xs font-semibold\">1. Acquisition</p>\n                <p class=\"text-muted-foreground text-xs tabular-nums\">120,000 Visitors</p>\n              </div>\n            </div>\n          </div>\n\n          <!-- Connector 1 -->\n          <div class=\"flex flex-col items-center justify-center py-1 md:py-0\">\n            <div class=\"flex items-center gap-1\">\n              <span class=\"text-muted-foreground text-xs font-medium tabular-nums\">6.8%</span>\n              <lucide-icon [img]=\"ArrowRight\" class=\"text-muted-foreground size-3.5\" aria-hidden=\"true\" />\n            </div>\n            <span class=\"text-muted-foreground/70 hidden text-xs md:inline\">Signup rate</span>\n          </div>\n\n          <!-- Stage 2 Pill -->\n          <div class=\"bg-muted/40 border-border/60 flex items-center justify-between rounded-lg border px-3 py-2\">\n            <div class=\"flex min-w-0 items-center gap-2\">\n              <div class=\"bg-chart-2/15 text-chart-2 flex size-6 items-center justify-center rounded-md\">\n                <lucide-icon [img]=\"Rocket\" class=\"size-3.5\" aria-hidden=\"true\" />\n              </div>\n              <div>\n                <p class=\"text-foreground text-xs font-semibold\">2. Activation</p>\n                <p class=\"text-muted-foreground text-xs tabular-nums\">8,160 Signups</p>\n              </div>\n            </div>\n          </div>\n\n          <!-- Connector 2 -->\n          <div class=\"flex flex-col items-center justify-center py-1 md:py-0\">\n            <div class=\"flex items-center gap-1\">\n              <span class=\"text-muted-foreground text-xs font-medium tabular-nums\">17.4%</span>\n              <lucide-icon [img]=\"ArrowRight\" class=\"text-muted-foreground size-3.5\" aria-hidden=\"true\" />\n            </div>\n            <span class=\"text-muted-foreground/70 hidden text-xs md:inline\">Upgrade rate</span>\n          </div>\n\n          <!-- Stage 3 Pill -->\n          <div class=\"bg-muted/40 border-border/60 flex items-center justify-between rounded-lg border px-3 py-2\">\n            <div class=\"flex min-w-0 items-center gap-2\">\n              <div class=\"bg-chart-3/15 text-chart-3 flex size-6 items-center justify-center rounded-md\">\n                <lucide-icon [img]=\"CreditCard\" class=\"size-3.5\" aria-hidden=\"true\" />\n              </div>\n              <div>\n                <p class=\"text-foreground text-xs font-semibold\">3. Monetization</p>\n                <p class=\"text-muted-foreground text-xs tabular-nums\">1,420 Paid</p>\n              </div>\n            </div>\n          </div>\n\n          <!-- Connector 3 -->\n          <div class=\"flex flex-col items-center justify-center py-1 md:py-0\">\n            <div class=\"flex items-center gap-1\">\n              <span class=\"text-muted-foreground text-xs font-medium tabular-nums\">92.0%</span>\n              <lucide-icon [img]=\"ArrowRight\" class=\"text-muted-foreground size-3.5\" aria-hidden=\"true\" />\n            </div>\n            <span class=\"text-muted-foreground/70 hidden text-xs md:inline\">Retention</span>\n          </div>\n\n          <!-- Stage 4 Pill -->\n          <div class=\"bg-muted/40 border-border/60 flex items-center justify-between rounded-lg border px-3 py-2\">\n            <div class=\"flex min-w-0 items-center gap-2\">\n              <div class=\"bg-chart-4/15 text-chart-4 flex size-6 items-center justify-center rounded-md\">\n                <lucide-icon [img]=\"HeartHandshake\" class=\"size-3.5\" aria-hidden=\"true\" />\n              </div>\n              <div>\n                <p class=\"text-foreground text-xs font-semibold\">4. Retention</p>\n                <p class=\"text-muted-foreground text-xs tabular-nums\">1,306 Advocates</p>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <!-- 4-Stage Horizontal Journey Grid -->\n      <div class=\"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4\">\n        @for (stage of stages; track stage.id; let idx = $index) {\n          <div\n            ui-card\n            role=\"button\"\n            tabindex=\"0\"\n            [attr.aria-pressed]=\"selectedStageIndex() === idx\"\n            [class]=\"stageCardClass(idx)\"\n            (click)=\"toggleStage(idx)\"\n            (keydown.enter)=\"toggleStage(idx)\"\n            (keydown.space)=\"toggleStageKey(idx, $event)\"\n          >\n            <div ui-card-header class=\"space-y-3 pb-3\">\n              <!-- Stage Badge & Number -->\n              <div class=\"flex items-center justify-between\">\n                <span ui-badge [variant]=\"stage.badgeVariant\" class=\"text-xs font-semibold\">\n                  Stage {{ stage.stageNumber }}\n                </span>\n                <span class=\"text-muted-foreground text-xs font-medium tracking-wider uppercase\">\n                  {{ stage.conversionLabel }}\n                </span>\n              </div>\n\n              <!-- Stage Icon & Title -->\n              <div class=\"flex items-start gap-3\">\n                <div [class]=\"stageIconClass(idx)\">\n                  <lucide-icon [img]=\"stage.icon\" class=\"size-5\" aria-hidden=\"true\" />\n                </div>\n                <div class=\"min-w-0 flex-1\">\n                  <h3 ui-card-title class=\"text-foreground text-base font-bold\">{{ stage.title }}</h3>\n                  <p ui-card-description class=\"text-muted-foreground text-xs\">{{ stage.subtitle }}</p>\n                </div>\n              </div>\n\n              <!-- Stage Volume Metric -->\n              <div\n                class=\"bg-muted/40 border-border/60 flex flex-wrap items-baseline justify-between gap-x-2 gap-y-0.5 rounded-lg border p-3\"\n              >\n                <div>\n                  <p class=\"text-muted-foreground text-xs font-medium\">{{ stage.volumeLabel }}</p>\n                  <p class=\"text-foreground text-2xl font-bold tracking-tight tabular-nums\">{{ stage.volume }}</p>\n                </div>\n                <div class=\"text-right\">\n                  <span\n                    ui-badge\n                    variant=\"outline\"\n                    class=\"border-success/30 bg-success/10 text-success gap-1 text-xs font-medium\"\n                  >\n                    <lucide-icon [img]=\"TrendingUp\" class=\"size-3\" aria-hidden=\"true\" />\n                    <span class=\"tabular-nums\">{{ stage.volumeChange }}</span>\n                  </span>\n                  <p class=\"text-muted-foreground mt-1 text-xs\">\n                    Conv: <span class=\"text-foreground font-semibold tabular-nums\">{{ stage.conversionRate }}</span>\n                  </p>\n                </div>\n              </div>\n            </div>\n\n            <div ui-card-content class=\"space-y-4 pt-0\">\n              <!-- Primary Customer Action -->\n              <div class=\"space-y-1.5\">\n                <p class=\"text-muted-foreground text-xs font-medium\">Primary Customer Action</p>\n                <div\n                  class=\"bg-accent/40 border-border/80 text-foreground flex min-w-0 items-center gap-2 rounded-md border px-2.5 py-1.5 text-xs font-medium\"\n                >\n                  <lucide-icon\n                    [img]=\"stage.primaryAction.icon\"\n                    class=\"text-primary size-3.5 shrink-0\"\n                    aria-hidden=\"true\"\n                  />\n                  <span class=\"truncate\">{{ stage.primaryAction.text }}</span>\n                </div>\n              </div>\n\n              <!-- Key Metrics Grid -->\n              <div class=\"space-y-1.5\">\n                <p class=\"text-muted-foreground text-xs font-medium\">Key Stage Signals</p>\n                <div class=\"grid grid-cols-1 gap-1.5\">\n                  @for (metric of stage.keyMetrics; track $index) {\n                    <div\n                      class=\"bg-background/60 border-border/60 flex items-center justify-between rounded-md border px-2.5 py-1.5 text-xs\"\n                    >\n                      <span class=\"text-muted-foreground\">{{ metric.label }}</span>\n                      <div class=\"flex items-center gap-1.5\">\n                        <span class=\"text-foreground font-semibold tabular-nums\">{{ metric.value }}</span>\n                        @if (metric.detail) {\n                          <span class=\"text-muted-foreground text-xs\">({{ metric.detail }})</span>\n                        }\n                      </div>\n                    </div>\n                  }\n                </div>\n              </div>\n\n              <!-- Key Touchpoints List -->\n              <div class=\"space-y-1.5\">\n                <p class=\"text-muted-foreground text-xs font-medium\">Active Touchpoints</p>\n                <ul class=\"space-y-1\">\n                  @for (tp of stage.touchpoints; track $index) {\n                    <li class=\"text-foreground/90 flex items-start gap-2 text-xs\">\n                      <div\n                        class=\"bg-primary/20 text-primary mt-0.5 flex size-3.5 shrink-0 items-center justify-center rounded-full\"\n                      >\n                        <span class=\"text-xs\">•</span>\n                      </div>\n                      <div class=\"min-w-0 flex-1\">\n                        <span>{{ tp.name }}</span>\n                        <span\n                          ui-badge\n                          variant=\"outline\"\n                          class=\"text-muted-foreground border-border ml-1.5 px-1 py-0 text-xs\"\n                        >\n                          {{ tp.channel }}\n                        </span>\n                      </div>\n                    </li>\n                  }\n                </ul>\n              </div>\n\n              <ui-separator class=\"my-2\" />\n\n              <!-- Sentiment Indicator -->\n              <div class=\"space-y-1.5\">\n                <div class=\"flex items-center justify-between text-xs\">\n                  <span class=\"text-muted-foreground flex items-center gap-1\">\n                    <!-- host display:contents + [class] on the svg: the svg itself is the flex item and shrinks\n                         when the label wraps, as React's bare <svg> does -->\n                    <lucide-icon [img]=\"Smile\" [class]=\"'text-primary size-3.5'\" aria-hidden=\"true\" />\n                    Sentiment Score\n                  </span>\n                  <span class=\"text-foreground font-semibold tabular-nums\">\n                    {{ stage.sentiment.gaugeLabel }} ({{ stage.sentiment.label }})\n                  </span>\n                </div>\n                <ui-progress [value]=\"sentimentValue(stage)\" class=\"h-1.5\" />\n              </div>\n\n              <!-- Friction / Drop-off Point Note -->\n              <div class=\"bg-destructive/5 border-destructive/20 rounded-md border p-2.5\">\n                <div class=\"flex items-start gap-2\">\n                  <!-- [class], not class=: lucide-angular copies a static class onto its host AND the svg, doubling mt-0.5 -->\n                  <lucide-icon\n                    [img]=\"ShieldAlert\"\n                    [class]=\"'text-destructive mt-0.5 size-3.5 shrink-0'\"\n                    aria-hidden=\"true\"\n                  />\n                  <div class=\"text-xs\">\n                    <span class=\"text-destructive font-semibold\">Friction Point: </span>\n                    <span class=\"text-foreground/80\">{{ stage.frictionPoint }}</span>\n                  </div>\n                </div>\n              </div>\n\n              <!-- Opportunity / Next Experiment Box -->\n              <div class=\"bg-primary/5 border-primary/20 rounded-md border p-2.5\">\n                <div class=\"flex items-start gap-2\">\n                  <lucide-icon [img]=\"Lightbulb\" [class]=\"'text-primary mt-0.5 size-3.5 shrink-0'\" aria-hidden=\"true\" />\n                  <div class=\"min-w-0 flex-1 space-y-0.5 text-xs\">\n                    <div class=\"flex flex-wrap items-center justify-between gap-1\">\n                      <span class=\"text-primary font-semibold\">Growth Experiment:</span>\n                      <span\n                        ui-badge\n                        variant=\"outline\"\n                        class=\"border-primary/30 text-primary bg-primary/10 text-xs font-semibold tabular-nums\"\n                      >\n                        {{ stage.opportunity.expectedImpact }}\n                      </span>\n                    </div>\n                    <p class=\"text-foreground/80 leading-relaxed\">{{ stage.opportunity.experiment }}</p>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </div>\n        }\n      </div>\n\n      <!-- Cross-Stage Conversion Velocity & Funnel Health Summary -->\n      <div ui-card class=\"border-border bg-card shadow-xs\">\n        <div ui-card-header class=\"pb-3\">\n          <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n            <div>\n              <h3 ui-card-title class=\"text-foreground text-lg font-bold\">\n                Lifecycle Conversion Velocity & Health Diagnostics\n              </h3>\n              <p ui-card-description class=\"text-muted-foreground text-xs\">\n                End-to-end efficiency metrics tracking user progression speed from initial acquisition to retained\n                advocacy.\n              </p>\n            </div>\n            <span\n              ui-badge\n              variant=\"outline\"\n              class=\"border-success/30 bg-success/10 text-success w-fit gap-1 text-xs font-semibold\"\n            >\n              <lucide-icon [img]=\"CheckCircle2\" class=\"size-3.5\" aria-hidden=\"true\" />\n              Healthy Velocity (+18% QoQ)\n            </span>\n          </div>\n        </div>\n\n        <div ui-card-content class=\"space-y-5\">\n          <!-- Metric Cards Strip -->\n          <div class=\"grid grid-cols-2 gap-3 sm:grid-cols-4\">\n            <div class=\"bg-muted/30 border-border/70 rounded-lg border p-3\">\n              <div class=\"flex items-center gap-1.5\">\n                <!-- host display:contents + [class] on the svg: the svg shrinks when the label wraps, as in React -->\n                <lucide-icon [img]=\"TrendingUp\" [class]=\"'text-chart-1 size-3.5'\" aria-hidden=\"true\" />\n                <span class=\"text-muted-foreground text-xs font-medium\">Overall Conversion</span>\n              </div>\n              <p class=\"text-foreground mt-1 text-2xl font-bold tracking-tight tabular-nums\">\n                {{ overallSummary.funnelConversion }}\n              </p>\n              <p class=\"text-muted-foreground text-xs\">{{ overallSummary.funnelConversionDetail }}</p>\n            </div>\n\n            <div class=\"bg-muted/30 border-border/70 rounded-lg border p-3\">\n              <div class=\"flex items-center gap-1.5\">\n                <lucide-icon [img]=\"Zap\" [class]=\"'text-chart-2 size-3.5'\" aria-hidden=\"true\" />\n                <span class=\"text-muted-foreground text-xs font-medium\">Time to Value (TTV)</span>\n              </div>\n              <p class=\"text-foreground mt-1 text-2xl font-bold tracking-tight tabular-nums\">\n                {{ overallSummary.timeToValue }}\n              </p>\n              <p class=\"text-muted-foreground text-xs\">{{ overallSummary.timeToValueDetail }}</p>\n            </div>\n\n            <div class=\"bg-muted/30 border-border/70 rounded-lg border p-3\">\n              <div class=\"flex items-center gap-1.5\">\n                <lucide-icon [img]=\"Clock\" [class]=\"'text-chart-3 size-3.5'\" aria-hidden=\"true\" />\n                <span class=\"text-muted-foreground text-xs font-medium\">Avg. Conversion Velocity</span>\n              </div>\n              <p class=\"text-foreground mt-1 text-2xl font-bold tracking-tight tabular-nums\">\n                {{ overallSummary.conversionVelocity }}\n              </p>\n              <p class=\"text-muted-foreground text-xs\">{{ overallSummary.conversionVelocityDetail }}</p>\n            </div>\n\n            <div class=\"bg-muted/30 border-border/70 rounded-lg border p-3\">\n              <div class=\"flex items-center gap-1.5\">\n                <lucide-icon [img]=\"HeartHandshake\" [class]=\"'text-chart-4 size-3.5'\" aria-hidden=\"true\" />\n                <span class=\"text-muted-foreground text-xs font-medium\">Net Revenue Retention</span>\n              </div>\n              <p class=\"text-foreground mt-1 text-2xl font-bold tracking-tight tabular-nums\">\n                {{ overallSummary.netRetention }}\n              </p>\n              <p class=\"text-muted-foreground text-xs\">{{ overallSummary.netRetentionDetail }}</p>\n            </div>\n          </div>\n\n          <!-- Stage Transition Flow Breakdown Bar -->\n          <div class=\"space-y-2\">\n            <div class=\"flex items-center justify-between text-xs\">\n              <span class=\"text-muted-foreground font-medium\">Lifecycle Pass-Through Velocity</span>\n              <span class=\"text-foreground font-semibold tabular-nums\">4 Stages Active • 120,000 Cohort Cohere</span>\n            </div>\n\n            <!-- Multi-segment Funnel Bar -->\n            <div class=\"bg-muted/60 flex h-3.5 w-full overflow-hidden rounded-full p-0.5\">\n              <div class=\"bg-chart-1 h-full w-[45%] rounded-l-full\" title=\"Acquisition (120,000)\"></div>\n              <div class=\"bg-chart-2 h-full w-[25%]\" title=\"Activation (8,160)\"></div>\n              <div class=\"bg-chart-3 h-full w-[18%]\" title=\"Monetization (1,420)\"></div>\n              <div class=\"bg-chart-4 h-full w-[12%] rounded-r-full\" title=\"Retention (92% NRR)\"></div>\n            </div>\n\n            <div class=\"grid grid-cols-2 gap-2 text-xs sm:grid-cols-4\">\n              <div class=\"flex items-center gap-1.5\">\n                <span class=\"bg-chart-1 size-2 rounded-full\"></span>\n                <span class=\"text-muted-foreground\">Acquisition (100%)</span>\n              </div>\n              <div class=\"flex items-center gap-1.5\">\n                <span class=\"bg-chart-2 size-2 rounded-full\"></span>\n                <span class=\"text-muted-foreground\">Activation (6.8%)</span>\n              </div>\n              <div class=\"flex items-center gap-1.5\">\n                <span class=\"bg-chart-3 size-2 rounded-full\"></span>\n                <span class=\"text-muted-foreground\">Monetization (17.4%)</span>\n              </div>\n              <div class=\"flex items-center gap-1.5\">\n                <span class=\"bg-chart-4 size-2 rounded-full\"></span>\n                <span class=\"text-muted-foreground\">Retention (92.0%)</span>\n              </div>\n            </div>\n          </div>\n\n          <ui-separator />\n\n          <!-- Key Strategic Growth Takeaway Callout -->\n          <div\n            class=\"bg-muted/40 border-border/80 flex flex-col gap-3 rounded-lg border p-4 sm:flex-row sm:items-center sm:justify-between\"\n          >\n            <div class=\"flex items-start gap-3\">\n              <div\n                class=\"bg-primary/10 text-primary border-primary/20 mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-lg border\"\n              >\n                <lucide-icon [img]=\"TrendingUp\" class=\"size-4\" aria-hidden=\"true\" />\n              </div>\n              <div class=\"space-y-1\">\n                <div class=\"flex min-w-0 items-center gap-2\">\n                  <p class=\"text-foreground text-sm font-semibold\">Primary Strategic Growth Takeaway</p>\n                  <span\n                    ui-badge\n                    variant=\"outline\"\n                    class=\"border-warning/30 bg-warning/10 text-warning text-xs font-medium\"\n                  >\n                    High Priority\n                  </span>\n                </div>\n                <p class=\"text-muted-foreground text-xs leading-relaxed\">\n                  The largest leverage point in the current cohort is the\n                  <strong class=\"text-foreground\">Activation-to-Monetization conversion gap (17.4%)</strong>.\n                  Implementing contextual in-app checkout prompts at high-usage milestones and launching annual billing\n                  discounts is modeled to generate an additional\n                  <span class=\"text-foreground font-semibold tabular-nums\">+$14,200 / mo</span> in net new MRR.\n                </p>\n              </div>\n            </div>\n\n            <button ui-button size=\"sm\" class=\"h-8 shrink-0 gap-1.5 text-xs font-semibold\">\n              <span>Apply Experiments</span>\n              <lucide-icon [img]=\"ArrowUpRight\" class=\"size-3.5\" aria-hidden=\"true\" />\n            </button>\n          </div>\n        </div>\n      </div>\n    </div>\n  `,\n})\nexport class UiCustomerJourneyMapComponent {\n  @Input('class') className?: string\n\n  readonly selectedTimeframe = signal('30d')\n  readonly isExporting = signal(false)\n  readonly selectedStageIndex = signal<number | null>(null)\n\n  protected readonly timeframes = timeframes\n  protected readonly stages = stages\n  protected readonly overallSummary = overallSummary\n\n  protected readonly ArrowRight = ArrowRight\n  protected readonly ArrowUpRight = ArrowUpRight\n  protected readonly CheckCircle2 = CheckCircle2\n  protected readonly Clock = Clock\n  protected readonly Compass = Compass\n  protected readonly CreditCard = CreditCard\n  protected readonly Download = Download\n  protected readonly HeartHandshake = HeartHandshake\n  protected readonly Lightbulb = Lightbulb\n  protected readonly Rocket = Rocket\n  protected readonly ShieldAlert = ShieldAlert\n  protected readonly Smile = Smile\n  protected readonly TrendingUp = TrendingUp\n  protected readonly Zap = Zap\n\n  get rootClass(): string {\n    return cn('space-y-6', this.className)\n  }\n\n  handleExport(): void {\n    this.isExporting.set(true)\n    setTimeout(() => {\n      this.isExporting.set(false)\n    }, 1200)\n  }\n\n  toggleStage(idx: number): void {\n    this.selectedStageIndex.set(this.selectedStageIndex() === idx ? null : idx)\n  }\n\n  toggleStageKey(idx: number, event: KeyboardEvent): void {\n    event.preventDefault()\n    this.toggleStage(idx)\n  }\n\n  protected timeframeClass(id: string): string {\n    return cn(\n      'focus-visible:ring-ring rounded-md px-2.5 py-1 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-hidden',\n      this.selectedTimeframe() === id\n        ? 'bg-background text-foreground shadow-xs'\n        : 'text-muted-foreground hover:text-foreground',\n    )\n  }\n\n  protected stageCardClass(idx: number): string {\n    return cn(\n      'border-border hover:border-primary/40 focus-visible:ring-ring relative flex cursor-pointer flex-col justify-between transition-colors duration-200 focus-visible:ring-2 focus-visible:outline-none',\n      this.selectedStageIndex() === idx && 'ring-primary/40 ring-2',\n    )\n  }\n\n  protected stageIconClass(idx: number): string {\n    return cn(\n      'flex size-10 shrink-0 items-center justify-center rounded-lg border shadow-xs',\n      idx === 0 && 'border-chart-1/30 bg-chart-1/10 text-chart-1',\n      idx === 1 && 'border-chart-2/30 bg-chart-2/10 text-chart-2',\n      idx === 2 && 'border-chart-3/30 bg-chart-3/10 text-chart-3',\n      idx === 3 && 'border-chart-4/30 bg-chart-4/10 text-chart-4',\n    )\n  }\n\n  protected sentimentValue(stage: JourneyStage): number {\n    return (stage.sentiment.score / stage.sentiment.maxScore) * 100\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/customer-journey-map/customer-journey-map.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/customer-journey-map/index.ts",
      "content": "export { UiCustomerJourneyMapComponent, type JourneyStage } from './customer-journey-map.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/customer-journey-map/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": "Visual customer lifecycle funnel and journey map tracking user touchpoints across Acquisition, Activation, Monetization, and Retention. Features conversion rates, friction analysis, sentiment gauges, growth experiment notes, and cross-stage velocity summaries.",
  "categories": [
    "analytics",
    "dashboard",
    "marketing"
  ]
}