{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "command-palette",
  "type": "registry:component",
  "title": "Command Palette with Argument Chips",
  "description": "Commands that take inline argument chips, fuzzy ranking, and a measured height morph.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "https://lab.moumen.dev/r/lab-theme.json"
  ],
  "files": [
    {
      "path": "registry/lab/command-palette/command-palette.tsx",
      "type": "registry:component",
      "target": "@components/lab/command-palette.tsx",
      "content": "\"use client\";\n\nimport { Fragment, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, type ReactNode } from \"react\";\nimport { MotionConfig, motion, useReducedMotion } from \"motion/react\";\n\n// Command palette with argument chips - Linear-style multi-step commands inside\n// a single input.\n//\n// The hard problem is focus choreography. A command like \"Assign to [person]\n// with priority [level]\" is really a tiny form; the obvious build gives each\n// picked value its own focusable element - then Tab order, Backspace and\n// screen-reader context all fracture mid-command. Here the palette has exactly\n// ONE focusable control, the text input, for its whole life:\n//\n//   · Picking a command collapses it into a CHIP painted before the input (the\n//     chip is render output, not a field). The list slides to that command's\n//     first argument slot and the same input now filters the options.\n//   · Filling a command's last slot STAGES it as a clause instead of running\n//     it - the list slides back to the remaining commands joined by an \"and\",\n//     so one session builds a compound. Nothing runs until ✓ Apply (⌘⏎);\n//     ✕ discards the whole stack.\n//   · Backspace on an empty query POPS the last chip - across the \"and\" too.\n//     Chips never join the tab order but ARE clickable: clicking one rewinds\n//     to that slot; the tail dims to preview the rewind scope.\n//\n// Matching is a fuzzy subsequence (\"mvp\" finds \"Move to project\") scored with\n// word-start + adjacency bonuses minus a gap penalty, matched letters\n// underlined in place. The list body's height is a measured px that motion\n// eases between filter states and view swaps; pushes slide in from the right,\n// pops from the left; chips grow in and pop instantly (Backspace must feel\n// immediate). Pass your own `commands` and handle `onApply`.\n//\n// Animation via motion/react; honours prefers-reduced-motion. Requires the\n// lab-theme tokens. Fully Tailwind, no CSS files.\n\nconst EASE = [0.22, 1, 0.36, 1] as const;\nconst EASE_ICON = [0.2, 0, 0, 1] as const;\nconst SLIDE = 28; // 1.75rem directional slide\n\nexport interface CommandOption {\n  value: string;\n  hint?: string;\n  dot?: string;\n}\nexport interface CommandSlot {\n  name: string;\n  prompt: string;\n  kind: \"person\" | \"dot\" | \"plain\";\n  options: CommandOption[];\n}\nexport interface Command {\n  id: string;\n  label: string;\n  icon?: ReactNode;\n  shortcut?: string;\n  danger?: boolean;\n  slots: CommandSlot[];\n  message: (values: CommandOption[]) => string;\n}\n\nexport interface CommandPaletteState {\n  mode: string;\n  depth: number;\n  staged: number;\n  query: string;\n  matches: number;\n  chips: string[];\n  height: number | null;\n  lastRun: string | null;\n}\n\n// ── Matching ───────────────────────────────────────────────────────────\nfunction scan(query: string, hay: string, boundaryFirst: boolean) {\n  const idx: number[] = [];\n  let pos = 0;\n  let score = 0;\n  let prev = -2;\n  for (const ch of query) {\n    let at = -1;\n    if (boundaryFirst) {\n      for (let i = pos; i < hay.length; i += 1) {\n        if (hay[i] === ch && (i === 0 || hay[i - 1] === \" \")) {\n          at = i;\n          break;\n        }\n      }\n    }\n    if (at === -1) at = hay.indexOf(ch, pos);\n    if (at === -1) return null;\n    if (at === 0 || hay[at - 1] === \" \") score += 10;\n    else score += 4;\n    if (at === prev + 1) score += 8;\n    score -= Math.min(6, at - pos);\n    idx.push(at);\n    prev = at;\n    pos = at + 1;\n  }\n  return { score, idx };\n}\n\nfunction fuzzyMatch(query: string, text: string) {\n  const q = query.toLowerCase().replace(/\\s+/g, \"\");\n  if (!q) return { score: 0, idx: [] };\n  const hay = text.toLowerCase();\n  const a = scan(q, hay, true);\n  const b = scan(q, hay, false);\n  if (!a) return b;\n  if (!b) return a;\n  return a.score >= b.score ? a : b;\n}\n\nfunction substringMatch(query: string, text: string) {\n  const q = query.trim().toLowerCase();\n  if (!q) return { score: 0, idx: [] };\n  const at = text.toLowerCase().indexOf(q);\n  if (at === -1) return null;\n  return { score: 100 - at, idx: Array.from({ length: q.length }, (_, i) => at + i) };\n}\n\n// Underline the matched letters where they sit - consecutive indices merge.\nfunction Highlight({ text, idx }: { text: string; idx: number[] }) {\n  if (!idx || idx.length === 0) return <>{text}</>;\n  const set = new Set(idx);\n  const out: ReactNode[] = [];\n  let run = \"\";\n  let marked = set.has(0);\n  for (let i = 0; i <= text.length; i += 1) {\n    const now = i < text.length && set.has(i);\n    if (i === text.length || now !== marked) {\n      if (run)\n        out.push(\n          marked ? (\n            <span key={`m${i}`} className=\"text-foreground underline decoration-muted-foreground/70 decoration-1 underline-offset-[3px] group-data-[danger=true]/opt:group-data-[active=true]/opt:text-inherit\">\n              {run}\n            </span>\n          ) : (\n            <Fragment key={`t${i}`}>{run}</Fragment>\n          ),\n        );\n      run = \"\";\n      marked = now;\n    }\n    if (i < text.length) run += text[i];\n  }\n  return <>{out}</>;\n}\n\nfunction initials(name: string) {\n  return name.split(\" \").map((w) => w[0]).slice(0, 2).join(\"\").toUpperCase();\n}\n\ninterface Clause {\n  command: Command;\n  values: CommandOption[];\n}\ninterface Row {\n  item: CommandOption | Command;\n  idx: number[];\n  score: number;\n  order: number;\n}\nconst labelOf = (item: CommandOption | Command) => (\"label\" in item ? item.label : item.value);\n\nexport default function CommandPalette({\n  commands,\n  matcher = \"fuzzy\",\n  morph = true,\n  onApply,\n  inspect = false,\n  onStateChange,\n}: {\n  commands: Command[];\n  /** \"fuzzy\" = scored subsequence · \"substring\" = plain indexOf. */\n  matcher?: \"fuzzy\" | \"substring\";\n  morph?: boolean;\n  /** Runs when ✓ Apply / ⌘⏎ commits the staged clauses. */\n  onApply?: (clauses: { command: Command; values: CommandOption[] }[]) => void;\n  inspect?: boolean;\n  onStateChange?: (state: CommandPaletteState) => void;\n}) {\n  const [query, setQuery] = useState(\"\");\n  const [command, setCommand] = useState<Command | null>(null);\n  const [slotIndex, setSlotIndex] = useState(0);\n  const [values, setValues] = useState<CommandOption[]>([]);\n  const [clauses, setClauses] = useState<Clause[]>([]);\n  const [active, setActive] = useState(0);\n  const [bodyH, setBodyH] = useState<number | null>(null);\n  const [leaving, setLeaving] = useState<{ rows: Row[]; ctx: { command: Command | null; slotIndex: number }; dir: number } | null>(null);\n  const [ran, setRan] = useState<{ message: string } | null>(null);\n  const [lastRun, setLastRun] = useState<string | null>(null);\n  const [hoveredChip, setHoveredChip] = useState<number | null>(null);\n\n  const inputRef = useRef<HTMLInputElement>(null);\n  const viewRef = useRef<HTMLDivElement>(null);\n  const listRef = useRef<HTMLUListElement>(null);\n  const leaveTimerRef = useRef<number>(0);\n  const ranTimerRef = useRef<number>(0);\n  const bodyFirstRef = useRef(true);\n  const listboxId = useId();\n  const reduced = useReducedMotion();\n\n  const slot = command ? command.slots[slotIndex] : null;\n  const stagedIds = useMemo(() => new Set(clauses.map((c) => c.command.id)), [clauses]);\n  const items = useMemo<(CommandOption | Command)[]>(\n    () => (slot ? slot.options : commands.filter((cmd) => !stagedIds.has(cmd.id))),\n    [slot, commands, stagedIds],\n  );\n  const viewKey = command ? `${command.id}:${slotIndex}` : \"root\";\n\n  const matches = useMemo<Row[]>(() => {\n    const match = matcher === \"fuzzy\" ? fuzzyMatch : substringMatch;\n    const out: Row[] = [];\n    items.forEach((item, order) => {\n      const hit = match(query, labelOf(item));\n      if (hit) out.push({ item, idx: hit.idx, score: hit.score, order });\n    });\n    out.sort((a, b) => b.score - a.score || a.order - b.order);\n    return out;\n  }, [items, query, matcher]);\n\n  const activeSafe = Math.min(active, Math.max(0, matches.length - 1));\n\n  const chipGroups = [\n    ...clauses.map((clause, index) => ({\n      key: `clause-${index}`,\n      chips: [\n        { key: \"cmd\", label: clause.command.label, kind: \"cmd\" as const, dot: undefined as string | undefined },\n        ...clause.values.map((v, i) => ({ key: `v${i}`, label: v.value, kind: \"val\" as const, dot: v.dot })),\n      ],\n    })),\n    ...(command\n      ? [\n          {\n            key: \"live\",\n            chips: [\n              { key: \"cmd\", label: command.label, kind: \"cmd\" as const, dot: undefined as string | undefined },\n              ...values.map((v, i) => ({ key: `v${i}`, label: v.value, kind: \"val\" as const, dot: v.dot })),\n            ],\n          },\n        ]\n      : []),\n  ];\n  const chips = chipGroups.flatMap((g) => g.chips.map((c) => c.label));\n\n  function shift(dir: number, mutate: () => void) {\n    if (morph && !reduced) {\n      setLeaving({ rows: matches, ctx: { command, slotIndex }, dir });\n      clearTimeout(leaveTimerRef.current);\n      leaveTimerRef.current = window.setTimeout(() => setLeaving(null), 320);\n    }\n    mutate();\n    setQuery(\"\");\n    setActive(0);\n  }\n\n  function stageClause(cmd: Command, vals: CommandOption[]) {\n    shift(1, () => {\n      setClauses((list) => [...list, { command: cmd, values: vals }]);\n      setCommand(null);\n      setSlotIndex(0);\n      setValues([]);\n    });\n  }\n\n  function applyAll() {\n    if (clauses.length === 0 || command) return;\n    const message = clauses.map((c) => c.command.message(c.values)).join(\" · \");\n    onApply?.(clauses.map((c) => ({ command: c.command, values: c.values })));\n    setRan({ message });\n    setLastRun(message);\n    clearTimeout(ranTimerRef.current);\n    ranTimerRef.current = window.setTimeout(() => setRan(null), 1600);\n    setClauses([]);\n    setQuery(\"\");\n    setActive(0);\n  }\n\n  function clearAll() {\n    if (command) {\n      shift(-1, () => {\n        setCommand(null);\n        setSlotIndex(0);\n        setValues([]);\n        setClauses([]);\n      });\n    } else {\n      setClauses([]);\n      setQuery(\"\");\n      setActive(0);\n    }\n  }\n\n  function pick(item: CommandOption | Command) {\n    if (!command) {\n      const cmd = item as Command;\n      if (cmd.slots.length === 0) {\n        stageClause(cmd, []);\n        return;\n      }\n      shift(1, () => {\n        setCommand(cmd);\n        setSlotIndex(0);\n        setValues([]);\n      });\n    } else if (slotIndex + 1 < command.slots.length) {\n      shift(1, () => {\n        setValues((list) => [...list, item as CommandOption]);\n        setSlotIndex(slotIndex + 1);\n      });\n    } else {\n      stageClause(command, [...values, item as CommandOption]);\n    }\n  }\n\n  function popChip() {\n    if (command) {\n      if (slotIndex > 0) {\n        shift(-1, () => {\n          setValues((list) => list.slice(0, -1));\n          setSlotIndex(slotIndex - 1);\n        });\n      } else {\n        shift(-1, () => {\n          setCommand(null);\n          setValues([]);\n        });\n      }\n    } else if (clauses.length > 0) {\n      const last = clauses[clauses.length - 1];\n      if (last.command.slots.length === 0) {\n        setClauses((list) => list.slice(0, -1));\n        setActive(0);\n      } else {\n        shift(-1, () => {\n          setClauses((list) => list.slice(0, -1));\n          setCommand(last.command);\n          setSlotIndex(last.command.slots.length - 1);\n          setValues(last.values.slice(0, -1));\n        });\n      }\n    }\n  }\n\n  function editChip(groupIndex: number, chipIndex: number) {\n    const keep = clauses.slice(0, groupIndex);\n    const isLive = command && groupIndex === clauses.length;\n    const cmd = isLive ? command! : clauses[groupIndex].command;\n    const vals = isLive ? values : clauses[groupIndex].values;\n    if (chipIndex === 0) {\n      if (!command) {\n        setClauses(keep);\n        setQuery(\"\");\n        setActive(0);\n      } else {\n        shift(-1, () => {\n          setClauses(keep);\n          setCommand(null);\n          setSlotIndex(0);\n          setValues([]);\n        });\n      }\n    } else {\n      shift(-1, () => {\n        setClauses(keep);\n        setCommand(cmd);\n        setSlotIndex(chipIndex - 1);\n        setValues(vals.slice(0, chipIndex - 1));\n      });\n    }\n  }\n\n  function handleKeyDown(event: React.KeyboardEvent) {\n    if (event.key === \"ArrowDown\") {\n      event.preventDefault();\n      if (matches.length) setActive((i) => (Math.min(i, matches.length - 1) + 1) % matches.length);\n    } else if (event.key === \"ArrowUp\") {\n      event.preventDefault();\n      if (matches.length) setActive((i) => (Math.min(i, matches.length - 1) - 1 + matches.length) % matches.length);\n    } else if (event.key === \"Enter\") {\n      event.preventDefault();\n      if (event.metaKey || event.ctrlKey) applyAll();\n      else {\n        const hit = matches[activeSafe];\n        if (hit) pick(hit.item);\n      }\n    } else if (event.key === \"Backspace\" && query === \"\" && (command || clauses.length > 0)) {\n      event.preventDefault();\n      popChip();\n    } else if (event.key === \"Escape\") {\n      if (query !== \"\") {\n        event.preventDefault();\n        setQuery(\"\");\n        setActive(0);\n      } else if (command || clauses.length > 0) {\n        event.preventDefault();\n        popChip();\n      }\n    }\n  }\n\n  // The height:auto illusion - measure the live view; motion eases `height`.\n  useLayoutEffect(() => {\n    const view = viewRef.current;\n    if (!view) return undefined;\n    const measure = () => setBodyH(view.offsetHeight);\n    measure();\n    requestAnimationFrame(() => {\n      bodyFirstRef.current = false;\n    });\n    const observer = typeof ResizeObserver !== \"undefined\" ? new ResizeObserver(measure) : null;\n    observer?.observe(view);\n    return () => observer?.disconnect();\n  }, [viewKey, matches.length]);\n\n  // Keep the keyboard selection on screen inside the capped list.\n  useEffect(() => {\n    const list = listRef.current;\n    const node = list?.children[activeSafe] as HTMLElement | undefined;\n    if (!list || !node) return;\n    if (node.offsetTop < list.scrollTop) list.scrollTop = node.offsetTop;\n    else if (node.offsetTop + node.offsetHeight > list.scrollTop + list.clientHeight) {\n      list.scrollTop = node.offsetTop + node.offsetHeight - list.clientHeight;\n    }\n  }, [activeSafe, viewKey]);\n\n  useEffect(\n    () => () => {\n      clearTimeout(leaveTimerRef.current);\n      clearTimeout(ranTimerRef.current);\n    },\n    [],\n  );\n\n  useEffect(() => {\n    onStateChange?.({\n      mode: command ? `${command.label} → ${command.slots[slotIndex].name}` : \"commands\",\n      depth: chips.length,\n      staged: clauses.length,\n      query,\n      matches: matches.length,\n      chips,\n      height: bodyH == null ? null : Math.round(bodyH),\n      lastRun,\n    });\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [command, slotIndex, clauses, query, matches.length, values, bodyH, lastRun, onStateChange]);\n\n  function renderRows(rows: Row[], ctx: { command: Command | null; slotIndex: number }, live: boolean) {\n    if (rows.length === 0) {\n      return query === \"\" ? (\n        <div className=\"flex flex-col items-center gap-1 px-3 py-[1.125rem] text-[0.8125rem] text-muted-foreground/70 text-center\">\n          Everything staged\n          <span className=\"text-[0.6875rem]\">✓ Apply runs it all · Backspace pops a chip</span>\n        </div>\n      ) : (\n        <div className=\"flex flex-col items-center gap-1 px-3 py-[1.125rem] text-[0.8125rem] text-muted-foreground/70 text-center\">\n          No matches for <span className=\"text-muted-foreground\">&ldquo;{query}&rdquo;</span>\n          <span className=\"text-[0.6875rem]\">Esc clears{ctx.command || clauses.length > 0 ? \" · Backspace pops a chip\" : \"\"}</span>\n        </div>\n      );\n    }\n    const kind = ctx.command ? ctx.command.slots[ctx.slotIndex].kind : \"command\";\n    return (\n      <ul\n        role={live ? \"listbox\" : undefined}\n        id={live ? listboxId : undefined}\n        aria-label={live ? (ctx.command ? ctx.command.slots[ctx.slotIndex].prompt : \"Commands\") : undefined}\n        className=\"flex flex-col gap-px m-0 p-0 list-none max-h-[13.5rem] overflow-y-auto\"\n        ref={live ? listRef : undefined}\n      >\n        {rows.map((row, index) => {\n          const isCommand = \"label\" in row.item;\n          return (\n            <li\n              key={labelOf(row.item)}\n              id={live ? `${listboxId}-${index}` : undefined}\n              role={live ? \"option\" : undefined}\n              aria-selected={live ? index === activeSafe : undefined}\n              className=\"group/opt flex items-center gap-2 px-2 py-[0.4375rem] rounded-lg text-[0.8125rem] text-foreground/80 cursor-pointer data-[active=true]:bg-accent data-[active=true]:text-foreground data-[danger=true]:data-[active=true]:bg-destructive/10 data-[danger=true]:data-[active=true]:text-destructive\"\n              data-active={live && index === activeSafe ? \"true\" : undefined}\n              data-danger={isCommand && (row.item as Command).danger ? \"true\" : undefined}\n              onMouseDown={\n                live\n                  ? (event) => {\n                      event.preventDefault();\n                      pick(row.item);\n                    }\n                  : undefined\n              }\n              onMouseMove={live ? () => setActive(index) : undefined}\n            >\n              {kind === \"command\" && (\n                <span className=\"inline-flex flex-none text-muted-foreground/70 group-data-[active=true]/opt:text-muted-foreground group-data-[danger=true]/opt:group-data-[active=true]/opt:text-destructive\">\n                  {(row.item as Command).icon}\n                </span>\n              )}\n              {kind === \"person\" && (\n                <span className=\"inline-flex items-center justify-center flex-none w-[1.375rem] h-[1.375rem] rounded-full bg-foreground/10 text-foreground/70 text-[0.5625rem] font-semibold tracking-[0.02em]\" aria-hidden=\"true\">\n                  {initials((row.item as CommandOption).value)}\n                </span>\n              )}\n              {kind === \"dot\" && (\n                <span\n                  className=\"inline-block flex-none w-2 h-2 rounded-full\"\n                  style={{ background: (row.item as CommandOption).dot ?? \"var(--color-muted-foreground)\" }}\n                  aria-hidden=\"true\"\n                />\n              )}\n              {kind === \"plain\" && (\n                <span className=\"inline-flex flex-none text-muted-foreground/70 group-data-[active=true]/opt:text-muted-foreground\">\n                  {ctx.command?.icon}\n                </span>\n              )}\n              <span className=\"flex-1 min-w-0 overflow-hidden text-ellipsis whitespace-nowrap\">\n                <Highlight text={labelOf(row.item)} idx={row.idx} />\n              </span>\n              {\"hint\" in row.item && row.item.hint && (\n                <span className=\"flex-none text-[0.6875rem] text-muted-foreground/70\">{row.item.hint}</span>\n              )}\n              {isCommand && (row.item as Command).shortcut ? (\n                <kbd className=\"inline-flex items-center justify-center min-w-4 px-1 rounded text-[0.625rem] font-mono leading-normal text-muted-foreground inset-ring inset-ring-foreground/10 group-data-[active=true]/opt:bg-background group-data-[active=true]/opt:inset-ring-0\" aria-hidden=\"true\">\n                  {(row.item as Command).shortcut}\n                </kbd>\n              ) : (\n                <kbd className=\"inline-flex items-center justify-center min-w-4 px-1 rounded text-[0.625rem] font-mono leading-normal bg-muted text-muted-foreground opacity-0 group-data-[active=true]/opt:opacity-100\" aria-hidden=\"true\">\n                  ↵\n                </kbd>\n              )}\n            </li>\n          );\n        })}\n      </ul>\n    );\n  }\n\n  // Flat chip counter for the tail-dim preview (hover a chip → later chips dim).\n  let flat = -1;\n\n  return (\n    <MotionConfig reducedMotion=\"user\">\n      <div className=\"relative w-full max-w-[24rem]\" data-inspect={inspect ? \"true\" : \"false\"}>\n        <div className=\"bg-popover rounded-xl shadow-border overflow-hidden\">\n          <div\n            className={`flex flex-wrap items-center gap-1.5 px-3 py-2.5 border-b border-border cursor-text${\n              inspect ? \" outline outline-[1.5px] outline-dashed outline-[#ef4444] -outline-offset-[3px]\" : \"\"\n            }`}\n            onClick={() => inputRef.current?.focus()}\n          >\n            <span className=\"inline-flex flex-none text-muted-foreground/70\" aria-hidden=\"true\">\n              <SearchIcon />\n            </span>\n            {chipGroups.map((group, groupIndex) => (\n              <Fragment key={group.key}>\n                {groupIndex > 0 &&\n                  (() => {\n                    flat += 1;\n                    const myFlat = flat;\n                    return (\n                      <span\n                        className=\"flex-none text-[0.6875rem] font-medium text-muted-foreground/70 transition-opacity duration-[240ms]\"\n                        style={{ opacity: hoveredChip != null && myFlat > hoveredChip ? 0.35 : 1 }}\n                      >\n                        and\n                      </span>\n                    );\n                  })()}\n                {group.chips.map((chip, chipIndex) => {\n                  flat += 1;\n                  const myFlat = flat;\n                  const isLast = groupIndex === chipGroups.length - 1 && chipIndex === group.chips.length - 1;\n                  return (\n                    <span\n                      className=\"inline-flex transition-opacity duration-[240ms]\"\n                      key={`${group.key}-${chip.key}`}\n                      style={{ opacity: hoveredChip != null && myFlat > hoveredChip ? 0.35 : 1 }}\n                    >\n                      <motion.button\n                        type=\"button\"\n                        tabIndex={-1}\n                        initial={morph && !reduced ? { opacity: 0, scale: 0.85, filter: \"blur(2px)\" } : false}\n                        animate={{ opacity: 1, scale: 1, filter: \"blur(0px)\" }}\n                        transition={{ duration: 0.24, ease: EASE }}\n                        className={`inline-flex items-center gap-[0.3125rem] min-w-0 overflow-hidden whitespace-nowrap px-[0.4375rem] py-[0.1875rem] rounded-md text-xs font-medium cursor-pointer active:scale-[0.96] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring ${\n                          chip.kind === \"cmd\"\n                            ? \"bg-primary text-primary-foreground [@media(hover:hover)_and_(pointer:fine)]:hover:bg-primary/85\"\n                            : \"bg-muted text-foreground [@media(hover:hover)_and_(pointer:fine)]:hover:bg-foreground/10\"\n                        }`}\n                        aria-label={`${chip.kind === \"cmd\" ? \"Remove\" : \"Change\"} ${chip.label}${isLast ? \"\" : \", also removes later chips\"}`}\n                        onMouseDown={(event) => event.preventDefault()}\n                        onMouseEnter={() => setHoveredChip(myFlat)}\n                        onMouseLeave={() => setHoveredChip(null)}\n                        onClick={() => editChip(groupIndex, chipIndex)}\n                      >\n                        {chip.dot && (\n                          <span className=\"inline-block flex-none w-2 h-2 rounded-full\" style={{ background: chip.dot }} aria-hidden=\"true\" />\n                        )}\n                        {chip.label}\n                      </motion.button>\n                    </span>\n                  );\n                })}\n              </Fragment>\n            ))}\n            <input\n              ref={inputRef}\n              className=\"flex-1 min-w-[5rem] border-0 outline-none bg-transparent text-sm text-foreground py-0.5 placeholder:text-muted-foreground/70\"\n              type=\"text\"\n              value={query}\n              placeholder={slot ? slot.prompt : \"Type a command\"}\n              aria-label={slot ? slot.prompt : \"Type a command\"}\n              role=\"combobox\"\n              aria-expanded=\"true\"\n              aria-controls={listboxId}\n              aria-activedescendant={matches.length ? `${listboxId}-${activeSafe}` : undefined}\n              aria-autocomplete=\"list\"\n              aria-describedby={chips.length > 0 ? `${listboxId}-trail` : undefined}\n              spellCheck={false}\n              autoComplete=\"off\"\n              onChange={(event) => {\n                setQuery(event.target.value);\n                setActive(0);\n              }}\n              onKeyDown={handleKeyDown}\n            />\n            <span id={`${listboxId}-trail`} className=\"sr-only\">\n              {chips.length > 0\n                ? `Building: ${chipGroups.map((g) => g.chips.map((c) => c.label).join(\" \")).join(\", and \")}. Backspace removes the last chip.`\n                : \"\"}\n            </span>\n          </div>\n\n          <motion.div\n            className={`relative overflow-hidden${inspect ? \" outline outline-[1.5px] outline-dashed outline-[#3b82f6] -outline-offset-[3px]\" : \"\"}`}\n            animate={{ height: bodyH ?? \"auto\" }}\n            transition={!morph || reduced || bodyFirstRef.current ? { duration: 0 } : { duration: 0.3, ease: EASE }}\n          >\n            {leaving && morph && !reduced && (\n              <motion.div\n                className=\"p-1 absolute top-0 left-0 w-full pointer-events-none\"\n                initial={{ x: 0, opacity: 1 }}\n                animate={{ x: -leaving.dir * SLIDE, opacity: 0 }}\n                transition={{ duration: 0.16, ease: \"easeOut\" }}\n                aria-hidden=\"true\"\n                inert\n              >\n                {renderRows(leaving.rows, leaving.ctx, false)}\n              </motion.div>\n            )}\n            <motion.div\n              className=\"p-1\"\n              key={viewKey}\n              ref={viewRef}\n              initial={leaving && morph && !reduced ? { x: leaving.dir * SLIDE, opacity: 0, filter: \"blur(2px)\" } : false}\n              animate={{ x: 0, opacity: 1, filter: \"blur(0px)\" }}\n              transition={{ duration: 0.3, ease: EASE }}\n            >\n              {renderRows(matches, { command, slotIndex }, true)}\n            </motion.div>\n          </motion.div>\n\n          <div className=\"relative flex items-center justify-between gap-2 min-h-8 px-3 py-[0.4375rem] border-t border-border text-[0.6875rem] text-muted-foreground/70\">\n            <motion.span\n              className=\"inline-flex items-center gap-[0.3125rem]\"\n              animate={ran ? { opacity: 0, y: -4, filter: \"blur(2px)\" } : { opacity: 1, y: 0, filter: \"blur(0px)\" }}\n              transition={{ duration: 0.25, ease: EASE_ICON }}\n              style={{ pointerEvents: ran ? \"none\" : undefined }}\n            >\n              {command ? (\n                <>\n                  {command.label} · {command.slots[slotIndex].name} {slotIndex + 1} of {command.slots.length}\n                </>\n              ) : clauses.length > 0 ? (\n                <>\n                  <span className=\"tabular-nums\">{clauses.length}</span> staged · add another or apply\n                </>\n              ) : (\n                <>{commands.length} commands</>\n              )}\n            </motion.span>\n            <motion.span\n              className=\"inline-flex items-center gap-3 group/apply\"\n              animate={ran ? { opacity: 0, y: -4, filter: \"blur(2px)\" } : { opacity: 1, y: 0, filter: \"blur(0px)\" }}\n              transition={{ duration: 0.25, ease: EASE_ICON }}\n              style={{ pointerEvents: ran ? \"none\" : undefined }}\n            >\n              <button\n                type=\"button\"\n                className=\"relative inline-flex items-center justify-center w-7 h-7 rounded-md bg-transparent text-muted-foreground/70 cursor-pointer transition-[background-color,color,opacity,scale] duration-150 hover:enabled:bg-accent hover:enabled:text-foreground active:enabled:scale-[0.96] disabled:opacity-35 disabled:cursor-default focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring after:content-[''] after:absolute after:-inset-1.5\"\n                disabled={clauses.length === 0 && !command && query === \"\"}\n                aria-label=\"Clear staged commands\"\n                onMouseDown={(event) => event.preventDefault()}\n                onClick={clearAll}\n              >\n                <XIcon />\n              </button>\n              <button\n                type=\"button\"\n                className=\"relative inline-flex items-center gap-[0.3125rem] h-7 px-2.5 rounded-[0.4375rem] bg-primary text-primary-foreground text-xs font-medium cursor-pointer transition-[background-color,color,scale] duration-150 active:enabled:scale-[0.96] disabled:bg-muted disabled:text-muted-foreground/70 disabled:cursor-default focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring after:content-[''] after:absolute after:-inset-y-1.5 after:inset-x-0 disabled:[&_[data-n]]:bg-foreground/[0.06]\"\n                disabled={clauses.length === 0 || !!command}\n                aria-label={`Apply ${clauses.length} staged ${clauses.length === 1 ? \"command\" : \"commands\"}`}\n                aria-keyshortcuts=\"Meta+Enter Control+Enter\"\n                title=\"⌘⏎\"\n                onMouseDown={(event) => event.preventDefault()}\n                onClick={applyAll}\n              >\n                <CheckIcon />\n                Apply\n                {clauses.length > 0 && (\n                  <span data-n className=\"inline-flex items-center justify-center min-w-4 px-1 rounded-[0.3125rem] bg-primary-foreground/[0.18] text-[0.625rem] leading-normal tabular-nums\">\n                    {clauses.length}\n                  </span>\n                )}\n              </button>\n            </motion.span>\n            <motion.span\n              className=\"absolute inset-0 flex items-center gap-1.5 px-3 text-foreground font-medium\"\n              aria-hidden={!ran}\n              initial={false}\n              animate={ran ? { opacity: 1, y: 0, filter: \"blur(0px)\" } : { opacity: 0, y: 4, filter: \"blur(2px)\" }}\n              transition={{ duration: 0.25, ease: EASE_ICON }}\n              style={{ pointerEvents: \"none\" }}\n            >\n              <span className=\"inline-flex flex-none text-[#16a34a]\">\n                <CheckIcon />\n              </span>\n              <span className=\"min-w-0 overflow-hidden text-ellipsis whitespace-nowrap\">{ran?.message ?? lastRun}</span>\n            </motion.span>\n          </div>\n        </div>\n\n        <span className=\"sr-only\" aria-live=\"polite\">\n          {ran\n            ? `Applied: ${ran.message}`\n            : `${slot ? `${slot.prompt}: ` : \"\"}${matches.length} ${matches.length === 1 ? \"result\" : \"results\"}${clauses.length > 0 ? `, ${clauses.length} staged` : \"\"}`}\n        </span>\n\n        {inspect && (\n          <>\n            <span className=\"absolute bottom-[calc(100%+0.4rem)] left-0 z-[6] whitespace-nowrap rounded-[0.25rem] border border-[#bfdbfe] bg-white px-[0.3125rem] py-[0.0625rem] text-[0.625rem] font-medium leading-normal tracking-[0.01em] text-[#2563eb] shadow-[0_1px_2px_rgba(0,0,0,0.08)] pointer-events-none tabular-nums\">\n              {matcher === \"fuzzy\" ? \"fuzzy: word-start +10 · adjacent +8 · gap −1\" : \"substring: indexOf, earlier hit wins\"}\n            </span>\n            <span className=\"absolute top-[calc(100%+0.4rem)] left-0 z-[6] whitespace-nowrap rounded-[0.25rem] border border-[#fecaca] bg-white px-[0.3125rem] py-[0.0625rem] text-[0.625rem] font-medium leading-normal tracking-[0.01em] text-[#dc2626] shadow-[0_1px_2px_rgba(0,0,0,0.08)] pointer-events-none tabular-nums\">\n              one tab stop · chip click rewinds · ⌫ pops · ⌘⏎ applies\n            </span>\n            <span className=\"absolute top-[calc(100%+0.4rem)] right-0 z-[6] whitespace-nowrap rounded-[0.25rem] border border-[#bfdbfe] bg-white px-[0.3125rem] py-[0.0625rem] text-[0.625rem] font-medium leading-normal tracking-[0.01em] text-[#2563eb] shadow-[0_1px_2px_rgba(0,0,0,0.08)] pointer-events-none tabular-nums\">\n              height: {bodyH == null ? \"auto\" : `${Math.round(bodyH)}px`} · measured → eased\n            </span>\n          </>\n        )}\n      </div>\n    </MotionConfig>\n  );\n}\n\nfunction Svg({ children, size = 15 }: { children: ReactNode; size?: number }) {\n  return (\n    <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n      {children}\n    </svg>\n  );\n}\nfunction SearchIcon() { return <Svg size={16}><circle cx=\"11\" cy=\"11\" r=\"8\" /><path d=\"m21 21-4.3-4.3\" /></Svg>; }\nfunction CheckIcon() { return <Svg size={13}><path d=\"M20 6 9 17l-5-5\" strokeWidth=\"2.5\" /></Svg>; }\nfunction XIcon() { return <Svg size={13}><path d=\"M18 6 6 18M6 6l12 12\" strokeWidth=\"2.5\" /></Svg>; }\n"
    }
  ]
}
