{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "service-health-matrix",
  "title": "Service Health Matrix",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/service-health-matrix/service-health-matrix.component.ts",
      "content": "// Statuspage / BetterStack style global region latency & infrastructure health matrix:\n// overall operational status banner, 6-region latency grid with SVG sparklines, 90-day\n// core service uptime bars, and an incident history timeline. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, DestroyRef, Input, computed, inject, signal } from '@angular/core'\nimport {\n  Activity,\n  AlertTriangle,\n  Bell,\n  Check,\n  CheckCircle2,\n  Clock,\n  Cpu,\n  Database,\n  Globe,\n  LucideAngularModule,\n  RefreshCw,\n  Server,\n  ShieldCheck,\n  Zap,\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'\n\nexport type RegionStatus = 'operational' | 'degraded' | 'outage' | 'maintenance'\nexport type DayStatus = 'up' | 'degraded' | 'down' | 'maintenance'\nexport type IncidentSeverity = 'minor' | 'major' | 'critical' | 'maintenance'\n\nexport interface RegionHealth {\n  id: string\n  name: string\n  location: string\n  code: string\n  latency: number\n  status: RegionStatus\n  uptime: number\n  p95Latency?: number\n  packetLoss?: number\n  latencyHistory?: number[]\n}\n\nexport interface ServiceHealthItem {\n  id: string\n  name: string\n  description?: string\n  icon?: 'auth' | 'cdn' | 'database' | 'webhook' | 'ai'\n  uptime: number\n  status: RegionStatus\n  days?: DayStatus[]\n}\n\nexport interface IncidentUpdate {\n  time: string\n  status: string\n  description: string\n}\n\nexport interface IncidentRecord {\n  id: string\n  title: string\n  date: string\n  severity: IncidentSeverity\n  resolved: boolean\n  duration: string\n  updates: IncidentUpdate[]\n}\n\nfunction generate90Days(blips: Array<{ dayAgo: number; status: DayStatus }> = []): DayStatus[] {\n  const days: DayStatus[] = Array.from({ length: 90 }, () => 'up')\n  for (const blip of blips) {\n    const idx = 89 - blip.dayAgo\n    if (idx >= 0 && idx < 90) {\n      days[idx] = blip.status\n    }\n  }\n  return days\n}\n\nconst defaultRegions: RegionHealth[] = [\n  {\n    id: 'us-east',\n    name: 'US East',\n    location: 'N. Virginia',\n    code: 'us-east-1',\n    latency: 24,\n    status: 'operational',\n    uptime: 100,\n    p95Latency: 28,\n    packetLoss: 0.0,\n    latencyHistory: [26, 25, 24, 25, 23, 24, 25, 24, 23, 24, 25, 24],\n  },\n  {\n    id: 'us-west',\n    name: 'US West',\n    location: 'Oregon',\n    code: 'us-west-2',\n    latency: 38,\n    status: 'operational',\n    uptime: 99.98,\n    p95Latency: 42,\n    packetLoss: 0.0,\n    latencyHistory: [40, 39, 38, 37, 38, 39, 38, 38, 37, 38, 39, 38],\n  },\n  {\n    id: 'eu-central',\n    name: 'EU Central',\n    location: 'Frankfurt',\n    code: 'eu-central-1',\n    latency: 18,\n    status: 'operational',\n    uptime: 100,\n    p95Latency: 21,\n    packetLoss: 0.0,\n    latencyHistory: [19, 18, 18, 17, 18, 19, 18, 18, 17, 18, 18, 18],\n  },\n  {\n    id: 'ap-south',\n    name: 'AP South',\n    location: 'Mumbai',\n    code: 'ap-south-1',\n    latency: 45,\n    status: 'operational',\n    uptime: 99.95,\n    p95Latency: 52,\n    packetLoss: 0.01,\n    latencyHistory: [47, 46, 45, 44, 45, 48, 46, 45, 44, 45, 46, 45],\n  },\n  {\n    id: 'ap-east',\n    name: 'AP East',\n    location: 'Tokyo',\n    code: 'ap-northeast-1',\n    latency: 32,\n    status: 'operational',\n    uptime: 99.99,\n    p95Latency: 36,\n    packetLoss: 0.0,\n    latencyHistory: [34, 33, 32, 31, 32, 33, 32, 32, 31, 32, 33, 32],\n  },\n  {\n    id: 'sa-east',\n    name: 'SA East',\n    location: 'São Paulo',\n    code: 'sa-east-1',\n    latency: 58,\n    status: 'operational',\n    uptime: 99.91,\n    p95Latency: 65,\n    packetLoss: 0.02,\n    latencyHistory: [62, 60, 59, 58, 61, 58, 59, 58, 57, 58, 60, 58],\n  },\n]\n\nconst defaultServices: ServiceHealthItem[] = [\n  {\n    id: 'auth-api',\n    name: 'Authentication API',\n    description: 'OAuth2 / SAML SSO · Session Tokens · JWT Validation',\n    icon: 'auth',\n    uptime: 99.99,\n    status: 'operational',\n    days: generate90Days(),\n  },\n  {\n    id: 'edge-cdn',\n    name: 'Edge CDN & DNS',\n    description: 'Anycast Global Routing · Edge Cache · SSL Termination',\n    icon: 'cdn',\n    uptime: 100.0,\n    status: 'operational',\n    days: generate90Days(),\n  },\n  {\n    id: 'postgres-cluster',\n    name: 'Postgres Database Cluster',\n    description: 'Primary Write Node · Regional Read Replicas · Pooler',\n    icon: 'database',\n    uptime: 99.97,\n    status: 'operational',\n    days: generate90Days([{ dayAgo: 42, status: 'degraded' }]),\n  },\n  {\n    id: 'webhook-dispatcher',\n    name: 'Webhook Dispatcher',\n    description: 'Event Streaming Engine · Exponential Backoff Retries',\n    icon: 'webhook',\n    uptime: 99.98,\n    status: 'operational',\n    days: generate90Days([{ dayAgo: 1, status: 'degraded' }]),\n  },\n  {\n    id: 'ai-gateway',\n    name: 'AI Inference Gateway',\n    description: 'Model Routing · Streaming Token Buffers · Semantic Cache',\n    icon: 'ai',\n    uptime: 99.95,\n    status: 'operational',\n    days: generate90Days([{ dayAgo: 18, status: 'degraded' }]),\n  },\n]\n\nconst defaultIncidents: IncidentRecord[] = [\n  {\n    id: 'inc-1',\n    title: 'Elevated latency on Webhook Dispatcher',\n    date: 'Yesterday · Aug 20, 2026',\n    severity: 'minor',\n    resolved: true,\n    duration: '18 minutes',\n    updates: [\n      {\n        time: '14:40 UTC',\n        status: 'Resolved',\n        description:\n          'The backlog of outgoing webhook payloads has fully drained. All queued webhook events were delivered with zero packet drop. Worker autoscaling thresholds have been adjusted.',\n      },\n      {\n        time: '14:22 UTC',\n        status: 'Investigating',\n        description:\n          'We identified a localized queue lock in the dispatch workers following a Redis connection pool saturation. Workers were scaled up and connection pool limits raised.',\n      },\n    ],\n  },\n  {\n    id: 'inc-2',\n    title: 'Scheduled Maintenance: Postgres Cluster Engine Upgrade',\n    date: 'Aug 14, 2026',\n    severity: 'maintenance',\n    resolved: true,\n    duration: '12 minutes',\n    updates: [\n      {\n        time: '02:12 UTC',\n        status: 'Completed',\n        description:\n          'Primary instance switchover completed smoothly. Read replicas synchronized without data lag. All database endpoints are fully operational.',\n      },\n      {\n        time: '02:00 UTC',\n        status: 'In Progress',\n        description:\n          'Scheduled rolling restart of secondary read replicas initiated while applying minor database engine updates.',\n      },\n    ],\n  },\n]\n\ninterface BannerConfig {\n  title: string\n  badge: string\n  badgeVariant: 'success' | 'warning' | 'destructive' | 'info'\n  containerClass: string\n  dotClass: string\n  textClass: string\n}\n\nconst statusBannerConfig: Record<RegionStatus, BannerConfig> = {\n  operational: {\n    title: 'All Systems Operational',\n    badge: '99.99% 90-day uptime',\n    badgeVariant: 'success',\n    containerClass: 'border-success/30 bg-success/10 text-success',\n    dotClass: 'bg-success',\n    textClass: 'text-success',\n  },\n  degraded: {\n    title: 'Active Service Degradation',\n    badge: 'Elevated Latency Detected',\n    badgeVariant: 'warning',\n    containerClass: 'border-warning/30 bg-warning/10 text-warning',\n    dotClass: 'bg-warning',\n    textClass: 'text-warning',\n  },\n  outage: {\n    title: 'Partial System Outage',\n    badge: 'Incident Under Investigation',\n    badgeVariant: 'destructive',\n    containerClass: 'border-destructive/30 bg-destructive/10 text-destructive',\n    dotClass: 'bg-destructive',\n    textClass: 'text-destructive',\n  },\n  maintenance: {\n    title: 'Scheduled Maintenance in Progress',\n    badge: 'Planned Upgrades',\n    badgeVariant: 'info',\n    containerClass: 'border-info/30 bg-info/10 text-info',\n    dotClass: 'bg-info',\n    textClass: 'text-info',\n  },\n}\n\nconst dayClassMap: Record<DayStatus, string> = {\n  up: 'bg-success/80 hover:bg-success bg-success/70 dark:hover:bg-success',\n  degraded: 'bg-warning/90 hover:bg-warning',\n  down: 'bg-destructive hover:bg-destructive',\n  maintenance: 'bg-info hover:bg-info',\n}\n\nconst dayLabelMap: Record<DayStatus, string> = {\n  up: 'Operational (100%)',\n  degraded: 'Degraded Performance',\n  down: 'Major Outage',\n  maintenance: 'Scheduled Maintenance',\n}\n\nconst severityBadgeMap: Record<IncidentSeverity, { variant: BadgeVariant; label: string }> = {\n  minor: { variant: 'warning', label: 'Minor' },\n  major: { variant: 'destructive', label: 'Major' },\n  critical: { variant: 'destructive', label: 'Critical' },\n  maintenance: { variant: 'secondary', label: 'Maintenance' },\n}\n\ninterface Sparkline {\n  path: string\n  area: string\n  lastPoint: { x: number; y: number }\n}\n\nfunction buildSparkline(history: number[] = [24, 24, 24, 24]): Sparkline {\n  const min = Math.min(...history)\n  const max = Math.max(...history)\n  const range = max - min || 1\n  const height = 26\n  const padding = 3\n  const points = history.map((val, idx) => {\n    const x = (idx / (history.length - 1)) * 100\n    const y = height - ((val - min) / range) * (height - padding * 2) - padding\n    return { x, y }\n  })\n  let path = `M ${points[0].x},${points[0].y}`\n  for (let i = 1; i < points.length; i++) {\n    const prev = points[i - 1]\n    const curr = points[i]\n    const cx = (prev.x + curr.x) / 2\n    path += ` C ${cx},${prev.y} ${cx},${curr.y} ${curr.x},${curr.y}`\n  }\n  const lastPoint = points[points.length - 1]\n  const area = `${path} L 100,32 L 0,32 Z`\n  return { path, area, lastPoint }\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-service-health-matrix, [ui-service-health-matrix]',\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    UiCardContentComponent,\n    UiCardDescriptionComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n  ],\n  template: `\n    <div data-slot=\"service-health-matrix\" [class]=\"rootClass\">\n      <!-- Header Banner -->\n      <div\n        role=\"status\"\n        [class]=\"\n          cn(\n            'flex flex-col gap-4 rounded-xl border p-4 shadow-xs transition-colors sm:p-5 md:flex-row md:items-center md:justify-between',\n            currentBanner().containerClass\n          )\n        \"\n      >\n        <div class=\"flex items-start gap-3.5 sm:items-center\">\n          <span class=\"relative mt-1 flex size-3 shrink-0 sm:mt-0\">\n            <span\n              [class]=\"cn('absolute inline-flex h-full w-full rounded-full opacity-75', currentBanner().dotClass)\"\n            ></span>\n            <span [class]=\"cn('relative inline-flex size-3 rounded-full', currentBanner().dotClass)\"></span>\n          </span>\n          <div class=\"space-y-1\">\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <h1 class=\"text-foreground text-base leading-none font-semibold tracking-tight sm:text-lg\">\n                {{ currentBanner().title }}\n              </h1>\n              <span [class]=\"cn('flex items-center gap-2 text-xs font-medium sm:text-sm', currentBanner().textClass)\">\n                {{ systemUptime() }} 90-day uptime\n              </span>\n            </div>\n            <p class=\"text-muted-foreground text-xs\">\n              Continuous synthetic telemetry and edge probe latency across all global endpoints.\n            </p>\n          </div>\n        </div>\n\n        <div class=\"flex flex-wrap items-center gap-2 self-end sm:gap-3 md:self-center\">\n          <div class=\"text-muted-foreground flex items-center gap-1.5 text-xs\">\n            <lucide-icon [img]=\"Clock\" class=\"size-3.5\" />\n            <span>{{ currentUpdatedText() }}</span>\n            <button\n              ui-button\n              variant=\"ghost\"\n              size=\"icon-sm\"\n              class=\"size-7 rounded-md\"\n              aria-label=\"Refresh status telemetry\"\n              (click)=\"handleRefresh()\"\n            >\n              <lucide-icon [img]=\"RefreshCw\" [class]=\"cn('size-3.5', isRefreshing() && 'animate-spin')\" />\n            </button>\n          </div>\n\n          <div class=\"relative\">\n            @if (!isSubscribed()) {\n              <button\n                ui-button\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"h-8 gap-1.5 text-xs font-medium shadow-xs\"\n                (click)=\"showSubscribeInput.set(!showSubscribeInput())\"\n              >\n                <lucide-icon [img]=\"Bell\" class=\"size-3.5\" />\n                <span>Subscribe to Updates</span>\n              </button>\n            } @else {\n              <span ui-badge variant=\"success\" class=\"h-8 gap-1.5 px-3 text-xs font-medium\">\n                <lucide-icon [img]=\"Check\" class=\"size-3.5\" />\n                Subscribed\n              </span>\n            }\n          </div>\n        </div>\n      </div>\n\n      <!-- Collapsible Subscribe Input Form -->\n      @if (showSubscribeInput() && !isSubscribed()) {\n        <div\n          class=\"border-border bg-card text-card-foreground flex flex-col items-stretch gap-2 rounded-lg border p-3 shadow-xs sm:flex-row sm:items-center\"\n        >\n          <div class=\"flex-1\">\n            <p class=\"text-foreground text-xs font-medium\">Get instant outage alerts via Email</p>\n            <p class=\"text-muted-foreground text-xs\">\n              We will only notify you for major severity incidents and maintenance.\n            </p>\n          </div>\n          <div class=\"flex items-center gap-2\">\n            <input\n              type=\"email\"\n              [value]=\"emailInput()\"\n              (input)=\"emailInput.set($any($event.target).value)\"\n              placeholder=\"admin@company.com\"\n              class=\"border-border bg-background placeholder:text-muted-foreground focus-visible:ring-ring h-8 w-full rounded-md border px-2.5 text-xs focus-visible:ring-2 focus-visible:outline-none sm:w-64\"\n              (keydown.enter)=\"handleSubscribeSubmit()\"\n            />\n            <button ui-button size=\"sm\" class=\"h-8 shrink-0 px-3 text-xs\" (click)=\"handleSubscribeSubmit()\">\n              Subscribe\n            </button>\n          </div>\n        </div>\n      }\n\n      <!-- Section 1: Global Region Latency Grid -->\n      <div class=\"space-y-3\">\n        <div class=\"flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between\">\n          <div>\n            <h2 class=\"text-foreground text-sm font-semibold tracking-tight\">Global Region Latency Grid</h2>\n            <p class=\"text-muted-foreground text-xs\">\n              Real-time edge response round-trip time and packet loss metrics.\n            </p>\n          </div>\n          <div class=\"text-muted-foreground flex items-center gap-2 text-xs\">\n            <span class=\"bg-success inline-flex size-2 rounded-full\"></span>\n            <span>All 6 Edge Zones Live</span>\n          </div>\n        </div>\n\n        <div class=\"grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-3\">\n          @for (region of regions(); track region.id) {\n            <div\n              ui-card\n              class=\"border-border/80 bg-card text-card-foreground hover:border-border shadow-xs transition-colors\"\n            >\n              <div ui-card-header class=\"p-4 pb-2\">\n                <div class=\"flex items-start justify-between gap-2\">\n                  <div class=\"flex items-center gap-2.5\">\n                    <div\n                      class=\"bg-muted/70 text-muted-foreground border-border/50 flex size-8 shrink-0 items-center justify-center rounded-md border\"\n                    >\n                      <lucide-icon [img]=\"Globe\" class=\"size-4\" />\n                    </div>\n                    <div>\n                      <h3 ui-card-title class=\"text-sm leading-snug font-semibold\">{{ region.name }}</h3>\n                      <p ui-card-description class=\"text-xs\">\n                        {{ region.location }} · <span class=\"text-muted-foreground font-mono\">{{ region.code }}</span>\n                      </p>\n                    </div>\n                  </div>\n\n                  <span\n                    ui-badge\n                    [variant]=\"regionBadgeVariant(region.status)\"\n                    class=\"shrink-0 text-xs font-medium capitalize\"\n                  >\n                    <span [class]=\"cn('mr-1 size-1.5 rounded-full', regionDotClass(region.status))\"></span>\n                    {{ region.status }}\n                  </span>\n                </div>\n              </div>\n\n              <div ui-card-content class=\"space-y-3 p-4 pt-1\">\n                <div class=\"flex flex-wrap items-baseline justify-between gap-x-2 gap-y-0.5 pt-1\">\n                  <div class=\"flex items-baseline gap-1.5\">\n                    <span class=\"text-foreground font-mono text-2xl font-bold tracking-tight\"\n                      >{{ region.latency }}ms</span\n                    >\n                    <span class=\"text-muted-foreground text-xs\">ping</span>\n                  </div>\n                  <div [class]=\"cn('flex items-center gap-1 text-xs font-medium', latencyToneClass(region.latency))\">\n                    <lucide-icon [img]=\"Activity\" class=\"size-3\" />\n                    <span>{{ latencyLabel(region.latency) }}</span>\n                  </div>\n                </div>\n\n                <div class=\"h-9 w-full overflow-hidden pt-1\" [attr.aria-label]=\"region.name + ' latency sparkline'\">\n                  <svg class=\"h-full w-full overflow-visible\" viewBox=\"0 0 100 32\" preserveAspectRatio=\"none\">\n                    <defs>\n                      <linearGradient [id]=\"'grad-ng-' + region.id\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n                        <stop offset=\"0%\" [attr.stop-color]=\"sparkColor(region.status)\" stop-opacity=\"0.25\" />\n                        <stop offset=\"100%\" [attr.stop-color]=\"sparkColor(region.status)\" stop-opacity=\"0.0\" />\n                      </linearGradient>\n                    </defs>\n                    <path [attr.d]=\"spark(region).area\" [attr.fill]=\"'url(#grad-ng-' + region.id + ')'\" />\n                    <path\n                      [attr.d]=\"spark(region).path\"\n                      fill=\"none\"\n                      [attr.stroke]=\"sparkColor(region.status)\"\n                      stroke-width=\"2\"\n                      stroke-linecap=\"round\"\n                      stroke-linejoin=\"round\"\n                    />\n                    <circle\n                      [attr.cx]=\"spark(region).lastPoint.x\"\n                      [attr.cy]=\"spark(region).lastPoint.y\"\n                      r=\"2.5\"\n                      [class]=\"region.status === 'operational' ? 'fill-success' : 'fill-warning'\"\n                    />\n                  </svg>\n                </div>\n\n                <div\n                  class=\"border-border/50 text-muted-foreground flex items-center justify-between border-t pt-2.5 text-xs\"\n                >\n                  <div class=\"text-foreground flex items-center gap-1 font-medium\">\n                    <lucide-icon [img]=\"CheckCircle2\" class=\"text-success size-3.5 shrink-0\" />\n                    <span>{{ region.uptime }}% uptime</span>\n                  </div>\n                  <div class=\"flex items-center gap-2 font-mono\">\n                    <span>P95: {{ region.p95Latency ?? 28 }}ms</span>\n                    <span>·</span>\n                    <span>{{ region.packetLoss ?? 0 }}% loss</span>\n                  </div>\n                </div>\n              </div>\n            </div>\n          }\n        </div>\n      </div>\n\n      <!-- Section 2: Core Services Component Health List -->\n      <div class=\"space-y-3\">\n        <div class=\"flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between\">\n          <div>\n            <h2 class=\"text-foreground text-sm font-semibold tracking-tight\">Core Services Component Health</h2>\n            <p class=\"text-muted-foreground text-xs\">90-day daily uptime history and service availability breakdown.</p>\n          </div>\n\n          <div class=\"text-muted-foreground flex flex-wrap items-center gap-3 text-xs\">\n            <div class=\"flex items-center gap-1.5\">\n              <span class=\"bg-success size-2 rounded-full\"></span>\n              <span>Operational</span>\n            </div>\n            <div class=\"flex items-center gap-1.5\">\n              <span class=\"bg-warning size-2 rounded-full\"></span>\n              <span>Degraded</span>\n            </div>\n            <div class=\"flex items-center gap-1.5\">\n              <span class=\"bg-destructive size-2 rounded-full\"></span>\n              <span>Outage</span>\n            </div>\n            <div class=\"flex items-center gap-1.5\">\n              <span class=\"bg-info size-2 rounded-full\"></span>\n              <span>Maintenance</span>\n            </div>\n          </div>\n        </div>\n\n        <div ui-card class=\"border-border/80 bg-card text-card-foreground overflow-hidden shadow-xs\">\n          <div class=\"divide-border/60 divide-y\">\n            @for (service of services(); track service.id) {\n              <div class=\"hover:bg-muted/15 space-y-3 p-4 transition-colors sm:p-5\">\n                <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n                  <div class=\"flex items-center gap-3\">\n                    <div\n                      class=\"bg-muted text-muted-foreground border-border/50 flex size-8 shrink-0 items-center justify-center rounded-lg border\"\n                    >\n                      @switch (service.icon) {\n                        @case ('auth') {\n                          <lucide-icon [img]=\"ShieldCheck\" class=\"size-4\" />\n                        }\n                        @case ('cdn') {\n                          <lucide-icon [img]=\"Globe\" class=\"size-4\" />\n                        }\n                        @case ('database') {\n                          <lucide-icon [img]=\"Database\" class=\"size-4\" />\n                        }\n                        @case ('webhook') {\n                          <lucide-icon [img]=\"Zap\" class=\"size-4\" />\n                        }\n                        @case ('ai') {\n                          <lucide-icon [img]=\"Cpu\" class=\"size-4\" />\n                        }\n                        @default {\n                          <lucide-icon [img]=\"Server\" class=\"size-4\" />\n                        }\n                      }\n                    </div>\n                    <div>\n                      <p class=\"text-foreground text-sm leading-tight font-semibold\">{{ service.name }}</p>\n                      @if (service.description) {\n                        <p class=\"text-muted-foreground mt-0.5 text-xs\">{{ service.description }}</p>\n                      }\n                    </div>\n                  </div>\n\n                  <div class=\"flex items-center gap-3 self-start sm:self-auto\">\n                    <span class=\"text-foreground font-mono text-xs font-semibold tabular-nums\">\n                      {{ service.uptime }}% uptime\n                    </span>\n                    <span\n                      ui-badge\n                      [variant]=\"serviceBadgeVariant(service.status)\"\n                      class=\"text-xs font-medium capitalize\"\n                    >\n                      <span [class]=\"cn('mr-1 size-1.5 rounded-full', regionDotClass(service.status))\"></span>\n                      {{ service.status }}\n                    </span>\n                  </div>\n                </div>\n\n                <div class=\"space-y-1.5\">\n                  <div\n                    class=\"flex w-full gap-px overflow-hidden sm:gap-[2px]\"\n                    role=\"img\"\n                    [attr.aria-label]=\"service.name + ' 90-day availability history (' + service.uptime + '%)'\"\n                  >\n                    @for (day of daysFor(service); track $index) {\n                      <span\n                        [class]=\"\n                          cn(\n                            'h-6 min-w-px flex-1 cursor-pointer rounded-xs transition-transform hover:scale-y-125',\n                            dayClass(day)\n                          )\n                        \"\n                        [attr.title]=\"'Day ' + (90 - $index) + ' ago: ' + dayLabel(day)\"\n                      ></span>\n                    }\n                  </div>\n\n                  <div class=\"text-muted-foreground flex items-center justify-between pt-0.5 text-xs\">\n                    <span>90 days ago</span>\n                    <span class=\"hidden sm:inline\">100% daily health check baseline</span>\n                    <span>Today</span>\n                  </div>\n                </div>\n              </div>\n            }\n          </div>\n        </div>\n      </div>\n\n      <!-- Section 3: Past Incidents Timeline -->\n      <div class=\"space-y-3\">\n        <div>\n          <h2 class=\"text-foreground text-sm font-semibold tracking-tight\">Past Incidents & Maintenance</h2>\n          <p class=\"text-muted-foreground text-xs\">Detailed post-mortems and scheduled infrastructure updates.</p>\n        </div>\n\n        <div ui-card class=\"border-border/80 bg-card text-card-foreground p-5 shadow-xs sm:p-6\">\n          @if (incidents().length > 0) {\n            <div class=\"space-y-8\">\n              @for (incident of incidents(); track incident.id) {\n                <div class=\"border-border/80 relative space-y-3 border-l-2 pb-2 pl-6 last:border-l-transparent sm:pl-8\">\n                  <div\n                    [class]=\"\n                      cn(\n                        'bg-background absolute top-0 -left-[11px] flex size-5 items-center justify-center rounded-full border',\n                        incident.resolved ? 'border-success text-success' : 'border-warning text-warning'\n                      )\n                    \"\n                  >\n                    @if (incident.resolved) {\n                      <lucide-icon [img]=\"Check\" class=\"size-3\" />\n                    } @else {\n                      <lucide-icon [img]=\"AlertTriangle\" class=\"size-3\" />\n                    }\n                  </div>\n\n                  <div class=\"flex flex-col gap-1.5 sm:flex-row sm:items-center sm:justify-between\">\n                    <div class=\"space-y-1\">\n                      <div class=\"flex flex-wrap items-center gap-2\">\n                        <h3 class=\"text-foreground text-sm font-semibold\">{{ incident.title }}</h3>\n                        <span ui-badge [variant]=\"incident.resolved ? 'success' : 'warning'\" class=\"text-xs\">\n                          {{ incident.resolved ? 'Resolved' : 'Ongoing' }}\n                        </span>\n                        <span ui-badge [variant]=\"severityBadge(incident.severity).variant\" class=\"text-xs\">\n                          {{ severityBadge(incident.severity).label }}\n                        </span>\n                      </div>\n                      <p class=\"text-muted-foreground text-xs\">{{ incident.date }}</p>\n                    </div>\n\n                    <span class=\"text-muted-foreground font-mono text-xs whitespace-nowrap\">\n                      Duration: {{ incident.duration }}\n                    </span>\n                  </div>\n\n                  <div class=\"bg-muted/40 border-border/60 space-y-3 rounded-lg border p-3.5 text-xs sm:p-4\">\n                    @for (update of incident.updates; track $index) {\n                      <div class=\"border-border/40 space-y-1 border-b pb-2.5 last:border-b-0 last:pb-0\">\n                        <div class=\"text-foreground flex items-center gap-2 font-medium\">\n                          <span class=\"text-muted-foreground font-mono\">{{ update.time }}</span>\n                          <span>·</span>\n                          <span\n                            [class]=\"\n                              update.status === 'Resolved' || update.status === 'Completed'\n                                ? 'text-success'\n                                : 'text-foreground'\n                            \"\n                          >\n                            {{ update.status }}\n                          </span>\n                        </div>\n                        <p class=\"text-muted-foreground pl-0 leading-relaxed sm:pl-2\">\n                          {{ update.description }}\n                        </p>\n                      </div>\n                    }\n                  </div>\n                </div>\n              }\n            </div>\n          } @else {\n            <div class=\"flex flex-col items-center justify-center py-8 text-center\">\n              <lucide-icon [img]=\"CheckCircle2\" class=\"text-success mb-2 size-8\" />\n              <p class=\"text-foreground text-sm font-medium\">No incidents reported</p>\n              <p class=\"text-muted-foreground mt-0.5 text-xs\">\n                All services have maintained 100% operational integrity.\n              </p>\n            </div>\n          }\n        </div>\n      </div>\n    </div>\n  `,\n})\nexport class UiServiceHealthMatrixComponent {\n  protected readonly cn = cn\n  protected readonly Activity = Activity\n  protected readonly AlertTriangle = AlertTriangle\n  protected readonly Bell = Bell\n  protected readonly Check = Check\n  protected readonly CheckCircle2 = CheckCircle2\n  protected readonly Clock = Clock\n  protected readonly Cpu = Cpu\n  protected readonly Database = Database\n  protected readonly Globe = Globe\n  protected readonly RefreshCw = RefreshCw\n  protected readonly Server = Server\n  protected readonly ShieldCheck = ShieldCheck\n  protected readonly Zap = Zap\n\n  @Input('systemStatus') set systemStatusInput(v: RegionStatus | undefined) {\n    if (v) this.systemStatus.set(v)\n  }\n  @Input('systemUptime') set systemUptimeInput(v: string | undefined) {\n    if (v !== undefined) this.systemUptime.set(v)\n  }\n  @Input('lastUpdated') set lastUpdatedInput(v: string | undefined) {\n    if (v !== undefined) {\n      this.lastUpdated.set(v)\n      this.currentUpdatedText.set(v)\n    }\n  }\n  @Input('regions') set regionsInput(v: RegionHealth[] | undefined) {\n    if (v)\n      this.regions.set(v.map((r) => ({ ...r, latencyHistory: r.latencyHistory ? [...r.latencyHistory] : undefined })))\n  }\n  @Input('services') set servicesInput(v: ServiceHealthItem[] | undefined) {\n    if (v) this.services.set(v.map((s) => ({ ...s, days: s.days ? [...s.days] : undefined })))\n  }\n  @Input('incidents') set incidentsInput(v: IncidentRecord[] | undefined) {\n    if (v) this.incidents.set(v.map((i) => ({ ...i, updates: i.updates.map((u) => ({ ...u })) })))\n  }\n  @Input('class') className?: string\n\n  readonly systemStatus = signal<RegionStatus>('operational')\n  readonly systemUptime = signal('99.99%')\n  readonly lastUpdated = signal('Updated 30s ago')\n  readonly regions = signal<RegionHealth[]>(\n    defaultRegions.map((r) => ({ ...r, latencyHistory: [...(r.latencyHistory ?? [])] })),\n  )\n  readonly services = signal<ServiceHealthItem[]>(defaultServices.map((s) => ({ ...s, days: [...(s.days ?? [])] })))\n  readonly incidents = signal<IncidentRecord[]>(\n    defaultIncidents.map((i) => ({ ...i, updates: i.updates.map((u) => ({ ...u })) })),\n  )\n\n  readonly isRefreshing = signal(false)\n  readonly isSubscribed = signal(false)\n  readonly showSubscribeInput = signal(false)\n  readonly emailInput = signal('')\n  readonly currentUpdatedText = signal('Updated 30s ago')\n\n  private refreshTimer: ReturnType<typeof setTimeout> | undefined\n\n  constructor() {\n    inject(DestroyRef).onDestroy(() => clearTimeout(this.refreshTimer))\n  }\n\n  readonly currentBanner = computed<BannerConfig>(\n    () => statusBannerConfig[this.systemStatus()] ?? statusBannerConfig.operational,\n  )\n\n  get rootClass(): string {\n    return cn('w-full space-y-6', this.className)\n  }\n\n  handleRefresh(): void {\n    this.isRefreshing.set(true)\n    clearTimeout(this.refreshTimer)\n    this.refreshTimer = setTimeout(() => {\n      this.isRefreshing.set(false)\n      this.currentUpdatedText.set('Updated just now')\n    }, 400)\n  }\n\n  handleSubscribeSubmit(): void {\n    if (this.emailInput().trim().length > 0) {\n      this.isSubscribed.set(true)\n      this.showSubscribeInput.set(false)\n      this.emailInput.set('')\n    }\n  }\n\n  daysFor(service: ServiceHealthItem): DayStatus[] {\n    return service.days ?? generate90Days()\n  }\n\n  dayClass(day: DayStatus): string {\n    return dayClassMap[day]\n  }\n\n  dayLabel(day: DayStatus): string {\n    return dayLabelMap[day]\n  }\n\n  severityBadge(severity: IncidentSeverity): { variant: BadgeVariant; label: string } {\n    return severityBadgeMap[severity]\n  }\n\n  spark(region: RegionHealth): Sparkline {\n    return buildSparkline(region.latencyHistory)\n  }\n\n  sparkColor(status: RegionStatus): string {\n    return status === 'operational' ? 'var(--color-emerald-500, #10b981)' : 'var(--color-amber-500, #f59e0b)'\n  }\n\n  regionBadgeVariant(status: RegionStatus): BadgeVariant {\n    return status === 'operational' ? 'success' : status === 'degraded' ? 'warning' : 'destructive'\n  }\n\n  serviceBadgeVariant(status: RegionStatus): BadgeVariant {\n    return status === 'operational' ? 'success' : status === 'degraded' ? 'warning' : 'destructive'\n  }\n\n  regionDotClass(status: RegionStatus): string {\n    return status === 'operational' ? 'bg-success' : status === 'degraded' ? 'bg-warning' : 'bg-destructive'\n  }\n\n  latencyToneClass(latency: number): string {\n    return latency < 30 ? 'text-success' : latency < 50 ? 'text-info' : 'text-warning'\n  }\n\n  latencyLabel(latency: number): string {\n    return latency < 30 ? 'Optimal' : latency < 50 ? 'Normal' : 'Elevated'\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/service-health-matrix/service-health-matrix.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/service-health-matrix/index.ts",
      "content": "export {\n  UiServiceHealthMatrixComponent,\n  type RegionStatus,\n  type DayStatus,\n  type IncidentSeverity,\n  type RegionHealth,\n  type ServiceHealthItem,\n  type IncidentUpdate,\n  type IncidentRecord,\n} from './service-health-matrix.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/service-health-matrix/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"
  ],
  "description": "Statuspage and BetterStack style global region latency & infrastructure health matrix with overall operational status banner, 6-region latency grid with sparklines, 90-day core service uptime bars, and incident history timeline.",
  "categories": [
    "devops",
    "dashboard"
  ]
}