{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ai-dynamic-island-01",
  "title": "AI Dynamic Island 01",
  "description": "A Dynamic Island-style AI status pill that morphs between idle, listening, thinking, working (with an unfolding step list) and done states, with a canvas-drawn particle orb and rippling energy curves.",
  "dependencies": [
    "clsx",
    "tailwind-merge"
  ],
  "files": [
    {
      "path": "registry/new-york/ai-dynamic-island-01/ai-dynamic-island-01.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nfunction cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\ntype RGB = [number, number, number];\ntype Mode = \"idle\" | \"listening\" | \"thinking\" | \"working\" | \"done\";\ntype Status = \"auto\" | Mode;\ntype Align = \"top\" | \"center\" | \"bottom\";\n\nexport interface AIDynamicIsland01Props {\n  status?: Status;\n  interactive?: boolean;\n  loop?: boolean;\n  stageSeconds?: number;\n  stepSeconds?: number;\n  idleText?: string;\n  listeningText?: string;\n  thinkingText?: string;\n  workingText?: string;\n  doneText?: string;\n  viewLabel?: string;\n  steps?: string[];\n  align?: Align;\n  shadow?: boolean;\n  expandedWidth?: number;\n  orbSize?: number;\n  particleSize?: number;\n  curves?: number;\n  curveWidth?: number;\n  curveAmp?: number;\n  curveColor?: string;\n  dotColor?: string;\n  accentColor?: string;\n  accentAmount?: number;\n  font?: React.CSSProperties;\n  textColor?: string;\n  mutedColor?: string;\n  listenColors?: string[];\n  thinkColors?: string[];\n  doneColors?: string[];\n  ringIntensity?: number;\n  ringSize?: number;\n  ringSpeed?: number;\n  background?: string;\n  borderColor?: string;\n  radius?: number;\n  padding?: number;\n  gap?: number;\n  onStart?: () => void;\n  onStop?: () => void;\n  onView?: () => void;\n  onComplete?: () => void;\n  className?: string;\n  style?: React.CSSProperties;\n}\n\nconst TAU = Math.PI * 2;\nconst LEAD = 40;\nconst STOP = 40;\nconst ROW = 32;\nconst ICON = 18;\nconst LIST_TOP = 4;\nconst LIST_BOTTOM = 14;\nconst CANVAS = 56;\nconst POINTS = 240;\nconst BANDS = 24;\nconst CURVE_POINTS = 72;\nconst LEVELS = 6;\nconst START_ANGLE = 40;\nconst STATIC_SHIMMER = 72;\nconst STATIC_TIME = 2.4;\nconst MODES: Mode[] = [\"idle\", \"listening\", \"thinking\", \"working\", \"done\"];\nconst RUNNING: Mode[] = [\"listening\", \"thinking\", \"working\"];\nconst EASE = \"cubic-bezier(0.2, 0.8, 0.2, 1)\";\nconst MORPH = \"0.62s cubic-bezier(0.3, 1.2, 0.4, 1)\";\nconst FONT_FALLBACK = \"Inter, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif\";\nconst HAIRLINE = \"rgba(255,255,255,0.14)\";\nconst HOVER_ON = \"inset 0 0 0 999px rgba(255,255,255,0.06)\";\nconst HOVER_OFF = \"inset 0 0 0 999px rgba(255,255,255,0)\";\nconst RING = \"0 0 0 2px rgba(255,255,255,0.35)\";\nconst NO_RING = \"0 0 0 0 rgba(255,255,255,0)\";\nconst SHEEN =\n  \"linear-gradient(115deg, rgba(255,255,255,0.08) 0%, rgba(255,255,255,0.02) 30%, rgba(255,255,255,0) 48%, rgba(255,255,255,0.04) 74%, rgba(255,255,255,0) 100%), linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0) 60%)\";\n\nconst DEFAULT_STEPS = [\"Searching the web\", \"Reading 4 sources\", \"Comparing the results\", \"Writing the answer\"];\nconst DEFAULT_LISTEN = [\"#7CF3FF\", \"#6EA8FF\", \"#9B7BFF\"];\nconst DEFAULT_THINK = [\"#9B7BFF\", \"#FF7BD5\", \"#FFB86B\"];\nconst DEFAULT_DONE = [\"#7CFFC4\", \"#7CF3FF\", \"#F5F6F8\"];\n\nconst SR_ONLY: React.CSSProperties = {\n  position: \"absolute\",\n  width: 1,\n  height: 1,\n  overflow: \"hidden\",\n  clip: \"rect(0 0 0 0)\",\n  whiteSpace: \"nowrap\",\n};\n\ntype Sizes = {\n  label: Record<Mode, number>;\n  step: number;\n  view: number;\n};\n\ntype Live = {\n  mode: Mode;\n  time: number;\n  spinT: number;\n  spin: number;\n  wave: number;\n  rot: number;\n  level: number;\n  curveA: number;\n  bands: Float32Array;\n  target: Float32Array;\n  pal: RGB[];\n  angle: number;\n  ringSpeed: number;\n  orbR: number;\n  dot: number;\n  curves: number;\n  thick: number;\n  amp: number;\n  core: RGB;\n  base: RGB;\n  accent: RGB;\n  accentAmount: number;\n  listen: RGB[];\n  think: RGB[];\n  done: RGB[];\n  still: boolean;\n  drawnMode: Mode | null;\n};\n\ntype Orb = {\n  n: number;\n  x: Float32Array;\n  y: Float32Array;\n  z: Float32Array;\n  phi: Float32Array;\n  jit: Float32Array;\n  sx: Float32Array;\n  sy: Float32Array;\n  rad: Float32Array;\n  lv: Uint8Array;\n  hot: Uint8Array;\n};\n\nfunction clamp01(v: number) {\n  return Math.min(1, Math.max(0, v));\n}\n\nfunction rng(seed: number) {\n  let a = Math.floor(seed) >>> 0;\n  return () => {\n    a = (a + 0x6d2b79f5) >>> 0;\n    let t = a;\n    t = Math.imul(t ^ (t >>> 15), t | 1);\n    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n  };\n}\n\nfunction parseRgb(input: string, fallback: RGB): RGB {\n  const s = (input || \"\").trim();\n  if (s.startsWith(\"#\")) {\n    let h = s.slice(1);\n    if (h.length === 3 || h.length === 4)\n      h = h\n        .split(\"\")\n        .map((c) => c + c)\n        .join(\"\");\n    const n = parseInt(h.slice(0, 6), 16);\n    if (h.length >= 6 && !Number.isNaN(n)) return [(n >> 16) & 255, (n >> 8) & 255, n & 255];\n  }\n  const m = s.match(/rgba?\\(\\s*([\\d.]+)[,\\s]+([\\d.]+)[,\\s]+([\\d.]+)/i);\n  if (m) return [Math.round(+m[1]), Math.round(+m[2]), Math.round(+m[3])];\n  return fallback;\n}\n\nfunction mixRgb(a: RGB, b: RGB, t: number): RGB {\n  return [Math.round(a[0] + (b[0] - a[0]) * t), Math.round(a[1] + (b[1] - a[1]) * t), Math.round(a[2] + (b[2] - a[2]) * t)];\n}\n\nfunction cleanList(list: string[] | undefined, fallback: string[]) {\n  const out = (list ?? []).filter((s): s is string => typeof s === \"string\" && s.trim() !== \"\");\n  return out.length ? out : fallback;\n}\n\nfunction sample3(list: RGB[]): RGB[] {\n  const n = list.length;\n  if (n === 0)\n    return [\n      [255, 255, 255],\n      [255, 255, 255],\n      [255, 255, 255],\n    ];\n  return [0, 0.5, 1].map((f) => {\n    const p = f * (n - 1);\n    const i = Math.floor(p);\n    return mixRgb(list[i], list[Math.min(n - 1, i + 1)], p - i);\n  });\n}\n\nfunction buildGradient(colors: string[], spread: number) {\n  const arc = Math.max(0.15, Math.min(1, spread)) * 360;\n  const n = colors.length;\n  if (n === 0) return \"linear-gradient(transparent, transparent)\";\n  const stops = colors.map((c, i) => {\n    const at = n === 1 ? 0.5 : 0.1 + (0.8 * i) / (n - 1);\n    return `${c} ${(at * arc).toFixed(1)}deg`;\n  });\n  return `conic-gradient(from var(--gl-angle, ${START_ANGLE}deg), transparent 0deg, ${stops.join(\", \")}, transparent ${arc.toFixed(1)}deg, transparent 360deg)`;\n}\n\nfunction ringStyle(width: number): React.CSSProperties {\n  return {\n    position: \"absolute\",\n    inset: 0,\n    boxSizing: \"border-box\",\n    borderRadius: \"inherit\",\n    padding: width,\n    WebkitMask: \"linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0)\",\n    WebkitMaskComposite: \"xor\",\n    mask: \"linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0)\",\n    maskComposite: \"exclude\",\n  };\n}\n\nfunction makeOrb(n: number): Orb {\n  const golden = Math.PI * (3 - Math.sqrt(5));\n  const rnd = rng(23);\n  const S: Orb = {\n    n,\n    x: new Float32Array(n),\n    y: new Float32Array(n),\n    z: new Float32Array(n),\n    phi: new Float32Array(n),\n    jit: new Float32Array(n),\n    sx: new Float32Array(n),\n    sy: new Float32Array(n),\n    rad: new Float32Array(n),\n    lv: new Uint8Array(n),\n    hot: new Uint8Array(n),\n  };\n  for (let i = 0; i < n; i++) {\n    const z = 1 - (2 * (i + 0.5)) / n;\n    const r = Math.sqrt(Math.max(0, 1 - z * z));\n    const a = i * golden;\n    S.x[i] = r * Math.cos(a);\n    S.y[i] = r * Math.sin(a);\n    S.z[i] = z;\n    S.phi[i] = a;\n    S.jit[i] = rnd();\n  }\n  return S;\n}\n\nfunction projectOrb(S: Orb, spinT: number, t: number, R: number, cx: number, cy: number, dot: number) {\n  const tilt = 0.42 + 0.08 * Math.sin(t * 0.45);\n  const ct = Math.cos(tilt);\n  const st = Math.sin(tilt);\n  const twist = 1.6 + 0.3 * Math.sin(t * 0.6);\n  for (let i = 0; i < S.n; i++) {\n    const z0 = S.z[i];\n    const a = spinT * 0.5 + twist * z0;\n    const c = Math.cos(a);\n    const s = Math.sin(a);\n    const x1 = S.x[i] * c - S.y[i] * s;\n    const y1 = S.x[i] * s + S.y[i] * c;\n    const y2 = y1 * ct - z0 * st;\n    const z2 = y1 * st + z0 * ct;\n    const d = (z2 + 1) / 2;\n    const f = 1 + z2 * 0.1;\n    S.sx[i] = cx + x1 * R * f;\n    S.sy[i] = cy + y2 * R * f;\n    const band = 0.5 + 0.5 * Math.cos(S.phi[i] + z0 * 2.2 - t * 1.1);\n    const hi = Math.pow(band, 6) * (0.35 + 0.65 * d);\n    const twinkle = 0.85 + 0.15 * Math.sin(t * 2.2 + S.jit[i] * 40);\n    const b = clamp01((0.16 + 0.5 * d + 0.6 * hi) * twinkle);\n    S.lv[i] = Math.min(LEVELS - 1, Math.floor(b * LEVELS));\n    S.rad[i] = dot * (0.42 + 0.5 * d + 0.75 * hi);\n    S.hot[i] = hi > 0.6 && d > 0.5 ? 1 : 0;\n  }\n}\n\nfunction levelLook(L: Live, k: number) {\n  const q = k / (LEVELS - 1);\n  const [r, g, b] = mixRgb(L.base, L.accent, clamp01(L.accentAmount * (0.15 + 1.5 * q * q)));\n  return { rgb: `${r},${g},${b}`, a: clamp01(0.12 + 0.88 * Math.pow(q, 1.2)) };\n}\n\nfunction simulateBands(t: number, mode: Mode, out: Float32Array) {\n  const n = out.length;\n  let base = 0.03;\n  if (mode === \"listening\") {\n    const x = 0.5 + 0.5 * Math.sin(t * 0.9 + 1.7 * Math.sin(t * 0.37));\n    const gate = clamp01((x - 0.35) / 0.3);\n    const syll = 0.55 + 0.45 * Math.sin(t * 7.3) * Math.sin(t * 2.1 + 0.6);\n    base = 0.14 + 0.86 * gate * gate * (3 - 2 * gate) * syll;\n  } else if (mode === \"thinking\" || mode === \"working\") {\n    const surge = 0.5 + 0.5 * Math.sin(t * 0.8 + 1.7 * Math.sin(t * 0.37));\n    const flutter = 0.6 + 0.4 * Math.sin(t * 3.1) * Math.sin(t * 1.3 + 0.6);\n    base = (mode === \"thinking\" ? 0.75 : 0.55) * (0.3 + 0.7 * surge * flutter);\n  }\n  for (let i = 0; i < n; i++) {\n    const f = i / (n - 1);\n    const shape = 0.25 + 0.75 * Math.exp(-Math.pow((f - 0.28) / 0.3, 2));\n    const v = 0.5 + 0.5 * Math.sin(t * (3.1 + i * 0.53) + i * 1.9) * Math.sin(t * (1.3 + i * 0.21) + i);\n    out[i] = clamp01(base * shape * (0.35 + 0.65 * v) * 0.9);\n  }\n}\n\nconst SMOOTH_A = new Float32Array(BANDS);\nconst SMOOTH_B = new Float32Array(BANDS);\n\nfunction smoothBands(src: Float32Array): Float32Array {\n  const n = src.length;\n  for (let i = 0; i < n; i++) SMOOTH_A[i] = 0.25 * src[Math.max(0, i - 1)] + 0.5 * src[i] + 0.25 * src[Math.min(n - 1, i + 1)];\n  for (let i = 0; i < n; i++) SMOOTH_B[i] = 0.25 * SMOOTH_A[Math.max(0, i - 1)] + 0.5 * SMOOTH_A[i] + 0.25 * SMOOTH_A[Math.min(n - 1, i + 1)];\n  return SMOOTH_B;\n}\n\nfunction curveRadius(\n  l: number,\n  theta: number,\n  bands: Float32Array,\n  level: number,\n  phase: number,\n  rot: number,\n  amp: number,\n  outer: number,\n  inner: number,\n) {\n  const dir = l % 2 === 0 ? 1 : -1;\n  const f = Math.abs(Math.sin((theta + rot * 0.3 * dir) / 2));\n  const bf = f * (bands.length - 1);\n  const i0 = Math.floor(bf);\n  const i1 = Math.min(bands.length - 1, i0 + 1);\n  const band = bands[i0] + (bands[i1] - bands[i0]) * (bf - i0);\n  const energy = 0.04 + band * 0.96 + level * 0.18;\n  const wave = 0.5 + 0.5 * Math.sin((3 + l) * theta + phase * (1.1 + l * 0.5) * dir + l * 1.9);\n  const base = inner + 0.03 * l * outer;\n  return Math.min(outer * 0.98, base + (outer * 0.98 - base) * 0.5 * energy * wave * amp);\n}\n\nfunction restRadius(orbR: number) {\n  return orbR * 1.1 + 3;\n}\n\nfunction updateEnergy(L: Live, dt: number) {\n  simulateBands(L.time, L.mode, L.target);\n  const n = L.bands.length;\n  let sum = 0;\n  for (let i = 0; i < n; i++) {\n    const tv = L.target[i];\n    const cur = L.bands[i];\n    L.bands[i] = cur + (tv - cur) * (tv > cur ? Math.min(1, dt * 22) : Math.min(1, dt * 6));\n    sum += L.bands[i];\n  }\n  L.level += (clamp01((sum / n) * 2.4) - L.level) * Math.min(1, dt * 14);\n  L.wave += dt * (1 + 1.6 * L.level);\n  L.rot += dt * 0.45 * (1 + L.level);\n  const spinTo = L.mode === \"thinking\" ? 1.1 : L.mode === \"working\" ? 0.9 : L.mode === \"listening\" ? 0.7 : 0.35;\n  L.spin += (spinTo - L.spin) * Math.min(1, dt * 3);\n  L.spinT += dt * L.spin;\n  const curveTo = RUNNING.indexOf(L.mode) >= 0 ? 1 : 0;\n  L.curveA += (curveTo - L.curveA) * Math.min(1, dt * 6);\n  const want = sample3(L.mode === \"listening\" ? L.listen : L.mode === \"done\" ? L.done : L.think);\n  for (let k = 0; k < 3; k++) L.pal[k] = mixRgb(L.pal[k], want[k], Math.min(1, dt * 4));\n}\n\nfunction drawLead(ctx: CanvasRenderingContext2D, w: number, h: number, L: Live, S: Orb) {\n  ctx.clearRect(0, 0, w, h);\n  const cx = w / 2;\n  const cy = h / 2;\n  const R = L.orbR;\n  const [ar, ag, ab] = L.accent;\n\n  const halo = ctx.createRadialGradient(cx, cy, R * 0.3, cx, cy, R * 1.7);\n  halo.addColorStop(0, `rgba(${ar},${ag},${ab},0.10)`);\n  halo.addColorStop(1, `rgba(${ar},${ag},${ab},0)`);\n  ctx.fillStyle = halo;\n  ctx.beginPath();\n  ctx.arc(cx, cy, R * 1.7, 0, TAU);\n  ctx.fill();\n\n  if (L.curveA > 0.01) {\n    const outer = (Math.min(w, h) / 2) * 0.98;\n    const inner = Math.min(outer * 0.9, restRadius(R));\n    const bands = smoothBands(L.bands);\n    const [kr, kg, kb] = L.core;\n    ctx.globalCompositeOperation = \"lighter\";\n    ctx.lineJoin = \"round\";\n    for (let l = 0; l < L.curves; l++) {\n      ctx.beginPath();\n      for (let i = 0; i <= CURVE_POINTS; i++) {\n        const theta = (i / CURVE_POINTS) * TAU;\n        const r = curveRadius(l, theta, bands, L.level, L.wave, L.rot, L.amp, outer, inner);\n        const x = cx + Math.sin(theta) * r;\n        const y = cy - Math.cos(theta) * r;\n        if (i === 0) ctx.moveTo(x, y);\n        else ctx.lineTo(x, y);\n      }\n      ctx.closePath();\n      const a = Math.max(0.3, 0.95 - l * 0.22);\n      let stroke: string | CanvasGradient = `rgba(${kr},${kg},${kb},${a.toFixed(2)})`;\n      if (typeof ctx.createConicGradient === \"function\") {\n        const g = ctx.createConicGradient(L.rot * 0.5 * (l % 2 === 0 ? 1 : -1) - Math.PI / 2, cx, cy);\n        const stops: RGB[] = [L.core, L.pal[0], L.pal[1], L.pal[2], L.core];\n        stops.forEach((c, k) => {\n          const edge = k === 0 || k === stops.length - 1;\n          g.addColorStop(k / (stops.length - 1), `rgba(${c[0]},${c[1]},${c[2]},${(edge ? a : a * 0.85).toFixed(2)})`);\n        });\n        stroke = g;\n      }\n      ctx.strokeStyle = stroke;\n      ctx.globalAlpha = 0.25 * L.curveA;\n      ctx.lineWidth = (3.4 - l * 0.5) * L.thick;\n      ctx.stroke();\n      ctx.globalAlpha = L.curveA;\n      ctx.lineWidth = Math.max(0.8, (1.4 - l * 0.2) * L.thick);\n      ctx.stroke();\n    }\n    ctx.globalAlpha = 1;\n    ctx.globalCompositeOperation = \"source-over\";\n  }\n\n  projectOrb(S, L.spinT, L.time, R, cx, cy, L.dot);\n  for (let k = 0; k < LEVELS; k++) {\n    const look = levelLook(L, k);\n    ctx.fillStyle = `rgba(${look.rgb},${look.a.toFixed(3)})`;\n    ctx.beginPath();\n    for (let i = 0; i < S.n; i++) {\n      if (S.lv[i] !== k) continue;\n      const r = S.rad[i];\n      ctx.moveTo(S.sx[i] + r, S.sy[i]);\n      ctx.arc(S.sx[i], S.sy[i], r, 0, TAU);\n    }\n    ctx.fill();\n  }\n  ctx.fillStyle = `rgba(${ar},${ag},${ab},0.10)`;\n  ctx.beginPath();\n  for (let i = 0; i < S.n; i++) {\n    if (!S.hot[i]) continue;\n    const r = S.rad[i] * 2.6;\n    ctx.moveTo(S.sx[i] + r, S.sy[i]);\n    ctx.arc(S.sx[i], S.sy[i], r, 0, TAU);\n  }\n  ctx.fill();\n}\n\nfunction estimate(text: string, px: number) {\n  return Math.ceil(text.length * px * 0.56);\n}\n\nfunction geometry(\n  mode: Mode,\n  sz: Sizes,\n  pad: number,\n  gap: number,\n  minExpanded: number,\n  rows: number,\n  actions: boolean,\n  hasView: boolean,\n) {\n  const head = LEAD + pad * 2;\n  let action = 0;\n  if (actions && RUNNING.indexOf(mode) >= 0) action = STOP;\n  else if (actions && hasView && mode === \"done\") action = sz.view;\n  let w = pad + LEAD + gap + sz.label[mode] + (action ? gap + action + pad : pad + 12);\n  let h = head;\n  if (mode === \"working\") {\n    const inset = pad + (LEAD - ICON) / 2;\n    w = Math.max(w, inset + ICON + 10 + sz.step + inset, minExpanded);\n    h = head + LIST_TOP + rows * ROW + LIST_BOTTOM;\n  }\n  return { w: Math.ceil(w), h: Math.ceil(h), action };\n}\n\nfunction useFocusVisible() {\n  const [focusVisible, setFocusVisible] = React.useState(false);\n  return {\n    focusVisible,\n    onFocus: (e: React.FocusEvent<HTMLElement>) => {\n      try {\n        setFocusVisible(e.currentTarget.matches(\":focus-visible\"));\n      } catch {\n        setFocusVisible(true);\n      }\n    },\n    onBlur: () => setFocusVisible(false),\n  };\n}\n\nfunction subscribeReducedMotion(callback: () => void) {\n  if (typeof window === \"undefined\" || typeof window.matchMedia !== \"function\") return () => undefined;\n  const mq = window.matchMedia(\"(prefers-reduced-motion: reduce)\");\n  if (typeof mq.addEventListener !== \"function\") return () => undefined;\n  mq.addEventListener(\"change\", callback);\n  return () => mq.removeEventListener(\"change\", callback);\n}\nfunction getReducedMotionSnapshot() {\n  return typeof window !== \"undefined\" && typeof window.matchMedia === \"function\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n}\nfunction getReducedMotionServerSnapshot() {\n  return false;\n}\n\nconst StopIcon = () => (\n  <svg width={22} height={22} viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\" focusable=\"false\" style={{ display: \"block\" }}>\n    <rect x=\"4\" y=\"4\" width=\"16\" height=\"16\" rx=\"4\" />\n  </svg>\n);\n\nconst ArrowIcon = () => (\n  <svg\n    width={13}\n    height={13}\n    viewBox=\"0 0 24 24\"\n    fill=\"none\"\n    stroke=\"currentColor\"\n    strokeWidth={2.4}\n    strokeLinecap=\"round\"\n    strokeLinejoin=\"round\"\n    aria-hidden=\"true\"\n    focusable=\"false\"\n    style={{ display: \"block\" }}\n  >\n    <path d=\"M7 17 17 7\" />\n    <path d=\"M8 7h9v9\" />\n  </svg>\n);\n\nconst CheckMark = ({ size, stroke }: { size: number; stroke: number }) => (\n  <svg\n    width={size}\n    height={size}\n    viewBox=\"0 0 24 24\"\n    fill=\"none\"\n    stroke=\"currentColor\"\n    strokeWidth={stroke}\n    strokeLinecap=\"round\"\n    strokeLinejoin=\"round\"\n    aria-hidden=\"true\"\n    focusable=\"false\"\n    style={{ display: \"block\" }}\n  >\n    <path d=\"M20 6 9 17l-5-5\" />\n  </svg>\n);\n\ntype ActionProps = {\n  label: string;\n  onClick: () => void;\n  on: boolean;\n  style: React.CSSProperties;\n  children: React.ReactNode;\n  ariaLabel?: string;\n};\n\nfunction ActionButton({ label, onClick, on, style, children, ariaLabel }: ActionProps) {\n  const [hover, setHover] = React.useState(false);\n  const [pressed, setPressed] = React.useState(false);\n  const focus = useFocusVisible();\n  const release = () => setPressed(false);\n  return (\n    <button\n      type=\"button\"\n      aria-label={ariaLabel ?? label}\n      aria-hidden={!on}\n      tabIndex={on ? 0 : -1}\n      disabled={!on}\n      onClick={onClick}\n      onMouseEnter={() => setHover(true)}\n      onMouseLeave={() => setHover(false)}\n      onPointerDown={() => setPressed(true)}\n      onPointerUp={release}\n      onPointerLeave={release}\n      onPointerCancel={release}\n      onFocus={focus.onFocus}\n      onBlur={focus.onBlur}\n      style={{\n        ...style,\n        position: \"absolute\",\n        margin: 0,\n        display: \"flex\",\n        alignItems: \"center\",\n        justifyContent: \"center\",\n        border: `1px solid ${HAIRLINE}`,\n        cursor: on ? \"pointer\" : \"default\",\n        outline: \"none\",\n        pointerEvents: on ? \"auto\" : \"none\",\n        opacity: on ? 1 : 0,\n        transform: on ? (pressed ? \"scale(0.92)\" : \"scale(1)\") : \"scale(0.7)\",\n        boxShadow: `${hover && on ? HOVER_ON : HOVER_OFF}, ${focus.focusVisible ? RING : NO_RING}`,\n        transition: `opacity ${on ? \"0.4s ease 0.2s\" : \"0.15s ease\"}, transform ${on ? `0.4s ${EASE} 0.2s` : \"0.15s ease\"}, box-shadow 0.2s ease, background-color 0.25s ease`,\n      }}\n    >\n      {children}\n    </button>\n  );\n}\n\nexport function AIDynamicIsland01(props: AIDynamicIsland01Props) {\n  const {\n    status = \"auto\",\n    interactive = true,\n    loop = false,\n    stageSeconds = 2.6,\n    stepSeconds = 1.7,\n    idleText = \"Ask AI\",\n    listeningText = \"Listening\",\n    thinkingText = \"Thinking\",\n    workingText = \"Working on it\",\n    doneText = \"Ready\",\n    viewLabel = \"View\",\n    steps = DEFAULT_STEPS,\n    align = \"top\",\n    expandedWidth = 300,\n    orbSize = 0.62,\n    particleSize = 1,\n    curves = 3,\n    curveWidth = 1,\n    curveAmp = 1,\n    curveColor = \"#FFFFFF\",\n    dotColor = \"#FFFFFF\",\n    accentColor = \"#9DB8FF\",\n    accentAmount = 0.35,\n    font = { fontSize: 15, lineHeight: 1.2 },\n    textColor = \"#EDEDED\",\n    mutedColor = \"#6B6B6B\",\n    listenColors = DEFAULT_LISTEN,\n    thinkColors = DEFAULT_THINK,\n    doneColors = DEFAULT_DONE,\n    ringIntensity = 0.6,\n    ringSize = 10,\n    ringSpeed = 40,\n    background = \"#0E0E10\",\n    borderColor = \"rgba(255,255,255,0.09)\",\n    radius = 28,\n    padding = 8,\n    gap = 10,\n    onStart,\n    onStop,\n    onView,\n    onComplete,\n    className,\n    style,\n  } = props;\n\n  const rootRef = React.useRef<HTMLDivElement>(null);\n  const canvasRef = React.useRef<HTMLCanvasElement>(null);\n  const measRef = React.useRef<HTMLDivElement>(null);\n  const measEls = React.useRef<Record<string, HTMLSpanElement | null>>({});\n  const textEls = React.useRef<(HTMLSpanElement | null)[]>([]);\n  const spinEls = React.useRef<(HTMLDivElement | null)[]>([]);\n  const ringEls = React.useRef<(HTMLDivElement | null)[]>([]);\n  const isVisibleRef = React.useRef(true);\n  const runRef = React.useRef(false);\n  const stageTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n  const stepIntervalRef = React.useRef<ReturnType<typeof setInterval> | null>(null);\n  const stepDoneTimerRef = React.useRef<ReturnType<typeof setTimeout> | null>(null);\n  const rafRef = React.useRef(0);\n  const prevMode = React.useRef<Mode>(status === \"auto\" ? \"idle\" : status);\n\n  const stepList = React.useMemo(() => cleanList(steps, DEFAULT_STEPS).slice(0, 6), [steps]);\n  const n = stepList.length;\n  const listenList = React.useMemo(() => cleanList(listenColors, DEFAULT_LISTEN), [listenColors]);\n  const thinkList = React.useMemo(() => cleanList(thinkColors, DEFAULT_THINK), [thinkColors]);\n  const doneList = React.useMemo(() => cleanList(doneColors, DEFAULT_DONE), [doneColors]);\n  const listenGradient = React.useMemo(() => buildGradient(listenList, 0.55), [listenList]);\n  const thinkGradient = React.useMemo(() => buildGradient(thinkList, 0.55), [thinkList]);\n  const doneGradient = React.useMemo(() => buildGradient(doneList, 0.55), [doneList]);\n  const listenRgb = React.useMemo(() => listenList.map((c) => parseRgb(c, [124, 243, 255])), [listenList]);\n  const thinkRgb = React.useMemo(() => thinkList.map((c) => parseRgb(c, [155, 123, 255])), [thinkList]);\n  const doneRgb = React.useMemo(() => doneList.map((c) => parseRgb(c, [124, 255, 196])), [doneList]);\n  const coreRgb = React.useMemo(() => parseRgb(curveColor, [255, 255, 255]), [curveColor]);\n  const baseRgb = React.useMemo(() => parseRgb(dotColor, [255, 255, 255]), [dotColor]);\n  const accentRgb = React.useMemo(() => parseRgb(accentColor, [157, 184, 255]), [accentColor]);\n  const orb = React.useMemo(() => makeOrb(POINTS), []);\n  const curveCount = Math.max(1, Math.min(4, Math.round(curves)));\n  const pad = Math.max(0, padding);\n  const gapPx = Math.max(0, gap);\n  const hasView = viewLabel.trim() !== \"\";\n\n  const [flow, setFlow] = React.useState<Mode>(status === \"auto\" ? \"idle\" : status);\n  const [run, setRun] = React.useState(status === \"auto\");\n  const [stepIdx, setStepIdx] = React.useState(0);\n  const [armed, setArmed] = React.useState(false);\n  const [hover, setHover] = React.useState(false);\n  const [pressed, setPressed] = React.useState(false);\n  const focus = useFocusVisible();\n  const reduce = React.useSyncExternalStore(subscribeReducedMotion, getReducedMotionSnapshot, getReducedMotionServerSnapshot);\n\n  const mode: Mode = flow;\n  const shownStep = stepIdx;\n  const morph = !reduce && armed;\n  const running = RUNNING.indexOf(mode) >= 0;\n  const idleAction = mode === \"idle\" && interactive;\n\n  // Prop-driven resets, done during render rather than in an effect: no DOM\n  // work is needed, just adjusting local state to match a changed input.\n  const [prevStatus, setPrevStatus] = React.useState(status);\n  if (prevStatus !== status) {\n    setPrevStatus(status);\n    setFlow(status === \"auto\" ? \"idle\" : status);\n    setRun(status === \"auto\");\n  }\n  const stepResetKey = `${flow}|${n}|${stepSeconds}`;\n  const [prevStepResetKey, setPrevStepResetKey] = React.useState(stepResetKey);\n  if (prevStepResetKey !== stepResetKey) {\n    setPrevStepResetKey(stepResetKey);\n    setStepIdx(0);\n  }\n  const [prevIdleAction, setPrevIdleAction] = React.useState(idleAction);\n  if (prevIdleAction !== idleAction) {\n    setPrevIdleAction(idleAction);\n    if (!idleAction) focus.onBlur();\n  }\n\n  const fontPx = React.useMemo(() => {\n    const fs = font && (font as React.CSSProperties).fontSize;\n    const v = typeof fs === \"number\" ? fs : parseFloat(String(fs));\n    return Number.isFinite(v) && v > 0 ? v : 15;\n  }, [font]);\n  const texts: Record<Mode, string> = {\n    idle: idleText,\n    listening: listeningText,\n    thinking: thinkingText,\n    working: workingText,\n    done: doneText,\n  };\n  const estSizes = (): Sizes => ({\n    label: {\n      idle: estimate(idleText, fontPx),\n      listening: estimate(listeningText, fontPx),\n      thinking: estimate(thinkingText, fontPx),\n      working: estimate(workingText, fontPx),\n      done: estimate(doneText, fontPx),\n    },\n    step: Math.max(0, ...stepList.map((s) => estimate(s, fontPx))),\n    view: estimate(viewLabel, fontPx) + 16 + 13 + 6 + 16,\n  });\n  const [sizes, setSizes] = React.useState<Sizes>(estSizes);\n\n  const liveRef = React.useRef<Live>({\n    mode,\n    time: STATIC_TIME,\n    spinT: STATIC_TIME,\n    spin: 0.35,\n    wave: 0.6,\n    rot: 0.8,\n    level: 0.3,\n    curveA: RUNNING.indexOf(mode) >= 0 ? 1 : 0,\n    bands: new Float32Array(BANDS),\n    target: new Float32Array(BANDS),\n    pal: sample3(thinkRgb),\n    angle: START_ANGLE,\n    ringSpeed,\n    orbR: (LEAD / 2) * orbSize,\n    dot: particleSize,\n    curves: curveCount,\n    thick: curveWidth,\n    amp: curveAmp,\n    core: coreRgb,\n    base: baseRgb,\n    accent: accentRgb,\n    accentAmount,\n    listen: listenRgb,\n    think: thinkRgb,\n    done: doneRgb,\n    still: false,\n    drawnMode: null,\n  });\n  React.useLayoutEffect(() => {\n    runRef.current = run;\n    const live = liveRef.current;\n    live.mode = mode;\n    live.ringSpeed = ringSpeed;\n    live.orbR = (LEAD / 2) * Math.max(0.3, Math.min(1, orbSize));\n    live.dot = particleSize;\n    live.curves = curveCount;\n    live.thick = curveWidth;\n    live.amp = curveAmp;\n    live.core = coreRgb;\n    live.base = baseRgb;\n    live.accent = accentRgb;\n    live.accentAmount = accentAmount;\n    live.listen = listenRgb;\n    live.think = thinkRgb;\n    live.done = doneRgb;\n    live.still = reduce;\n  });\n\n  React.useEffect(() => {\n    if (!run) return;\n    let next: Mode | null = null;\n    if (flow === \"idle\") next = \"listening\";\n    else if (flow === \"listening\") next = \"thinking\";\n    else if (flow === \"thinking\") next = \"working\";\n    else if (flow === \"done\") next = \"idle\";\n    if (!next) return;\n    const to = next;\n    if (stageTimerRef.current) clearTimeout(stageTimerRef.current);\n    stageTimerRef.current = setTimeout(\n      () => {\n        setFlow(to);\n        if (flow === \"done\" && !(status === \"auto\" && loop)) setRun(false);\n      },\n      Math.max(0.6, stageSeconds) * 1000,\n    );\n    return () => {\n      if (stageTimerRef.current) clearTimeout(stageTimerRef.current);\n    };\n  }, [run, flow, stageSeconds, status, loop]);\n\n  React.useEffect(() => {\n    if (flow !== \"working\") return;\n    let i = 0;\n    if (stepIntervalRef.current) clearInterval(stepIntervalRef.current);\n    if (stepDoneTimerRef.current) clearTimeout(stepDoneTimerRef.current);\n    stepIntervalRef.current = setInterval(\n      () => {\n        if (!isVisibleRef.current || i >= n) return;\n        i += 1;\n        if (i >= n && !runRef.current) {\n          if (stepIntervalRef.current) clearInterval(stepIntervalRef.current);\n          return;\n        }\n        setStepIdx(i);\n        if (i >= n) {\n          if (stepIntervalRef.current) clearInterval(stepIntervalRef.current);\n          stepDoneTimerRef.current = setTimeout(() => setFlow(\"done\"), 700);\n        }\n      },\n      Math.max(0.4, stepSeconds) * 1000,\n    );\n    return () => {\n      if (stepIntervalRef.current) clearInterval(stepIntervalRef.current);\n      if (stepDoneTimerRef.current) clearTimeout(stepDoneTimerRef.current);\n    };\n  }, [flow, n, stepSeconds]);\n\n  React.useEffect(() => {\n    const prev = prevMode.current;\n    prevMode.current = mode;\n    if (prev === \"idle\" && RUNNING.indexOf(mode) >= 0) onStart?.();\n    else if (RUNNING.indexOf(prev) >= 0 && mode === \"idle\") onStop?.();\n    if (mode === \"done\" && prev !== \"done\") onComplete?.();\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [mode]);\n\n  React.useEffect(() => {\n    const el = rootRef.current;\n    if (!el) return;\n    const io = new IntersectionObserver(\n      ([entry]) => {\n        isVisibleRef.current = entry.isIntersecting;\n      },\n      { threshold: 0 },\n    );\n    io.observe(el);\n    return () => io.disconnect();\n  }, []);\n\n  const measureKey = `${idleText}|${listeningText}|${thinkingText}|${workingText}|${doneText}|${viewLabel}|${stepList.join(\"|\")}|${JSON.stringify(font)}`;\n  React.useEffect(() => {\n    const el = measRef.current;\n    if (!el) return;\n    const w = (k: string) => {\n      const node = measEls.current[k];\n      return node ? node.offsetWidth + 1 : 0;\n    };\n    const measure = () => {\n      const next: Sizes = {\n        label: {\n          idle: w(\"idle\"),\n          listening: w(\"listening\"),\n          thinking: w(\"thinking\"),\n          working: w(\"working\"),\n          done: w(\"done\"),\n        },\n        step: Math.max(0, ...stepList.map((_, i) => w(`step${i}`))),\n        view: w(\"view\") + 16 + 13 + 6 + 16,\n      };\n      setSizes((prev) => {\n        const same = prev.step === next.step && prev.view === next.view && MODES.every((m) => prev.label[m] === next.label[m]);\n        return same ? prev : next;\n      });\n    };\n    measure();\n    const arm = requestAnimationFrame(() => setArmed(true));\n    let ro: ResizeObserver | null = null;\n    if (typeof ResizeObserver === \"function\") {\n      ro = new ResizeObserver(measure);\n      ro.observe(el);\n    }\n    return () => {\n      cancelAnimationFrame(arm);\n      if (ro) ro.disconnect();\n    };\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [measureKey]);\n\n  React.useEffect(() => {\n    const root = rootRef.current;\n    const canvas = canvasRef.current;\n    const ctx = canvas ? canvas.getContext(\"2d\") : null;\n    if (!root) return;\n\n    let last = performance.now();\n    let w = 0;\n    let h = 0;\n\n    const fit = () => {\n      if (!canvas || !ctx) return;\n      const dpr = Math.min(window.devicePixelRatio || 1, 2);\n      w = CANVAS;\n      h = CANVAS;\n      canvas.width = Math.round(w * dpr);\n      canvas.height = Math.round(h * dpr);\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    };\n    const draw = () => {\n      if (!ctx) return;\n      drawLead(ctx, w, h, liveRef.current, orb);\n    };\n    const updateDom = (L: Live) => {\n      const t = L.time;\n      const pos = (100 - 100 * ((t / 2.4) % 1)).toFixed(2);\n      for (const node of textEls.current) if (node) node.style.backgroundPosition = `${pos}% 50%`;\n      const pulse = (0.55 + 0.3 * Math.sin(t * 2.2)).toFixed(3);\n      for (const node of ringEls.current) if (node) node.style.opacity = pulse;\n      const deg = `rotate(${((t * 300) % 360).toFixed(1)}deg)`;\n      for (const node of spinEls.current) if (node) node.style.transform = deg;\n    };\n\n    fit();\n    if (reduce) root.style.setProperty(\"--gl-angle\", `${START_ANGLE}deg`);\n\n    const frame = (now: number) => {\n      const dt = Math.min((now - last) / 1000, 0.05);\n      last = now;\n      if (isVisibleRef.current) {\n        const L = liveRef.current;\n        if (L.still) {\n          if (L.drawnMode !== L.mode) {\n            simulateBands(STATIC_TIME, L.mode, L.target);\n            L.bands.set(L.target);\n            L.curveA = RUNNING.indexOf(L.mode) >= 0 ? 1 : 0;\n            const want = sample3(L.mode === \"listening\" ? L.listen : L.mode === \"done\" ? L.done : L.think);\n            for (let k = 0; k < 3; k++) L.pal[k] = want[k];\n            L.time = STATIC_TIME;\n            L.spinT = STATIC_TIME;\n            draw();\n            updateDom(L);\n            L.drawnMode = L.mode;\n          }\n        } else {\n          L.time += dt;\n          L.angle = (L.angle + L.ringSpeed * dt) % 360;\n          updateEnergy(L, dt);\n          root.style.setProperty(\"--gl-angle\", `${L.angle.toFixed(2)}deg`);\n          draw();\n          updateDom(L);\n          L.drawnMode = L.mode;\n        }\n      }\n      rafRef.current = requestAnimationFrame(frame);\n    };\n    rafRef.current = requestAnimationFrame(frame);\n\n    return () => cancelAnimationFrame(rafRef.current);\n  }, [reduce, orb]);\n\n  const handleStart = () => {\n    if (!interactive) return;\n    setRun(true);\n    setFlow(\"listening\");\n  };\n  const handleStop = () => {\n    if (!interactive) return;\n    setRun(false);\n    setFlow(\"idle\");\n  };\n  const handleView = () => {\n    if (!interactive) return;\n    onView?.();\n    setFlow(\"idle\");\n  };\n  const onKey = (e: React.KeyboardEvent<HTMLDivElement>) => {\n    if (e.key === \"Escape\" && running && interactive) {\n      e.preventDefault();\n      handleStop();\n    }\n  };\n\n  const typography: React.CSSProperties = {\n    fontFamily: FONT_FALLBACK,\n    fontWeight: 500,\n    lineHeight: 1.2,\n    ...font,\n    margin: 0,\n  };\n  const geo = geometry(mode, sizes, pad, gapPx, expandedWidth, n, interactive, hasView);\n  const shimmerGradient = `linear-gradient(90deg, ${mutedColor} 0%, ${mutedColor} 32%, ${textColor} 50%, ${mutedColor} 68%, ${mutedColor} 100%)`;\n  const softRing = Math.max(2, Math.min(12, ringSize * 0.45));\n  const softBlur = ringSize * 0.7;\n  const doneAccent = doneList[0];\n  const currentStepLabel = stepList[Math.min(shownStep, n - 1)] || \"\";\n  const statusCopy =\n    mode === \"working\"\n      ? `AI assistant status: working. ${workingText}. Current step: ${currentStepLabel}.`\n      : `AI assistant status: ${mode}. ${texts[mode]}.`;\n\n  const shimmerStyle: React.CSSProperties = {\n    ...typography,\n    display: \"block\",\n    whiteSpace: \"nowrap\",\n    color: \"transparent\",\n    backgroundImage: shimmerGradient,\n    backgroundSize: \"300% 100%\",\n    backgroundPosition: `${STATIC_SHIMMER}% 50%`,\n    WebkitBackgroundClip: \"text\",\n    backgroundClip: \"text\",\n    WebkitTextFillColor: \"transparent\",\n  };\n  const plainStyle: React.CSSProperties = {\n    ...typography,\n    display: \"block\",\n    whiteSpace: \"nowrap\",\n    color: textColor,\n  };\n\n  const ringLayer = (idx: number, active: boolean, gradient: string, intensity: number) => (\n    <div\n      aria-hidden=\"true\"\n      style={{\n        position: \"absolute\",\n        inset: 0,\n        borderRadius: \"inherit\",\n        pointerEvents: \"none\",\n        opacity: active ? intensity : 0,\n        transition: \"opacity 0.6s ease\",\n      }}\n    >\n      <div\n        ref={(el) => {\n          ringEls.current[idx] = el;\n        }}\n        style={{ position: \"absolute\", inset: 0, borderRadius: \"inherit\", opacity: 0.6 }}\n      >\n        <div style={{ position: \"absolute\", inset: 0, borderRadius: \"inherit\", filter: `blur(${softBlur}px)` }}>\n          <div style={{ ...ringStyle(softRing), background: gradient }} />\n        </div>\n        <div style={{ ...ringStyle(1.2), background: gradient }} />\n      </div>\n    </div>\n  );\n\n  const labelNode = (\n    <div\n      aria-hidden=\"true\"\n      style={{\n        position: \"relative\",\n        flex: 1,\n        minWidth: 0,\n        height: LEAD,\n        overflow: \"hidden\",\n        marginRight: geo.action ? gapPx + geo.action : 0,\n        transition: morph ? `margin-right ${MORPH}` : \"none\",\n      }}\n    >\n      {MODES.map((m, i) => {\n        const on = m === mode;\n        const shimmer = m === \"listening\" || m === \"thinking\" || m === \"working\";\n        return (\n          <div\n            key={m}\n            style={{\n              position: \"absolute\",\n              left: 0,\n              top: \"50%\",\n              opacity: on ? 1 : 0,\n              transform: `translateY(calc(-50% + ${on ? 0 : 6}px))`,\n              transition: on\n                ? `opacity 0.4s ease 0.18s, transform 0.4s ${EASE} 0.18s`\n                : \"opacity 0.16s ease, transform 0.16s ease\",\n            }}\n          >\n            <span\n              ref={(el) => {\n                textEls.current[i] = shimmer ? el : null;\n              }}\n              style={shimmer ? shimmerStyle : plainStyle}\n            >\n              {texts[m]}\n            </span>\n          </div>\n        );\n      })}\n    </div>\n  );\n\n  const leadNode = (\n    <div style={{ position: \"relative\", flex: \"none\", width: LEAD, height: LEAD }}>\n      <div\n        aria-hidden=\"true\"\n        style={{\n          position: \"absolute\",\n          left: (LEAD - CANVAS) / 2,\n          top: (LEAD - CANVAS) / 2,\n          width: CANVAS,\n          height: CANVAS,\n          opacity: mode === \"done\" ? 0 : 1,\n          transform: mode === \"done\" ? \"scale(0.6)\" : \"scale(1)\",\n          transition: `opacity 0.3s ease, transform 0.4s ${EASE}`,\n        }}\n      >\n        <canvas\n          ref={canvasRef}\n          style={{ position: \"absolute\", inset: 0, width: CANVAS, height: CANVAS, display: \"block\" }}\n          aria-hidden=\"true\"\n        />\n      </div>\n      <div\n        aria-hidden=\"true\"\n        style={{\n          position: \"absolute\",\n          left: 4,\n          top: 4,\n          width: LEAD - 8,\n          height: LEAD - 8,\n          borderRadius: \"50%\",\n          display: \"flex\",\n          alignItems: \"center\",\n          justifyContent: \"center\",\n          color: doneAccent,\n          background: \"rgba(255,255,255,0.07)\",\n          border: `1px solid ${HAIRLINE}`,\n          boxShadow: `0 0 14px rgba(${parseRgb(doneAccent, [124, 255, 196]).join(\",\")},0.28)`,\n          opacity: mode === \"done\" ? 1 : 0,\n          transform: mode === \"done\" ? \"scale(1)\" : \"scale(0.5)\",\n          transition: `opacity 0.3s ease 0.15s, transform 0.5s cubic-bezier(0.3, 1.4, 0.5, 1) 0.15s`,\n        }}\n      >\n        <CheckMark size={18} stroke={2.6} />\n      </div>\n    </div>\n  );\n\n  const stepsNode = (\n    <div\n      aria-hidden=\"true\"\n      style={{\n        position: \"absolute\",\n        left: 0,\n        right: 0,\n        top: LEAD + pad * 2 + LIST_TOP,\n        pointerEvents: \"none\",\n      }}\n    >\n      {stepList.map((text, i) => {\n        const on = mode === \"working\";\n        const state = i < shownStep ? \"done\" : i === shownStep ? \"active\" : \"pending\";\n        const inset = pad + (LEAD - ICON) / 2;\n        return (\n          <div\n            key={i}\n            style={{\n              display: \"flex\",\n              alignItems: \"center\",\n              gap: 10,\n              height: ROW,\n              padding: `0 ${inset}px`,\n              boxSizing: \"border-box\",\n              opacity: on ? 1 : 0,\n              transform: on ? \"translateY(0px)\" : \"translateY(-8px)\",\n              transition: on\n                ? `opacity 0.4s ease ${(0.22 + i * 0.06).toFixed(2)}s, transform 0.45s ${EASE} ${(0.22 + i * 0.06).toFixed(2)}s`\n                : \"opacity 0.14s ease, transform 0.14s ease\",\n            }}\n          >\n            <div style={{ position: \"relative\", flex: \"none\", width: ICON, height: ICON }}>\n              <div\n                style={{\n                  position: \"absolute\",\n                  inset: 0,\n                  borderRadius: \"50%\",\n                  display: \"flex\",\n                  alignItems: \"center\",\n                  justifyContent: \"center\",\n                  color: textColor,\n                  background: \"rgba(255,255,255,0.10)\",\n                  opacity: state === \"done\" ? 1 : 0,\n                  transform: state === \"done\" ? \"scale(1)\" : \"scale(0.5)\",\n                  transition: \"opacity 0.25s ease, transform 0.4s cubic-bezier(0.3, 1.4, 0.5, 1)\",\n                }}\n              >\n                <CheckMark size={11} stroke={3} />\n              </div>\n\n              <div\n                ref={(el) => {\n                  spinEls.current[i] = el;\n                }}\n                style={{ position: \"absolute\", inset: 0, opacity: state === \"active\" ? 1 : 0, transition: \"opacity 0.2s ease\" }}\n              >\n                <svg width={ICON} height={ICON} viewBox=\"0 0 18 18\" aria-hidden=\"true\" focusable=\"false\" style={{ display: \"block\" }}>\n                  <circle cx=\"9\" cy=\"9\" r=\"7\" fill=\"none\" stroke=\"rgba(255,255,255,0.14)\" strokeWidth=\"1.6\" />\n                  <path d=\"M9 2a7 7 0 0 1 7 7\" fill=\"none\" stroke={textColor} strokeWidth=\"1.8\" strokeLinecap=\"round\" />\n                </svg>\n              </div>\n              <div\n                style={{\n                  position: \"absolute\",\n                  left: ICON / 2 - 3,\n                  top: ICON / 2 - 3,\n                  width: 6,\n                  height: 6,\n                  borderRadius: \"50%\",\n                  background: mutedColor,\n                  opacity: state === \"pending\" ? 0.55 : 0,\n                  transition: \"opacity 0.25s ease\",\n                }}\n              />\n            </div>\n            <span\n              ref={(el) => {\n                textEls.current[MODES.length + i] = state === \"active\" ? el : null;\n              }}\n              style={{\n                ...(state === \"active\" ? shimmerStyle : plainStyle),\n                minWidth: 0,\n                overflow: \"hidden\",\n                textOverflow: \"ellipsis\",\n                color: state === \"active\" ? \"transparent\" : mutedColor,\n                opacity: state === \"pending\" ? 0.6 : 1,\n                transition: \"opacity 0.3s ease\",\n              }}\n            >\n              {text}\n            </span>\n          </div>\n        );\n      })}\n    </div>\n  );\n\n  const alignItems = align === \"top\" ? \"flex-start\" : align === \"bottom\" ? \"flex-end\" : \"center\";\n\n  return (\n    <div\n      ref={rootRef}\n      role=\"group\"\n      aria-label=\"AI assistant dynamic island status\"\n      onKeyDown={onKey}\n      className={cn(\"relative box-border h-full w-full\", className)}\n      style={{ ...style, display: \"flex\", justifyContent: \"center\", alignItems }}\n    >\n      <p role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" style={SR_ONLY}>\n        {statusCopy}\n      </p>\n\n      <div\n        ref={measRef}\n        aria-hidden=\"true\"\n        style={{ position: \"absolute\", left: 0, top: 0, height: 0, overflow: \"hidden\", visibility: \"hidden\", pointerEvents: \"none\" }}\n      >\n        {MODES.map((m) => (\n          <span\n            key={m}\n            ref={(el) => {\n              measEls.current[m] = el;\n            }}\n            style={{ ...typography, display: \"block\", width: \"max-content\", whiteSpace: \"nowrap\" }}\n          >\n            {texts[m]}\n          </span>\n        ))}\n        <span\n          ref={(el) => {\n            measEls.current.view = el;\n          }}\n          style={{ ...typography, display: \"block\", width: \"max-content\", whiteSpace: \"nowrap\" }}\n        >\n          {viewLabel}\n        </span>\n        {stepList.map((text, i) => (\n          <span\n            key={i}\n            ref={(el) => {\n              measEls.current[`step${i}`] = el;\n            }}\n            style={{ ...typography, display: \"block\", width: \"max-content\", whiteSpace: \"nowrap\" }}\n          >\n            {text}\n          </span>\n        ))}\n      </div>\n\n      <div\n        onMouseEnter={() => setHover(true)}\n        onMouseLeave={() => {\n          setHover(false);\n          setPressed(false);\n        }}\n        style={{\n          position: \"relative\",\n          flex: \"none\",\n          boxSizing: \"border-box\",\n          width: geo.w,\n          maxWidth: \"100%\",\n          height: geo.h,\n          overflow: \"hidden\",\n          borderRadius: radius,\n          background,\n          backgroundImage: SHEEN,\n          backdropFilter: \"blur(14px)\",\n          WebkitBackdropFilter: \"blur(14px)\",\n          transform: idleAction && pressed ? \"scale(0.97)\" : idleAction && hover ? \"scale(1.03)\" : \"scale(1)\",\n          boxShadow: [\n            idleAction && hover ? HOVER_ON : HOVER_OFF,\n            `inset 0 0 0 1px ${borderColor}`,\n            \"inset 0 1px 0 rgba(255,255,255,0.12)\",\n            focus.focusVisible ? RING : NO_RING,\n          ].join(\", \"),\n          transition: morph\n            ? `width ${MORPH}, height ${MORPH}, transform 0.25s ${EASE}, box-shadow 0.25s ease`\n            : `transform 0.25s ${EASE}, box-shadow 0.25s ease`,\n        }}\n      >\n        {ringLayer(0, mode === \"listening\", listenGradient, ringIntensity)}\n        {ringLayer(1, mode === \"thinking\" || mode === \"working\", thinkGradient, ringIntensity)}\n        {ringLayer(2, mode === \"done\", doneGradient, ringIntensity * 0.55)}\n\n        <div\n          style={{\n            position: \"absolute\",\n            left: 0,\n            right: 0,\n            top: 0,\n            height: LEAD + pad * 2,\n            display: \"flex\",\n            alignItems: \"center\",\n            padding: `0 0 0 ${pad}px`,\n            gap: gapPx,\n            boxSizing: \"border-box\",\n          }}\n        >\n          {leadNode}\n          {labelNode}\n          {interactive && (\n            <>\n              <ActionButton\n                label=\"Stop\"\n                ariaLabel=\"Stop AI assistant\"\n                on={running}\n                onClick={handleStop}\n                style={{\n                  right: pad,\n                  top: pad,\n                  width: STOP,\n                  height: STOP,\n                  padding: 0,\n                  borderRadius: \"50%\",\n                  background: textColor,\n                  color: \"#0E0E10\",\n                }}\n              >\n                <StopIcon />\n              </ActionButton>\n              {hasView && (\n                <ActionButton\n                  label={viewLabel}\n                  ariaLabel={`${viewLabel} AI result`}\n                  on={mode === \"done\"}\n                  onClick={handleView}\n                  style={{\n                    right: pad,\n                    top: pad + (STOP - 36) / 2,\n                    height: 36,\n                    padding: \"0 16px\",\n                    gap: 6,\n                    borderRadius: 999,\n                    background: textColor,\n                    color: \"#0E0E10\",\n                    ...typography,\n                    fontWeight: 600,\n                    whiteSpace: \"nowrap\",\n                  }}\n                >\n                  {viewLabel}\n                  <ArrowIcon />\n                </ActionButton>\n              )}\n            </>\n          )}\n        </div>\n\n        {stepsNode}\n\n        {idleAction && (\n          <button\n            type=\"button\"\n            aria-label={idleText}\n            onClick={handleStart}\n            onPointerDown={() => setPressed(true)}\n            onPointerUp={() => setPressed(false)}\n            onPointerCancel={() => setPressed(false)}\n            onFocus={focus.onFocus}\n            onBlur={focus.onBlur}\n            style={{\n              position: \"absolute\",\n              inset: 0,\n              zIndex: 2,\n              margin: 0,\n              padding: 0,\n              border: \"none\",\n              borderRadius: \"inherit\",\n              background: \"transparent\",\n              cursor: \"pointer\",\n              outline: \"none\",\n            }}\n          />\n        )}\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}