{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "dotm-square-1",
  "type": "registry:ui",
  "title": "Neon Drift",
  "description": "Same ripple family as the icon, with a wave that sweeps from the top-right toward the bottom-left.",
  "dependencies": [],
  "registryDependencies": [],
  "meta": {
    "animation": "css-only"
  },
  "files": [
    {
      "path": "components/ui/dotm-square-1.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\n\nimport type { CSSProperties } from \"react\";\n\nimport { DotMatrixBase } from \"@/components/ui/dotmatrix-core\";\nimport { useDotMatrixPhases } from \"@/components/ui/dotmatrix-hooks\";\nimport { trBlPathNormFromIndex } from \"@/components/ui/dotmatrix-core\";\nimport { usePrefersReducedMotion } from \"@/components/ui/dotmatrix-hooks\";\nimport type { DotAnimationResolver } from \"@/components/ui/dotmatrix-core\";\nimport type { DotMatrixCommonProps } from \"@/components/ui/dotmatrix-core\";\n\nexport type DotmSquare1Props = DotMatrixCommonProps;\n\nconst animationResolver: DotAnimationResolver = ({ isActive, index, row, col, reducedMotion, phase }) => {\n  if (!isActive) {\n    return { className: \"dmx-inactive\" };\n  }\n\n  const path = trBlPathNormFromIndex(index);\n  const slice = row + (4 - col);\n  const parity = slice % 2;\n  const style = {\n    \"--dmx-path\": path,\n    \"--dmx-diagonal-parity\": parity\n  } as CSSProperties;\n\n  if (reducedMotion || phase === \"idle\") {\n    return {\n      style: {\n        ...style,\n        opacity: parity === 0 ? 0.88 : 0.14\n      }\n    };\n  }\n\n  return { className: \"dmx-diagonal-alt-sweep\", style };\n};\n\nexport function DotmSquare1({\n  speed = 1.1,\n  pattern = \"full\",\n  animated = true,\n  hoverAnimated = false,\n  ...rest\n}: DotmSquare1Props) {\n  const reducedMotion = usePrefersReducedMotion();\n  const { phase: matrixPhase, onMouseEnter, onMouseLeave } = useDotMatrixPhases({\n    animated: Boolean(animated && !reducedMotion),\n    hoverAnimated: Boolean(hoverAnimated && !reducedMotion),\n    speed\n  });\n\n  return (\n    <DotMatrixBase\n      {...rest}\n      size={rest.size ?? 36}\n      dotSize={rest.dotSize ?? 5}\n      speed={speed}\n      pattern={pattern}\n      animated={animated}\n      phase={matrixPhase}\n      onMouseEnter={onMouseEnter}\n      onMouseLeave={onMouseLeave}\n      reducedMotion={reducedMotion}\n      animationResolver={animationResolver}\n    />\n  );\n}\n"
    },
    {
      "path": "components/ui/dotmatrix-core.tsx",
      "type": "registry:lib",
      "content": "\"use client\";\n\nimport type { CSSProperties } from \"react\";\n\nimport \"@/components/dotmatrix-loader.css\";\nimport type { ReactNode } from \"react\";\nimport { useEffect, useMemo, useRef } from \"react\";\nimport { useDotMatrixPhases, usePrefersReducedMotion, useCyclePhase } from \"@/components/ui/dotmatrix-hooks\";\n\nexport type MatrixPattern = \"diamond\" | \"full\" | \"outline\" | \"rose\" | \"cross\" | \"rings\";\nexport type DotShape = \"circle\" | \"square\" | \"diamond\" | \"hearts\";\nexport type DotMatrixPhase = \"idle\" | \"collapse\" | \"hoverRipple\" | \"loadingRipple\";\nexport type DotMatrixColorPreset =\n  | \"solid-theme\"\n  | \"solid-mint\"\n  | \"grad-sunset\"\n  | \"grad-ocean\"\n  | \"grad-neon\"\n  | \"grad-aurora\"\n  | \"grad-fire\"\n  | \"grad-prism\";\n\nconst DOT_MATRIX_COLOR_PRESETS: Record<\n  DotMatrixColorPreset,\n  {\n    fill: string;\n    glow: string;\n  }\n> = {\n  \"solid-theme\": {\n    fill: \"var(--color-dot-on)\",\n    glow: \"var(--color-dot-on)\"\n  },\n  \"solid-mint\": {\n    fill: \"#34d399\",\n    glow: \"#34d399\"\n  },\n  \"grad-sunset\": {\n    fill: \"linear-gradient(135deg, #ff5f6d 0%, #ffc371 52%, #ffe29a 100%)\",\n    glow: \"#ff8b73\"\n  },\n  \"grad-ocean\": {\n    fill: \"linear-gradient(140deg, #00c6ff 0%, #0072ff 48%, #4facfe 100%)\",\n    glow: \"#2f8fff\"\n  },\n  \"grad-neon\": {\n    fill: \"linear-gradient(145deg, #b4ff39 0%, #39ffb6 46%, #00d4ff 100%)\",\n    glow: \"#59ffc8\"\n  },\n  \"grad-aurora\": {\n    fill: \"linear-gradient(145deg, #ff3cac 0%, #784ba0 45%, #2b86c5 100%)\",\n    glow: \"#9c64bf\"\n  },\n  \"grad-fire\": {\n    fill: \"linear-gradient(145deg, #ff512f 0%, #dd2476 45%, #ffb347 100%)\",\n    glow: \"#f96a5f\"\n  },\n  \"grad-prism\": {\n    fill: \"linear-gradient(145deg, #12c2e9 0%, #c471ed 45%, #f64f59 100%)\",\n    glow: \"#9e7de8\"\n  }\n};\n\nexport function resolveDmxColorTokens(color: string, colorPreset?: DotMatrixColorPreset): {\n  resolvedColor: string;\n  dotFill: string;\n} {\n  if (!colorPreset) {\n    return { resolvedColor: color, dotFill: color };\n  }\n\n  const preset = DOT_MATRIX_COLOR_PRESETS[colorPreset];\n  if (!preset) {\n    return { resolvedColor: color, dotFill: color };\n  }\n\n  return { resolvedColor: preset.glow, dotFill: preset.fill };\n}\n\nexport interface DotMatrixCommonProps {\n  size?: number;\n  dotSize?: number;\n  color?: string;\n  colorPreset?: DotMatrixColorPreset;\n  speed?: number;\n  ariaLabel?: string;\n  className?: string;\n  pattern?: MatrixPattern;\n  muted?: boolean;\n  /**\n   * Adds a glow on dots from opacity 0.6 (weakest) through 1 (strongest), after remapping.\n   */\n  bloom?: boolean;\n  /** Uniform glow on every active dot (0…1); slightly wider falloff than selective `bloom`. */\n  halo?: number;\n  animated?: boolean;\n  hoverAnimated?: boolean;\n  dotClassName?: string;\n  dotShape?: DotShape;\n  opacityBase?: number;\n  opacityMid?: number;\n  opacityPeak?: number;\n  cellPadding?: number;\n  boxSize?: number;\n  minSize?: number;\n}\n\nexport interface DotAnimationContext {\n  index: number;\n  row: number;\n  col: number;\n  distanceFromCenter: number;\n  angleFromCenter: number;\n  radiusNormalized: number;\n  manhattanDistance: number;\n  phase: DotMatrixPhase;\n  isActive: boolean;\n  reducedMotion: boolean;\n}\n\nexport interface DotAnimationState {\n  className?: string;\n  style?: CSSProperties;\n}\n\nexport type DotAnimationResolver = (ctx: DotAnimationContext) => DotAnimationState;\n\nexport function cx(...values: Array<string | undefined | null | false>): string {\n  return values.filter(Boolean).join(\" \");\n}\n\nexport const MATRIX_SIZE = 5;\nconst CENTER = Math.floor(MATRIX_SIZE / 2);\nconst RANGE = Array.from({ length: MATRIX_SIZE }, (_, index) => index);\nconst MAX_RADIUS = Math.hypot(CENTER, CENTER);\n\nexport const FULL_INDEXES = RANGE.flatMap((row) => RANGE.map((col) => rowMajorIndex(row, col)));\n\nexport const DIAMOND_INDEXES = FULL_INDEXES.filter((index) => {\n  const { row, col } = indexToCoord(index);\n  return Math.abs(row - CENTER) + Math.abs(col - CENTER) <= 2;\n});\n\nexport const OUTLINE_INDEXES = FULL_INDEXES.filter((index) => {\n  const { row, col } = indexToCoord(index);\n  return row === 0 || row === MATRIX_SIZE - 1 || col === 0 || col === MATRIX_SIZE - 1;\n});\n\nexport const CROSS_INDEXES = FULL_INDEXES.filter((index) => {\n  const { row, col } = indexToCoord(index);\n  return row === CENTER || col === CENTER;\n});\n\nexport const RINGS_INDEXES = FULL_INDEXES.filter((index) => {\n  const { row, col } = indexToCoord(index);\n  const radius = Math.hypot(row - CENTER, col - CENTER);\n  return Math.round(radius) === 1 || Math.round(radius) === 2;\n});\n\nexport const ROSE_INDEXES = FULL_INDEXES.filter((index) => {\n  const { row, col } = indexToCoord(index);\n  const dx = col - CENTER;\n  const dy = row - CENTER;\n  const angle = Math.atan2(dy, dx);\n  const radius = Math.hypot(dx, dy);\n  const rose = Math.abs(Math.sin(3 * angle));\n  return rose > 0.6 && radius >= 1;\n});\n\nconst PATTERN_INDEXES: Record<MatrixPattern, number[]> = {\n  diamond: DIAMOND_INDEXES,\n  full: FULL_INDEXES,\n  outline: OUTLINE_INDEXES,\n  rose: ROSE_INDEXES,\n  cross: CROSS_INDEXES,\n  rings: RINGS_INDEXES\n};\n\nexport function getPatternIndexes(pattern: MatrixPattern = \"diamond\"): number[] {\n  return PATTERN_INDEXES[pattern];\n}\n\nexport function rowMajorIndex(row: number, col: number): number {\n  return row * MATRIX_SIZE + col;\n}\n\nexport function indexToCoord(index: number): { row: number; col: number } {\n  return {\n    row: Math.floor(index / MATRIX_SIZE),\n    col: index % MATRIX_SIZE\n  };\n}\n\nexport function distanceFromCenter(index: number): number {\n  const { row, col } = indexToCoord(index);\n  return Math.hypot(row - CENTER, col - CENTER);\n}\n\nexport function rowDistance(index: number): number {\n  const { row } = indexToCoord(index);\n  return Math.abs(row - CENTER);\n}\n\nexport function polarAngle(index: number): number {\n  const { row, col } = indexToCoord(index);\n  return Math.atan2(row - CENTER, col - CENTER);\n}\n\nexport function normalizedRadius(index: number): number {\n  const { row, col } = indexToCoord(index);\n  return Math.hypot(row - CENTER, col - CENTER) / MAX_RADIUS;\n}\n\nexport function manhattanDistance(index: number): number {\n  const { row, col } = indexToCoord(index);\n  return Math.abs(row - CENTER) + Math.abs(col - CENTER);\n}\n\nexport function harmonicPhase(row: number, col: number, a: number, b: number): number {\n  return Math.sin((row + 1) * a + (col + 1) * b);\n}\n\nexport function lissajousOffset(\n  row: number,\n  col: number,\n  amplitude = 2.25\n): { x: number; y: number; phase: number } {\n  const x = Math.sin((row + 1) * 1.15 + (col + 1) * 2.2) * amplitude;\n  const y = Math.cos((row + 1) * 2.45 + (col + 1) * 0.95) * amplitude;\n  const phase = Math.abs(Math.sin((row + 1) * 0.7 + (col + 1) * 1.1));\n  return { x, y, phase };\n}\n\nexport function spiralOffset(\n  angle: number,\n  radiusNormalizedValue: number,\n  amplitude = 2.8\n): { x: number; y: number; phase: number } {\n  const spin = angle + radiusNormalizedValue * Math.PI * 2.1;\n  const radius = radiusNormalizedValue * amplitude;\n  const x = Math.cos(spin) * radius;\n  const y = Math.sin(spin) * radius;\n  const phase = Math.abs(Math.sin(spin * 0.5));\n  return { x, y, phase };\n}\n\nexport function isPrime(value: number): boolean {\n  if (value <= 1) {\n    return false;\n  }\n  if (value === 2) {\n    return true;\n  }\n  if (value % 2 === 0) {\n    return false;\n  }\n\n  const limit = Math.floor(Math.sqrt(value));\n  for (let divisor = 3; divisor <= limit; divisor += 2) {\n    if (value % divisor === 0) {\n      return false;\n    }\n  }\n\n  return true;\n}\n\nconst N = MATRIX_SIZE;\nconst C = Math.floor(MATRIX_SIZE / 2);\nconst CELLS = N * N;\nconst MAX_TRBL = (N - 1) * 2;\n\nexport function trBlPathNormFromIndex(index: number): number {\n  const { row, col } = indexToCoord(index);\n  return (row + (N - 1 - col)) / MAX_TRBL;\n}\n\nfunction buildSnakeOrderToIndexMap(): number[] {\n  const pathOrder = new Array<number>(CELLS);\n  const key = (row: number, col: number) => rowMajorIndex(row, col);\n  let t = 0;\n  for (let row = 0; row < N; row += 1) {\n    if (row % 2 === 0) {\n      for (let col = 0; col < N; col += 1) {\n        pathOrder[key(row, col)] = t;\n        t += 1;\n      }\n    } else {\n      for (let col = N - 1; col >= 0; col -= 1) {\n        pathOrder[key(row, col)] = t;\n        t += 1;\n      }\n    }\n  }\n  return pathOrder;\n}\n\nconst SNAKE_ORDER: readonly number[] = buildSnakeOrderToIndexMap();\n\nexport function snakePathNormFromIndex(index: number): number {\n  return SNAKE_ORDER[index]! / (CELLS - 1);\n}\n\nexport function snakePathOrderValue(index: number): number {\n  return SNAKE_ORDER[index]!;\n}\n\nfunction buildSpiralInwardOrderToIndexMap(): number[] {\n  const order = new Array<number>(CELLS);\n  let top = 0;\n  let bottom = N - 1;\n  let left = 0;\n  let right = N - 1;\n  let t = 0;\n\n  while (top <= bottom && left <= right) {\n    for (let col = left; col <= right; col += 1) {\n      order[rowMajorIndex(top, col)] = t;\n      t += 1;\n    }\n\n    for (let row = top + 1; row <= bottom; row += 1) {\n      order[rowMajorIndex(row, right)] = t;\n      t += 1;\n    }\n\n    if (top < bottom) {\n      for (let col = right - 1; col >= left; col -= 1) {\n        order[rowMajorIndex(bottom, col)] = t;\n        t += 1;\n      }\n    }\n\n    if (left < right) {\n      for (let row = bottom - 1; row > top; row -= 1) {\n        order[rowMajorIndex(row, left)] = t;\n        t += 1;\n      }\n    }\n\n    top += 1;\n    bottom -= 1;\n    left += 1;\n    right -= 1;\n  }\n\n  return order;\n}\n\nconst SPIRAL_INWARD_ORDER: readonly number[] = buildSpiralInwardOrderToIndexMap();\n\nexport function spiralInwardNormFromIndex(index: number): number {\n  return SPIRAL_INWARD_ORDER[index]! / (CELLS - 1);\n}\n\nexport function spiralInwardOrderValue(index: number): number {\n  return SPIRAL_INWARD_ORDER[index]!;\n}\n\nfunction buildOuterRingClockwiseOrderToIndexMap(): number[] {\n  const order = new Array<number>(CELLS).fill(-1);\n  const coords: Array<[number, number]> = [\n    [0, 0],\n    [0, 1],\n    [0, 2],\n    [0, 3],\n    [0, 4],\n    [1, 4],\n    [2, 4],\n    [3, 4],\n    [4, 4],\n    [4, 3],\n    [4, 2],\n    [4, 1],\n    [4, 0],\n    [3, 0],\n    [2, 0],\n    [1, 0]\n  ];\n\n  for (let t = 0; t < coords.length; t += 1) {\n    const [row, col] = coords[t]!;\n    order[rowMajorIndex(row, col)] = t;\n  }\n\n  return order;\n}\n\nfunction buildMiddleRingAntiClockwiseOrderToIndexMap(): number[] {\n  const order = new Array<number>(CELLS).fill(-1);\n  const coords: Array<[number, number]> = [\n    [1, 1],\n    [2, 1],\n    [3, 1],\n    [3, 2],\n    [3, 3],\n    [2, 3],\n    [1, 3],\n    [1, 2]\n  ];\n\n  for (let t = 0; t < coords.length; t += 1) {\n    const [row, col] = coords[t]!;\n    order[rowMajorIndex(row, col)] = t;\n  }\n\n  return order;\n}\n\nconst OUTER_RING_CLOCKWISE_ORDER: readonly number[] = buildOuterRingClockwiseOrderToIndexMap();\nconst MIDDLE_RING_ANTI_CLOCKWISE_ORDER: readonly number[] = buildMiddleRingAntiClockwiseOrderToIndexMap();\n\nexport function outerRingClockwiseOrderValue(index: number): number {\n  return OUTER_RING_CLOCKWISE_ORDER[index]!;\n}\n\nexport function outerRingClockwiseNormFromIndex(index: number): number {\n  const order = outerRingClockwiseOrderValue(index);\n  return order >= 0 ? order / 15 : 0;\n}\n\nexport function middleRingAntiClockwiseOrderValue(index: number): number {\n  return MIDDLE_RING_ANTI_CLOCKWISE_ORDER[index]!;\n}\n\nexport function middleRingAntiClockwiseNormFromIndex(index: number): number {\n  const order = middleRingAntiClockwiseOrderValue(index);\n  return order >= 0 ? order / 7 : 0;\n}\n\nfunction buildDiagonalSnakeOrderToIndexMap(): number[] {\n  const order = new Array<number>(CELLS);\n  let t = 0;\n\n  for (let diagonal = 0; diagonal <= (N - 1) * 2; diagonal += 1) {\n    const rowStart = Math.max(0, diagonal - (N - 1));\n    const rowEnd = Math.min(N - 1, diagonal);\n\n    if (diagonal % 2 === 0) {\n      for (let row = rowEnd; row >= rowStart; row -= 1) {\n        const col = diagonal - row;\n        order[rowMajorIndex(row, col)] = t;\n        t += 1;\n      }\n    } else {\n      for (let row = rowStart; row <= rowEnd; row += 1) {\n        const col = diagonal - row;\n        order[rowMajorIndex(row, col)] = t;\n        t += 1;\n      }\n    }\n  }\n\n  return order;\n}\n\nconst DIAGONAL_SNAKE_ORDER: readonly number[] = buildDiagonalSnakeOrderToIndexMap();\n\nexport function diagonalSnakeOrderValue(index: number): number {\n  return DIAGONAL_SNAKE_ORDER[index]!;\n}\n\nexport function diagonalSnakeNormFromIndex(index: number): number {\n  return DIAGONAL_SNAKE_ORDER[index]! / (CELLS - 1);\n}\n\nfunction buildRowWaveSnakeOrderToIndexMap(): number[] {\n  const order = new Array<number>(CELLS);\n  const route: Array<{ col: number; dir: \"up\" | \"down\" }> = [\n    { col: 0, dir: \"up\" },\n    { col: 2, dir: \"down\" },\n    { col: 1, dir: \"up\" },\n    { col: 3, dir: \"down\" },\n    { col: 2, dir: \"up\" },\n    { col: 4, dir: \"down\" }\n  ];\n\n  let t = 0;\n  for (const step of route) {\n    if (step.dir === \"up\") {\n      for (let row = N - 1; row >= 0; row -= 1) {\n        order[rowMajorIndex(row, step.col)] = t;\n        t += 1;\n      }\n    } else {\n      for (let row = 0; row < N; row += 1) {\n        order[rowMajorIndex(row, step.col)] = t;\n        t += 1;\n      }\n    }\n  }\n\n  return order;\n}\n\nconst ROW_WAVE_SNAKE_ORDER: readonly number[] = buildRowWaveSnakeOrderToIndexMap();\nconst ROW_WAVE_SNAKE_MAX_ORDER = Math.max(...ROW_WAVE_SNAKE_ORDER);\n\nexport function rowWaveOrderValue(index: number): number {\n  return ROW_WAVE_SNAKE_ORDER[index]!;\n}\n\nexport function rowWaveNormFromIndex(index: number): number {\n  return ROW_WAVE_SNAKE_MAX_ORDER > 0 ? rowWaveOrderValue(index) / ROW_WAVE_SNAKE_MAX_ORDER : 0;\n}\n\nexport function colWaveNormFromIndex(index: number): number {\n  const { col } = indexToCoord(index);\n  return N > 1 ? col / (N - 1) : 0;\n}\n\nexport function concentricRingNormFromIndex(index: number): number {\n  const { row, col } = indexToCoord(index);\n  return Math.max(Math.abs(row - C), Math.abs(col - C)) / C;\n}\n\nconst CORNER_COORDS = new Set([\"0,0\", \"0,4\", \"4,0\", \"4,4\"]);\n\nexport function isWithinCircularMask(row: number, col: number): boolean {\n  return !CORNER_COORDS.has(`${row},${col}`);\n}\n\nexport function stylePx(n: number): string {\n  return `${n}px`;\n}\n\nexport function styleOpacity(opacity: number): number {\n  return Math.round(opacity * 1e6) / 1e6;\n}\n\nconst SOURCE_BASE_OPACITY = 0.08;\nconst SOURCE_MID_OPACITY = 0.34;\nconst SOURCE_PEAK_OPACITY = 0.94;\n\nfunction lerpDmx(start: number, end: number, progress: number): number {\n  return start + (end - start) * progress;\n}\n\nfunction normalizeProgressDmx(value: number, start: number, end: number): number {\n  const span = end - start;\n  if (Math.abs(span) < Number.EPSILON) {\n    return 0;\n  }\n  return Math.min(1, Math.max(0, (value - start) / span));\n}\n\nfunction coerceOpacityDmx(value: number | undefined): number | undefined {\n  if (value == null || !Number.isFinite(value)) {\n    return undefined;\n  }\n  return Math.min(1, Math.max(0, value));\n}\n\nexport function remapOpacityToTriplet(\n  opacity: number,\n  opacityBase: number | undefined,\n  opacityMid: number | undefined,\n  opacityPeak: number | undefined\n): number {\n  if (!Number.isFinite(opacity)) {\n    return opacity;\n  }\n\n  const hasOverrides = opacityBase !== undefined || opacityMid !== undefined || opacityPeak !== undefined;\n  const safeOpacity = Math.min(1, Math.max(0, opacity));\n  if (!hasOverrides) {\n    return safeOpacity;\n  }\n\n  const targetBase = coerceOpacityDmx(opacityBase) ?? SOURCE_BASE_OPACITY;\n  const targetMid = coerceOpacityDmx(opacityMid) ?? SOURCE_MID_OPACITY;\n  const targetPeak = coerceOpacityDmx(opacityPeak) ?? SOURCE_PEAK_OPACITY;\n\n  if (safeOpacity <= SOURCE_BASE_OPACITY) {\n    const progress = normalizeProgressDmx(safeOpacity, 0, SOURCE_BASE_OPACITY);\n    return Math.min(1, Math.max(0, lerpDmx(0, targetBase, progress)));\n  }\n\n  if (safeOpacity <= SOURCE_MID_OPACITY) {\n    const progress = normalizeProgressDmx(safeOpacity, SOURCE_BASE_OPACITY, SOURCE_MID_OPACITY);\n    return Math.min(1, Math.max(0, lerpDmx(targetBase, targetMid, progress)));\n  }\n\n  if (safeOpacity <= SOURCE_PEAK_OPACITY) {\n    const progress = normalizeProgressDmx(safeOpacity, SOURCE_MID_OPACITY, SOURCE_PEAK_OPACITY);\n    return Math.min(1, Math.max(0, lerpDmx(targetMid, targetPeak, progress)));\n  }\n\n  const progress = normalizeProgressDmx(safeOpacity, SOURCE_PEAK_OPACITY, 1);\n  return Math.min(1, Math.max(0, lerpDmx(targetPeak, 1, progress)));\n}\n\n/** Remapped opacity where bloom begins (weakest glow); scales linearly to full bloom at 1. */\nexport const DMX_BLOOM_OPACITY_MIN = 0.6;\n\nexport function opacityToBloomLevel(remappedOpacity: number): number {\n  return Math.max(0, Math.min(1, (remappedOpacity - DMX_BLOOM_OPACITY_MIN) / (1 - DMX_BLOOM_OPACITY_MIN)));\n}\n\nexport function remappedOpacityQualifiesForBloom(remappedOpacity: number): boolean {\n  return remappedOpacity >= DMX_BLOOM_OPACITY_MIN;\n}\n\nfunction clampHalo(value: number | undefined): number {\n  if (value == null || !Number.isFinite(value)) {\n    return 0;\n  }\n  return Math.min(1, Math.max(0, value));\n}\n\nexport function dmxBloomRootActive(bloom: boolean, halo: number | undefined): boolean {\n  return bloom || clampHalo(halo) > 0;\n}\n\n/** Root class when `halo` > 0 — CSS widens drop-shadow falloff for a softer, more diffuse glow. */\nexport function dmxBloomHaloSpreadClass(halo: number | undefined): \"dmx-bloom-halo\" | false {\n  return clampHalo(halo) > 0 ? \"dmx-bloom-halo\" : false;\n}\n\n/**\n * Bloom level and dot class for one cell. `curveOpacity` is the loader’s logical opacity **before**\n * `remapOpacityToTriplet` (same as `bloom` uses today).\n */\nexport function dmxDotBloomParts(\n  isActive: boolean,\n  curveOpacity: number,\n  bloom: boolean,\n  halo: number | undefined,\n  ob: number | undefined,\n  om: number | undefined,\n  op: number | undefined\n): { level: number; bloomDot: boolean } {\n  const haloN = clampHalo(halo);\n  if (!isActive) {\n    return { level: 0, bloomDot: false };\n  }\n  const remapped = remapOpacityToTriplet(curveOpacity, ob, om, op);\n  const fromBloom = bloom ? opacityToBloomLevel(remapped) : 0;\n  return {\n    level: fromBloom,\n    bloomDot: haloN > 0 || (bloom && remappedOpacityQualifiesForBloom(remapped))\n  };\n}\n\nfunction getMatrix5Layout(\n  size: number,\n  dotSize: number,\n  cellPadding?: number\n): { gap: number; matrixSpan: number } {\n  const n = MATRIX_SIZE;\n  if (cellPadding != null) {\n    const g = Math.max(0, cellPadding);\n    const matrixSpan = dotSize * n + g * (n - 1);\n    return { gap: g, matrixSpan };\n  }\n  const g = Math.max(1, Math.floor((size - dotSize * n) / (n - 1)));\n  return { gap: g, matrixSpan: size };\n}\n\nfunction resolveDmxBoxOuterDim(\n  options: { boxSize?: number; minSize?: number } | null | undefined\n): { outerDim: number; useWrapper: boolean } {\n  const b = options?.boxSize;\n  const hasBox = b != null && b > 0 && Number.isFinite(b);\n  if (!hasBox) {\n    return { outerDim: 0, useWrapper: false };\n  }\n  const m = options?.minSize;\n  if (m != null && m > 0 && Number.isFinite(m)) {\n    return { outerDim: Math.max(b, m), useWrapper: true };\n  }\n  return { outerDim: b, useWrapper: true };\n}\n\nfunction clamp01Dmx(n: number | undefined) {\n  if (n == null) {\n    return;\n  }\n  if (!Number.isFinite(n)) {\n    return;\n  }\n  return Math.min(1, Math.max(0, n));\n}\n\ninterface DotMatrixBaseProps extends DotMatrixCommonProps {\n  phase: DotMatrixPhase;\n  reducedMotion?: boolean;\n  onMouseEnter?: () => void;\n  onMouseLeave?: () => void;\n  animationResolver?: DotAnimationResolver;\n}\n\nexport function DotMatrixBase({\n  size = 24,\n  dotSize = 3,\n  color = \"currentColor\",\n  colorPreset,\n  speed = 1,\n  ariaLabel = \"Loading\",\n  className,\n  pattern = \"diamond\",\n  dotShape = \"circle\",\n  muted = false,\n  bloom = false,\n  halo = 0,\n  dotClassName,\n  phase,\n  reducedMotion = false,\n  onMouseEnter,\n  onMouseLeave,\n  animationResolver,\n  opacityBase,\n  opacityMid,\n  opacityPeak,\n  cellPadding,\n  boxSize,\n  minSize\n}: DotMatrixBaseProps) {\n  const patternIndexes = new Set(getPatternIndexes(pattern));\n  const safeSpeed = speed > 0 ? speed : 1;\n  const speedScale = 1 / safeSpeed;\n  const { gap, matrixSpan } = getMatrix5Layout(size, dotSize, cellPadding);\n  const { outerDim, useWrapper } = resolveDmxBoxOuterDim({ boxSize, minSize });\n  const scale = useWrapper && matrixSpan > 0 ? outerDim / matrixSpan : 1;\n  const center = Math.floor(MATRIX_SIZE / 2);\n  const ob = clamp01Dmx(opacityBase);\n  const om = clamp01Dmx(opacityMid);\n  const op = clamp01Dmx(opacityPeak);\n  const unit = dotSize + gap;\n  const { resolvedColor, dotFill } = resolveDmxColorTokens(color, colorPreset);\n\n  const dmxVarStyle = {\n    width: matrixSpan,\n    height: matrixSpan,\n    \"--dmx-speed\": speedScale,\n    [\"--dmx-dot-size\" as const]: `${dotSize}px`,\n    [\"--dmx-halo-level\" as const]: halo,\n    [\"--dmx-dot-fill\" as const]: dotFill,\n    color: resolvedColor,\n    ...(ob !== undefined && { [\"--dmx-opacity-base\" as const]: ob }),\n    ...(om !== undefined && { [\"--dmx-opacity-mid\" as const]: om }),\n    ...(op !== undefined && { [\"--dmx-opacity-peak\" as const]: op }),\n    ...(useWrapper\n      ? {\n        transform: `scale(${scale})`,\n        transformOrigin: \"center center\" as const\n      }\n      : { minWidth: minSize, minHeight: minSize })\n  } as unknown as CSSProperties;\n\n  const dots = Array.from({ length: MATRIX_SIZE * MATRIX_SIZE }).map((_, index) => {\n    const { row, col } = indexToCoord(index);\n    const isActive = patternIndexes.has(index);\n    const distance = distanceFromCenter(index);\n    const angle = polarAngle(index);\n    const radiusNormalizedValue = normalizedRadius(index);\n    const manhattan = manhattanDistance(index);\n    const deltaX = (col - center) * unit;\n    const deltaY = (row - center) * unit;\n\n    const animationState = animationResolver\n      ? animationResolver({\n        index,\n        row,\n        col,\n        distanceFromCenter: distance,\n        angleFromCenter: angle,\n        radiusNormalized: radiusNormalizedValue,\n        manhattanDistance: manhattan,\n        phase,\n        isActive,\n        reducedMotion\n      })\n      : {};\n\n    const resolvedAnimationStyle = animationState.style ? { ...animationState.style } : undefined;\n    let isBloomDot = false;\n    let stylePatch: CSSProperties | undefined = resolvedAnimationStyle;\n\n    if (isActive) {\n      const rawOpacity = stylePatch?.opacity;\n      if (stylePatch != null && typeof rawOpacity === \"number\") {\n        const remappedOpacity = remapOpacityToTriplet(rawOpacity, ob, om, op);\n        stylePatch = { ...stylePatch, opacity: remappedOpacity };\n        const parts = dmxDotBloomParts(true, rawOpacity, bloom, halo, ob, om, op);\n        (stylePatch as CSSProperties & { \"--dmx-bloom-level\"?: number })[\"--dmx-bloom-level\"] = parts.level;\n        isBloomDot = parts.bloomDot;\n      } else {\n        const parts = dmxDotBloomParts(true, 0, bloom, halo, ob, om, op);\n        if (parts.level > 0) {\n          stylePatch = {\n            ...(stylePatch ?? {}),\n            [\"--dmx-bloom-level\" as const]: parts.level\n          } as CSSProperties & { \"--dmx-bloom-level\"?: number };\n        }\n        isBloomDot = parts.bloomDot;\n      }\n    }\n\n    const dotStyle = {\n      width: dotSize,\n      height: dotSize,\n      \"--dmx-distance\": distance,\n      \"--dmx-row\": row,\n      \"--dmx-col\": col,\n      \"--dmx-x\": `${deltaX}px`,\n      \"--dmx-y\": `${deltaY}px`,\n      \"--dmx-angle\": angle,\n      \"--dmx-radius\": radiusNormalizedValue,\n      \"--dmx-manhattan\": manhattan,\n      ...stylePatch,\n      ...(!isActive\n        ? {\n          opacity: 0,\n          visibility: \"hidden\" as const,\n          pointerEvents: \"none\" as const,\n          animation: \"none\"\n        }\n        : {})\n    } as CSSProperties;\n\n    return (\n      <span\n        key={index}\n        aria-hidden=\"true\"\n        className={cx(\n          \"dmx-dot\",\n          !isActive && \"dmx-inactive\",\n          isBloomDot && \"dmx-bloom-dot\",\n          dotClassName,\n          animationState.className\n        )}\n        style={dotStyle}\n      />\n    );\n  });\n\n  const matrix = (\n    <div\n      className={cx(\n        \"dmx-root\",\n        `dmx-dot-shape-${dotShape}`,\n        muted && \"dmx-muted\",\n        dmxBloomRootActive(bloom, halo) && \"dmx-bloom\",\n        dmxBloomHaloSpreadClass(halo),\n        !useWrapper && className\n      )}\n      style={dmxVarStyle}\n    >\n      <div className=\"dmx-grid\" style={{ gap }}>{dots}</div>\n    </div>\n  );\n\n  if (useWrapper) {\n    return (\n      <div\n        role=\"status\"\n        aria-live=\"polite\"\n        aria-label={ariaLabel}\n        className={className}\n        style={{\n          display: \"inline-flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          width: outerDim,\n          height: outerDim,\n          minWidth: minSize,\n          minHeight: minSize,\n          overflow: \"hidden\"\n        }}\n        onMouseEnter={onMouseEnter}\n        onMouseLeave={onMouseLeave}\n      >\n        {matrix}\n      </div>\n    );\n  }\n\n  return (\n    <div\n      role=\"status\"\n      aria-live=\"polite\"\n      aria-label={ariaLabel}\n      className={cx(\n        \"dmx-root\",\n        `dmx-dot-shape-${dotShape}`,\n        muted && \"dmx-muted\",\n        dmxBloomRootActive(bloom, halo) && \"dmx-bloom\",\n        dmxBloomHaloSpreadClass(halo),\n        className\n      )}\n      style={dmxVarStyle}\n      onMouseEnter={onMouseEnter}\n      onMouseLeave={onMouseLeave}\n    >\n      <div className=\"dmx-grid\" style={{ gap }}>{dots}</div>\n    </div>\n  );\n}\n\nexport const MATRIX_SIZE_3 = 3;\n\nconst CENTER_3 = Math.floor(MATRIX_SIZE_3 / 2);\nconst RANGE_3 = Array.from({ length: MATRIX_SIZE_3 }, (_, index) => index);\nconst MAX_RADIUS_3 = Math.hypot(CENTER_3, CENTER_3);\n\nexport const FULL_INDEXES_3 = RANGE_3.flatMap((row) =>\n  RANGE_3.map((col) => rowMajorIndex3(row, col))\n);\n\nexport const OUTLINE_INDEXES_3 = FULL_INDEXES_3.filter((index) => {\n  const { row, col } = indexToCoord3(index);\n  return row === 0 || row === MATRIX_SIZE_3 - 1 || col === 0 || col === MATRIX_SIZE_3 - 1;\n});\n\nexport const DIAMOND_INDEXES_3 = FULL_INDEXES_3.filter((index) => {\n  const { row, col } = indexToCoord3(index);\n  return Math.abs(row - CENTER_3) + Math.abs(col - CENTER_3) <= 1;\n});\n\nexport const CROSS_INDEXES_3 = FULL_INDEXES_3.filter((index) => {\n  const { row, col } = indexToCoord3(index);\n  return row === CENTER_3 || col === CENTER_3;\n});\n\nexport const RINGS_INDEXES_3 = FULL_INDEXES_3.filter((index) => {\n  const { row, col } = indexToCoord3(index);\n  return Math.round(Math.hypot(row - CENTER_3, col - CENTER_3)) === 1;\n});\n\nexport const ROSE_INDEXES_3 = FULL_INDEXES_3.filter((index) => {\n  const { row, col } = indexToCoord3(index);\n  const dx = col - CENTER_3;\n  const dy = row - CENTER_3;\n  const angle = Math.atan2(dy, dx);\n  const radius = Math.hypot(dx, dy);\n  const rose = Math.abs(Math.sin(3 * angle));\n  return rose > 0.55 && radius >= 0.75;\n});\n\nconst PATTERN_INDEXES_3: Record<MatrixPattern, number[]> = {\n  diamond: DIAMOND_INDEXES_3,\n  full: FULL_INDEXES_3,\n  outline: OUTLINE_INDEXES_3,\n  rose: ROSE_INDEXES_3,\n  cross: CROSS_INDEXES_3,\n  rings: RINGS_INDEXES_3\n};\n\nexport function getPattern3Indexes(pattern: MatrixPattern = \"full\"): number[] {\n  return PATTERN_INDEXES_3[pattern];\n}\n\nexport function rowMajorIndex3(row: number, col: number): number {\n  return row * MATRIX_SIZE_3 + col;\n}\n\nexport function indexToCoord3(index: number): { row: number; col: number } {\n  return {\n    row: Math.floor(index / MATRIX_SIZE_3),\n    col: index % MATRIX_SIZE_3\n  };\n}\n\nexport function distanceFromCenter3(index: number): number {\n  const { row, col } = indexToCoord3(index);\n  return Math.hypot(row - CENTER_3, col - CENTER_3);\n}\n\nexport function manhattanDistance3(index: number): number {\n  const { row, col } = indexToCoord3(index);\n  return Math.abs(row - CENTER_3) + Math.abs(col - CENTER_3);\n}\n\nconst MAX_DIAGONAL_3 = (MATRIX_SIZE_3 - 1) * 2;\n\nexport type DiagonalWave3Direction = \"tr-bl\" | \"tl-br\" | \"br-tl\" | \"bl-tr\";\n\nexport function trBlPath3NormFromIndex(index: number): number {\n  const { row, col } = indexToCoord3(index);\n  return (row + (MATRIX_SIZE_3 - 1 - col)) / MAX_DIAGONAL_3;\n}\n\nexport function tlBrPath3NormFromIndex(index: number): number {\n  const { row, col } = indexToCoord3(index);\n  return (row + col) / MAX_DIAGONAL_3;\n}\n\nexport function brTlPath3NormFromIndex(index: number): number {\n  const { row, col } = indexToCoord3(index);\n  return (MAX_DIAGONAL_3 - row - col) / MAX_DIAGONAL_3;\n}\n\nexport function blTrPath3NormFromIndex(index: number): number {\n  const { row, col } = indexToCoord3(index);\n  return (MAX_DIAGONAL_3 - row - (MATRIX_SIZE_3 - 1 - col)) / MAX_DIAGONAL_3;\n}\n\nconst DIAGONAL_PATH_3: Record<DiagonalWave3Direction, (index: number) => number> = {\n  \"tr-bl\": trBlPath3NormFromIndex,\n  \"tl-br\": tlBrPath3NormFromIndex,\n  \"br-tl\": brTlPath3NormFromIndex,\n  \"bl-tr\": blTrPath3NormFromIndex\n};\n\nexport function diagonalWave3PathNormFromIndex(\n  index: number,\n  direction: DiagonalWave3Direction\n): number {\n  return DIAGONAL_PATH_3[direction](index);\n}\n\nexport function diagonalWave3BandIndex(\n  row: number,\n  col: number,\n  direction: DiagonalWave3Direction\n): number {\n  if (direction === \"tr-bl\" || direction === \"bl-tr\") {\n    return row + (MATRIX_SIZE_3 - 1 - col);\n  }\n  return row + col;\n}\n\nfunction buildSpiralInwardOrderToIndexMap3(): number[] {\n  const N = MATRIX_SIZE_3;\n  const CELLS = N * N;\n  const order = new Array<number>(CELLS);\n  let top = 0;\n  let bottom = N - 1;\n  let left = 0;\n  let right = N - 1;\n  let t = 0;\n\n  while (top <= bottom && left <= right) {\n    for (let col = left; col <= right; col += 1) {\n      order[rowMajorIndex3(top, col)] = t;\n      t += 1;\n    }\n\n    for (let row = top + 1; row <= bottom; row += 1) {\n      order[rowMajorIndex3(row, right)] = t;\n      t += 1;\n    }\n\n    if (top < bottom) {\n      for (let col = right - 1; col >= left; col -= 1) {\n        order[rowMajorIndex3(bottom, col)] = t;\n        t += 1;\n      }\n    }\n\n    if (left < right) {\n      for (let row = bottom - 1; row > top; row -= 1) {\n        order[rowMajorIndex3(row, left)] = t;\n        t += 1;\n      }\n    }\n\n    top += 1;\n    bottom -= 1;\n    left += 1;\n    right -= 1;\n  }\n\n  return order;\n}\n\nconst SPIRAL_INWARD_ORDER_3: readonly number[] = buildSpiralInwardOrderToIndexMap3();\n\nexport function spiralInward3NormFromIndex(index: number): number {\n  return SPIRAL_INWARD_ORDER_3[index]! / (MATRIX_SIZE_3 * MATRIX_SIZE_3 - 1);\n}\n\nexport function spiralInward3OrderValue(index: number): number {\n  return SPIRAL_INWARD_ORDER_3[index]!;\n}\n\nfunction buildOuterRingClockwiseOrder3(): number[] {\n  const order = new Array<number>(MATRIX_SIZE_3 * MATRIX_SIZE_3).fill(-1);\n  const path: ReadonlyArray<readonly [number, number]> = [\n    [0, 0],\n    [0, 1],\n    [0, 2],\n    [1, 2],\n    [2, 2],\n    [2, 1],\n    [2, 0],\n    [1, 0]\n  ];\n\n  path.forEach(([row, col], step) => {\n    order[rowMajorIndex3(row, col)] = step;\n  });\n\n  return order;\n}\n\nconst OUTER_RING_CLOCKWISE_ORDER_3: readonly number[] = buildOuterRingClockwiseOrder3();\n\nexport function outerRingClockwise3OrderValue(index: number): number {\n  return OUTER_RING_CLOCKWISE_ORDER_3[index]!;\n}\n\nexport function outerRingClockwise3NormFromIndex(index: number): number {\n  const order = OUTER_RING_CLOCKWISE_ORDER_3[index]!;\n  if (order < 0) {\n    return 0;\n  }\n  return order / 7;\n}\n\nexport function isCenterCell3(row: number, col: number): boolean {\n  const center = Math.floor(MATRIX_SIZE_3 / 2);\n  return row === center && col === center;\n}\n\nexport function rowWave3NormFromRow(row: number): number {\n  return row / (MATRIX_SIZE_3 - 1);\n}\n\nexport function colWave3NormFromCol(col: number): number {\n  return col / (MATRIX_SIZE_3 - 1);\n}\n\nexport function colWave3NormFromColReverse(col: number): number {\n  return (MATRIX_SIZE_3 - 1 - col) / (MATRIX_SIZE_3 - 1);\n}\n\nexport function wave3PathOpacityFromNorm(\n  norm: number,\n  base = 0.06,\n  mid = 0.38,\n  peak = 0.88\n): number {\n  const t = Math.min(1, Math.max(0, norm));\n  if (t <= 0.5) {\n    return base + (t / 0.5) * (mid - base);\n  }\n  return mid + ((t - 0.5) / 0.5) * (peak - mid);\n}\n\nfunction getMatrix3Layout(\n  size: number,\n  dotSize: number,\n  cellPadding?: number\n): { gap: number; matrixSpan: number } {\n  const n = MATRIX_SIZE_3;\n  if (cellPadding != null) {\n    const g = Math.max(0, cellPadding);\n    const matrixSpan = dotSize * n + g * (n - 1);\n    return { gap: g, matrixSpan };\n  }\n  const g = Math.max(0, Math.floor((size - dotSize * n) / (n - 1)));\n  return { gap: g, matrixSpan: size };\n}\n\ninterface DotMatrix3BaseProps extends DotMatrixCommonProps {\n  phase: DotMatrixPhase;\n  reducedMotion?: boolean;\n  onMouseEnter?: () => void;\n  onMouseLeave?: () => void;\n  animationResolver?: DotAnimationResolver;\n}\n\nexport function DotMatrix3Base({\n  size = 24,\n  dotSize = 3,\n  color = \"currentColor\",\n  colorPreset,\n  speed = 1,\n  ariaLabel = \"Loading\",\n  className,\n  pattern = \"full\",\n  dotShape = \"circle\",\n  muted = false,\n  bloom = false,\n  halo = 0,\n  dotClassName,\n  phase,\n  reducedMotion = false,\n  onMouseEnter,\n  onMouseLeave,\n  animationResolver,\n  opacityBase = 0.06,\n  opacityMid,\n  opacityPeak,\n  cellPadding = 1,\n  boxSize,\n  minSize\n}: DotMatrix3BaseProps) {\n  const patternIndexes = new Set(getPattern3Indexes(pattern));\n  const safeSpeed = speed > 0 ? speed : 1;\n  const speedScale = 1 / safeSpeed;\n  const { gap, matrixSpan } = getMatrix3Layout(size, dotSize, cellPadding);\n  const { outerDim, useWrapper } = resolveDmxBoxOuterDim({ boxSize, minSize });\n  const scale = useWrapper && matrixSpan > 0 ? outerDim / matrixSpan : 1;\n  const center = CENTER_3;\n  const ob = clamp01Dmx(opacityBase);\n  const om = clamp01Dmx(opacityMid);\n  const op = clamp01Dmx(opacityPeak);\n  const unit = dotSize + gap;\n  const { resolvedColor, dotFill } = resolveDmxColorTokens(color, colorPreset);\n\n  const dmxVarStyle = {\n    width: matrixSpan,\n    height: matrixSpan,\n    \"--dmx-speed\": speedScale,\n    [\"--dmx-dot-size\" as const]: `${dotSize}px`,\n    [\"--dmx-halo-level\" as const]: halo,\n    [\"--dmx-dot-fill\" as const]: dotFill,\n    color: resolvedColor,\n    ...(ob !== undefined && { [\"--dmx-opacity-base\" as const]: ob }),\n    ...(om !== undefined && { [\"--dmx-opacity-mid\" as const]: om }),\n    ...(op !== undefined && { [\"--dmx-opacity-peak\" as const]: op }),\n    ...(useWrapper\n      ? {\n        transform: `scale(${scale})`,\n        transformOrigin: \"center center\" as const\n      }\n      : { minWidth: minSize, minHeight: minSize })\n  } as unknown as CSSProperties;\n\n  const gridStyle = {\n    gap,\n    gridTemplateColumns: `repeat(${MATRIX_SIZE_3}, minmax(0, 1fr))`,\n    gridTemplateRows: `repeat(${MATRIX_SIZE_3}, minmax(0, 1fr))`\n  };\n\n  const dots = Array.from({ length: MATRIX_SIZE_3 * MATRIX_SIZE_3 }).map((_, index) => {\n    const { row, col } = indexToCoord3(index);\n    const isActive = patternIndexes.has(index);\n    const distance = distanceFromCenter3(index);\n    const angle = Math.atan2(row - center, col - center);\n    const radiusNormalizedValue = Math.hypot(row - center, col - center) / MAX_RADIUS_3;\n    const manhattan = manhattanDistance3(index);\n    const deltaX = (col - center) * unit;\n    const deltaY = (row - center) * unit;\n\n    const animationState = animationResolver\n      ? animationResolver({\n        index,\n        row,\n        col,\n        distanceFromCenter: distance,\n        angleFromCenter: angle,\n        radiusNormalized: radiusNormalizedValue,\n        manhattanDistance: manhattan,\n        phase,\n        isActive,\n        reducedMotion\n      })\n      : {};\n\n    const resolvedAnimationStyle = animationState.style ? { ...animationState.style } : undefined;\n    let isBloomDot = false;\n    let stylePatch: CSSProperties | undefined = resolvedAnimationStyle;\n\n    if (isActive) {\n      const rawOpacity = stylePatch?.opacity;\n      if (stylePatch != null && typeof rawOpacity === \"number\") {\n        const remappedOpacity = remapOpacityToTriplet(rawOpacity, ob, om, op);\n        stylePatch = { ...stylePatch, opacity: remappedOpacity };\n        const parts = dmxDotBloomParts(true, rawOpacity, bloom, halo, ob, om, op);\n        (stylePatch as CSSProperties & { \"--dmx-bloom-level\"?: number })[\"--dmx-bloom-level\"] = parts.level;\n        isBloomDot = parts.bloomDot;\n      } else {\n        const parts = dmxDotBloomParts(true, 0, bloom, halo, ob, om, op);\n        if (parts.level > 0) {\n          stylePatch = {\n            ...(stylePatch ?? {}),\n            [\"--dmx-bloom-level\" as const]: parts.level\n          } as CSSProperties & { \"--dmx-bloom-level\"?: number };\n        }\n        isBloomDot = parts.bloomDot;\n      }\n    }\n\n    const dotStyle = {\n      width: dotSize,\n      height: dotSize,\n      \"--dmx-distance\": distance,\n      \"--dmx-row\": row,\n      \"--dmx-col\": col,\n      \"--dmx-x\": `${deltaX}px`,\n      \"--dmx-y\": `${deltaY}px`,\n      \"--dmx-angle\": angle,\n      \"--dmx-radius\": radiusNormalizedValue,\n      \"--dmx-manhattan\": manhattan,\n      ...stylePatch,\n      ...(!isActive\n        ? {\n          opacity: 0,\n          visibility: \"hidden\" as const,\n          pointerEvents: \"none\" as const,\n          animation: \"none\"\n        }\n        : {})\n    } as CSSProperties;\n\n    return (\n      <span\n        key={index}\n        aria-hidden=\"true\"\n        className={cx(\n          \"dmx-dot\",\n          !isActive && \"dmx-inactive\",\n          isBloomDot && \"dmx-bloom-dot\",\n          dotClassName,\n          animationState.className\n        )}\n        style={dotStyle}\n      />\n    );\n  });\n\n  const matrix = (\n    <div\n      className={cx(\n        \"dmx-root\",\n        \"dmx-matrix-3\",\n        `dmx-dot-shape-${dotShape}`,\n        muted && \"dmx-muted\",\n        dmxBloomRootActive(bloom, halo) && \"dmx-bloom\",\n        dmxBloomHaloSpreadClass(halo),\n        !useWrapper && className\n      )}\n      style={dmxVarStyle}\n    >\n      <div className=\"dmx-grid\" style={gridStyle}>{dots}</div>\n    </div>\n  );\n\n  if (useWrapper) {\n    return (\n      <div\n        role=\"status\"\n        aria-live=\"polite\"\n        aria-label={ariaLabel}\n        className={className}\n        style={{\n          display: \"inline-flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          width: outerDim,\n          height: outerDim,\n          minWidth: minSize,\n          minHeight: minSize,\n          overflow: \"hidden\"\n        }}\n        onMouseEnter={onMouseEnter}\n        onMouseLeave={onMouseLeave}\n      >\n        {matrix}\n      </div>\n    );\n  }\n\n  return (\n    <div\n      role=\"status\"\n      aria-live=\"polite\"\n      aria-label={ariaLabel}\n      className={cx(\n        \"dmx-root\",\n        \"dmx-matrix-3\",\n        `dmx-dot-shape-${dotShape}`,\n        muted && \"dmx-muted\",\n        dmxBloomRootActive(bloom, halo) && \"dmx-bloom\",\n        dmxBloomHaloSpreadClass(halo),\n        className\n      )}\n      style={dmxVarStyle}\n      onMouseEnter={onMouseEnter}\n      onMouseLeave={onMouseLeave}\n    >\n      <div className=\"dmx-grid\" style={gridStyle}>{dots}</div>\n    </div>\n  );\n}\n\ntype NormFn = (ctx: Pick<DotAnimationContext, \"row\" | \"col\" | \"index\">) => number;\n\nexport function createPathWaveResolver(getPathNorm: NormFn): DotAnimationResolver {\n  return ({ isActive, row, col, index, reducedMotion, phase }) => {\n    if (!isActive) {\n      return { className: \"dmx-inactive\" };\n    }\n\n    const path = getPathNorm({ row, col, index });\n    const style = { \"--dmx-path\": path } as CSSProperties;\n\n    if (reducedMotion || phase === \"idle\") {\n      return {\n        style: {\n          ...style,\n          opacity: 0.12 + path * 0.72\n        }\n      };\n    }\n\n    return { className: \"dmx-path\", style };\n  };\n}\n\ntype PathWaveComponentProps = DotMatrixCommonProps;\n\nexport function createPathWaveComponent(displayName: string, getPathNorm: NormFn) {\n  const resolve = createPathWaveResolver(getPathNorm);\n\n  function PathWaveComponent({\n    pattern = \"full\",\n    animated = true,\n    hoverAnimated = false,\n    speed = 1,\n    ...rest\n  }: PathWaveComponentProps) {\n    const reducedMotion = usePrefersReducedMotion();\n    const { phase: matrixPhase, onMouseEnter, onMouseLeave } = useDotMatrixPhases({\n      animated: Boolean(animated && !reducedMotion),\n      hoverAnimated: Boolean(hoverAnimated && !reducedMotion),\n      speed\n    });\n    return (\n      <DotMatrixBase\n        {...rest}\n        speed={speed}\n        pattern={pattern}\n        animated={animated}\n        phase={matrixPhase}\n        reducedMotion={reducedMotion}\n        onMouseEnter={onMouseEnter}\n        onMouseLeave={onMouseLeave}\n        animationResolver={resolve}\n      />\n    );\n  }\n\n  PathWaveComponent.displayName = displayName;\n  return PathWaveComponent;\n}\n\nexport function createDiagonalWave3Resolver(direction: DiagonalWave3Direction): DotAnimationResolver {\n  return ({ isActive, index, reducedMotion, phase }) => {\n    if (!isActive) {\n      return { className: \"dmx-inactive\" };\n    }\n\n    const path = diagonalWave3PathNormFromIndex(index, direction);\n    const style = { \"--dmx-path\": path } as CSSProperties;\n\n    if (reducedMotion || phase === \"idle\") {\n      return {\n        style: {\n          ...style,\n          opacity: path * 0.88\n        }\n      };\n    }\n\n    return { className: \"dmx-path-3\", style };\n  };\n}\n\ntype DiagonalWave3ComponentProps = DotMatrixCommonProps;\n\nexport function createDiagonalWave3Component(\n  displayName: string,\n  direction: DiagonalWave3Direction\n) {\n  const resolve = createDiagonalWave3Resolver(direction);\n\n  function DiagonalWave3Component({\n    pattern = \"full\",\n    animated = true,\n    hoverAnimated = false,\n    speed = 1.15,\n    ...rest\n  }: DiagonalWave3ComponentProps) {\n    const reducedMotion = usePrefersReducedMotion();\n    const { phase: matrixPhase, onMouseEnter, onMouseLeave } = useDotMatrixPhases({\n      animated: Boolean(animated && !reducedMotion),\n      hoverAnimated: Boolean(hoverAnimated && !reducedMotion),\n      speed\n    });\n\n    return (\n      <DotMatrix3Base\n        {...rest}\n        speed={speed}\n        pattern={pattern}\n        animated={animated}\n        phase={matrixPhase}\n        onMouseEnter={onMouseEnter}\n        onMouseLeave={onMouseLeave}\n        reducedMotion={reducedMotion}\n        animationResolver={resolve}\n      />\n    );\n  }\n\n  DiagonalWave3Component.displayName = displayName;\n  return DiagonalWave3Component;\n}\n\ntype Dotm3x3ComponentProps = DotMatrixCommonProps;\n\nexport function createDotm3x3Component(\n  displayName: string,\n  animationResolver: DotAnimationResolver,\n  defaultSpeed = 1.15\n) {\n  function Dotm3x3Component({\n    pattern = \"full\",\n    dotShape = \"circle\",\n    animated = true,\n    hoverAnimated = false,\n    speed = defaultSpeed,\n    ...rest\n  }: Dotm3x3ComponentProps) {\n    const reducedMotion = usePrefersReducedMotion();\n    const { phase: matrixPhase, onMouseEnter, onMouseLeave } = useDotMatrixPhases({\n      animated: Boolean(animated && !reducedMotion),\n      hoverAnimated: Boolean(hoverAnimated && !reducedMotion),\n      speed\n    });\n\n    return (\n      <DotMatrix3Base\n        {...rest}\n        speed={speed}\n        pattern={pattern}\n        dotShape={dotShape}\n        animated={animated}\n        phase={matrixPhase}\n        onMouseEnter={onMouseEnter}\n        onMouseLeave={onMouseLeave}\n        reducedMotion={reducedMotion}\n        animationResolver={animationResolver}\n      />\n    );\n  }\n\n  Dotm3x3Component.displayName = displayName;\n  return Dotm3x3Component;\n}\n\nconst GLYPH_SPIN_BASE_OPACITY = 0.09;\nconst GLYPH_SPIN_PEAK_OPACITY = 0.88;\nconst GLYPH_SPIN_STEP_MS = 180;\nconst GLYPH_SPIN_ROTATION_STEPS = 4;\nconst GLYPH_SPIN_CYCLE_MS_BASE = GLYPH_SPIN_STEP_MS * GLYPH_SPIN_ROTATION_STEPS;\n\nfunction glyphSpinSmoothstep(value: number): number {\n  const t = Math.min(1, Math.max(0, value));\n  return t * t * (3 - 2 * t);\n}\n\nexport function rotate3x3(pattern: readonly number[], turns: number): readonly number[] {\n  const t = ((turns % GLYPH_SPIN_ROTATION_STEPS) + GLYPH_SPIN_ROTATION_STEPS) % GLYPH_SPIN_ROTATION_STEPS;\n  if (t === 0) {\n    return pattern;\n  }\n\n  let out = [...pattern];\n  for (let k = 0; k < t; k += 1) {\n    const next = new Array<number>(9).fill(0);\n    for (let i = 0; i < 9; i += 1) {\n      const r = Math.floor(i / 3);\n      const c = i % 3;\n      const nr = c;\n      const nc = 2 - r;\n      next[nr * 3 + nc] = out[i]!;\n    }\n    out = next;\n  }\n  return out;\n}\n\nfunction glyphSpinOpacity(current: readonly number[], next: readonly number[], index: number, t: number): number {\n  const weight = (current[index] ?? 0) * (1 - t) + (next[index] ?? 0) * t;\n  return GLYPH_SPIN_BASE_OPACITY + weight * (GLYPH_SPIN_PEAK_OPACITY - GLYPH_SPIN_BASE_OPACITY);\n}\n\ntype GlyphSpin3ComponentProps = DotMatrixCommonProps;\n\nexport function createGlyphSpin3Component(\n  displayName: string,\n  glyph: readonly number[],\n  defaultSpeed = 1\n) {\n  function GlyphSpin3Component({\n    speed = defaultSpeed,\n    pattern = \"full\",\n    dotShape = \"circle\",\n    animated = true,\n    hoverAnimated = false,\n    ...rest\n  }: GlyphSpin3ComponentProps) {\n    const reducedMotion = usePrefersReducedMotion();\n    const { phase: matrixPhase, onMouseEnter, onMouseLeave } = useDotMatrixPhases({\n      animated: Boolean(animated && !reducedMotion),\n      hoverAnimated: Boolean(hoverAnimated && !reducedMotion),\n      speed\n    });\n    const cyclePhase = useCyclePhase({\n      active: !reducedMotion && matrixPhase !== \"idle\",\n      cycleMsBase: GLYPH_SPIN_CYCLE_MS_BASE,\n      speed\n    });\n\n    const animationResolver = useMemo<DotAnimationResolver>(() => {\n      const scaledPhase = cyclePhase * GLYPH_SPIN_ROTATION_STEPS;\n      const turns = Math.floor(scaledPhase) % GLYPH_SPIN_ROTATION_STEPS;\n      const segmentT = glyphSpinSmoothstep(scaledPhase - Math.floor(scaledPhase));\n      const current = rotate3x3(glyph, turns);\n      const next = rotate3x3(glyph, turns + 1);\n\n      return ({ isActive, index, reducedMotion: rm, phase }) => {\n        if (!isActive) {\n          return { className: \"dmx-inactive\" };\n        }\n\n        if (rm || phase === \"idle\") {\n          return { style: { opacity: glyphSpinOpacity(glyph, glyph, index, 0) } };\n        }\n\n        return { style: { opacity: glyphSpinOpacity(current, next, index, segmentT) } };\n      };\n    }, [cyclePhase]);\n\n    return (\n      <DotMatrix3Base\n        {...rest}\n        speed={speed}\n        pattern={pattern}\n        dotShape={dotShape}\n        animated={animated}\n        phase={matrixPhase}\n        onMouseEnter={onMouseEnter}\n        onMouseLeave={onMouseLeave}\n        reducedMotion={reducedMotion}\n        animationResolver={animationResolver}\n      />\n    );\n  }\n\n  GlyphSpin3Component.displayName = displayName;\n  return GlyphSpin3Component;\n}\n\n"
    },
    {
      "path": "components/ui/dotmatrix-hooks.ts",
      "type": "registry:lib",
      "content": "\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport type { DotMatrixPhase } from \"@/components/ui/dotmatrix-core\";\n\nexport function usePrefersReducedMotion(): boolean {\n  const [prefersReducedMotion, setPrefersReducedMotion] = useState(false);\n\n  useEffect(() => {\n    const query = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n\n    const update = () => {\n      setPrefersReducedMotion(query.matches);\n    };\n\n    update();\n    query.addEventListener(\"change\", update);\n\n    return () => {\n      query.removeEventListener(\"change\", update);\n    };\n  }, []);\n\n  return prefersReducedMotion;\n}\n\nexport interface UseCyclePhaseOptions {\n  active: boolean;\n  cycleMsBase: number;\n  speed?: number;\n}\n\nexport function useCyclePhase({ active, cycleMsBase, speed = 1 }: UseCyclePhaseOptions): number {\n  const [phase, setPhase] = useState(0);\n\n  useEffect(() => {\n    if (!active) {\n      setPhase(0);\n      return;\n    }\n\n    const safeSpeed = speed > 0 ? speed : 1;\n    const raw = cycleMsBase / safeSpeed;\n    const cycleMs = raw > 0 && Number.isFinite(raw) ? raw : 1000;\n    const start = performance.now();\n    let rafId = 0;\n\n    const tick = (now: number) => {\n      const elapsed = ((now - start) % cycleMs + cycleMs) % cycleMs;\n      setPhase(elapsed / cycleMs);\n      rafId = requestAnimationFrame(tick);\n    };\n\n    rafId = requestAnimationFrame(tick);\n    return () => cancelAnimationFrame(rafId);\n  }, [active, cycleMsBase, speed]);\n\n  return phase;\n}\n\ninterface UseSteppedCycleOptions {\n  active: boolean;\n  cycleMsBase: number;\n  steps: number;\n  speed?: number;\n  idleStep?: number;\n}\n\ntype FrameListener = (now: number) => void;\n\nconst listeners = new Set<FrameListener>();\nlet rafId: number | null = null;\n\nfunction emit(now: number) {\n  listeners.forEach((listener) => {\n    listener(now);\n  });\n}\n\nfunction tick(now: number) {\n  emit(now);\n  if (listeners.size > 0) {\n    rafId = window.requestAnimationFrame(tick);\n  } else {\n    rafId = null;\n  }\n}\n\nfunction subscribeFrame(listener: FrameListener) {\n  listeners.add(listener);\n  if (rafId === null) {\n    rafId = window.requestAnimationFrame(tick);\n  }\n  return () => {\n    listeners.delete(listener);\n    if (listeners.size === 0 && rafId !== null) {\n      window.cancelAnimationFrame(rafId);\n      rafId = null;\n    }\n  };\n}\n\nexport function useSteppedCycle({\n  active,\n  cycleMsBase,\n  steps,\n  speed = 1,\n  idleStep = 0\n}: UseSteppedCycleOptions): number {\n  const safeSteps = Math.max(1, Math.floor(steps));\n  const safeSpeed = speed > 0 ? speed : 1;\n  const rawCycleMs = cycleMsBase / safeSpeed;\n  const rawStepMs = rawCycleMs / safeSteps;\n  const stepMs = rawStepMs > 0 && Number.isFinite(rawStepMs) ? rawStepMs : 1;\n  const cycleMs = stepMs * safeSteps;\n\n  const [step, setStep] = useState(() => (active ? 0 : idleStep));\n  const startMsRef = useRef<number>(0);\n  const activeRef = useRef(false);\n  const currentStepRef = useRef(idleStep);\n\n  useEffect(() => {\n    if (!active) {\n      activeRef.current = false;\n      currentStepRef.current = idleStep;\n      setStep(idleStep);\n      return;\n    }\n\n    const updateStep = (now: number) => {\n      if (!activeRef.current) {\n        startMsRef.current = now;\n        activeRef.current = true;\n      }\n\n      const elapsed = Math.max(0, now - startMsRef.current);\n      const nextStep = Math.floor((elapsed % cycleMs) / stepMs) % safeSteps;\n      if (nextStep !== currentStepRef.current) {\n        currentStepRef.current = nextStep;\n        setStep(nextStep);\n      }\n    };\n\n    updateStep(performance.now());\n    return subscribeFrame(updateStep);\n  }, [active, cycleMs, idleStep, safeSteps, stepMs]);\n\n  return active ? step : idleStep;\n}\n\ninterface UseDotMatrixPhasesOptions {\n  animated?: boolean;\n  hoverAnimated?: boolean;\n  speed?: number;\n}\n\ninterface DotMatrixPhasesResult {\n  phase: DotMatrixPhase;\n  onMouseEnter: () => void;\n  onMouseLeave: () => void;\n}\n\nexport function useDotMatrixPhases({\n  animated = false,\n  hoverAnimated = false,\n  speed = 1\n}: UseDotMatrixPhasesOptions): DotMatrixPhasesResult {\n  const safeSpeed = speed > 0 ? speed : 1;\n  const autoRun = Boolean(animated && !hoverAnimated);\n  const [hoverPhase, setHoverPhase] = useState<DotMatrixPhase>(\"idle\");\n  const timeouts = useRef<number[]>([]);\n  const hoverGen = useRef(0);\n\n  const clearTimers = useCallback(() => {\n    for (let i = 0; i < timeouts.current.length; i += 1) {\n      window.clearTimeout(timeouts.current[i]!);\n    }\n    timeouts.current = [];\n  }, []);\n\n  useEffect(() => {\n    hoverGen.current += 1;\n    clearTimers();\n    return clearTimers;\n  }, [autoRun, hoverAnimated, clearTimers]);\n\n  const onMouseEnter = useCallback(() => {\n    if (!hoverAnimated || autoRun) {\n      return;\n    }\n    clearTimers();\n    const gen = ++hoverGen.current;\n    setHoverPhase(\"collapse\");\n    const collapseMs = Math.max(1, Math.round(300 / safeSpeed));\n    const id = window.setTimeout(() => {\n      if (hoverGen.current !== gen) {\n        return;\n      }\n      setHoverPhase(\"hoverRipple\");\n    }, collapseMs);\n    timeouts.current.push(id);\n  }, [hoverAnimated, autoRun, safeSpeed, clearTimers]);\n\n  const onMouseLeave = useCallback(() => {\n    if (!hoverAnimated || autoRun) {\n      return;\n    }\n    hoverGen.current += 1;\n    clearTimers();\n    setHoverPhase(\"idle\");\n  }, [hoverAnimated, autoRun, clearTimers]);\n\n  const phase: DotMatrixPhase = autoRun ? \"loadingRipple\" : hoverAnimated ? hoverPhase : \"idle\";\n\n  return useMemo(\n    () => ({\n      phase,\n      onMouseEnter,\n      onMouseLeave\n    }),\n    [phase, onMouseEnter, onMouseLeave]\n  );\n}\n"
    },
    {
      "path": "components/dotmatrix-loader.css",
      "type": "registry:style",
      "content": ".dmx-root {\n  display: inline-flex;\n  align-items: center;\n  justify-content: center;\n  vertical-align: middle;\n  /* One base loop at speed=1; --dmx-speed from JS scales inversely with the speed prop */\n  --dmx-cycle: 1500ms;\n  /* Rest / mid / bright — override via opacityBase, opacityMid, opacityPeak on the component */\n  --dmx-opacity-base: 0.16;\n  --dmx-opacity-mid: 0.32;\n  --dmx-opacity-peak: 1;\n  --dmx-halo-level: 0;\n}\n\n.dmx-grid {\n  display: grid;\n  grid-template-columns: repeat(5, minmax(0, 1fr));\n  grid-template-rows: repeat(5, minmax(0, 1fr));\n}\n\n.dmx-dot {\n  border-radius: 999px;\n  clip-path: none;\n  display: block;\n  background: var(--dmx-dot-fill, currentColor);\n  /* Matches prior 0.24 with default base/mid */\n  opacity: calc(0.5 * (var(--dmx-opacity-base) + var(--dmx-opacity-mid)));\n  --dmx-bloom-level: 0;\n  transform-origin: center;\n  transform: none;\n  will-change: opacity;\n}\n\n.dmx-root.dmx-dot-shape-circle .dmx-dot {\n  border-radius: 999px;\n  clip-path: none;\n  -webkit-mask: none;\n  mask: none;\n}\n\n.dmx-root.dmx-dot-shape-square .dmx-dot {\n  border-radius: 0;\n  clip-path: none;\n  -webkit-mask: none;\n  mask: none;\n}\n\n.dmx-root.dmx-dot-shape-diamond .dmx-dot {\n  border-radius: 0;\n  clip-path: none;\n  -webkit-mask: none;\n  mask: none;\n  transform: rotate(45deg) scale(0.7071067812);\n}\n\n.dmx-root.dmx-dot-shape-hearts .dmx-dot {\n  position: relative;\n  border-radius: 0;\n  clip-path: none;\n  transform: none;\n  background: none;\n  -webkit-mask: none;\n  mask: none;\n}\n\n.dmx-root.dmx-dot-shape-hearts .dmx-dot::before {\n  content: \"\";\n  position: absolute;\n  inset: 0;\n  background: var(--dmx-dot-fill, currentColor);\n  -webkit-mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath fill='black' d='m8.593.827c-1.008.012-1.953.464-2.593,1.227-.641-.762-1.586-1.214-2.598-1.227C1.519.839-.007,2.378,0,4.257,0,8.362,4.201,10.875,5.488,11.547h0c.16.084.336.125.511.125s.352-.042.511-.125c1.287-.672,5.489-3.184,5.489-7.289.007-1.88-1.519-3.42-3.407-3.431Z'/%3E%3C/svg%3E\");\n  mask-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath fill='black' d='m8.593.827c-1.008.012-1.953.464-2.593,1.227-.641-.762-1.586-1.214-2.598-1.227C1.519.839-.007,2.378,0,4.257,0,8.362,4.201,10.875,5.488,11.547h0c.16.084.336.125.511.125s.352-.042.511-.125c1.287-.672,5.489-3.184,5.489-7.289.007-1.88-1.519-3.42-3.407-3.431Z'/%3E%3C/svg%3E\");\n  -webkit-mask-position: center;\n  mask-position: center;\n  -webkit-mask-size: 100% 100%;\n  mask-size: 100% 100%;\n  -webkit-mask-repeat: no-repeat;\n  mask-repeat: no-repeat;\n}\n\n.dmx-bloom .dmx-dot {\n  filter:\n    drop-shadow(\n      0 0\n      calc(\n        var(--dmx-dot-size, 3px) * 0.75 *\n          max(var(--dmx-bloom-level, 0), var(--dmx-halo-level, 0))\n      )\n      currentColor\n    )\n    drop-shadow(\n      0 0\n      calc(\n        var(--dmx-dot-size, 3px) * 1.35 *\n          max(var(--dmx-bloom-level, 0), var(--dmx-halo-level, 0))\n      )\n      currentColor\n    );\n  will-change: opacity, filter;\n}\n\n/* Halo: modestly wider falloff than selective bloom (same --dmx-bloom-level on each dot). */\n.dmx-root.dmx-bloom-halo.dmx-bloom .dmx-dot {\n  filter:\n    drop-shadow(\n      0 0\n      calc(\n        var(--dmx-dot-size, 3px) * 0.92 *\n          max(var(--dmx-bloom-level, 0), var(--dmx-halo-level, 0))\n      )\n      currentColor\n    )\n    drop-shadow(\n      0 0\n      calc(\n        var(--dmx-dot-size, 3px) * 1.62 *\n          max(var(--dmx-bloom-level, 0), var(--dmx-halo-level, 0))\n      )\n      currentColor\n    )\n    drop-shadow(\n      0 0\n      calc(\n        var(--dmx-dot-size, 3px) * 2.55 *\n          max(var(--dmx-bloom-level, 0), var(--dmx-halo-level, 0))\n      )\n      currentColor\n    );\n  will-change: opacity, filter;\n}\n\n/* Bloom strength comes from inline --dmx-bloom-level (see opacityToBloomLevel). */\n\n.dmx-muted .dmx-dot {\n  opacity: calc(0.44 * var(--dmx-opacity-mid));\n  --dmx-bloom-level: 0;\n}\n\n/* Inactive off-cells (Base also sets inline opacity/animation:none so keyframes cannot win). */\n.dmx-dot.dmx-inactive {\n  opacity: 0 !important;\n  --dmx-bloom-level: 0;\n  animation: none !important;\n  visibility: hidden;\n  pointer-events: none;\n  will-change: auto;\n  filter: none;\n}\n\n.dmx-ripple {\n  animation: dmx-ripple calc(var(--dmx-cycle) * var(--dmx-speed, 1)) cubic-bezier(0.42, 0, 0.58, 1)\n    infinite;\n  animation-delay: calc(var(--dmx-ripple-ring, 0) * 0.2333 * var(--dmx-cycle) * var(--dmx-speed, 1));\n  will-change: opacity;\n}\n\n.dmx-ripple-echo {\n  animation: dmx-ripple-echo calc(var(--dmx-cycle) * var(--dmx-speed, 1)) ease-in-out infinite;\n  animation-delay: calc(\n    (var(--dmx-ripple-ring, 0) * 0.14 + var(--dmx-ripple-parity, 0) * 0.03) *\n      var(--dmx-cycle) *\n      var(--dmx-speed, 1)\n  );\n  will-change: opacity;\n}\n\n.dmx-center-origin-ripple {\n  animation: dmx-center-origin-ripple calc(var(--dmx-cycle) * var(--dmx-speed, 1)) ease-in-out infinite;\n  animation-delay: calc(\n    var(--dmx-center-ripple-ring, 0) * 0.16 * var(--dmx-cycle) * var(--dmx-speed, 1)\n  );\n  will-change: opacity;\n}\n\n.dmx-collapse {\n  animation: dmx-collapse calc(var(--dmx-cycle) * 0.2 * var(--dmx-speed, 1)) ease-in forwards;\n  animation-delay: calc(\n    (4 - var(--dmx-manhattan, 0)) * 0.032 * var(--dmx-cycle) * var(--dmx-speed, 1)\n  );\n}\n\n.dmx-hover-ripple {\n  animation: dmx-hover-ripple calc(var(--dmx-cycle) * var(--dmx-speed, 1)) ease-in-out infinite;\n  animation-delay: calc(var(--dmx-distance, 0) * 0.127 * var(--dmx-cycle) * var(--dmx-speed, 1));\n}\n\n.dmx-path {\n  animation: dmx-ripple calc(var(--dmx-cycle) * var(--dmx-speed, 1)) cubic-bezier(0.42, 0, 0.58, 1)\n    infinite;\n  animation-delay: calc(var(--dmx-path, 0) * 0.2333 * var(--dmx-cycle) * var(--dmx-speed, 1));\n  will-change: opacity;\n}\n\n.dmx-root.dmx-matrix-3 {\n  --dmx-cycle: 1500ms;\n}\n\n.dmx-path-3 {\n  animation: dmx-ripple-3 calc(0.68 * var(--dmx-cycle) * var(--dmx-speed, 1)) cubic-bezier(0.42, 0, 0.58, 1)\n    infinite;\n  animation-delay: calc(var(--dmx-path, 0) * 0.19 * var(--dmx-cycle) * var(--dmx-speed, 1));\n  will-change: opacity;\n}\n\n.dmx-diagonal-alt-sweep {\n  animation: dmx-diagonal-alt-sweep calc(var(--dmx-cycle) * var(--dmx-speed, 1)) linear infinite;\n  animation-delay: calc(\n    (var(--dmx-path, 0) * 0.2 + var(--dmx-diagonal-parity, 0) * 0.5) *\n      var(--dmx-cycle) *\n      var(--dmx-speed, 1)\n  );\n  will-change: opacity;\n}\n\n.dmx-spiral-snake {\n  animation: dmx-spiral-snake calc(var(--dmx-cycle) * var(--dmx-speed, 1)) linear infinite;\n  animation-delay: calc(var(--dmx-spiral-order, 0) * 0.04 * var(--dmx-cycle) * var(--dmx-speed, 1));\n  will-change: opacity;\n}\n\n.dmx-spiral-snake-3 {\n  animation: dmx-spiral-snake calc(0.78 * var(--dmx-cycle) * var(--dmx-speed, 1)) linear infinite;\n  animation-delay: calc(var(--dmx-spiral-order, 0) * 0.038 * var(--dmx-cycle) * var(--dmx-speed, 1));\n  will-change: opacity;\n}\n\n.dmx-center-ripple-3 {\n  animation: dmx-center-origin-ripple calc(0.82 * var(--dmx-cycle) * var(--dmx-speed, 1)) ease-in-out infinite;\n  animation-delay: calc(\n    var(--dmx-center-ripple-ring, 0) * 0.11 * var(--dmx-cycle) * var(--dmx-speed, 1)\n  );\n  will-change: opacity;\n}\n\n.dmx-snake-path-3 {\n  animation: dmx-ripple-3 calc(1.04 * var(--dmx-cycle) * var(--dmx-speed, 1)) cubic-bezier(0.42, 0, 0.58, 1)\n    infinite;\n  animation-delay: calc(var(--dmx-snake-order, 0) * 0.085 * var(--dmx-cycle) * var(--dmx-speed, 1));\n  will-change: opacity;\n}\n\n.dmx-frame-chase-3 {\n  animation: dmx-ripple-3 calc(0.98 * var(--dmx-cycle) * var(--dmx-speed, 1)) cubic-bezier(0.42, 0, 0.58, 1)\n    infinite;\n  animation-delay: calc(var(--dmx-frame-order, 0) * 0.09 * var(--dmx-cycle) * var(--dmx-speed, 1));\n  will-change: opacity;\n}\n\n.dmx-core-pulse-3 {\n  animation: dmx-ripple-3 calc(0.46 * var(--dmx-cycle) * var(--dmx-speed, 1)) cubic-bezier(0.42, 0, 0.58, 1)\n    infinite;\n  will-change: opacity;\n}\n\n.dmx-distance-ripple-3 {\n  animation: dmx-ripple-3 calc(1.3 * var(--dmx-cycle) * var(--dmx-speed, 1)) ease-out infinite;\n  animation-delay: calc(var(--dmx-distance, 0) * 0.13 * var(--dmx-cycle) * var(--dmx-speed, 1));\n  will-change: opacity;\n}\n\n.dmx-ripple-echo-3 {\n  animation: dmx-ripple-echo calc(1.06 * var(--dmx-cycle) * var(--dmx-speed, 1)) ease-in-out infinite;\n  animation-delay: calc(\n    (var(--dmx-ripple-ring, 0) * 0.1 + var(--dmx-ripple-parity, 0) * 0.02) *\n      var(--dmx-cycle) *\n      var(--dmx-speed, 1)\n  );\n  will-change: opacity;\n}\n\n.dmx-diagonal-snake {\n  animation: dmx-diagonal-snake calc(var(--dmx-cycle) * var(--dmx-speed, 1)) linear infinite;\n  animation-delay: calc(\n    var(--dmx-diagonal-snake-order, 0) * 0.04 * var(--dmx-cycle) * var(--dmx-speed, 1)\n  );\n  will-change: opacity;\n}\n\n.dmx-outer-snake {\n  animation: dmx-ring-snake calc(var(--dmx-cycle) * var(--dmx-speed, 1)) linear infinite;\n  animation-delay: calc(var(--dmx-outer-order, 0) * 0.0625 * var(--dmx-cycle) * var(--dmx-speed, 1));\n  will-change: opacity;\n}\n\n.dmx-middle-snake {\n  animation: dmx-ring-snake calc(var(--dmx-cycle) * var(--dmx-speed, 1)) linear infinite;\n  animation-delay: calc(var(--dmx-middle-order, 0) * 0.125 * var(--dmx-cycle) * var(--dmx-speed, 1));\n  will-change: opacity;\n}\n\n@keyframes dmx-ripple {\n  0%,\n  100% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  50% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n}\n\n@keyframes dmx-ripple-3 {\n  0%,\n  100% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  3% {\n    opacity: calc(0.62 * var(--dmx-opacity-mid) + 0.38 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  6% {\n    opacity: calc(0.35 * var(--dmx-opacity-peak) + 0.65 * var(--dmx-opacity-mid));\n    --dmx-bloom-level: 0.35;\n  }\n\n  10% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  14% {\n    opacity: calc(0.35 * var(--dmx-opacity-peak) + 0.65 * var(--dmx-opacity-mid));\n    --dmx-bloom-level: 0.35;\n  }\n\n  17% {\n    opacity: calc(0.62 * var(--dmx-opacity-mid) + 0.38 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  20% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n}\n\n@keyframes dmx-ripple-echo {\n  0%,\n  100% {\n    opacity: calc(0.625 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  28% {\n    opacity: calc(0.98 * var(--dmx-opacity-peak));\n    --dmx-bloom-level: 0.9;\n  }\n\n  56% {\n    opacity: var(--dmx-opacity-mid);\n    --dmx-bloom-level: 0;\n  }\n\n  78% {\n    opacity: calc(0.68 * var(--dmx-opacity-peak) + 0.32 * var(--dmx-opacity-mid));\n    --dmx-bloom-level: 0;\n  }\n}\n\n@keyframes dmx-center-origin-ripple {\n  0%,\n  100% {\n    opacity: calc(0.625 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  34% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  60% {\n    opacity: calc(0.5 * (var(--dmx-opacity-base) + var(--dmx-opacity-mid)));\n    --dmx-bloom-level: 0;\n  }\n}\n\n@keyframes dmx-collapse {\n  0% {\n    opacity: calc(0.95 * var(--dmx-opacity-peak) + 0.05 * var(--dmx-opacity-mid));\n    --dmx-bloom-level: 0.75;\n  }\n\n  100% {\n    opacity: calc(0.375 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n}\n\n@keyframes dmx-hover-ripple {\n  0% {\n    opacity: calc(0.5 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  45% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  100% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n}\n\n@keyframes dmx-diagonal-alt-sweep {\n  0%,\n  100% {\n    opacity: calc(0.5 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  14% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  30% {\n    opacity: calc(0.75 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n}\n\n@keyframes dmx-spiral-snake {\n  0%,\n  100% {\n    opacity: calc(0.5 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  8% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  16% {\n    opacity: calc(0.5 * var(--dmx-opacity-peak) + 0.4 * var(--dmx-opacity-mid) + 0.1 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  24% {\n    opacity: calc(0.25 * var(--dmx-opacity-peak) + 0.45 * var(--dmx-opacity-mid) + 0.3 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  32% {\n    opacity: calc(0.5 * var(--dmx-opacity-mid) + 0.5 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  40% {\n    opacity: calc(0.75 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n}\n\n@keyframes dmx-diagonal-snake {\n  0%,\n  100% {\n    opacity: calc(0.5 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  8% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  16% {\n    opacity: calc(0.5 * var(--dmx-opacity-peak) + 0.4 * var(--dmx-opacity-mid) + 0.1 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  24% {\n    opacity: calc(0.25 * var(--dmx-opacity-peak) + 0.45 * var(--dmx-opacity-mid) + 0.3 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  32% {\n    opacity: calc(0.5 * var(--dmx-opacity-mid) + 0.5 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  40% {\n    opacity: calc(0.75 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n}\n\n@keyframes dmx-ring-snake {\n  0%,\n  100% {\n    opacity: calc(0.5 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  10% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  20% {\n    opacity: calc(0.45 * var(--dmx-opacity-peak) + 0.45 * var(--dmx-opacity-mid) + 0.1 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  30% {\n    opacity: calc(0.2 * var(--dmx-opacity-peak) + 0.4 * var(--dmx-opacity-mid) + 0.4 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  40% {\n    opacity: calc(0.875 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n}\n\n.dmx-square9-bit {\n  animation-duration: calc(5200ms * var(--dmx-speed, 1));\n  animation-timing-function: steps(52, end);\n  animation-iteration-count: infinite;\n  will-change: opacity;\n}\n\n.dmx-square9-d1 {\n  animation-name: dmx-square9-d1;\n}\n\n.dmx-square9-d2 {\n  animation-name: dmx-square9-d2;\n}\n\n.dmx-square9-d3 {\n  animation-name: dmx-square9-d3;\n}\n\n.dmx-square9-d4 {\n  animation-name: dmx-square9-d4;\n}\n\n.dmx-square9-d5 {\n  animation-name: dmx-square9-d5;\n}\n\n.dmx-square9-d6 {\n  animation-name: dmx-square9-d6;\n}\n\n@keyframes dmx-square9-d1 {\n  0%,\n  3.846154% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  3.846154%,\n  30.769231% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  30.769231%,\n  46.153846% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  46.153846%,\n  50% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  50%,\n  53.846154% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  53.846154%,\n  57.692308% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  57.692308%,\n  65.384615% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  65.384615%,\n  71.153846% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  71.153846%,\n  80.769231% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  80.769231%,\n  84.615385% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  84.615385%,\n  88.461538% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  88.461538%,\n  92.307692% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  92.307692%,\n  100% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n}\n\n@keyframes dmx-square9-d2 {\n  0%,\n  5.769231% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  5.769231%,\n  25% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  25%,\n  30.769231% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  30.769231%,\n  36.538462% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  36.538462%,\n  50% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  50%,\n  53.846154% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  53.846154%,\n  57.692308% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  57.692308%,\n  61.538462% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  61.538462%,\n  65.384615% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  65.384615%,\n  76.923077% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  76.923077%,\n  80.769231% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  80.769231%,\n  84.615385% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  84.615385%,\n  88.461538% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  88.461538%,\n  92.307692% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  92.307692%,\n  100% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n}\n\n@keyframes dmx-square9-d3 {\n  0%,\n  7.692308% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  7.692308%,\n  25% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  25%,\n  36.538462% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  36.538462%,\n  42.307692% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  42.307692%,\n  46.153846% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  46.153846%,\n  50% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  50%,\n  53.846154% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  53.846154%,\n  57.692308% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  57.692308%,\n  71.153846% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  71.153846%,\n  76.923077% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  76.923077%,\n  80.769231% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  80.769231%,\n  84.615385% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  84.615385%,\n  88.461538% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  88.461538%,\n  92.307692% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  92.307692%,\n  100% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n}\n\n@keyframes dmx-square9-d4 {\n  0%,\n  13.461538% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  13.461538%,\n  30.769231% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  30.769231%,\n  50% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  50%,\n  53.846154% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  53.846154%,\n  57.692308% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  57.692308%,\n  61.538462% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  61.538462%,\n  65.384615% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  65.384615%,\n  71.153846% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  71.153846%,\n  84.615385% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  84.615385%,\n  88.461538% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  88.461538%,\n  92.307692% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  92.307692%,\n  96.153846% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  96.153846%,\n  100% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n}\n\n@keyframes dmx-square9-d5 {\n  0%,\n  15.384615% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  15.384615%,\n  25% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  25%,\n  30.769231% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  30.769231%,\n  36.538462% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  36.538462%,\n  46.153846% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  46.153846%,\n  50% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  50%,\n  53.846154% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  53.846154%,\n  57.692308% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  57.692308%,\n  65.384615% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  65.384615%,\n  76.923077% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  76.923077%,\n  84.615385% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  84.615385%,\n  88.461538% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  88.461538%,\n  92.307692% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  92.307692%,\n  96.153846% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  96.153846%,\n  100% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n}\n\n@keyframes dmx-square9-d6 {\n  0%,\n  17.307692% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  17.307692%,\n  25% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  25%,\n  36.538462% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  36.538462%,\n  42.307692% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  42.307692%,\n  50% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  50%,\n  53.846154% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  53.846154%,\n  57.692308% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  57.692308%,\n  61.538462% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  61.538462%,\n  71.153846% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  71.153846%,\n  76.923077% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  76.923077%,\n  84.615385% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  84.615385%,\n  88.461538% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  88.461538%,\n  92.307692% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n\n  92.307692%,\n  96.153846% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  96.153846%,\n  100% {\n    opacity: var(--dmx-opacity-base);\n    --dmx-bloom-level: 0;\n  }\n}\n\n.dmx-square6-col-snake {\n  animation: dmx-square6-col-snake calc(var(--dmx-cycle) * var(--dmx-speed, 1)) steps(5, end) infinite;\n  animation-delay: calc(var(--dmx-col-pos, 0) * 0.2 * var(--dmx-cycle) * var(--dmx-speed, 1));\n  will-change: opacity;\n}\n\n@keyframes dmx-square6-col-snake {\n  0%,\n  20% {\n    opacity: calc(0.6 * var(--dmx-opacity-peak) + 0.25 * var(--dmx-opacity-mid) + 0.15 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  20%,\n  40% {\n    opacity: calc(0.3 * var(--dmx-opacity-peak) + 0.5 * var(--dmx-opacity-mid) + 0.2 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  40%,\n  60% {\n    opacity: calc(0.6 * var(--dmx-opacity-mid) + 0.4 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  60%,\n  80% {\n    opacity: calc(0.2 * var(--dmx-opacity-mid) + 0.8 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  80%,\n  100% {\n    opacity: calc(0.625 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n}\n\n.dmx-circular2-ring {\n  animation: dmx-circular2-ring calc(var(--dmx-cycle) * var(--dmx-speed, 1)) steps(12, end) infinite;\n  animation-delay: calc(var(--dmx-ring-order, 0) * 0.0833333333 * var(--dmx-cycle) * var(--dmx-speed, 1));\n  will-change: opacity;\n}\n\n@keyframes dmx-circular2-ring {\n  0%,\n  8.333333% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  8.333333%,\n  16.666667% {\n    opacity: calc(0.6 * var(--dmx-opacity-peak) + 0.4 * var(--dmx-opacity-mid));\n    --dmx-bloom-level: 0;\n  }\n\n  16.666667%,\n  25% {\n    opacity: calc(0.5 * var(--dmx-opacity-mid) + 0.5 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  25%,\n  33.333333% {\n    opacity: calc(0.3 * var(--dmx-opacity-mid) + 0.7 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  33.333333%,\n  41.666667% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  41.666667%,\n  50% {\n    opacity: calc(0.6 * var(--dmx-opacity-peak) + 0.4 * var(--dmx-opacity-mid));\n    --dmx-bloom-level: 0;\n  }\n\n  50%,\n  58.333333% {\n    opacity: calc(0.5 * var(--dmx-opacity-mid) + 0.5 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  58.333333%,\n  66.666667% {\n    opacity: calc(0.3 * var(--dmx-opacity-mid) + 0.7 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  66.666667%,\n  75% {\n    opacity: var(--dmx-opacity-peak);\n    --dmx-bloom-level: 1;\n  }\n\n  75%,\n  83.333333% {\n    opacity: calc(0.6 * var(--dmx-opacity-peak) + 0.4 * var(--dmx-opacity-mid));\n    --dmx-bloom-level: 0;\n  }\n\n  83.333333%,\n  91.666667% {\n    opacity: calc(0.5 * var(--dmx-opacity-mid) + 0.5 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n\n  91.666667%,\n  100% {\n    opacity: calc(0.3 * var(--dmx-opacity-mid) + 0.7 * var(--dmx-opacity-base));\n    --dmx-bloom-level: 0;\n  }\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .dmx-dot,\n  .dmx-ripple,\n  .dmx-ripple-echo,\n  .dmx-center-origin-ripple,\n  .dmx-collapse,\n  .dmx-hover-ripple,\n  .dmx-path,\n  .dmx-path-3,\n  .dmx-diagonal-alt-sweep,\n  .dmx-spiral-snake,\n  .dmx-spiral-snake-3,\n  .dmx-center-ripple-3,\n  .dmx-snake-path-3,\n  .dmx-frame-chase-3,\n  .dmx-core-pulse-3,\n  .dmx-distance-ripple-3,\n  .dmx-ripple-echo-3,\n  .dmx-diagonal-snake,\n  .dmx-outer-snake,\n  .dmx-middle-snake,\n  .dmx-square9-bit,\n  .dmx-square6-col-snake,\n  .dmx-circular2-ring {\n    animation: none !important;\n    transition: none !important;\n  }\n}\n"
    }
  ]
}
