{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "longest-chain", "title": "Most-work chain", "description": "Interactive Bitcoin chain-race timeline with canonical, competing, stale, and orphan states.", "registryDependencies": [ "dennisonbertram/bitcoin-ui/bitcoin-core", "dennisonbertram/bitcoin-ui/bitcoin-theme" ], "files": [ { "path": "components/bitcoin/longest-chain.tsx", "content": "\"use client\";\n\nimport {\n useId,\n useState,\n type ComponentProps,\n type CSSProperties,\n} from \"react\";\n\nimport {\n formatBlockHeight,\n formatTimestamp,\n truncateMiddle,\n} from \"@/lib/bitcoin\";\nimport { componentClasses } from \"@/lib/utils\";\n\nimport styles from \"./longest-chain.module.css\";\nimport type { BitcoinVisualProps } from \"./shared\";\n\nexport type ChainBranchState = \"competing\" | \"stale\" | \"orphan\";\n\nexport type LongestChainBlock = {\n /** Stable identifier used for selection state. */\n id: string;\n height: number;\n /** Optional real hash supplied by the caller. */\n hash?: string;\n timestamp?: number | Date;\n transactionCount?: number;\n miner?: string;\n /** Caller-supplied chainwork or decision note. */\n work?: string;\n};\n\nexport type LongestChainBranch = {\n id: string;\n label: string;\n state: ChainBranchState;\n /**\n * Height on the canonical chain where this branch diverges. Leave empty for\n * an orphan whose parent is not known to the current view.\n */\n forkHeight?: number;\n /** Places the branch above or below the most-work path. @default \"above\" */\n direction?: \"above\" | \"below\";\n blocks: readonly LongestChainBlock[];\n};\n\nexport type LongestChainProps = Omit, \"children\"> &\n BitcoinVisualProps & {\n canonical: readonly LongestChainBlock[];\n branches?: readonly LongestChainBranch[];\n /** Pauses the traveling chainwork signal. @default false */\n paused?: boolean;\n /** @default \"Most-work chain\" */\n title?: string;\n /** Accessible description of the represented fixture or network snapshot. */\n description?: string;\n };\n\ntype PositionedNode = {\n block: LongestChainBlock;\n branchId: string;\n branchLabel: string;\n direction: \"main\" | \"above\" | \"below\";\n state: \"canonical\" | \"tip\" | ChainBranchState;\n x: number;\n y: number;\n};\n\ntype ChainNodeStyle = CSSProperties & {\n \"--chain-x\": string;\n \"--chain-y\": string;\n};\n\nconst VIEWBOX_WIDTH = 1_000;\nconst VIEWBOX_HEIGHT = 360;\nconst MAIN_Y = 180;\nconst X_START = 88;\nconst X_END = 912;\n\nfunction pathThrough(points: readonly { x: number; y: number }[]) {\n if (points.length === 0) return \"\";\n if (points.length === 1) {\n const point = points[0];\n return `M ${point.x - 54} ${point.y} L ${point.x} ${point.y}`;\n }\n\n return points.slice(1).reduce((path, point, index) => {\n const previous = points[index];\n const midpoint = (previous.x + point.x) / 2;\n return `${path} C ${midpoint} ${previous.y}, ${midpoint} ${point.y}, ${point.x} ${point.y}`;\n }, `M ${points[0].x} ${points[0].y}`);\n}\n\nfunction stateLabel(state: PositionedNode[\"state\"]) {\n switch (state) {\n case \"canonical\":\n return \"Most-work chain\";\n case \"tip\":\n return \"Canonical tip\";\n case \"competing\":\n return \"Competing fork\";\n case \"stale\":\n return \"Stale sibling\";\n case \"orphan\":\n return \"Orphan · parent unknown\";\n }\n}\n\nexport function LongestChain({\n canonical,\n branches = [],\n paused,\n title = \"Most-work chain\",\n description = \"The branch with the greatest accumulated proof of work remains canonical.\",\n unstyled,\n className,\n ...props\n}: LongestChainProps) {\n const baseId = useId();\n const [hoveredId, setHoveredId] = useState(null);\n const [pinnedId, setPinnedId] = useState(null);\n const safeCanonical = canonical.filter((block) =>\n Number.isFinite(block.height),\n );\n const safeBranches = branches\n .map((branch) => ({\n ...branch,\n blocks: branch.blocks.filter((block) => Number.isFinite(block.height)),\n }))\n .filter((branch) => branch.blocks.length > 0);\n const allHeights = [\n ...safeCanonical.map((block) => block.height),\n ...safeBranches.flatMap((branch) =>\n branch.blocks.map((block) => block.height),\n ),\n ];\n const minHeight = Math.min(...allHeights);\n const maxHeight = Math.max(...allHeights);\n const heightRange =\n Number.isFinite(minHeight) && Number.isFinite(maxHeight)\n ? Math.max(1, maxHeight - minHeight)\n : 1;\n const xForHeight = (height: number) =>\n X_START + ((height - minHeight) / heightRange) * (X_END - X_START);\n\n const branchCounts = {\n above: safeBranches.filter(\n (branch) => (branch.direction ?? \"above\") === \"above\",\n ).length,\n below: safeBranches.filter(\n (branch) => (branch.direction ?? \"above\") === \"below\",\n ).length,\n };\n const directionIndexes = { above: 0, below: 0 };\n const canonicalNodes: PositionedNode[] = safeCanonical.map(\n (block, index) => ({\n block,\n branchId: \"canonical\",\n branchLabel: \"Most-work chain\",\n direction: \"main\",\n state:\n index === safeCanonical.length - 1\n ? (\"tip\" as const)\n : (\"canonical\" as const),\n x: xForHeight(block.height),\n y: MAIN_Y,\n }),\n );\n const branchNodes: PositionedNode[] = safeBranches.flatMap((branch) => {\n const direction = branch.direction ?? \"above\";\n const directionIndex = directionIndexes[direction]++;\n const directionCount = branchCounts[direction];\n const magnitude =\n directionCount <= 1\n ? 96\n : 88 + (directionIndex / (directionCount - 1)) * 52;\n const y = MAIN_Y + (direction === \"above\" ? -magnitude : magnitude);\n\n return branch.blocks.map((block) => ({\n block,\n branchId: branch.id,\n branchLabel: branch.label,\n direction,\n state: branch.state,\n x: xForHeight(block.height),\n y,\n }));\n });\n const nodes = [...canonicalNodes, ...branchNodes];\n\n const defaultNode =\n canonicalNodes[canonicalNodes.length - 1] ?? nodes[0];\n const activeId = hoveredId ?? pinnedId ?? defaultNode?.block.id ?? null;\n const activeNode =\n nodes.find((node) => node.block.id === activeId) ?? defaultNode;\n const canonicalPath = pathThrough(\n safeCanonical.map((block) => ({ x: xForHeight(block.height), y: MAIN_Y })),\n );\n\n return (\n \n
\n
\n \n Consensus history\n \n {title}\n
\n

{description}

\n
\n\n
\n
    \n {(\n [\n [\"canonical\", \"Most-work chain\"],\n [\"competing\", \"Competing fork\"],\n [\"stale\", \"Stale sibling\"],\n [\"orphan\", \"Orphan · parent unknown\"],\n ] as const\n ).map(([state, label]) => (\n
  • \n \n {label}\n
  • \n ))}\n
\n Bitcoin has no rewarded uncle state.\n
\n\n
\n
\n \n \n \n \n \n \n \n \n \n {safeBranches.map((branch) => {\n const branchNodes = nodes.filter(\n (node) => node.branchId === branch.id,\n );\n const forkNode =\n branch.forkHeight === undefined\n ? undefined\n : safeCanonical.find(\n (block) => block.height === branch.forkHeight,\n );\n const points = [\n ...(forkNode\n ? [{ x: xForHeight(forkNode.height), y: MAIN_Y }]\n : []),\n ...branchNodes.map((node) => ({ x: node.x, y: node.y })),\n ];\n\n return (\n \n );\n })}\n \n\n {nodes.map((node, index) => {\n const tooltipId = `${baseId}-node-${index}`;\n const isPinned = pinnedId === node.block.id;\n const nodeLabel = `${stateLabel(node.state)}, block ${formatBlockHeight(\n node.block.height,\n )}${node.block.miner ? `, mined by ${node.block.miner}` : \"\"}`;\n\n return (\n setHoveredId(node.block.id)}\n onMouseLeave={() => setHoveredId(null)}\n >\n setHoveredId(node.block.id)}\n onBlur={() => setHoveredId(null)}\n onClick={() =>\n setPinnedId((current) =>\n current === node.block.id ? null : node.block.id,\n )\n }\n onKeyDown={(event) => {\n if (event.key === \"Escape\") {\n setPinnedId(null);\n setHoveredId(null);\n }\n }}\n >\n \n {unstyled ? (\n {formatBlockHeight(node.block.height)}\n ) : (\n <>\n \n {formatBlockHeight(node.block.height)}\n \n \n {String(node.block.height).slice(-3)}\n \n \n )}\n \n
\n
\n );\n })}\n \n \n\n {activeNode ? (\n \n
\n Selected block\n {stateLabel(activeNode.state)}\n
\n
\n
\n
Height
\n
{formatBlockHeight(activeNode.block.height)}
\n
\n
\n
Branch
\n
{activeNode.branchLabel}
\n
\n {activeNode.block.hash ? (\n
\n
Hash
\n
\n {truncateMiddle(activeNode.block.hash, 6, 6)}\n
\n
\n ) : null}\n {activeNode.block.miner ? (\n
\n
Miner
\n
{activeNode.block.miner}
\n
\n ) : null}\n {activeNode.block.transactionCount !== undefined ? (\n
\n
Transactions
\n
\n {new Intl.NumberFormat(\"en-US\").format(\n activeNode.block.transactionCount,\n )}\n
\n
\n ) : null}\n {activeNode.block.timestamp ? (\n
\n
Seen
\n
{formatTimestamp(activeNode.block.timestamp)}
\n
\n ) : null}\n {activeNode.block.work ? (\n
\n
Chainwork
\n
{activeNode.block.work}
\n
\n ) : null}\n
\n \n ) : null}\n\n

\n Terminology: a valid sibling that loses the chainwork\n race is stale. “Uncle” is an Ethereum term; Bitcoin does not reward\n these blocks. An orphan has no known parent in the current view.\n

\n \n );\n}\n", "type": "registry:component" }, { "path": "components/bitcoin/longest-chain.module.css", "content": "/* Hallmark · component: longest-chain illustrator · genre: modern-minimal · macrostructure: chain-race timeline\n * theme: Vercel monochrome + semantic chain-state accents\n * pre-emit critique: P5 H5 E5 S5 R5 V5\n * states: default · hover · focus · active · pinned · paused · reduced-motion\n * contrast: pass (46–50) · slop: pass (component scope)\n */\n\n.figure {\n display: grid;\n min-width: 0;\n margin: 0;\n gap: var(--space-5);\n color: var(--color-ink);\n font-variant-numeric: tabular-nums;\n}\n\n.header {\n display: grid;\n grid-template-columns: minmax(0, 0.7fr) minmax(16rem, 1fr);\n align-items: end;\n gap: var(--space-8);\n}\n\n.header > div {\n display: grid;\n gap: var(--space-2);\n}\n\n.header strong {\n font-size: var(--text-xl);\n font-weight: 560;\n letter-spacing: -0.025em;\n}\n\n.eyebrow {\n color: var(--color-muted);\n font-family: var(--font-mono);\n font-size: 0.6875rem;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n}\n\n.header p,\n.note {\n max-width: 66ch;\n margin: 0;\n color: var(--color-muted);\n font-size: var(--text-xs);\n line-height: 1.6;\n}\n\n.legendRow {\n display: flex;\n min-width: 0;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-4);\n padding-block: var(--space-3);\n border-block: var(--rule-hair) solid var(--color-rule);\n}\n\n.legendRow ul {\n display: flex;\n min-width: 0;\n margin: 0;\n padding: 0;\n flex-wrap: wrap;\n gap: var(--space-3) var(--space-5);\n list-style: none;\n}\n\n.legendRow li,\n.legendRow > span {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n color: var(--color-muted);\n font-size: 0.6875rem;\n}\n\n.legendRow li i {\n width: var(--space-4);\n height: var(--rule-hair);\n background: var(--chain-state-color);\n box-shadow: 0 0 var(--space-2) var(--chain-state-glow);\n}\n\n.legendRow li[data-state=\"canonical\"] {\n --chain-state-color: var(--color-chain-canonical);\n --chain-state-glow: var(--color-chain-canonical-soft);\n}\n\n.legendRow li[data-state=\"competing\"] {\n --chain-state-color: var(--color-chain-competing);\n --chain-state-glow: var(--color-chain-competing-soft);\n}\n\n.legendRow li[data-state=\"stale\"] {\n --chain-state-color: var(--color-chain-stale);\n --chain-state-glow: var(--color-chain-stale-soft);\n}\n\n.legendRow li[data-state=\"orphan\"] {\n --chain-state-color: var(--color-chain-orphan);\n --chain-state-glow: var(--color-chain-orphan-soft);\n}\n\n.legendRow > span {\n flex: 0 0 auto;\n font-family: var(--font-mono);\n}\n\n.viewport {\n min-width: 0;\n overflow: clip;\n border: var(--rule-hair) solid var(--color-rule-strong);\n border-radius: var(--radius-lg);\n background:\n linear-gradient(var(--color-rule-subtle) var(--rule-hair), transparent var(--rule-hair))\n 0 25% / 100% 25%,\n var(--color-surface);\n}\n\n.canvas {\n position: relative;\n width: 100%;\n min-width: 0;\n height: clamp(20rem, 38vw, 27rem);\n isolation: isolate;\n overflow: hidden;\n}\n\n.paths {\n position: absolute;\n z-index: var(--z-canvas);\n inset: 0;\n width: 100%;\n height: 100%;\n overflow: visible;\n}\n\n.paths path {\n fill: none;\n vector-effect: non-scaling-stroke;\n stroke: var(--chain-state-color);\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-width: 2;\n}\n\n.paths path[data-state=\"canonical\"],\n.paths path[data-state=\"canonical-glow\"],\n.paths path[data-state=\"signal\"] {\n --chain-state-color: var(--color-chain-canonical);\n}\n\n.paths path[data-state=\"canonical-glow\"] {\n stroke: var(--color-chain-canonical-soft);\n stroke-width: 18;\n opacity: 0.7;\n}\n\n.paths path[data-state=\"signal\"] {\n stroke: var(--color-chain-signal);\n stroke-dasharray: 1 99;\n stroke-width: 5;\n animation: chain-signal var(--dur-relay) linear infinite;\n}\n\n.paths path[data-state=\"competing\"] {\n --chain-state-color: var(--color-chain-competing);\n}\n\n.paths path[data-state=\"stale\"] {\n --chain-state-color: var(--color-chain-stale);\n}\n\n.paths path[data-state=\"orphan\"] {\n --chain-state-color: var(--color-chain-orphan);\n stroke-dasharray: 2 7;\n}\n\n.paths path[data-disconnected=\"true\"] {\n stroke-dasharray: 2 8;\n opacity: 0.7;\n}\n\n.node {\n --chain-state-color: var(--color-chain-canonical);\n --chain-state-soft: var(--color-chain-canonical-soft);\n position: absolute;\n z-index: var(--z-content);\n top: var(--chain-y);\n left: var(--chain-x);\n transform: translate(-50%, -50%);\n}\n\n.node[data-state=\"tip\"] {\n --chain-state-color: var(--color-chain-canonical);\n --chain-state-soft: var(--color-chain-canonical-soft);\n}\n\n.node[data-state=\"competing\"] {\n --chain-state-color: var(--color-chain-competing);\n --chain-state-soft: var(--color-chain-competing-soft);\n}\n\n.node[data-state=\"stale\"] {\n --chain-state-color: var(--color-chain-stale);\n --chain-state-soft: var(--color-chain-stale-soft);\n}\n\n.node[data-state=\"orphan\"] {\n --chain-state-color: var(--color-chain-orphan);\n --chain-state-soft: var(--color-chain-orphan-soft);\n}\n\n.node button {\n display: grid;\n min-width: clamp(2.75rem, 7.5vw, 4.8rem);\n min-height: clamp(3rem, 5.5vw, 3.5rem);\n padding: var(--space-2);\n place-items: center;\n gap: var(--space-1);\n border: var(--rule-hair) solid var(--chain-state-color);\n border-radius: var(--radius-sm);\n outline: 2px solid transparent;\n outline-offset: 3px;\n cursor: pointer;\n appearance: none;\n color: var(--color-ink);\n background: var(--color-surface-raised);\n box-shadow:\n 0 0 0 var(--rule-hair) var(--color-paper),\n 0 0 var(--space-4) var(--chain-state-soft);\n font: inherit;\n transition:\n transform var(--dur-base) var(--ease-out),\n border-color var(--dur-fast) var(--ease-out),\n background-color var(--dur-fast) var(--ease-out),\n box-shadow var(--dur-base) var(--ease-out);\n}\n\n.node button i {\n width: 1.5rem;\n height: var(--space-1);\n border-radius: var(--radius-full);\n background: var(--chain-state-color);\n box-shadow: 0 0 var(--space-2) var(--chain-state-soft);\n}\n\n.node button span {\n font-family: var(--font-mono);\n font-size: 0.6875rem;\n}\n\n.heightShort {\n display: none;\n}\n\n.node button:focus-visible {\n outline-color: var(--color-focus);\n}\n\n.node button:active {\n transform: translateY(1px);\n background: var(--color-surface-active);\n}\n\n.node button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.node[data-active=\"true\"] button,\n.node[data-pinned=\"true\"] button {\n transform: translateY(calc(var(--space-1) * -1));\n border-width: 2px;\n background: var(--color-surface-hover);\n box-shadow:\n 0 0 0 var(--rule-hair) var(--color-paper),\n 0 0 var(--space-6) var(--chain-state-soft);\n}\n\n.tooltip {\n position: absolute;\n z-index: var(--z-toolbar);\n bottom: calc(100% + var(--space-3));\n left: 50%;\n display: grid;\n width: 10.5rem;\n padding: var(--space-3);\n gap: var(--space-1);\n transform: translate(-50%, var(--space-1));\n border: var(--rule-hair) solid var(--color-rule-strong);\n border-radius: var(--radius-sm);\n color: var(--color-ink);\n background: var(--color-surface-raised);\n opacity: 0;\n pointer-events: none;\n visibility: hidden;\n transition:\n opacity var(--dur-base) var(--ease-out) 900ms,\n transform var(--dur-base) var(--ease-out) 900ms,\n visibility 0s linear 900ms;\n}\n\n.node[data-direction=\"above\"] .tooltip {\n top: calc(100% + var(--space-3));\n bottom: auto;\n transform: translate(-50%, calc(var(--space-1) * -1));\n}\n\n.node[data-edge=\"start\"] .tooltip {\n right: auto;\n left: 0;\n transform: translate(0, var(--space-1));\n}\n\n.node[data-edge=\"end\"] .tooltip {\n right: 0;\n left: auto;\n transform: translate(0, var(--space-1));\n}\n\n.node[data-direction=\"above\"][data-edge=\"start\"] .tooltip,\n.node[data-direction=\"above\"][data-edge=\"end\"] .tooltip {\n transform: translate(0, calc(var(--space-1) * -1));\n}\n\n.tooltip strong,\n.tooltip span,\n.tooltip small {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.tooltip strong {\n font-size: 0.6875rem;\n font-weight: 560;\n}\n\n.tooltip span,\n.tooltip small {\n color: var(--color-muted);\n font-family: var(--font-mono);\n font-size: 0.625rem;\n}\n\n.node:focus-within .tooltip,\n.node[data-pinned=\"true\"] .tooltip {\n transform: translate(-50%, 0);\n opacity: 1;\n visibility: visible;\n transition-delay: 0s;\n}\n\n.node[data-edge=\"start\"]:focus-within .tooltip,\n.node[data-edge=\"end\"]:focus-within .tooltip,\n.node[data-edge=\"start\"][data-pinned=\"true\"] .tooltip,\n.node[data-edge=\"end\"][data-pinned=\"true\"] .tooltip {\n transform: translate(0, 0);\n}\n\n.inspector {\n display: grid;\n min-width: 0;\n padding: var(--space-4);\n grid-template-columns: minmax(10rem, 14rem) minmax(0, 1fr);\n gap: var(--space-3);\n border: var(--rule-hair) solid var(--chain-state-color);\n border-radius: var(--radius-md);\n color: var(--color-ink);\n background: var(--color-surface-raised);\n box-shadow: 0 0 var(--space-6) var(--chain-state-soft);\n}\n\n.inspector[data-state=\"canonical\"],\n.inspector[data-state=\"tip\"] {\n --chain-state-color: var(--color-chain-canonical);\n --chain-state-soft: var(--color-chain-canonical-soft);\n}\n\n.inspector[data-state=\"competing\"] {\n --chain-state-color: var(--color-chain-competing);\n --chain-state-soft: var(--color-chain-competing-soft);\n}\n\n.inspector[data-state=\"stale\"] {\n --chain-state-color: var(--color-chain-stale);\n --chain-state-soft: var(--color-chain-stale-soft);\n}\n\n.inspector[data-state=\"orphan\"] {\n --chain-state-color: var(--color-chain-orphan);\n --chain-state-soft: var(--color-chain-orphan-soft);\n}\n\n.inspector header,\n.inspector dl > div {\n display: flex;\n min-width: 0;\n align-items: center;\n justify-content: space-between;\n gap: var(--space-3);\n}\n\n.inspector header {\n padding-bottom: var(--space-3);\n align-items: flex-start;\n justify-content: center;\n flex-direction: column;\n border-right: var(--rule-hair) solid var(--color-rule);\n}\n\n.inspector header span,\n.inspector dt {\n color: var(--color-muted);\n font-size: 0.6875rem;\n}\n\n.inspector header strong {\n color: var(--color-ink);\n font-size: 0.6875rem;\n font-weight: 560;\n}\n\n.inspector dl {\n display: grid;\n margin: 0;\n padding-left: var(--space-3);\n grid-template-columns: repeat(2, minmax(0, 1fr));\n gap: var(--space-2);\n}\n\n.inspector dd {\n min-width: 0;\n margin: 0;\n overflow: hidden;\n font-family: var(--font-mono);\n font-size: 0.6875rem;\n text-align: right;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.note {\n padding-left: var(--space-4);\n border-left: 2px solid var(--color-chain-canonical);\n}\n\n.note strong {\n margin-right: var(--space-1);\n color: var(--color-ink);\n font-weight: 560;\n}\n\n@media (hover: hover) and (pointer: fine) {\n .node:hover button {\n transform: translateY(calc(var(--space-1) * -1));\n background: var(--color-surface-hover);\n box-shadow:\n 0 0 0 var(--rule-hair) var(--color-paper),\n 0 0 var(--space-6) var(--chain-state-soft);\n }\n\n .node:hover .tooltip {\n transform: translate(-50%, 0);\n opacity: 1;\n visibility: visible;\n }\n\n .node[data-edge=\"start\"]:hover .tooltip,\n .node[data-edge=\"end\"]:hover .tooltip {\n transform: translate(0, 0);\n }\n}\n\n[data-paused=\"true\"] .paths path[data-state=\"signal\"] {\n animation-play-state: paused;\n}\n\n@keyframes chain-signal {\n from {\n stroke-dashoffset: 100;\n }\n to {\n stroke-dashoffset: 0;\n }\n}\n\n@media (max-width: 48rem) {\n .header {\n grid-template-columns: 1fr;\n gap: var(--space-3);\n }\n\n .legendRow {\n align-items: flex-start;\n flex-direction: column;\n }\n\n .node button {\n padding: var(--space-1);\n }\n\n .node button span {\n font-size: 0.5625rem;\n }\n\n .inspector {\n grid-template-columns: 1fr;\n }\n\n .inspector header {\n padding-bottom: var(--space-3);\n border-right: 0;\n border-bottom: var(--rule-hair) solid var(--color-rule);\n }\n\n .inspector dl {\n padding-left: 0;\n grid-template-columns: 1fr;\n }\n}\n\n@media (max-width: 32rem) {\n .node button {\n min-width: var(--space-10);\n padding: var(--space-1) 0;\n }\n\n .heightFull {\n display: none;\n }\n\n .heightShort {\n display: inline;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .paths path[data-state=\"signal\"] {\n display: none;\n animation: none;\n }\n\n .node button,\n .tooltip {\n transition: none;\n }\n}\n", "type": "registry:file", "target": "components/bitcoin/longest-chain.module.css" } ], "type": "registry:component" }