{
  "name": "status-dot",
  "type": "registry:ui",
  "title": "StatusDot + ReadinessDot",
  "description": "G6 embodied: status is a dot until it isn't. StatusDot for ambient system state (click expands to detail); ReadinessDot for per-object readiness in rows.",
  "dependencies": [
    "@candlelight-ds/tokens",
    "clsx",
    "tailwind-merge"
  ],
  "registryDependencies": [
    "tooltip",
    "utils"
  ],
  "files": [
    {
      "path": "components/instruments/StatusDot.tsx",
      "type": "registry:ui",
      "content": "'use client'\n\n/**\n * StatusDot + ReadinessDot — G6 embodied: status is a dot until it isn't.\n *\n * StatusDot: ambient SYSTEM state (connection, sync, readiness) as an\n * 8px-hit dot; click expands to detail. No persistent status bars, no\n * preemptive banners.\n *\n * ReadinessDot: per-OBJECT readiness as a 6px dot with a name — list\n * rows, pre-flight, upload rows.\n *\n * Use when: glanceable state that should not shout.\n * Don't use when: the state demands immediate action (Announcer/Toast).\n */\n\nimport { Tooltip } from '@/components/ui/Tooltip'\nimport { cn } from '@/lib/utils'\n\nexport type StatusDotState = 'ok' | 'warn' | 'off' | 'busy'\n\ninterface StatusDotProps {\n  state: StatusDotState\n  /** Accessible name + tooltip text — name the state, not the color. */\n  label: string\n  /** Click-to-detail (G6): open the expansion overlay. */\n  onClick?: () => void\n  className?: string\n}\n\nconst DOT_CLASS: Record<StatusDotState, string> = {\n  ok: 'bg-live',\n  warn: 'bg-danger animate-pulse motion-reduce:animate-none',\n  off: 'border border-ink-faint',\n  busy: 'bg-brass animate-pulse motion-reduce:animate-none',\n}\n\nexport function StatusDot({ state, label, onClick, className }: StatusDotProps) {\n  return (\n    <Tooltip content={label}>\n      <button\n        type=\"button\"\n        onClick={onClick}\n        aria-label={label}\n        className={cn(\n          'flex h-8 w-8 items-center justify-center rounded-full transition-colors hover:bg-fill-hover',\n          className\n        )}\n      >\n        <span className={cn('h-2 w-2 rounded-full', DOT_CLASS[state])} />\n      </button>\n    </Tooltip>\n  )\n}\n\nexport type ReadinessState = 'ready' | 'partial' | 'failed' | 'pending'\n\nconst READINESS_DOT: Record<ReadinessState, string> = {\n  ready: 'bg-ready',\n  partial: 'bg-warn',\n  failed: 'bg-danger',\n  pending: 'bg-ink-faint animate-pulse motion-reduce:animate-none',\n}\n\ninterface ReadinessDotProps {\n  state: ReadinessState\n  /** Tooltip/aria text — name the issue, not just the color. */\n  label: string\n  className?: string\n}\n\nexport function ReadinessDot({ state, label, className }: ReadinessDotProps) {\n  return (\n    <Tooltip content={label}>\n      <span\n        aria-label={label}\n        className={cn('inline-block h-1.5 w-1.5 rounded-full', READINESS_DOT[state], className)}\n      />\n    </Tooltip>\n  )\n}\n",
      "target": "components/instruments/StatusDot.tsx"
    }
  ],
  "meta": {
    "candlelight": {
      "category": "instrument",
      "gRules": [
        "G6"
      ],
      "useWhen": "Glanceable state that should not shout — connection, sync, per-row readiness.",
      "dontUseWhen": "The state demands immediate action (Announcer/Toast) — no persistent status bars, no preemptive banners.",
      "states": [
        "ok",
        "warn (pulse)",
        "off",
        "busy (pulse)",
        "ready/partial/failed/pending (readiness)"
      ],
      "keyboard": [],
      "acceptanceTests": [
        "Every dot carries a text equivalent (tooltip + aria-label) that names the state, not the color.",
        "Pulses die under reduced motion."
      ]
    }
  }
}