{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "decision-matrix-table",
  "title": "Decision Matrix Table",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/decision-matrix-table/DecisionMatrixTable.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport {\n  AlertCircle,\n  Award,\n  BarChart3,\n  Check,\n  CheckCircle2,\n  ChevronDown,\n  ChevronUp,\n  FileCode2,\n  HelpCircle,\n  Info,\n  Plus,\n  RefreshCw,\n  Scale,\n  ShieldCheck,\n  SlidersHorizontal,\n  PlusCircle,\n  Trash2,\n  XCircle,\n} from 'lucide-react'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Input } from '@/components/ui/input'\nimport { Separator } from '@/components/ui/separator'\nimport { Slider } from '@/components/ui/slider'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\n\nexport type FrameworkType = 'weighted-matrix' | 'rice'\n\nexport interface DecisionMatrixTableProps extends React.HTMLAttributes<HTMLDivElement> {\n  title?: string\n  subtitle?: string\n  defaultFramework?: FrameworkType\n}\n\nexport interface CriterionDef {\n  key: 'impact' | 'confidence' | 'effort' | 'dx' | 'maintenance'\n  label: string\n  shortLabel: string\n  description: string\n  defaultWeight: number\n}\n\nexport interface MatrixOption {\n  id: string\n  name: string\n  architecture: string\n  summary: string\n  keyRisk: string\n  color: string\n  pros: string[]\n  cons: string[]\n  scores: {\n    impact: number // 1 to 5\n    confidence: number // 1 to 5\n    effort: number // 1 to 5 (simplicity / low effort)\n    dx: number // 1 to 5 (dx ownership)\n    maintenance: number // 1 to 5 (low maintenance overhead)\n  }\n  rice: {\n    reach: number // 0 to 100 (% of engineers / services)\n    impact: number // 1 to 5 multiplier\n    confidence: number // 50 to 100 (%)\n    effort: number // 1 to 5 person-sprints\n  }\n  isCustom?: boolean\n}\n\nconst criteriaList: CriterionDef[] = [\n  {\n    key: 'impact',\n    label: 'Engineering Impact',\n    shortLabel: 'Impact',\n    description: 'System modularity, bundle footprint reduction, and runtime performance gains.',\n    defaultWeight: 25,\n  },\n  {\n    key: 'confidence',\n    label: 'Confidence / Feasibility',\n    shortLabel: 'Confidence',\n    description: 'Ecosystem support, library maturity, and developer team readiness.',\n    defaultWeight: 25,\n  },\n  {\n    key: 'effort',\n    label: 'Simplicity (Low Effort)',\n    shortLabel: 'Low Effort',\n    description: 'Frictionless adoption curve, zero monolith refactors, fast time to market.',\n    defaultWeight: 15,\n  },\n  {\n    key: 'dx',\n    label: 'DX & Consumer Ownership',\n    shortLabel: 'DX Ownership',\n    description: 'Full source access, effortless Tailwind styling customization, zero semver lock-in.',\n    defaultWeight: 20,\n  },\n  {\n    key: 'maintenance',\n    label: 'Low Maintenance',\n    shortLabel: 'Low Maint.',\n    description: 'Decoupled component lifecycles, zero breaking upstream transitive dependency cascades.',\n    defaultWeight: 15,\n  },\n]\n\nconst initialOptions: MatrixOption[] = [\n  {\n    id: 'opt-a',\n    name: 'Option A: Unbundled Registry architecture',\n    architecture: 'UIPKGE / shadcn Model',\n    summary:\n      'Components copy directly into consumer source tree. Zero semver locks, complete styling autonomy, and unconstrained design customization.',\n    keyRisk: 'Downstream drift from upstream patches managed through automated registry diffing.',\n    color: '#10b981',\n    pros: [\n      'Zero npm package version lock-in or dependency gridlock',\n      'Immediate Tailwind class-level and DOM customization',\n      '100% dead-code elimination and optimal bundle footprint',\n    ],\n    cons: ['Manual or CLI-assisted updates when upstream security patches land'],\n    scores: {\n      impact: 4.8,\n      confidence: 4.7,\n      effort: 4.5,\n      dx: 5.0,\n      maintenance: 4.4,\n    },\n    rice: {\n      reach: 96,\n      impact: 5.0,\n      confidence: 95,\n      effort: 1.8,\n    },\n  },\n  {\n    id: 'opt-b',\n    name: 'Option B: Monolithic Multi-Framework NPM',\n    architecture: 'Centralized Monorepo Package',\n    summary:\n      'Single heavy versioned library published to private registry. Standardized tokens but painful breaking version cascades across product suites.',\n    keyRisk: 'High cross-team dependency coupling and blocked semver upgrades.',\n    color: '#f59e0b',\n    pros: [\n      'Single point of governance for security and accessibility patches',\n      'Familiar `npm install` workflow for junior developers',\n    ],\n    cons: [\n      'Massive wrapper overhead and difficult Tailwind class overrides',\n      'Breaking changes in one component delay releases for entire company',\n      'Bloated runtime JS bundle containing unused component code',\n    ],\n    scores: {\n      impact: 3.2,\n      confidence: 4.1,\n      effort: 3.8,\n      dx: 2.3,\n      maintenance: 2.6,\n    },\n    rice: {\n      reach: 82,\n      impact: 3.0,\n      confidence: 85,\n      effort: 3.6,\n    },\n  },\n  {\n    id: 'opt-c',\n    name: 'Option C: Custom Web Components Wrapper',\n    architecture: 'Custom Elements v1 & Shadow DOM',\n    summary:\n      'Framework-agnostic web components encapsulated in Shadow DOM. Cross-platform runtime interoperability, but major SSR hydration and styling friction.',\n    keyRisk: 'SSR rendering latency and challenging CSS theme token propagation through shadow boundaries.',\n    color: '#6366f1',\n    pros: [\n      'Universal encapsulation across Vue, React, Angular, and vanilla HTML',\n      'Strict CSS isolation prevents accidental style collisions',\n    ],\n    cons: [\n      'Complex SSR and Declarative Shadow DOM hydration mechanics',\n      'Difficult theme token synchronization and slot styling gymnastics',\n      'Suboptimal ergonomics with React synthetic event systems',\n    ],\n    scores: {\n      impact: 3.7,\n      confidence: 3.4,\n      effort: 2.8,\n      dx: 3.1,\n      maintenance: 3.5,\n    },\n    rice: {\n      reach: 90,\n      impact: 3.5,\n      confidence: 70,\n      effort: 3.2,\n    },\n  },\n  {\n    id: 'opt-d',\n    name: 'Option D: Micro-Frontend Module Federation',\n    architecture: 'Webpack / Vite Runtime Federation',\n    summary:\n      'Dynamic runtime module stitching over HTTP. Independent team deployments, but vulnerable to CSS leakage, network latency, and orchestration failures.',\n    keyRisk: 'Runtime script evaluation latency and version mismatch instability in production.',\n    color: '#ef4444',\n    pros: ['Fully decentralized team deployments without monorepo synchronization'],\n    cons: [\n      'High network overhead and cumulative layout shifts on initial load',\n      'Complex local development sandbox and shared singleton debugging',\n      'Runtime failures when remote hosts experience temporary downtime',\n    ],\n    scores: {\n      impact: 3.0,\n      confidence: 2.5,\n      effort: 1.8,\n      dx: 2.6,\n      maintenance: 1.6,\n    },\n    rice: {\n      reach: 58,\n      impact: 3.0,\n      confidence: 55,\n      effort: 4.6,\n    },\n  },\n]\n\nexport function DecisionMatrixTable({\n  className,\n  title = 'Architectural Decision Matrix (RICE / Weighted Scoring)',\n  subtitle = 'Evaluate technical options against weighted business and engineering criteria.',\n  defaultFramework = 'weighted-matrix',\n  ...props\n}: DecisionMatrixTableProps) {\n  const [activeFramework, setActiveFramework] = React.useState<FrameworkType>(defaultFramework)\n  const [showWeightEditor, setShowWeightEditor] = React.useState(false)\n  const [showAddOptionForm, setShowAddOptionForm] = React.useState(false)\n  const [selectedOptionId, setSelectedOptionId] = React.useState<string>('opt-a')\n\n  const [criterionWeights, setCriterionWeights] = React.useState<Record<string, number>>({\n    impact: 25,\n    confidence: 25,\n    effort: 15,\n    dx: 20,\n    maintenance: 15,\n  })\n\n  const [options, setOptions] = React.useState<MatrixOption[]>(initialOptions)\n\n  // Add custom option inputs\n  const [newOptionName, setNewOptionName] = React.useState('')\n  const [newOptionParadigm, setNewOptionParadigm] = React.useState('')\n  const [newOptionSummary, setNewOptionSummary] = React.useState('')\n  const [newOptionScores, setNewOptionScores] = React.useState({\n    impact: 4.0,\n    confidence: 4.0,\n    effort: 3.5,\n    dx: 4.0,\n    maintenance: 3.5,\n  })\n\n  const totalWeight = React.useMemo(() => {\n    return Object.values(criterionWeights).reduce((sum, w) => sum + (Number(w) || 0), 0)\n  }, [criterionWeights])\n\n  const resetWeights = () => {\n    const fresh: Record<string, number> = {}\n    criteriaList.forEach((c) => {\n      fresh[c.key] = c.defaultWeight\n    })\n    setCriterionWeights(fresh)\n  }\n\n  const resetOptions = () => {\n    setOptions(initialOptions)\n    setSelectedOptionId('opt-a')\n  }\n\n  const handleAddOption = () => {\n    if (!newOptionName.trim()) return\n\n    const newId = `opt-custom-${Date.now()}`\n    const created: MatrixOption = {\n      id: newId,\n      name: newOptionName.trim(),\n      architecture: newOptionParadigm.trim() || 'Custom Technical Architecture',\n      summary: newOptionSummary.trim() || 'Custom evaluated technical approach for this architectural decision.',\n      keyRisk: 'Requires comprehensive proof-of-concept testing in staging environments.',\n      color: '#06b6d4',\n      pros: ['Tailored to immediate domain constraints', 'Custom architectural design'],\n      cons: ['Needs dedicated long-term ownership and testing framework'],\n      scores: { ...newOptionScores },\n      rice: {\n        reach: 75,\n        impact: newOptionScores.impact,\n        confidence: Number((newOptionScores.confidence * 20).toFixed(0)),\n        effort: Number((6 - newOptionScores.effort).toFixed(1)),\n      },\n      isCustom: true,\n    }\n\n    setOptions((prev) => [...prev, created])\n    setSelectedOptionId(newId)\n    setNewOptionName('')\n    setNewOptionParadigm('')\n    setNewOptionSummary('')\n    setShowAddOptionForm(false)\n  }\n\n  const removeOption = (id: string) => {\n    setOptions((prev) => prev.filter((opt) => opt.id !== id))\n    if (selectedOptionId === id) {\n      setSelectedOptionId(options[0]?.id || '')\n    }\n  }\n\n  // Scored Options Calculation\n  const scoredOptions = React.useMemo(() => {\n    const sumW = totalWeight || 100\n\n    const calculated = options.map((opt) => {\n      const weightedSum =\n        opt.scores.impact * (criterionWeights.impact ?? 25) +\n        opt.scores.confidence * (criterionWeights.confidence ?? 25) +\n        opt.scores.effort * (criterionWeights.effort ?? 15) +\n        opt.scores.dx * (criterionWeights.dx ?? 20) +\n        opt.scores.maintenance * (criterionWeights.maintenance ?? 15)\n\n      const weightedScore = Number(((weightedSum / (5 * sumW)) * 100).toFixed(1))\n\n      const reachFactor = opt.rice.reach\n      const impactFactor = opt.rice.impact\n      const confidenceFactor = opt.rice.confidence / 100\n      const effortFactor = Math.max(0.5, opt.rice.effort)\n      const riceScore = Number(((reachFactor * impactFactor * confidenceFactor) / effortFactor).toFixed(1))\n\n      return {\n        ...opt,\n        weightedScore,\n        riceScore,\n        rank: 0,\n        verdict: 'Discarded' as const,\n        verdictVariant: 'destructive' as const,\n      }\n    })\n\n    calculated.sort((a, b) => {\n      if (activeFramework === 'rice') {\n        return b.riceScore - a.riceScore\n      }\n      return b.weightedScore - a.weightedScore\n    })\n\n    return calculated.map((item, index) => {\n      const rank = index + 1\n      let verdict: 'Recommended Winner' | 'Second Choice' | 'Alternative' | 'Discarded' = 'Discarded'\n      let verdictVariant: 'success' | 'info' | 'warning' | 'destructive' = 'destructive'\n\n      if (rank === 1) {\n        verdict = 'Recommended Winner'\n        verdictVariant = 'success'\n      } else if (rank === 2) {\n        verdict = 'Second Choice'\n        verdictVariant = 'info'\n      } else if (rank === 3) {\n        verdict = 'Alternative'\n        verdictVariant = 'warning'\n      } else {\n        verdict = 'Discarded'\n        verdictVariant = 'destructive'\n      }\n\n      return {\n        ...item,\n        rank,\n        verdict,\n        verdictVariant,\n      }\n    })\n  }, [options, totalWeight, criterionWeights, activeFramework])\n\n  const winningOption = scoredOptions[0]\n  const activeSelectedOption = scoredOptions.find((opt) => opt.id === selectedOptionId) ?? winningOption\n\n  // Radar chart SVG geometry\n  const radarCenter = { x: 170, y: 155 }\n  const radarRadius = 95\n  const radarAxesCount = 5\n\n  const getRadarPoint = (axisIndex: number, scoreValue: number, maxVal = 5) => {\n    const angle = -Math.PI / 2 + (axisIndex * 2 * Math.PI) / radarAxesCount\n    const ratio = Math.min(1, Math.max(0, scoreValue / maxVal))\n    const r = radarRadius * ratio\n    const x = radarCenter.x + r * Math.cos(angle)\n    const y = radarCenter.y + r * Math.sin(angle)\n    return { x, y }\n  }\n\n  const getRadarPolygon = (scores: {\n    impact: number\n    confidence: number\n    effort: number\n    dx: number\n    maintenance: number\n  }) => {\n    const values = [scores.impact, scores.confidence, scores.effort, scores.dx, scores.maintenance]\n    return values\n      .map((val, idx) => {\n        const pt = getRadarPoint(idx, val)\n        return `${pt.x.toFixed(1)},${pt.y.toFixed(1)}`\n      })\n      .join(' ')\n  }\n\n  const getRingPolygon = (ratio: number) => {\n    return Array.from({ length: radarAxesCount })\n      .map((_, idx) => {\n        const pt = getRadarPoint(idx, ratio * 5)\n        return `${pt.x.toFixed(1)},${pt.y.toFixed(1)}`\n      })\n      .join(' ')\n  }\n\n  const radarAxisLabels = [\n    { index: 0, label: 'Impact', x: 170, y: 38, anchor: 'middle' as const },\n    { index: 1, label: 'Confidence', x: 285, y: 115, anchor: 'start' as const },\n    { index: 2, label: 'Simplicity', x: 245, y: 258, anchor: 'middle' as const },\n    { index: 3, label: 'DX & Own', x: 95, y: 258, anchor: 'middle' as const },\n    { index: 4, label: 'Low Maint', x: 55, y: 115, anchor: 'end' as const },\n  ]\n\n  const getScoreBadgeVariant = (score: number): 'success' | 'default' | 'secondary' | 'outline' => {\n    if (score >= 4.5) return 'success'\n    if (score >= 3.5) return 'default'\n    if (score >= 2.5) return 'secondary'\n    return 'outline'\n  }\n\n  return (\n    <div\n      data-slot=\"decision-matrix-table\"\n      className={cn('bg-background text-foreground w-full space-y-6', className)}\n      {...props}\n    >\n      {/* Header Card: Controls and Metadata */}\n      <Card className=\"border-border bg-card shadow-xs\">\n        <CardHeader className=\"pb-4\">\n          <div className=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n            <div className=\"space-y-1.5\">\n              <div className=\"flex flex-wrap items-center gap-2\">\n                <Badge variant=\"outline\" className=\"gap-1 text-xs font-semibold tracking-wide uppercase\">\n                  <Scale className=\"text-primary size-3.5\" />\n                  ADR-042 Evaluation\n                </Badge>\n                <Badge variant=\"secondary\" className=\"text-xs\">\n                  Updated Aug 2026\n                </Badge>\n              </div>\n              <CardTitle className=\"text-xl font-semibold tracking-tight sm:text-2xl\">{title}</CardTitle>\n              <CardDescription className=\"text-sm\">{subtitle}</CardDescription>\n            </div>\n\n            {/* Framework Switcher & Action Toolbar */}\n            <div className=\"flex flex-wrap items-center gap-2.5\">\n              <div className=\"bg-muted border-border inline-flex items-center rounded-lg border p-1\">\n                <button\n                  type=\"button\"\n                  className={cn(\n                    'focus-visible:ring-ring rounded-md px-3 py-1.5 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                    activeFramework === 'weighted-matrix'\n                      ? 'bg-background text-foreground font-semibold shadow-xs'\n                      : 'text-muted-foreground hover:text-foreground',\n                  )}\n                  onClick={() => setActiveFramework('weighted-matrix')}\n                >\n                  Weighted Value-Risk Matrix\n                </button>\n                <button\n                  type=\"button\"\n                  className={cn(\n                    'focus-visible:ring-ring rounded-md px-3 py-1.5 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none',\n                    activeFramework === 'rice'\n                      ? 'bg-background text-foreground font-semibold shadow-xs'\n                      : 'text-muted-foreground hover:text-foreground',\n                  )}\n                  onClick={() => setActiveFramework('rice')}\n                >\n                  RICE Framework\n                </button>\n              </div>\n\n              {activeFramework === 'weighted-matrix' && (\n                <Button\n                  variant=\"outline\"\n                  size=\"sm\"\n                  className=\"gap-1.5 text-xs\"\n                  onClick={() => setShowWeightEditor((v) => !v)}\n                >\n                  <SlidersHorizontal className=\"text-muted-foreground size-3.5\" />\n                  <span>Criterion Weights</span>\n                  <Badge\n                    variant=\"secondary\"\n                    className={cn(\n                      'ml-0.5 px-1.5 py-0 text-xs tabular-nums',\n                      totalWeight === 100 ? 'text-foreground' : 'bg-warning/20 text-warning font-semibold',\n                    )}\n                  >\n                    {totalWeight}%\n                  </Badge>\n                  {!showWeightEditor ? (\n                    <ChevronDown className=\"text-muted-foreground size-3\" />\n                  ) : (\n                    <ChevronUp className=\"text-muted-foreground size-3\" />\n                  )}\n                </Button>\n              )}\n\n              <Button size=\"sm\" className=\"gap-1.5 text-xs font-medium\" onClick={() => setShowAddOptionForm((v) => !v)}>\n                <Plus className=\"size-3.5\" />\n                <span>Add Option</span>\n              </Button>\n            </div>\n          </div>\n        </CardHeader>\n\n        {/* Expandable Criterion Weights Adjuster */}\n        {showWeightEditor && activeFramework === 'weighted-matrix' && (\n          <div className=\"border-border bg-muted/20 border-t px-6 py-5\">\n            <div className=\"space-y-4\">\n              <div className=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n                <div>\n                  <h4 className=\"text-foreground text-sm font-semibold tracking-tight\">\n                    Calibrate Evaluation Criteria Weights\n                  </h4>\n                  <p className=\"text-muted-foreground text-xs\">\n                    Adjust criteria percentages to reflect your organization's architectural priorities.\n                  </p>\n                </div>\n                <div className=\"flex items-center gap-2\">\n                  <span\n                    className={cn(\n                      'inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-semibold tabular-nums',\n                      totalWeight === 100 ? 'bg-success/10 text-success' : 'bg-warning/15 text-warning font-bold',\n                    )}\n                  >\n                    {totalWeight === 100 ? <CheckCircle2 className=\"size-3\" /> : <AlertCircle className=\"size-3\" />}\n                    Total Weight: {totalWeight}%\n                  </span>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"xs\"\n                    className=\"text-muted-foreground gap-1 text-xs\"\n                    onClick={resetWeights}\n                  >\n                    <RefreshCw className=\"size-3\" />\n                    Reset Defaults\n                  </Button>\n                </div>\n              </div>\n\n              <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-5\">\n                {criteriaList.map((criterion) => (\n                  <div\n                    key={criterion.key}\n                    className=\"border-border bg-card space-y-2.5 rounded-lg border p-3.5 shadow-2xs\"\n                  >\n                    <div className=\"flex items-center justify-between gap-1\">\n                      <span className=\"text-foreground truncate text-xs font-semibold\" title={criterion.label}>\n                        {criterion.label}\n                      </span>\n                      <span className=\"bg-primary/10 text-primary rounded px-1.5 py-0.5 text-xs font-bold tabular-nums\">\n                        {criterionWeights[criterion.key] ?? criterion.defaultWeight}%\n                      </span>\n                    </div>\n                    <p className=\"text-muted-foreground line-clamp-2 h-8 text-xs leading-tight\">\n                      {criterion.description}\n                    </p>\n                    <div className=\"pt-1\">\n                      <Slider\n                        value={[criterionWeights[criterion.key] ?? criterion.defaultWeight]}\n                        min={0}\n                        max={50}\n                        step={5}\n                        size=\"small\"\n                        onValueChange={(vals) =>\n                          setCriterionWeights((prev) => ({\n                            ...prev,\n                            [criterion.key]: vals[0] ?? 0,\n                          }))\n                        }\n                      />\n                    </div>\n                  </div>\n                ))}\n              </div>\n            </div>\n          </div>\n        )}\n\n        {/* Expandable Add Custom Proposal Form */}\n        {showAddOptionForm && (\n          <div className=\"border-border bg-muted/30 border-t px-6 py-5\">\n            <div className=\"max-w-3xl space-y-4\">\n              <div className=\"flex items-center justify-between gap-x-2\">\n                <h4 className=\"text-foreground flex items-center gap-1.5 text-sm font-semibold tracking-tight\">\n                  <PlusCircle className=\"text-primary size-4\" />\n                  Add Technical Architecture Option to Matrix\n                </h4>\n                <Button variant=\"ghost\" size=\"xs\" onClick={() => setShowAddOptionForm(false)}>\n                  Cancel\n                </Button>\n              </div>\n\n              <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n                <div className=\"space-y-1\">\n                  <label className=\"text-foreground text-xs font-medium\">Option Proposal Name</label>\n                  <Input\n                    value={newOptionName}\n                    onChange={(e) => setNewOptionName(e.target.value)}\n                    placeholder=\"e.g. Option E: Shared UI Submodule\"\n                    size=\"small\"\n                  />\n                </div>\n                <div className=\"space-y-1\">\n                  <label className=\"text-foreground text-xs font-medium\">Architectural architecture</label>\n                  <Input\n                    value={newOptionParadigm}\n                    onChange={(e) => setNewOptionParadigm(e.target.value)}\n                    placeholder=\"e.g. Git Submodule & Monorepo Link\"\n                    size=\"small\"\n                  />\n                </div>\n              </div>\n\n              <div className=\"space-y-1\">\n                <label className=\"text-foreground text-xs font-medium\">Executive Architectural Summary</label>\n                <Input\n                  value={newOptionSummary}\n                  onChange={(e) => setNewOptionSummary(e.target.value)}\n                  placeholder=\"Brief summary of distribution mechanics, bundle characteristics, and DX impact...\"\n                  size=\"small\"\n                />\n              </div>\n\n              <div className=\"space-y-2\">\n                <label className=\"text-foreground text-xs font-medium\">Initial Scores (1.0 to 5.0)</label>\n                <div className=\"grid grid-cols-2 gap-2.5 sm:grid-cols-5\">\n                  {criteriaList.map((criterion) => (\n                    <div key={criterion.key} className=\"border-border bg-card rounded-md border p-2 text-center\">\n                      <div className=\"text-muted-foreground truncate text-xs font-medium\">{criterion.shortLabel}</div>\n                      <div className=\"text-foreground mt-0.5 text-sm font-bold tabular-nums\">\n                        {newOptionScores[criterion.key]} / 5\n                      </div>\n                      <div className=\"pt-1.5\">\n                        <Slider\n                          value={[newOptionScores[criterion.key]]}\n                          min={1}\n                          max={5}\n                          step={0.5}\n                          size=\"small\"\n                          onValueChange={(vals) =>\n                            setNewOptionScores((prev) => ({\n                              ...prev,\n                              [criterion.key]: vals[0] ?? 3,\n                            }))\n                          }\n                        />\n                      </div>\n                    </div>\n                  ))}\n                </div>\n              </div>\n\n              <div className=\"flex items-center justify-end gap-2 pt-2\">\n                <Button variant=\"outline\" size=\"sm\" onClick={() => setShowAddOptionForm(false)}>\n                  Cancel\n                </Button>\n                <Button size=\"sm\" disabled={!newOptionName.trim()} onClick={handleAddOption}>\n                  Add to Matrix\n                </Button>\n              </div>\n            </div>\n          </div>\n        )}\n      </Card>\n\n      {/* Main Scoring Matrix Table */}\n      <Card className=\"border-border bg-card overflow-hidden shadow-xs\">\n        <div className=\"overflow-x-auto\">\n          <Table>\n            <TableHeader className=\"bg-muted/50\">\n              <TableRow className=\"hover:bg-transparent\">\n                <TableHead className=\"text-muted-foreground w-[42px] px-3 text-center text-xs font-semibold\">\n                  Rank\n                </TableHead>\n                <TableHead className=\"text-foreground min-w-[240px] text-xs font-semibold\">\n                  Technical Option & architecture\n                </TableHead>\n\n                {activeFramework === 'weighted-matrix' ? (\n                  <>\n                    {criteriaList.map((criterion) => (\n                      <TableHead\n                        key={criterion.key}\n                        className=\"text-foreground min-w-[130px] text-center text-xs font-semibold\"\n                      >\n                        <div className=\"flex flex-col items-center\">\n                          <span>{criterion.shortLabel}</span>\n                          <span className=\"text-muted-foreground text-xs font-normal tabular-nums\">\n                            {criterionWeights[criterion.key] ?? criterion.defaultWeight}% wt\n                          </span>\n                        </div>\n                      </TableHead>\n                    ))}\n                    <TableHead className=\"text-foreground min-w-[140px] text-center text-xs font-semibold\">\n                      Weighted Score\n                    </TableHead>\n                  </>\n                ) : (\n                  <>\n                    <TableHead className=\"text-foreground min-w-[110px] text-center text-xs font-semibold\">\n                      <div className=\"flex flex-col items-center\">\n                        <span>Reach</span>\n                        <span className=\"text-muted-foreground text-xs font-normal\">Dev Scale %</span>\n                      </div>\n                    </TableHead>\n                    <TableHead className=\"text-foreground min-w-[110px] text-center text-xs font-semibold\">\n                      <div className=\"flex flex-col items-center\">\n                        <span>Impact</span>\n                        <span className=\"text-muted-foreground text-xs font-normal\">Multiplier (1-5)</span>\n                      </div>\n                    </TableHead>\n                    <TableHead className=\"text-foreground min-w-[110px] text-center text-xs font-semibold\">\n                      <div className=\"flex flex-col items-center\">\n                        <span>Confidence</span>\n                        <span className=\"text-muted-foreground text-xs font-normal\">% Certainty</span>\n                      </div>\n                    </TableHead>\n                    <TableHead className=\"text-foreground min-w-[110px] text-center text-xs font-semibold\">\n                      <div className=\"flex flex-col items-center\">\n                        <span>Effort</span>\n                        <span className=\"text-muted-foreground text-xs font-normal\">Sprints (1-5)</span>\n                      </div>\n                    </TableHead>\n                    <TableHead className=\"text-foreground min-w-[130px] text-center text-xs font-semibold\">\n                      RICE Score\n                    </TableHead>\n                  </>\n                )}\n\n                <TableHead className=\"text-foreground min-w-[160px] text-center text-xs font-semibold\">\n                  ADR Verdict\n                </TableHead>\n                <TableHead className=\"text-muted-foreground w-[80px] text-center text-xs font-semibold\">\n                  Inspect\n                </TableHead>\n              </TableRow>\n            </TableHeader>\n\n            <TableBody>\n              {scoredOptions.map((opt) => (\n                <TableRow\n                  key={opt.id}\n                  className={cn(\n                    'cursor-pointer transition-colors duration-150',\n                    opt.id === selectedOptionId ? 'bg-primary/5 dark:bg-primary/10' : 'hover:bg-muted/40',\n                    opt.rank === 1 && 'font-medium',\n                  )}\n                  onClick={() => setSelectedOptionId(opt.id)}\n                >\n                  {/* Rank Column */}\n                  <TableCell className=\"px-3 text-center\">\n                    <span\n                      className={cn(\n                        'inline-flex size-6 items-center justify-center rounded-full text-xs font-semibold tabular-nums',\n                        opt.rank === 1\n                          ? 'bg-success text-white shadow-xs'\n                          : opt.rank === 2\n                            ? 'bg-info/15 text-info font-semibold'\n                            : 'bg-muted text-muted-foreground font-normal',\n                      )}\n                    >\n                      {opt.rank}\n                    </span>\n                  </TableCell>\n\n                  {/* Proposal Name & Summary */}\n                  <TableCell>\n                    <div className=\"space-y-1 py-1\">\n                      <div className=\"flex flex-wrap items-center gap-2\">\n                        <span className=\"text-foreground text-sm font-semibold tracking-tight\">{opt.name}</span>\n                        <span\n                          className=\"size-2 shrink-0 rounded-full\"\n                          style={{ backgroundColor: opt.color }}\n                          title={opt.name}\n                        />\n                        {opt.isCustom && (\n                          <Badge variant=\"outline\" className=\"text-xs\">\n                            Custom\n                          </Badge>\n                        )}\n                      </div>\n                      <div className=\"text-muted-foreground text-xs font-medium\">{opt.architecture}</div>\n                      <p className=\"text-muted-foreground/80 line-clamp-1 max-w-[220px] text-xs\">{opt.summary}</p>\n                    </div>\n                  </TableCell>\n\n                  {/* Matrix Criteria Columns */}\n                  {activeFramework === 'weighted-matrix' ? (\n                    <>\n                      {criteriaList.map((criterion) => (\n                        <TableCell key={criterion.key} className=\"text-center\">\n                          <div className=\"inline-flex flex-col items-center gap-0.5\">\n                            <Badge\n                              variant={getScoreBadgeVariant(opt.scores[criterion.key])}\n                              className=\"px-2 py-0.5 text-xs font-semibold tabular-nums\"\n                            >\n                              {opt.scores[criterion.key].toFixed(1)}\n                            </Badge>\n                            <div className=\"mt-1 flex items-center gap-0.5\">\n                              {[1, 2, 3, 4, 5].map((seg) => (\n                                <span\n                                  key={seg}\n                                  className={cn(\n                                    'size-1 rounded-full',\n                                    seg <= Math.round(opt.scores[criterion.key])\n                                      ? 'bg-primary'\n                                      : 'bg-muted-foreground/20',\n                                  )}\n                                />\n                              ))}\n                            </div>\n                          </div>\n                        </TableCell>\n                      ))}\n\n                      {/* Weighted Score */}\n                      <TableCell className=\"text-center\">\n                        <div className=\"inline-flex flex-col items-center gap-1\">\n                          <span\n                            className={cn(\n                              'text-base font-semibold tracking-tight tabular-nums',\n                              opt.rank === 1\n                                ? 'text-success'\n                                : opt.weightedScore >= 70\n                                  ? 'text-foreground'\n                                  : 'text-muted-foreground',\n                            )}\n                          >\n                            {opt.weightedScore}\n                            <span className=\"text-muted-foreground text-xs font-normal\">/ 100</span>\n                          </span>\n                          <div className=\"bg-muted h-1.5 w-20 overflow-hidden rounded-full\">\n                            <div\n                              className={cn(\n                                'h-full rounded-full transition-[width,background-color] duration-300',\n                                opt.rank === 1\n                                  ? 'bg-success'\n                                  : opt.weightedScore >= 70\n                                    ? 'bg-info'\n                                    : opt.weightedScore >= 50\n                                      ? 'bg-warning'\n                                      : 'bg-destructive',\n                              )}\n                              style={{ width: `${opt.weightedScore}%` }}\n                            />\n                          </div>\n                        </div>\n                      </TableCell>\n                    </>\n                  ) : (\n                    <>\n                      <TableCell className=\"text-center text-xs font-semibold tabular-nums\">\n                        {opt.rice.reach}%\n                      </TableCell>\n                      <TableCell className=\"text-center text-xs font-semibold tabular-nums\">\n                        {opt.rice.impact.toFixed(1)}x\n                      </TableCell>\n                      <TableCell className=\"text-center text-xs font-semibold tabular-nums\">\n                        {opt.rice.confidence}%\n                      </TableCell>\n                      <TableCell className=\"text-center text-xs font-semibold tabular-nums\">\n                        {opt.rice.effort.toFixed(1)} sprints\n                      </TableCell>\n                      <TableCell className=\"text-center\">\n                        <div className=\"inline-flex flex-col items-center\">\n                          <span className=\"text-primary text-base font-semibold tabular-nums\">{opt.riceScore}</span>\n                          <span className=\"text-muted-foreground text-xs font-medium\">RICE Pts</span>\n                        </div>\n                      </TableCell>\n                    </>\n                  )}\n\n                  {/* Verdict Column */}\n                  <TableCell className=\"text-center\">\n                    {opt.rank === 1 ? (\n                      <span className=\"border-success/30 bg-success/10 text-success inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-semibold\">\n                        <Award className=\"size-3.5\" />\n                        Recommended Winner\n                      </span>\n                    ) : opt.rank === 2 ? (\n                      <span className=\"border-info/30 bg-info/10 text-info inline-flex items-center gap-1 rounded-full border px-2.5 py-1 text-xs font-semibold\">\n                        <CheckCircle2 className=\"size-3.5\" />\n                        Second Choice\n                      </span>\n                    ) : opt.rank === 3 ? (\n                      <span className=\"border-border bg-muted/60 text-muted-foreground inline-flex items-center gap-1 rounded-full border px-2.5 py-1 text-xs font-medium\">\n                        <HelpCircle className=\"size-3.5\" />\n                        Alternative\n                      </span>\n                    ) : (\n                      <span className=\"border-destructive/20 bg-destructive/10 text-destructive inline-flex items-center gap-1 rounded-full border px-2.5 py-1 text-xs font-medium\">\n                        <XCircle className=\"size-3.5\" />\n                        Discarded\n                      </span>\n                    )}\n                  </TableCell>\n\n                  {/* Action / Inspect */}\n                  <TableCell className=\"text-center\" onClick={(e) => e.stopPropagation()}>\n                    {opt.isCustom ? (\n                      <Button\n                        variant=\"ghost\"\n                        size=\"icon-sm\"\n                        className=\"text-muted-foreground hover:text-destructive\"\n                        title=\"Remove Custom Option\"\n                        onClick={() => removeOption(opt.id)}\n                      >\n                        <Trash2 className=\"size-3.5\" />\n                      </Button>\n                    ) : (\n                      <Button\n                        variant=\"ghost\"\n                        size=\"icon-sm\"\n                        className=\"text-muted-foreground hover:text-foreground\"\n                        title={`Inspect ${opt.name}`}\n                        onClick={() => setSelectedOptionId(opt.id)}\n                      >\n                        <Info className=\"size-3.5\" />\n                      </Button>\n                    )}\n                  </TableCell>\n                </TableRow>\n              ))}\n            </TableBody>\n          </Table>\n        </div>\n\n        <CardFooter className=\"border-border bg-muted/20 text-muted-foreground flex flex-wrap items-center justify-between gap-3 border-t px-6 py-3 text-xs\">\n          <div className=\"flex items-center gap-2\">\n            <span className=\"bg-success inline-block size-2 rounded-full\" />\n            <span>Scores normalize dynamically to a 0–100 scale based on active criteria weights.</span>\n          </div>\n          <div className=\"flex items-center gap-3\">\n            <Button variant=\"ghost\" size=\"xs\" className=\"text-muted-foreground gap-1 text-xs\" onClick={resetOptions}>\n              <RefreshCw className=\"size-3\" />\n              Reset Matrix Options\n            </Button>\n          </div>\n        </CardFooter>\n      </Card>\n\n      {/* Tradeoff Visualizer & ADR Recommendation Section */}\n      <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-12\">\n        {/* Radar Chart: Multi-Option Criteria Comparison */}\n        <Card className=\"border-border bg-card flex flex-col shadow-xs lg:col-span-6\">\n          <CardHeader className=\"pb-2\">\n            <div className=\"flex items-center justify-between gap-x-2\">\n              <div className=\"space-y-0.5\">\n                <CardTitle className=\"flex items-center gap-2 text-base font-semibold tracking-tight\">\n                  <BarChart3 className=\"text-primary size-4\" />\n                  Decision Tradeoff Radar\n                </CardTitle>\n                <CardDescription className=\"text-xs\">\n                  Multi-dimensional polygon overlay comparing architectural options.\n                </CardDescription>\n              </div>\n              <Badge variant=\"outline\" className=\"text-xs font-normal\">\n                5 Axes (1-5)\n              </Badge>\n            </div>\n          </CardHeader>\n\n          <CardContent className=\"flex flex-1 flex-col items-center justify-center p-4\">\n            {/* SVG Radar Canvas */}\n            <div className=\"relative flex aspect-square w-full max-w-[340px] items-center justify-center\">\n              <svg viewBox=\"0 0 340 310\" className=\"h-full w-full overflow-visible\">\n                {/* Background Concentric Grid Rings */}\n                {[0.2, 0.4, 0.6, 0.8, 1.0].map((ring) => (\n                  <polygon\n                    key={ring}\n                    points={getRingPolygon(ring)}\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    strokeWidth=\"1\"\n                    className=\"text-border/50\"\n                    strokeDasharray={ring === 1.0 ? 'none' : '2,2'}\n                  />\n                ))}\n\n                {/* Radial Axes Lines */}\n                {Array.from({ length: radarAxesCount }).map((_, idx) => (\n                  <line\n                    key={idx}\n                    x1={radarCenter.x}\n                    y1={radarCenter.y}\n                    x2={getRadarPoint(idx, 5).x}\n                    y2={getRadarPoint(idx, 5).y}\n                    stroke=\"currentColor\"\n                    strokeWidth=\"1\"\n                    className=\"text-border\"\n                  />\n                ))}\n\n                {/* Polygons for non-selected options */}\n                {scoredOptions.map(\n                  (opt) =>\n                    opt.id !== activeSelectedOption.id && (\n                      <polygon\n                        key={opt.id}\n                        points={getRadarPolygon(opt.scores)}\n                        fill={opt.color}\n                        fillOpacity=\"0.08\"\n                        stroke={opt.color}\n                        strokeWidth=\"1.5\"\n                        strokeOpacity=\"0.45\"\n                        className=\"cursor-pointer transition-colors duration-300\"\n                        onClick={() => setSelectedOptionId(opt.id)}\n                      />\n                    ),\n                )}\n\n                {/* Polygon for Selected Option */}\n                <polygon\n                  points={getRadarPolygon(activeSelectedOption.scores)}\n                  fill={activeSelectedOption.color}\n                  fillOpacity=\"0.25\"\n                  stroke={activeSelectedOption.color}\n                  strokeWidth=\"2.5\"\n                  className=\"transition-colors duration-300\"\n                />\n\n                {/* Vertex Dots for Selected Option */}\n                {[\n                  activeSelectedOption.scores.impact,\n                  activeSelectedOption.scores.confidence,\n                  activeSelectedOption.scores.effort,\n                  activeSelectedOption.scores.dx,\n                  activeSelectedOption.scores.maintenance,\n                ].map((val, idx) => (\n                  <circle\n                    key={idx}\n                    cx={getRadarPoint(idx, val).x}\n                    cy={getRadarPoint(idx, val).y}\n                    r=\"4\"\n                    fill={activeSelectedOption.color}\n                    className=\"stroke-background stroke-2 transition-colors duration-300\"\n                  />\n                ))}\n\n                {/* Axis Labels */}\n                {radarAxisLabels.map((axis) => (\n                  <text\n                    key={axis.index}\n                    x={axis.x}\n                    y={axis.y}\n                    textAnchor={axis.anchor}\n                    className=\"fill-foreground text-xs font-semibold select-none\"\n                    style={{ fontSize: 11 }}\n                  >\n                    {axis.label}\n                  </text>\n                ))}\n              </svg>\n            </div>\n\n            {/* Radar Chart Legend */}\n            <div className=\"border-border flex w-full flex-wrap items-center justify-center gap-3 border-t pt-3\">\n              {scoredOptions.map((opt) => (\n                <button\n                  key={opt.id}\n                  type=\"button\"\n                  className={cn(\n                    'inline-flex items-center gap-1.5 rounded-md px-2 py-1 text-xs transition-colors',\n                    opt.id === activeSelectedOption.id\n                      ? 'bg-muted text-foreground ring-border font-semibold ring-1'\n                      : 'text-muted-foreground hover:text-foreground opacity-80',\n                  )}\n                  onClick={() => setSelectedOptionId(opt.id)}\n                >\n                  <span className=\"size-2.5 shrink-0 rounded-full\" style={{ backgroundColor: opt.color }} />\n                  <span className=\"max-w-[120px] truncate\">{opt.name.split(':')[0]}</span>\n                </button>\n              ))}\n            </div>\n          </CardContent>\n        </Card>\n\n        {/* Architectural Consensus & Tradeoff Detail Card */}\n        <Card className=\"border-border bg-card flex flex-col justify-between shadow-xs lg:col-span-6\">\n          <CardHeader className=\"pb-3\">\n            <div className=\"flex flex-wrap items-start justify-between gap-3\">\n              <div className=\"min-w-0 space-y-1\">\n                <div className=\"flex flex-wrap items-center gap-2\">\n                  <Badge variant=\"outline\" className=\"text-xs\">\n                    Selected Option Details\n                  </Badge>\n                  <Badge\n                    variant={activeSelectedOption.verdictVariant === 'success' ? 'success' : 'secondary'}\n                    className=\"text-xs font-semibold\"\n                  >\n                    {activeSelectedOption.verdict}\n                  </Badge>\n                </div>\n                <CardTitle className=\"text-foreground text-lg font-semibold tracking-tight\">\n                  {activeSelectedOption.name}\n                </CardTitle>\n                <CardDescription className=\"text-primary text-xs font-medium\">\n                  {activeSelectedOption.architecture}\n                </CardDescription>\n              </div>\n              <div className=\"shrink-0 text-right\">\n                <div className=\"text-foreground text-2xl font-semibold tabular-nums\">\n                  {activeFramework === 'rice' ? activeSelectedOption.riceScore : activeSelectedOption.weightedScore}\n                </div>\n                <div className=\"text-muted-foreground text-xs\">\n                  {activeFramework === 'rice' ? 'RICE Score' : 'Weighted Total'}\n                </div>\n              </div>\n            </div>\n          </CardHeader>\n\n          <CardContent className=\"space-y-4 text-xs\">\n            {/* Summary paragraph */}\n            <p className=\"text-muted-foreground text-sm leading-relaxed\">{activeSelectedOption.summary}</p>\n\n            <Separator />\n\n            {/* Pros & Cons Grid */}\n            <div className=\"grid grid-cols-1 gap-3.5 sm:grid-cols-2\">\n              {/* Advantages */}\n              <div className=\"border-success/20 bg-success/5 space-y-2 rounded-lg border p-3\">\n                <span className=\"text-success flex items-center gap-1.5 text-xs font-semibold\">\n                  <Check className=\"size-3.5\" />\n                  Strategic Advantages\n                </span>\n                <ul className=\"text-muted-foreground space-y-1.5\">\n                  {activeSelectedOption.pros.map((pro, idx) => (\n                    <li key={idx} className=\"flex items-start gap-1.5\">\n                      <span className=\"text-success mt-0.5\">•</span>\n                      <span>{pro}</span>\n                    </li>\n                  ))}\n                </ul>\n              </div>\n\n              {/* Friction & Tradeoffs */}\n              <div className=\"border-destructive/20 bg-destructive/5 space-y-2 rounded-lg border p-3\">\n                <span className=\"text-destructive flex items-center gap-1.5 text-xs font-semibold\">\n                  <AlertCircle className=\"size-3.5\" />\n                  Compromises & Friction\n                </span>\n                <ul className=\"text-muted-foreground space-y-1.5\">\n                  {activeSelectedOption.cons.map((con, idx) => (\n                    <li key={idx} className=\"flex items-start gap-1.5\">\n                      <span className=\"text-destructive mt-0.5\">•</span>\n                      <span>{con}</span>\n                    </li>\n                  ))}\n                </ul>\n              </div>\n            </div>\n\n            {/* Risk Mitigation */}\n            <div className=\"border-border bg-muted/40 space-y-1 rounded-md border p-3\">\n              <span className=\"text-foreground flex items-center gap-1.5 font-semibold\">\n                <ShieldCheck className=\"text-primary size-3.5\" />\n                Risk Mitigation & Governance Policy:\n              </span>\n              <p className=\"text-muted-foreground\">{activeSelectedOption.keyRisk}</p>\n            </div>\n          </CardContent>\n\n          <CardFooter className=\"border-border bg-muted/20 flex items-center justify-between gap-x-2 border-t px-6 py-3\">\n            <div className=\"flex items-center gap-2\">\n              <FileCode2 className=\"text-muted-foreground size-4\" />\n              <span className=\"text-muted-foreground text-xs font-medium\">ADR Record Consensus: </span>\n              <span className=\"text-foreground text-xs font-semibold\">\n                {winningOption.name.split(':')[1] || winningOption.name}\n              </span>\n            </div>\n            <Badge variant=\"outline\" className=\"gap-1 text-xs\">\n              <Award className=\"text-success size-3\" />\n              Rank #{activeSelectedOption.rank}\n            </Badge>\n          </CardFooter>\n        </Card>\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/DecisionMatrixTable.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/badge.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/card.json",
    "https://uipkge.dev/r/react/input.json",
    "https://uipkge.dev/r/react/separator.json",
    "https://uipkge.dev/r/react/slider.json",
    "https://uipkge.dev/r/react/table.json"
  ],
  "description": "Product and architectural decision matrix with dynamic weighted scoring algorithms (Impact, Confidence, Effort, Risk), RICE framework toggle, interactive weight sliders, option creator, multi-dimensional SVG tradeoff radar, and ADR consensus breakdown.",
  "categories": [
    "productivity",
    "app",
    "table"
  ]
}