{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "table-heat-shimmer",
  "title": "Table Heat Shimmer",
  "description": "Dense ops table where rows above a heat threshold shimmer like air over asphalt: live DOM text refracts through an animated SVG displacement filter while cold rows sit dead-still behind hairline borders.",
  "dependencies": [],
  "files": [
    {
      "path": "registry/core/table-heat-shimmer/component.tsx",
      "content": "\"use client\";\n\nimport {\n  useEffect,\n  useId,\n  useMemo,\n  useRef,\n  useState,\n  type CSSProperties,\n  type FocusEvent,\n} from \"react\";\n\n// ---------------------------------------------------------------------------\n// HeatwaveLedger — dense ops table where rows above a heat threshold shimmer\n// like air over asphalt: real DOM text refracts through an animated SVG\n// feTurbulence → feDisplacementMap filter (one filter per hot-row slot, unique\n// per instance), while cold rows sit dead-still behind hairline borders. A\n// pointer-events-none overlay canvas adds per-hot-row edge haze strips, fully\n// cleared and redrawn each frame. The hot/cold contrast IS the piece — warmth\n// is implied by motion, never by hue. One shared rAF walks only the hot list;\n// hover/focus on a hot row snaps its displacement to 0 for legibility.\n// ---------------------------------------------------------------------------\n\nexport type LedgerRow = {\n  id: string;\n  /** service name */\n  service: string;\n  /** deploy region */\n  region: string;\n  /** requests per second */\n  reqs: number;\n  /** p95 latency in ms */\n  p95: number;\n  /** heat score 0–100 — rows at/above `threshold` shimmer */\n  heat: number;\n};\n\ntype SortKey = \"service\" | \"region\" | \"reqs\" | \"p95\" | \"heat\";\ntype SortDir = \"asc\" | \"desc\";\n\ntype Vec3 = [number, number, number];\n\nfunction parseColor(raw: string): Vec3 | null {\n  const s = raw.trim();\n  if (s.startsWith(\"#\")) {\n    const hex = s.slice(1);\n    if (hex.length === 3) {\n      const r = parseInt(hex.slice(0, 1) + hex.slice(0, 1), 16);\n      const g = parseInt(hex.slice(1, 2) + hex.slice(1, 2), 16);\n      const b = parseInt(hex.slice(2, 3) + hex.slice(2, 3), 16);\n      return Number.isNaN(r + g + b) ? null : [r, g, b];\n    }\n    if (hex.length >= 6) {\n      const r = parseInt(hex.slice(0, 2), 16);\n      const g = parseInt(hex.slice(2, 4), 16);\n      const b = parseInt(hex.slice(4, 6), 16);\n      return Number.isNaN(r + g + b) ? null : [r, g, b];\n    }\n    return null;\n  }\n  const m = s.match(/rgba?\\(\\s*([\\d.]+)[,\\s]+([\\d.]+)[,\\s]+([\\d.]+)/);\n  return m ? [Number(m[1]), Number(m[2]), Number(m[3])] : null;\n}\n\nfunction mix(a: Vec3, b: Vec3, t: number): Vec3 {\n  return [\n    Math.round(a[0] + (b[0] - a[0]) * t),\n    Math.round(a[1] + (b[1] - a[1]) * t),\n    Math.round(a[2] + (b[2] - a[2]) * t),\n  ];\n}\n\nconst DEFAULT_ROWS: LedgerRow[] = [\n  { id: \"edge-gateway\", service: \"edge-gateway\", region: \"iad-1\", reqs: 12480, p95: 811, heat: 92 },\n  { id: \"auth-service\", service: \"auth-service\", region: \"fra-1\", reqs: 8921, p95: 640, heat: 84 },\n  { id: \"search-index\", service: \"search-index\", region: \"sfo-2\", reqs: 6115, p95: 505, heat: 76 },\n  { id: \"billing-api\", service: \"billing-api\", region: \"iad-1\", reqs: 2210, p95: 189, heat: 48 },\n  { id: \"media-transcode\", service: \"media-transcode\", region: \"ams-1\", reqs: 940, p95: 152, heat: 41 },\n  { id: \"notifications\", service: \"notifications\", region: \"sfo-2\", reqs: 3308, p95: 96, heat: 34 },\n  { id: \"feature-flags\", service: \"feature-flags\", region: \"fra-1\", reqs: 5170, p95: 22, heat: 21 },\n  { id: \"audit-log\", service: \"audit-log\", region: \"iad-2\", reqs: 1204, p95: 64, heat: 18 },\n  { id: \"static-assets\", service: \"static-assets\", region: \"global\", reqs: 22930, p95: 12, heat: 11 },\n  { id: \"cron-runner\", service: \"cron-runner\", region: \"ams-1\", reqs: 88, p95: 45, heat: 7 },\n];\n\nconst COLUMNS: { key: SortKey; label: string; numeric: boolean }[] = [\n  { key: \"service\", label: \"Service\", numeric: false },\n  { key: \"region\", label: \"Region\", numeric: false },\n  { key: \"reqs\", label: \"Req/s\", numeric: true },\n  { key: \"p95\", label: \"p95 ms\", numeric: true },\n  { key: \"heat\", label: \"Heat\", numeric: true },\n];\n\n// shimmer numbers\nconst PERIOD_S = 2.2; // per-row sine period\nconst PHASE_S = 0.4; // phase offset per hot-row index\nconst SCALE_MIN = 1.5; // px displacement floor\nconst SCALE_MAX = 3.0; // px displacement ceiling\nconst RESEED_MS = 4000; // turbulence seed re-randomize interval\nconst ATTR_MS = 1000 / 30; // SVG attribute writes throttled to 30fps\nconst FREEZE_IN_MS = 120; // hover legibility snap\nconst FREEZE_OUT_MS = 400; // ease back on leave\nconst FREEZE_DEADLINE_MS = 500; // forced completion — no stranded mid-wobble\nconst HAZE_H = 24; // gradient strip height in px\nconst HAZE_ALPHA = 0.08;\n\ntype FreezeState = { v: number; from: number; target: number; start: number };\n\nexport function HeatwaveLedger({\n  rows = DEFAULT_ROWS,\n  threshold = 70,\n  title = \"Server load — last 24h\",\n  timestamp = \"updated 09:41:07 UTC\",\n  className = \"\",\n}: {\n  /** table data — rows with heat >= threshold shimmer */\n  rows?: LedgerRow[];\n  /** heat score at/above which a row is hot */\n  threshold?: number;\n  /** card title */\n  title?: string;\n  /** mono timestamp shown beside the title */\n  timestamp?: string;\n  /** extra classes merged onto the rendered root element */\n  className?: string;\n}) {\n  // unique, hydration-stable filter id prefix (useId sanitized for url(#…))\n  const rawId = useId();\n  const uid = useMemo(() => \"heat\" + rawId.replace(/[^a-zA-Z0-9_-]/g, \"\"), [rawId]);\n\n  const [sortKey, setSortKey] = useState<SortKey>(\"heat\");\n  const [sortDir, setSortDir] = useState<SortDir>(\"desc\");\n  const [selected, setSelected] = useState<ReadonlySet<string>>(() => new Set());\n  const [reduced, setReduced] = useState(false);\n  // mirrors row hover into a data-attribute alongside the CSS `hover:` classes\n  // below — Chromium never advances `:hover` for the site's synthetic\n  // (isTrusted: false) autoplay driver, so the cosmetic hover tint needs a JS\n  // source of truth too (same pattern as button-glass).\n  const [hoveredId, setHoveredId] = useState<string | null>(null);\n\n  const wrapRef = useRef<HTMLDivElement>(null);\n  const tableRef = useRef<HTMLTableElement>(null);\n  const tbodyRef = useRef<HTMLTableSectionElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const rowEls = useRef(new Map<string, HTMLTableRowElement>());\n  const dispEls = useRef<(SVGFEDisplacementMapElement | null)[]>([]);\n  const turbEls = useRef<(SVGFETurbulenceElement | null)[]>([]);\n  const freezeRef = useRef(new Map<string, FreezeState>());\n  const wakeRef = useRef<(() => void) | null>(null);\n\n  const sorted = useMemo(() => {\n    const arr = [...rows];\n    arr.sort((a, b) => {\n      const c =\n        sortKey === \"service\" || sortKey === \"region\"\n          ? a[sortKey].localeCompare(b[sortKey])\n          : a[sortKey] - b[sortKey];\n      return sortDir === \"asc\" ? c : -c;\n    });\n    return arr;\n  }, [rows, sortKey, sortDir]);\n\n  // hot rows in sorted order — index drives the shimmer phase, so sorting\n  // (by heat or anything else) re-phases the field\n  const hot = useMemo(\n    () =>\n      sorted\n        .map((r, i) => ({ id: r.id, index: i }))\n        .filter((_, i) => (sorted[i]?.heat ?? 0) >= threshold),\n    [sorted, threshold]\n  );\n  const hotSlotById = useMemo(\n    () => new Map(hot.map((h, k) => [h.id, k])),\n    [hot]\n  );\n  const hotSig = useMemo(\n    () => hot.map((h) => `${h.id}:${h.index}`).join(\"|\"),\n    [hot]\n  );\n\n  // reduced motion: no filter, no canvas — static accent rule instead\n  useEffect(() => {\n    const mq = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n    setReduced(mq.matches);\n    const onChange = () => setReduced(mq.matches);\n    mq.addEventListener(\"change\", onChange);\n    return () => mq.removeEventListener(\"change\", onChange);\n  }, []);\n\n  // -- hover/focus freeze: eases a hot row's displacement to 0 for legibility\n  const setFreeze = (id: string, target: number) => {\n    const m = freezeRef.current;\n    const s = m.get(id) ?? { v: 0, from: 0, target: 0, start: 0 };\n    if (s.target === target) return;\n    s.from = s.v;\n    s.target = target;\n    s.start = performance.now();\n    m.set(id, s);\n    wakeRef.current?.();\n  };\n\n  // -- shared rAF: walks ONLY the hot list ---------------------------------\n  useEffect(() => {\n    if (reduced || hot.length === 0) return;\n    const wrap = wrapRef.current;\n    const table = tableRef.current;\n    const tbody = tbodyRef.current;\n    const canvas = canvasRef.current;\n    if (!wrap || !table || !tbody || !canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    const hotList = hot; // captured — effect re-runs when hotSig changes\n\n    // haze ink: --ns-accent mixed 20% into --ns-muted, derived at mount and\n    // re-derived live on documentElement class flips\n    let haze: Vec3 = [114, 121, 145];\n    const derive = () => {\n      const cs = getComputedStyle(document.documentElement);\n      const muted = parseColor(cs.getPropertyValue(\"--ns-muted\")) ?? [143, 143, 143];\n      const accent = parseColor(cs.getPropertyValue(\"--ns-accent\")) ?? [0, 107, 255];\n      haze = mix(muted, accent, 0.2);\n    };\n    derive();\n\n    // overlay canvas is a replaced element — explicit style.width/height,\n    // backing store scaled by dpr\n    let w = 0;\n    let h = 0;\n    let dpr = 1;\n    let sized = false;\n    const resize = () => {\n      const rect = wrap.getBoundingClientRect();\n      if (rect.width < 2 || rect.height < 2) {\n        sized = false; // zero-size guard — RO wakes us when real\n        return;\n      }\n      w = rect.width;\n      h = rect.height;\n      dpr = Math.min(2, window.devicePixelRatio || 1);\n      canvas.width = Math.max(1, Math.round(w * dpr));\n      canvas.height = Math.max(1, Math.round(h * dpr));\n      canvas.style.width = `${w}px`;\n      canvas.style.height = `${h}px`;\n      sized = true;\n    };\n    resize();\n\n    let raf = 0;\n    let visible = true;\n    let lastAttr = 0;\n    let lastSeed = 0;\n\n    const clearCanvas = () => {\n      ctx.setTransform(1, 0, 0, 1, 0, 0);\n      ctx.clearRect(0, 0, canvas.width, canvas.height);\n    };\n\n    const allFrozen = () =>\n      hotList.every((hr) => {\n        const s = freezeRef.current.get(hr.id);\n        return s !== undefined && s.target === 1 && s.v >= 0.999;\n      });\n\n    const strip = (yFrom: number, yTo: number, a: number) => {\n      const g = ctx.createLinearGradient(0, yFrom, 0, yTo);\n      const [r, gg, b] = haze;\n      g.addColorStop(0, `rgba(${r},${gg},${b},${a})`);\n      g.addColorStop(1, `rgba(${r},${gg},${b},0)`);\n      ctx.fillStyle = g;\n      ctx.fillRect(0, Math.min(yFrom, yTo), w, Math.abs(yTo - yFrom));\n    };\n\n    const step = (now: number) => {\n      raf = 0;\n      if (!visible) return; // paused offscreen — IO wakes us\n\n      // advance freeze transitions (ease-out cubic, hard deadline at 500ms\n      // so a fast hover-scrub can never strand a row mid-wobble)\n      for (const hr of hotList) {\n        const s = freezeRef.current.get(hr.id);\n        if (!s || s.v === s.target) continue;\n        const el = now - s.start;\n        const dur = s.target === 1 ? FREEZE_IN_MS : FREEZE_OUT_MS;\n        if (el >= dur || el >= FREEZE_DEADLINE_MS) {\n          s.v = s.target;\n        } else {\n          const p = el / dur;\n          const e = 1 - Math.pow(1 - p, 3);\n          s.v = s.from + (s.target - s.from) * e;\n        }\n      }\n\n      const writeAttrs = now - lastAttr >= ATTR_MS;\n      if (writeAttrs) lastAttr = now;\n      // reseed rides an attribute-write frame so the throttle can't drop it\n      const reseed = writeAttrs && now - lastSeed >= RESEED_MS;\n      if (reseed) lastSeed = now;\n\n      // haze canvas: fully cleared and redrawn every frame — no accumulation\n      const tbodyH = tbody.offsetHeight;\n      const drawable = sized && tbodyH >= 2;\n      if (sized) clearCanvas();\n      if (drawable) {\n        ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n        ctx.save();\n        // clip to the tbody band — haze never bleeds into thead/footer\n        const clipTop = table.offsetTop + tbody.offsetTop;\n        ctx.beginPath();\n        ctx.rect(0, clipTop, w, tbodyH);\n        ctx.clip();\n      }\n\n      const t = now / 1000;\n      for (let k = 0; k < hotList.length; k++) {\n        const hr = hotList[k];\n        if (!hr) continue;\n        const fr = freezeRef.current.get(hr.id)?.v ?? 0;\n        const osc =\n          0.5 + 0.5 * Math.sin(((t - hr.index * PHASE_S) / PERIOD_S) * Math.PI * 2);\n        const scale = (SCALE_MIN + (SCALE_MAX - SCALE_MIN) * osc) * (1 - fr);\n\n        if (writeAttrs) {\n          dispEls.current[k]?.setAttribute(\"scale\", scale.toFixed(2));\n          if (reseed)\n            turbEls.current[k]?.setAttribute(\n              \"seed\",\n              String(Math.floor(Math.random() * 1000))\n            );\n        }\n\n        if (drawable && fr < 0.999) {\n          const tr = rowEls.current.get(hr.id);\n          if (tr) {\n            // offset coords within the wrapper (tr.offsetParent is the table,\n            // table's offsetParent is the relative wrapper) — never page-absolute\n            const top = table.offsetTop + tr.offsetTop;\n            const bottom = top + tr.offsetHeight;\n            const a = HAZE_ALPHA * (0.55 + 0.45 * osc) * (1 - fr);\n            strip(top, top - HAZE_H, a); // rises off the top edge\n            strip(bottom, bottom + HAZE_H, a); // sinks off the bottom edge\n          }\n        }\n      }\n      if (drawable) ctx.restore();\n\n      // sleep: every hot row hover-frozen and settled — displacement is 0,\n      // haze is 0; pin scales to exactly 0 and stop the loop entirely\n      if (allFrozen()) {\n        for (let k = 0; k < hotList.length; k++)\n          dispEls.current[k]?.setAttribute(\"scale\", \"0\");\n        if (sized) clearCanvas();\n        return;\n      }\n      raf = requestAnimationFrame(step);\n    };\n\n    const wake = () => {\n      if (!raf && visible) raf = requestAnimationFrame(step);\n    };\n    wakeRef.current = wake;\n    raf = requestAnimationFrame(step);\n\n    const io = new IntersectionObserver((entries) => {\n      visible = entries[0]?.isIntersecting ?? true;\n      if (visible) wake();\n    });\n    io.observe(wrap);\n\n    const ro = new ResizeObserver(() => {\n      resize();\n      wake();\n    });\n    ro.observe(wrap);\n\n    const mo = new MutationObserver(() => {\n      derive();\n      wake();\n    });\n    mo.observe(document.documentElement, {\n      attributes: true,\n      attributeFilter: [\"class\"],\n    });\n\n    return () => {\n      cancelAnimationFrame(raf);\n      raf = 0;\n      wakeRef.current = null;\n      io.disconnect();\n      ro.disconnect();\n      mo.disconnect();\n      clearCanvas();\n    };\n  }, [reduced, hotSig, hot]);\n\n  const onSort = (key: SortKey) => {\n    if (key === sortKey) {\n      setSortDir((d) => (d === \"asc\" ? \"desc\" : \"asc\"));\n    } else {\n      setSortKey(key);\n      setSortDir(key === \"service\" || key === \"region\" ? \"asc\" : \"desc\");\n    }\n  };\n\n  const toggleSelect = (id: string) => {\n    setSelected((prev) => {\n      const next = new Set(prev);\n      if (next.has(id)) next.delete(id);\n      else next.add(id);\n      return next;\n    });\n  };\n\n  const onRowBlur = (id: string) => (e: FocusEvent<HTMLTableRowElement>) => {\n    // focus-within: stay frozen while focus moves inside the row\n    if (e.currentTarget.contains(e.relatedTarget as Node | null)) return;\n    setFreeze(id, 0);\n  };\n\n  return (\n    <div\n      className={`overflow-hidden rounded-md border border-border bg-surface ${className}`}\n    >\n      <div className=\"flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1 px-5 pb-4 pt-5\">\n        <h2 className=\"text-sm font-semibold tracking-tight text-foreground\">\n          {title}\n        </h2>\n        <span className=\"font-mono text-[11px] tracking-wider text-ns-muted\">\n          {timestamp}\n        </span>\n      </div>\n\n      <div ref={wrapRef} className=\"relative\">\n        {/* one filter per hot-row slot, ids unique per instance */}\n        {!reduced && hot.length > 0 && (\n          <svg aria-hidden width=\"0\" height=\"0\" className=\"absolute\" focusable=\"false\">\n            <defs>\n              {hot.map((h, k) => (\n                <filter\n                  key={h.id}\n                  id={`${uid}-h${k}`}\n                  x=\"-2%\"\n                  y=\"-60%\"\n                  width=\"104%\"\n                  height=\"220%\"\n                  colorInterpolationFilters=\"sRGB\"\n                >\n                  <feTurbulence\n                    ref={(el) => {\n                      turbEls.current[k] = el;\n                    }}\n                    type=\"fractalNoise\"\n                    baseFrequency=\"0.008 0.02\"\n                    numOctaves={2}\n                    seed={7 + k * 13}\n                    result=\"n\"\n                  />\n                  <feDisplacementMap\n                    ref={(el) => {\n                      dispEls.current[k] = el;\n                    }}\n                    in=\"SourceGraphic\"\n                    in2=\"n\"\n                    scale=\"0\"\n                    xChannelSelector=\"R\"\n                    yChannelSelector=\"G\"\n                  />\n                </filter>\n              ))}\n            </defs>\n          </svg>\n        )}\n\n        <table ref={tableRef} className=\"w-full border-collapse text-sm\">\n          <thead>\n            <tr className=\"border-b border-border\">\n              <th scope=\"col\" className=\"w-10 px-5 py-2.5\">\n                <span className=\"sr-only\">Select</span>\n              </th>\n              {COLUMNS.map((col) => {\n                const active = sortKey === col.key;\n                return (\n                  <th\n                    key={col.key}\n                    scope=\"col\"\n                    aria-sort={\n                      active\n                        ? sortDir === \"asc\"\n                          ? \"ascending\"\n                          : \"descending\"\n                        : undefined\n                    }\n                    className={`px-3 py-2.5 first:pl-5 last:pr-5 ${\n                      col.numeric ? \"text-right\" : \"text-left\"\n                    }`}\n                  >\n                    <button\n                      type=\"button\"\n                      onClick={() => onSort(col.key)}\n                      className={`inline-flex items-center gap-1 rounded-sm font-mono text-[11px] uppercase tracking-widest transition-colors duration-150 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ns-accent ${\n                        active ? \"text-foreground\" : \"text-ns-muted hover:text-foreground\"\n                      } ${col.numeric ? \"flex-row-reverse\" : \"\"}`}\n                    >\n                      {col.label}\n                      <svg\n                        viewBox=\"0 0 8 8\"\n                        aria-hidden\n                        className={`h-2 w-2 transition-opacity duration-150 ${\n                          active ? \"opacity-100\" : \"opacity-0\"\n                        } ${active && sortDir === \"asc\" ? \"rotate-180\" : \"\"}`}\n                        fill=\"currentColor\"\n                      >\n                        <path d=\"M4 6 0.8 2h6.4Z\" />\n                      </svg>\n                    </button>\n                  </th>\n                );\n              })}\n            </tr>\n          </thead>\n          <tbody ref={tbodyRef}>\n            {sorted.map((row) => {\n              const slot = hotSlotById.get(row.id);\n              const isHot = slot !== undefined;\n              const isSel = selected.has(row.id);\n\n              const style: CSSProperties = {};\n              if (isHot && !reduced) style.filter = `url(#${uid}-h${slot})`;\n              const shadows: string[] = [];\n              if (isHot && reduced)\n                shadows.push(\"inset 2px 0 0 0 var(--ns-accent)\"); // static heat rule\n              if (isSel)\n                shadows.push(\n                  \"inset 0 0 0 1px color-mix(in srgb, var(--foreground) 35%, var(--ns-muted))\"\n                );\n              if (shadows.length > 0) style.boxShadow = shadows.join(\", \");\n\n              // token-relative fills only: hover raises one surface step,\n              // selection sits one step above that\n              // (`data-[hover=true]` mirrors `:hover` for synthetic/driver input)\n              const bg = isSel\n                ? \"bg-foreground/[0.06]\"\n                : isHot && reduced\n                  ? \"bg-foreground/[0.04] hover:bg-foreground/[0.06] data-[hover=true]:bg-foreground/[0.06]\"\n                  : \"hover:bg-foreground/[0.04] data-[hover=true]:bg-foreground/[0.04]\";\n\n              return (\n                <tr\n                  key={row.id}\n                  ref={(el) => {\n                    if (el) rowEls.current.set(row.id, el);\n                    else rowEls.current.delete(row.id);\n                  }}\n                  style={style}\n                  aria-selected={isSel}\n                  data-hover={hoveredId === row.id}\n                  onPointerEnter={() => {\n                    setHoveredId(row.id);\n                    if (isHot && !reduced) setFreeze(row.id, 1);\n                  }}\n                  onPointerLeave={() => {\n                    setHoveredId((h) => (h === row.id ? null : h));\n                    if (isHot && !reduced) setFreeze(row.id, 0);\n                  }}\n                  onFocus={isHot && !reduced ? () => setFreeze(row.id, 1) : undefined}\n                  onBlur={isHot && !reduced ? onRowBlur(row.id) : undefined}\n                  className={`border-b border-border transition-colors duration-150 last:border-b-0 ${bg}`}\n                >\n                  <td className=\"px-5 py-3\">\n                    <input\n                      type=\"checkbox\"\n                      checked={isSel}\n                      onChange={() => toggleSelect(row.id)}\n                      aria-label={`Select ${row.service}`}\n                      className=\"block h-3.5 w-3.5 cursor-pointer\"\n                      style={{ accentColor: \"var(--ns-accent)\" }}\n                    />\n                  </td>\n                  <td className=\"px-3 py-3 font-medium text-foreground\">\n                    {row.service}\n                  </td>\n                  <td className=\"px-3 py-3 font-mono text-xs tracking-wide text-ns-muted\">\n                    {row.region}\n                  </td>\n                  <td className=\"px-3 py-3 text-right font-mono text-xs tabular-nums text-ns-muted\">\n                    {row.reqs.toLocaleString(\"en-US\")}\n                  </td>\n                  <td className=\"px-3 py-3 text-right font-mono text-xs tabular-nums text-ns-muted\">\n                    {row.p95.toLocaleString(\"en-US\")}\n                  </td>\n                  <td\n                    className={`px-3 py-3 pr-5 text-right font-mono text-xs tabular-nums ${\n                      isHot ? \"font-medium text-foreground\" : \"text-ns-muted\"\n                    }`}\n                  >\n                    {row.heat}\n                  </td>\n                </tr>\n              );\n            })}\n          </tbody>\n        </table>\n\n        {/* edge-haze overlay — explicit CSS size set in the resize handler */}\n        {!reduced && hot.length > 0 && (\n          <canvas\n            ref={canvasRef}\n            aria-hidden\n            className=\"pointer-events-none absolute left-0 top-0\"\n          />\n        )}\n      </div>\n\n      <div className=\"flex flex-wrap items-center justify-between gap-x-4 gap-y-2 border-t border-border px-5 py-3\">\n        <span className=\"font-mono text-[11px] tracking-wider text-ns-muted\">\n          {sorted.length} services · {hot.length} above threshold · {selected.size}{\" \"}\n          selected\n        </span>\n        <div className=\"flex items-center gap-2\">\n          <button\n            type=\"button\"\n            disabled\n            className=\"rounded-sm border border-border px-2.5 py-1 font-mono text-[11px] text-ns-muted opacity-50 transition-colors duration-150 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ns-accent\"\n          >\n            Prev\n          </button>\n          <span className=\"font-mono text-[11px] tabular-nums text-ns-muted\">1 / 1</span>\n          <button\n            type=\"button\"\n            disabled\n            className=\"rounded-sm border border-border px-2.5 py-1 font-mono text-[11px] text-ns-muted opacity-50 transition-colors duration-150 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ns-accent\"\n          >\n            Next\n          </button>\n        </div>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/ui/table-heat-shimmer.tsx"
    }
  ],
  "cssVars": {
    "theme": {
      "color-ns-muted": "var(--ns-muted)",
      "color-ns-accent": "var(--ns-accent)",
      "color-surface": "var(--surface)"
    },
    "light": {
      "ns-muted": "#4d4d4d",
      "ns-accent": "#006bff",
      "surface": "#fafafa"
    },
    "dark": {
      "ns-muted": "#8f8f8f",
      "surface": "#171717"
    }
  },
  "meta": {
    "collection": "core",
    "tags": [
      "table",
      "data-viz",
      "svg-filter",
      "displacement",
      "heat-haze",
      "canvas",
      "sortable",
      "dashboard"
    ],
    "instruction": "Dense data table where rows above a heat threshold visibly shimmer like air over asphalt: real content refracts via an animated SVG displacement filter while cold rows sit dead-still with 1px hairline borders — the hot/cold contrast IS the piece; warmth is implied by motion, never by hue (no orange anywhere). RENDERING: semantic DOM <table> (sortable headers with real client-side comparators, selectable checkbox rows) inside a padded rounded-md surface card, plus (a) one inline SVG <filter> per hot-row slot with instance-unique ids (useId): feTurbulence type=fractalNoise baseFrequency='0.008 0.02' numOctaves=2 feeding feDisplacementMap; each hot <tr> gets style.filter=url(#heat-<id>) so its actual text/cells refract; and (b) a pointer-events:none overlay canvas over the tbody (explicit style.width/height, dpr-scaled backing store, clipped to the tbody band) drawing per-hot-row edge haze: two 24px vertical-fade gradient strips off each hot row's top and bottom edges, ink = --ns-accent mixed 20% into --ns-muted at alpha 0.08. MOTION: displacement scale oscillates 1.5→3.0px on a per-row sine (period 2.2s, phase offset 0.4s per sorted row index — resorting re-phases the field); turbulence seed re-randomized every 4s for non-looping shimmer; SVG attribute writes throttled to 30fps inside one shared rAF that walks ONLY the hot-row list and fully clears/redraws the haze canvas each frame (no accumulation). Hover or focus-within on a hot row eases its displacement to 0 over 120ms (legibility snap), back over 400ms on leave, with a forced completion deadline at 500ms so fast hover-scrubs never strand rows mid-wobble. INTERACTION: header sort (sorting by heat re-phases shimmer), checkbox selection with token-relative fill (surface step + 1px foreground/muted mix ring via color-mix), hover raises row background one surface step (bg-foreground/[0.04]). TOKENS: haze ink derived from getComputedStyle(--ns-accent, --ns-muted) at mount, re-derived live via MutationObserver on documentElement class. SLEEP/TEARDOWN: rAF stops entirely when no row exceeds threshold or all hot rows are hover-frozen (scales pinned to 0, canvas cleared); IntersectionObserver pauses offscreen; ResizeObserver with zero-size tbody guard; all listeners/observers/rAF torn down on unmount. REDUCED MOTION: no filter, no canvas — hot rows get a static 2px --ns-accent left rule and slightly elevated surface fill. DEMO: dashboard card 'Server load — last 24h' with mono timestamp, 10 believable ops rows (service, region, req/s, p95 ms, heat score), 3 hot at default threshold 70, footer row count + pagination stub, demo-level threshold segmented control."
  },
  "type": "registry:ui"
}