@magicx-eng/ai-autocomplete-react 0.14.2 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/AIAutocomplete.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/AIAutocomplete.module.css.js","../src/AIAutocompleteDropdown.tsx","plain-css:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/appearance.css.js","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/AIAutocompleteDropdown.module.css.js","../src/components/DateGrid.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/DateGrid.module.css.js","../src/components/DropdownFooter.tsx","plain-css:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/layout/Cluster.css.js","../src/layout/Cluster.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/DropdownFooter.module.css.js","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/ParamPill.module.css.js","../src/components/ParamPill.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/PillList.module.css.js","../src/components/PillList.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/ProductStrip.module.css.js","../src/components/ProductStrip.tsx","../src/components/SuggestionGrid.tsx","../src/layout/Grid.tsx","plain-css:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/layout/Grid.css.js","../src/components/SuggestionItem.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/SuggestionItem.module.css.js","plain-css:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/layout/Stack.css.js","../src/layout/Stack.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/SubmitButton.module.css.js","../src/components/SubmitButton.tsx","../src/hooks/useAIAutocomplete.ts","../src/hooks/useProductsProxy.ts","../src/hooks/useContentEditableEditor.ts"],"sourcesContent":["export {\n buildSubmitResult,\n // Date helpers, for turning a committed date back into a `Date` and for\n // rendering a custom calendar in Tier 3.\n cellDay,\n cellIso,\n formatDate,\n isoDate,\n monthLabel,\n parseDate,\n parseLooseDate,\n WEEKDAY_LABELS,\n withSkippedParams,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nexport { AIAutocomplete } from \"./AIAutocomplete\";\nexport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nexport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nexport type {\n AccessTokenConfig,\n AccessTokenResult,\n AIAutocompleteDropdownProps,\n AIAutocompleteHandle,\n AIAutocompleteProps,\n APIConfig,\n APIKeyConfig,\n AppearanceMode,\n AutocompleteResult,\n CompletedParam,\n CompletedParamState,\n DateMonthView,\n FormatType,\n OptionOverrides,\n Product,\n ProductsConfig,\n Segment,\n SkippedParamState,\n Suggestion,\n SuggestionOption,\n TaskKind,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"./types\";\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n} from \"react\";\nimport styles from \"./AIAutocomplete.module.css\";\nimport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nimport \"./appearance.css\";\nimport {\n type AppearanceMode,\n type AutocompleteResult,\n buildSubmitResult,\n ModeController,\n setCursorOffset,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { PillList } from \"./components/PillList\";\nimport { SubmitButton } from \"./components/SubmitButton\";\nimport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nimport { useContentEditableEditor } from \"./hooks/useContentEditableEditor\";\nimport type { AIAutocompleteHandle, AIAutocompleteProps } from \"./types\";\n\nfunction resolveInitialMode(mode: AppearanceMode): \"light\" | \"dark\" {\n if (mode !== \"auto\") return mode;\n if (typeof window === \"undefined\") return \"dark\";\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\";\n}\n\nexport const AIAutocomplete = forwardRef<AIAutocompleteHandle, AIAutocompleteProps>(\n function AIAutocomplete(\n {\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n className,\n apiConfig,\n additionalContext,\n columns,\n pillPlacement = \"dropdown\",\n mode = \"auto\",\n optionsPosition = \"below\",\n animations = true,\n dropdownTrigger,\n closeDropdownOnBlur,\n showNonTappableOptions,\n showSkipButton,\n autoFocus = true,\n onFocus,\n onBlur,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n products,\n onProductSelect,\n submitButton,\n },\n ref,\n ) {\n const containerRef = useRef<HTMLDivElement>(null);\n const pillContainerRef = useRef<HTMLSpanElement>(null);\n const handleSubmitRef = useRef<(result: AutocompleteResult) => void>(() => {});\n const modeControllerRef = useRef<ModeController | null>(null);\n // Holds the editor's input *ref object* (not its current value) so the\n // setCursor callback — defined before useContentEditableEditor runs — can\n // dereference the live DOM element at call time without a one-render lag.\n const editorInputRefHolder = useRef<React.RefObject<HTMLDivElement> | null>(null);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n if (modeControllerRef.current) {\n modeControllerRef.current.setMode(mode);\n } else {\n modeControllerRef.current = new ModeController(el, mode);\n }\n return () => {\n modeControllerRef.current?.destroy();\n modeControllerRef.current = null;\n };\n }, [mode]);\n\n const handleSetCursor = useCallback((offset: number) => {\n const el = editorInputRefHolder.current?.current;\n if (!el) return;\n el.focus();\n setCursorOffset(el, offset);\n }, []);\n\n const {\n completedParams,\n skippedParams,\n suggestionPills,\n setActivePill,\n skipActivePill,\n segments,\n newParamId,\n clearNewParamId,\n placeholderText,\n isFocused,\n isDropdownOpen,\n isActivePillSelected,\n isLoading,\n activeIndex,\n listboxId,\n handleTextChange,\n handleKeyDown,\n setFocused,\n editingParam,\n editingIdentified,\n editingAnchor,\n caretOffset,\n startEditingParam,\n handleCaretAfterInput,\n handleCaretMove,\n replaceEditingRange,\n dropdownProps,\n reset,\n } = useAIAutocomplete({\n onSubmit: (result) => handleSubmitRef.current(result),\n onError,\n optionOverrides,\n maskCompletedText,\n apiConfig,\n additionalContext,\n columns,\n dropdownTrigger,\n optionsPosition,\n closeDropdownOnBlur,\n showNonTappableOptions,\n showSkipButton,\n onFocus,\n onBlur,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n products,\n onProductSelect,\n source: \"full-sdk\",\n setCursor: handleSetCursor,\n });\n\n // Shimmer auto-clear after the animation finishes.\n useEffect(() => {\n if (!newParamId) return;\n const t = window.setTimeout(() => clearNewParamId(), 650);\n return () => window.clearTimeout(t);\n }, [newParamId, clearNewParamId]);\n\n const activeDescendantId = activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : undefined;\n\n const { inputRef, editorProps, focus, blur, getPlainText } = useContentEditableEditor({\n segments,\n newParamId,\n editingParam,\n editingIdentified,\n editingAnchor,\n caretOffset,\n placeholderText,\n isFocused,\n isDropdownOpen,\n listboxId,\n activeDescendantId,\n autoFocus,\n handleTextChange,\n handleKeyDown,\n handleCaretAfterInput,\n handleCaretMove,\n startEditingParam,\n replaceEditingRange,\n setFocused,\n });\n\n // Wire the holder to the hook's ref. The ref *object* is stable across\n // renders, so this assignment is idempotent and reaches the live DOM\n // element via `.current` without snapshotting null on the first render.\n editorInputRefHolder.current = inputRef;\n\n // The pill list sits inline-adjacent to the editor and carries an 8px\n // left margin so it doesn't butt against the editor's text. When the\n // editor's text fills its line and the pill list wraps to a new line,\n // that margin becomes a stray indent at the start of the wrapped line —\n // detect that case and drop the margin via a data attribute the CSS\n // keys off. The wrap detection (pill row's top vs editor's bottom)\n // already handles the placeholder-only case correctly: the placeholder\n // still occupies the editor's line box, so pills sitting beside it are\n // NOT wrapped and the margin stays.\n // biome-ignore lint/correctness/useExhaustiveDependencies: segments/suggestionPills/isLoading are intentional re-measure triggers, not reads\n useLayoutEffect(() => {\n const container = pillContainerRef.current;\n const editor = inputRef.current;\n if (!container || !editor) return;\n\n const update = () => {\n const inner = container.firstElementChild as HTMLElement | null;\n if (!inner) return;\n const cRect = inner.getBoundingClientRect();\n const eRect = editor.getBoundingClientRect();\n const wrapped = cRect.top >= eRect.bottom - 2;\n if (wrapped) container.setAttribute(\"data-aia-pill-wrapped\", \"\");\n else container.removeAttribute(\"data-aia-pill-wrapped\");\n };\n\n update();\n const ro = new ResizeObserver(update);\n ro.observe(editor);\n return () => ro.disconnect();\n }, [segments, suggestionPills.length, isLoading, inputRef]);\n\n useImperativeHandle(\n ref,\n () => ({\n focus,\n blur,\n reset,\n setMode: (m) => modeControllerRef.current?.setMode(m),\n skipActivePill,\n }),\n [focus, blur, reset, skipActivePill],\n );\n\n const canSubmit = !!segments.length || completedParams.length > 0;\n\n const handleSubmit = useCallback(() => {\n if (!canSubmit) return;\n const text = getPlainText();\n onSubmit(buildSubmitResult(text, completedParams, skippedParams));\n reset();\n }, [canSubmit, completedParams, skippedParams, onSubmit, reset, getPlainText]);\n\n handleSubmitRef.current = handleSubmit;\n\n const handleWrapperClick = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n // Clicking a pill activates it; don't steal focus away from where it lands.\n const target = e.target as HTMLElement | null;\n if (target?.closest(\"[data-aia-pill]\")) return;\n focus();\n },\n [focus],\n );\n\n const showInlinePills = pillPlacement === \"inline\";\n const showDropdownPills = pillPlacement === \"dropdown\";\n\n return (\n <div\n ref={containerRef}\n className={`magicx-aia ${styles.container} ${className ?? \"\"}`}\n data-pill-placement={pillPlacement}\n data-options-position={optionsPosition}\n data-animations={animations ? \"on\" : \"off\"}\n data-mode={resolveInitialMode(mode)}\n >\n <AIAutocompleteDropdown {...dropdownProps} showPills={showDropdownPills} />\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: container click delegates to editor focus */}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: wrapper delegates focus to editor */}\n <div className={styles.inputWrapper} onClick={handleWrapperClick}>\n <div className={styles.editorArea} data-aia-editor=\"\">\n <div {...editorProps} className={styles.input} data-aia-input=\"\" />\n {showInlinePills && (isLoading || suggestionPills.length > 0) && (\n <span\n ref={pillContainerRef}\n className={styles.pillListContainer}\n data-aia-pill-list-container=\"\"\n >\n <PillList\n pills={suggestionPills}\n activePillIndex={0}\n activeSelected={isActivePillSelected}\n onSelectPill={setActivePill}\n loading={isLoading}\n />\n </span>\n )}\n </div>\n {submitButton === null ? null : submitButton === undefined ? (\n <SubmitButton disabled={!canSubmit} onClick={handleSubmit} />\n ) : (\n // biome-ignore lint/a11y/useKeyWithClickEvents: consumer-provided element handles its own keyboard interaction\n // biome-ignore lint/a11y/noStaticElementInteractions: transparent slot — click bubbles from consumer's element\n <span\n data-aia-submit=\"\"\n className={styles.submitSlot}\n onClick={(e) => {\n if (!canSubmit) return;\n e.stopPropagation();\n handleSubmit();\n }}\n >\n {submitButton}\n </span>\n )}\n </div>\n </div>\n );\n },\n);\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-67791514\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-67791514\";\n s.textContent = `.AIAutocomplete-module_container_KKjFU {\n position: relative;\n /* Inherits the host page's font by default. Consumers can pin a specific\n font on the library via \\`--aia-font-family: 'Custom Font'\\` without\n affecting the surrounding page. */\n font-family: var(--aia-font-family, inherit);\n container-type: inline-size;\n}\n\n.AIAutocomplete-module_inputWrapper_FLq1b {\n padding: 12px 16px;\n border: 1px solid var(--aia-border, #b0b0b0);\n border-radius: 20px;\n background: var(--aia-surface, #ffffff);\n box-shadow: var(--aia-shadow, none);\n overflow: hidden;\n display: flex;\n /* Top-align so the submit button stays by the first line while the editor\n grows downward and then scrolls internally. */\n align-items: flex-start;\n gap: 12px;\n}\n\n.AIAutocomplete-module_editorArea_7rBWq {\n position: relative;\n flex: 1;\n min-width: 0;\n min-height: 22px;\n /* Airy line box so wrapped rows of chips (and plain text) don't touch. */\n line-height: var(--aia-editor-line-height, 1.9);\n font-family: inherit;\n font-size: var(--aia-written-text-font-size, 14px);\n white-space: pre-wrap;\n word-break: break-word;\n overflow-wrap: anywhere;\n /* Grow with content up to a cap of five rows, then hold height and scroll\n internally — the caret stays in view as the text is pushed up. The\n scrollbar is hidden so the box reads as a clean growing field. The cap is\n five line boxes rather than a fixed pixel height so it still lands on a\n whole row when a consumer resizes the text via\n --aia-written-text-font-size (\\`em\\` here resolves against this element's\n own font-size, which is that token). */\n max-height: var(--aia-editor-max-height, calc(var(--aia-editor-line-height, 1.9) * 5em));\n overflow-y: auto;\n scrollbar-width: none;\n}\n\n.AIAutocomplete-module_editorArea_7rBWq::-webkit-scrollbar {\n display: none;\n}\n\n.AIAutocomplete-module_input_IW-P- {\n display: inline;\n outline: none;\n background: transparent;\n color: var(--aia-written-text-color, var(--aia-color-text-default, #fff));\n caret-color: var(\n --aia-caret-color,\n var(--aia-written-text-color, var(--aia-color-text-default, #fff))\n );\n font-weight: 300;\n /* Align the text's inline box with the pill list (also vertical-align: middle)\n so they share a vertical center when pills stretch the line box to ~36px. */\n vertical-align: middle;\n}\n\n/* Completed params render as inline pills (Figma \"RichTextPill\") — a compact\n ~26px chip with regular-weight primary-color text on a faint-gray fill.\n inline-block gives the padding/radius a box while the text stays part of the\n editable plain text (the caret system counts characters inside this\n <strong>). The completed class is stamped by the shared renderer as a global\n string, so match it via [class~=] to bypass CSS Modules' hashing. */\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--completed\"] {\n /* inline (not inline-block) so a chip too wide for the line breaks across two\n lines; box-decoration-break: clone gives each fragment its own padding /\n radius / fill, so an over-long recognized phrase renders as two little\n rounded blocks instead of overflowing the field. */\n display: inline;\n padding: 3px 6px;\n /* Rounded rectangle, not a full capsule. */\n border-radius: 6px;\n -webkit-box-decoration-break: clone;\n box-decoration-break: clone;\n background: var(--aia-completed-pill-bg, rgba(189, 189, 189, 0.105));\n color: var(--aia-completed-pill-color, var(--aia-written-text-color, #fff));\n font-size: var(--aia-pill-font-size, 14px);\n font-weight: 400;\n line-height: normal;\n white-space: normal;\n /* Tighten the tracking so the chip's horizontal padding doesn't make the\n recognized phrase read wider than the same words as plain text. The exact\n per-chip amount is set inline by the renderer (renderEditable); this is a\n fallback for any chip the renderer didn't stamp. */\n letter-spacing: var(--aia-completed-pill-tracking, -0.02em);\n cursor: pointer;\n /* Smooth hover fade. Neutralized by the data-animations=\"off\" block. */\n transition: background-color 150ms ease;\n}\n\n/* Hover highlight — a slightly stronger fill so a pointed-at pill reads as\n tappable. Declared between the base and editing rules so editing wins. */\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--completed\"]:hover {\n background: var(--aia-completed-pill-bg-active, rgba(189, 189, 189, 0.35));\n}\n\n/* Re-edit highlight — applied to the completed pill being re-edited (after a\n tap). Reuses the exact hover fill so the highlight persists from tap until an\n option is selected. Hides the native caret; cursor switches to text since the\n pill is in text-replacement mode. The editing class is written by the shared\n renderer (a global string), so target it via an attribute selector to bypass\n CSS Modules' hashing. Declared last so it wins on a strong carrying both\n classes. */\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--editing\"] {\n background: var(--aia-completed-pill-bg-active, rgba(189, 189, 189, 0.35));\n caret-color: transparent;\n cursor: text;\n}\n\n/* In re-edit mode the caret is parked just *before* the bold strong (see\n useContentEditableEditor.ts) — that means it sits in the parent .input, not\n inside the strong, so the rule above doesn't hide it. Use :has() to hide\n the caret on the whole editor while any completed param is selected. */\n.AIAutocomplete-module_input_IW-P-:has(strong[class~=\"magicx-aia-segment--editing\"]) {\n caret-color: transparent;\n}\n\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--editing\"]::selection {\n background: transparent;\n color: inherit;\n}\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--editing\"]::-moz-selection {\n background: transparent;\n color: inherit;\n}\n\n/* Placeholder via ::before so it doesn't enter the editable DOM. The text is\n typed in one character at a time by the core's typewriter (the attribute\n holds the typed prefix); the only fade is the outgoing phrase when the\n placeholder changes — its duration mirrors PLACEHOLDER_FADE_OUT_MS. */\n.AIAutocomplete-module_input_IW-P-[data-aia-empty=\"true\"][data-placeholder]::before {\n content: attr(data-placeholder);\n color: var(--aia-color-text-muted, #c1c4cb);\n opacity: 0.7;\n pointer-events: none;\n transition: opacity var(--aia-placeholder-fade, 120ms) ease-out;\n}\n\n.AIAutocomplete-module_input_IW-P-[data-aia-placeholder-leaving]::before {\n opacity: 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .AIAutocomplete-module_input_IW-P-[data-aia-empty=\"true\"][data-placeholder]::before {\n transition-duration: 0s;\n }\n}\n\n/* Empty inline contentEditables have no inline box for the caret to render\n in. Switch to inline-block (min-width matches the caret line) when empty,\n so the caret stays visible while focused. */\n.AIAutocomplete-module_input_IW-P-[data-aia-empty=\"true\"] {\n display: inline-block;\n min-width: 1px;\n}\n\n.AIAutocomplete-module_pillListContainer_h92IA {\n display: inline;\n margin-left: 8px;\n}\n\n.AIAutocomplete-module_pillListContainer_h92IA:empty,\n.AIAutocomplete-module_pillListContainer_h92IA[data-aia-pill-wrapped] {\n margin-left: 0;\n}\n\n.AIAutocomplete-module_submitSlot_GhuCM {\n display: contents;\n}\n\n/* Promotion reveal on a newly promoted completed param. The shared renderer\n (core/render/renderEditable.ts) stamps the global shimmer classes onto the\n just-added <strong>; we match them via [class~=] to bypass CSS Modules'\n hashing. Completed params are now pills with a solid background, so the old\n text-clip gradient shimmer can't be used (background-clip: text would wipe\n the pill background). The reveal is a simple fade-in of the whole pill,\n riding on shimmer-sweep so it only plays on genuine promotions. */\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-shimmer-sweep\"] {\n animation: AIAutocomplete-module_aiaPillReveal_wf05b 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n@keyframes AIAutocomplete-module_aiaPillReveal_wf05b {\n from {\n opacity: 0;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"container\":\"AIAutocomplete-module_container_KKjFU\",\"inputWrapper\":\"AIAutocomplete-module_inputWrapper_FLq1b\",\"editorArea\":\"AIAutocomplete-module_editorArea_7rBWq\",\"input\":\"AIAutocomplete-module_input_IW-P-\",\"pillListContainer\":\"AIAutocomplete-module_pillListContainer_h92IA\",\"submitSlot\":\"AIAutocomplete-module_submitSlot_GhuCM\",\"aiaPillReveal\":\"AIAutocomplete-module_aiaPillReveal_wf05b\"};","import {\n attachScrollArrow,\n SCROLL_ARROW_LABEL,\n type ScrollArrowController,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { type RefObject, useEffect, useRef, useState } from \"react\";\n// Self-inject the appearance layer (design tokens, box-sizing reset, and the\n// optionsPosition=\"above\" layout-reversal rules). Tier 1 already imports this,\n// but headless consumers render only this dropdown — importing it here means\n// they get correct styling and a working `optionsPosition` with no extra setup.\nimport \"./appearance.css\";\nimport styles from \"./AIAutocompleteDropdown.module.css\";\nimport { DateGrid } from \"./components/DateGrid\";\nimport { DropdownFooter } from \"./components/DropdownFooter\";\nimport { PillList } from \"./components/PillList\";\nimport { ProductStrip } from \"./components/ProductStrip\";\nimport { SuggestionGrid } from \"./components/SuggestionGrid\";\nimport { Cluster } from \"./layout/Cluster\";\nimport { Stack } from \"./layout/Stack\";\nimport type { AIAutocompleteDropdownProps } from \"./types\";\n\nconst FALLBACK_SKELETON_BAR_WIDTHS = [159, 119, 164];\n\n// Module constant, not an inline arrow: a fresh closure per render would defeat\n// ProductStrip's prop stability for no reason. Reached only by a Tier 2\n// consumer who renders products without wiring onProductSelect.\nconst NOOP_PRODUCT_SELECT = () => {};\n/** A Tier 2 consumer who renders the dropdown without wiring month paging gets inert arrows, not a crash. */\nconst NOOP_MONTH = () => {};\n\n/**\n * Resolve the `mode` prop to a concrete `\"light\" | \"dark\"` (or `undefined` when\n * unset, meaning \"don't self-scope — inherit from a `.magicx-aia` ancestor\").\n * `\"auto\"` tracks `prefers-color-scheme` live.\n */\nfunction useResolvedMode(\n mode: \"light\" | \"dark\" | \"auto\" | undefined,\n): \"light\" | \"dark\" | undefined {\n const prefersDark = () =>\n typeof window !== \"undefined\" &&\n typeof window.matchMedia === \"function\" &&\n window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n const [systemDark, setSystemDark] = useState(prefersDark);\n\n useEffect(() => {\n if (\n mode !== \"auto\" ||\n typeof window === \"undefined\" ||\n typeof window.matchMedia !== \"function\"\n ) {\n return;\n }\n const mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n const onChange = () => setSystemDark(mq.matches);\n mq.addEventListener(\"change\", onChange);\n return () => mq.removeEventListener(\"change\", onChange);\n }, [mode]);\n\n if (mode === undefined) return undefined;\n if (mode === \"auto\") return systemDark ? \"dark\" : \"light\";\n return mode;\n}\n\n/**\n * Keeps the core's \"more below\" arrow controller bound to whichever options\n * grid the dropdown currently renders. The controller owns the behaviour\n * (measuring, visibility, the page-scroll on click — see the core's\n * scrollArrow.ts); this hook only hands it the live elements and tells it to\n * re-measure after every render, re-attaching when the grid element is\n * replaced and tearing down when there is no grid.\n */\nfunction useScrollArrow(\n rootRef: RefObject<HTMLDivElement>,\n buttonRef: RefObject<HTMLButtonElement>,\n): void {\n const boundRef = useRef<{ grid: HTMLElement; controller: ScrollArrowController } | null>(null);\n\n // No dependency array on purpose: the grid can come and go with any render,\n // and update() is a cheap attribute compare when nothing changed. This\n // effect deliberately returns no cleanup — a cleanup here would run before\n // every re-run and tear the controller down on each render (re-arming its\n // \"new group\" gate every time). The controller's lifetime is instead tied to\n // the grid element (destroyed when the grid is replaced or gone, below) and\n // to the component (the mount-only effect after this one), which also\n // survives StrictMode's mount → cleanup → mount pass.\n // biome-ignore lint/correctness/useExhaustiveDependencies: runs after every render by design\n useEffect(() => {\n const root = rootRef.current;\n const button = buttonRef.current;\n if (!root || !button) return;\n const grid = root.querySelector<HTMLElement>(\".aia-grid[data-scroll]\");\n if (boundRef.current && boundRef.current.grid !== grid) {\n boundRef.current.controller.destroy();\n boundRef.current = null;\n }\n if (grid && !boundRef.current) {\n boundRef.current = {\n grid,\n controller: attachScrollArrow({ dropdown: root, grid, button }),\n };\n return; // attach() runs the first update itself\n }\n boundRef.current?.controller.update();\n });\n\n useEffect(\n () => () => {\n boundRef.current?.controller.destroy();\n boundRef.current = null;\n },\n [],\n );\n}\n\nexport function AIAutocompleteDropdown({\n suggestions,\n activeIndex,\n onSelect,\n onHighlight,\n isOpen,\n id,\n className,\n pills,\n onPillClick,\n showPills = true,\n onSkip,\n showSkipButton = true,\n skipDisabled = false,\n activeSelected = false,\n isLoading = false,\n isInputEmpty = false,\n products,\n onProductSelect,\n onProductFocusChange,\n formatType = \"options\",\n dateView = null,\n selectedDateIso = null,\n onPreviousMonth,\n onNextMonth,\n optionsPosition = \"below\",\n mode,\n}: AIAutocompleteDropdownProps) {\n // When `mode` is set, self-scope: add `magicx-aia` + `data-mode` to our own\n // root so the dropdown is styled without a `.magicx-aia` wrapper. When unset,\n // stay class-less and inherit from an ancestor (Tier 1 / a custom wrapper).\n const resolvedMode = useResolvedMode(mode);\n const selfScope = resolvedMode !== undefined;\n\n const rootRef = useRef<HTMLDivElement>(null);\n const scrollArrowRef = useRef<HTMLButtonElement>(null);\n useScrollArrow(rootRef, scrollArrowRef);\n\n // Visibility is computed from the CURRENT props and drives the opacity fade.\n const liveOptions = suggestions[0]?.options ?? [];\n const liveHasRealPills = Boolean(pills && pills.length > 0 && onPillClick);\n // Either half is enough to keep the panel up: products render with no\n // suggestions, suggestions render with no products.\n const liveHasProducts = Boolean(products && products.length > 0);\n const isVisible =\n isOpen &&\n (liveOptions.length > 0 || (showPills && liveHasRealPills) || isLoading || liveHasProducts);\n\n // Freeze the content-driving values while the dropdown is open. When it\n // closes we render this frozen snapshot during the 400ms opacity fade, so the\n // whole populated dropdown fades out as one. Otherwise the pills/options\n // unmount the instant the underlying state empties (e.g. skipping the last\n // pill with →), leaving the always-present footer alone for a flash of a\n // footer-only \"no options\" box. Content is refreshed on the next open.\n const snapshot = {\n suggestions,\n activeIndex,\n pills,\n showPills,\n showSkipButton,\n skipDisabled,\n activeSelected,\n isLoading,\n isInputEmpty,\n products,\n formatType,\n dateView,\n selectedDateIso,\n };\n const lastVisibleRef = useRef(snapshot);\n if (isVisible) lastVisibleRef.current = snapshot;\n const content = isVisible ? snapshot : lastVisibleRef.current;\n\n const activeSuggestion = content.suggestions[0];\n const options = activeSuggestion?.options ?? [];\n const isOptionHighlighted =\n content.activeIndex >= 0 && Boolean(options[content.activeIndex]?.is_tappable);\n const hasRealPills = Boolean(content.pills && content.pills.length > 0 && onPillClick);\n // Guarantee at least one option bar during loading — if the cached state\n // had no options, render the fallback skeleton bars regardless of whether\n // pills are present, so the dropdown never shows pills with an empty body.\n const showsRealPills = content.showPills && hasRealPills;\n const showsLoadingPills = content.showPills && !hasRealPills && content.isLoading;\n const showsPillBar = showsRealPills || showsLoadingPills;\n // The trailing \"skip\" button only makes sense next to a real, skippable\n // pill — the fallback skeleton bar has nothing to skip. Requires onSkip:\n // a Tier 2 consumer rendering the dropdown without wiring it gets no\n // dead button. Deliberately NOT gated on showPills: with pills rendered\n // elsewhere (pillPlacement \"inline\"/\"hidden\") the bar renders as a\n // skip-only row holding just the button. Hidden while the input is empty —\n // the footer hint doesn't advertise \"→ to skip\" until the user has typed,\n // so the pristine starting state stays free of the affordance too.\n const showsSkip =\n hasRealPills && content.showSkipButton && !content.isInputEmpty && Boolean(onSkip);\n const activePillLabel = content.pills?.[0]?.text;\n // Exactly one body renders. `options` above already holds the visible\n // month's cells when this is a date — the core swapped them in its derive\n // layer — so the two are the same list drawn two different ways, and never\n // both at once (two elements answering to `#${id}-option-0` would break\n // keyboard commit).\n const isDate = content.formatType === \"date\" && content.dateView != null;\n const showsOptions = options.length > 0 && !isDate;\n const showsDateGrid = options.length > 0 && isDate;\n const showsFallbackSkeleton = content.isLoading && !showsOptions && !showsDateGrid;\n // `data-aia-has-products` below is the layout hook: the band the footer\n // rides up over only makes sense when the footer sits directly on the\n // scrolling option list, and appearance.css reads the attribute to zero it\n // at the source when a strip is in between.\n const stripProducts = content.products ?? [];\n\n return (\n <div\n ref={rootRef}\n id={id}\n role=\"listbox\"\n data-aia-dropdown=\"\"\n data-options-position={optionsPosition}\n data-mode={resolvedMode}\n data-aia-loading={content.isLoading ? \"\" : undefined}\n data-aia-has-products={stripProducts.length > 0 ? \"\" : undefined}\n className={`${selfScope ? \"magicx-aia \" : \"\"}${styles.dropdown} ${isVisible ? styles.visible : \"\"} ${className ?? \"\"}`}\n onMouseDown={(e) => e.preventDefault()}\n >\n <Stack space=\"8px\">\n {(showsPillBar || showsSkip) && (\n <Cluster noWrap className={styles.pillBar} data-aia-pillbar=\"\">\n {/* The scroll + right-edge fade live on this wrapper (not the bar)\n so the skip button stays outside the masked region — pinned and\n fully opaque while overflowing pills fade under it. The\n data-aia-pill-scroll attribute is the public styling hook for\n the mask, since the module class hash isn't part of the API.\n Absent in a skip-only row (pills rendered elsewhere). */}\n {showsPillBar && (\n <span className={styles.pillScroll} data-aia-pill-scroll=\"\">\n <PillList\n pills={content.pills ?? []}\n activePillIndex={0}\n activeSelected={content.activeSelected}\n onSelectPill={onPillClick ?? (() => {})}\n rounded\n loading={content.isLoading}\n />\n </span>\n )}\n {showsSkip && (\n <button\n type=\"button\"\n tabIndex={-1}\n className={styles.skip}\n data-aia-skip=\"\"\n disabled={content.isLoading || content.skipDisabled}\n aria-label={activePillLabel ? `Skip ${activePillLabel}` : \"Skip\"}\n onClick={onSkip}\n >\n skip\n </button>\n )}\n </Cluster>\n )}\n {showsOptions && (\n <SuggestionGrid\n options={options}\n activeIndex={content.activeIndex}\n onSelect={onSelect}\n onHighlight={onHighlight}\n listboxId={id}\n loading={content.isLoading}\n groupKey={activeSuggestion ? `${activeSuggestion.type} ${activeSuggestion.text}` : \"\"}\n optionsPosition={optionsPosition}\n />\n )}\n {showsDateGrid && content.dateView && (\n <DateGrid\n options={options}\n activeIndex={content.activeIndex}\n listboxId={id}\n view={content.dateView}\n selectedIso={content.selectedDateIso ?? null}\n onSelect={onSelect}\n onHighlight={onHighlight}\n onPreviousMonth={onPreviousMonth ?? NOOP_MONTH}\n onNextMonth={onNextMonth ?? NOOP_MONTH}\n />\n )}\n {showsFallbackSkeleton && (\n <div className={styles.skeletonBars} data-aia-skeleton-bars=\"\">\n {FALLBACK_SKELETON_BAR_WIDTHS.map((w) => (\n <span key={`bar-${w}`} className={styles.skeletonBar} style={{ width: w }} />\n ))}\n </div>\n )}\n <ProductStrip\n products={stripProducts}\n listboxId={id}\n onSelect={onProductSelect ?? NOOP_PRODUCT_SELECT}\n onFocusChange={onProductFocusChange}\n focusable={isVisible}\n />\n <DropdownFooter\n isOptionHighlighted={isOptionHighlighted}\n isInputEmpty={content.isInputEmpty}\n />\n </Stack>\n {/* \"More below\" arrow — an overlay on the panel, not a section of the\n stack. Shown/positioned by the core's controller (useScrollArrow);\n markup mirrors vanilla's createScrollArrowButton. */}\n <button\n ref={scrollArrowRef}\n type=\"button\"\n tabIndex={-1}\n className={styles.scrollArrow}\n data-aia-scroll-arrow=\"\"\n aria-label={SCROLL_ARROW_LABEL}\n aria-hidden=\"true\"\n >\n <svg\n viewBox=\"0 0 16 16\"\n width=\"14\"\n height=\"14\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d=\"M4 6.5 8 10.5l4-4\" />\n </svg>\n </button>\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-0ae03977\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-0ae03977\";\n s.textContent = `/*\n * Built-in appearance defaults — zero specificity via :where().\n * Consumer CSS always wins without !important.\n *\n * Resolution priority (highest wins):\n * 1. Consumer CSS targeting new vars (--aia-pill-bg, etc.)\n * 2. Consumer CSS targeting legacy vars (--aia-color-*, via fallback chain)\n * 3. These built-in defaults\n */\n\n/*\n * Library-scoped box-sizing reset. The SDK's pill / option / wrapper styles\n * mix explicit dimensions with padding (e.g. .magicx-aia-pill has height:36px\n * + padding:13px) and were authored assuming \\`border-box\\`. In consumer apps\n * without a global \\`* { box-sizing: border-box }\\` reset the pill rendered\n * ~62px tall instead of 36px. Scoping the reset to \\`.magicx-aia\\` descendants\n * keeps the library self-contained without leaking onto consumer markup.\n */\n:where(.magicx-aia, .magicx-aia *, .magicx-aia *::before, .magicx-aia *::after) {\n box-sizing: border-box;\n}\n\n/*\n * Primitive color ramp — single source of truth, mirroring the Figma\n * \"Primitives\" collection. INTERNAL: theme via the public --aia-* vars below,\n * not these. Mode-independent (raw values; the same in light and dark).\n */\n:where(.magicx-aia) {\n --aia-primitive-neutral-0: #000000;\n --aia-primitive-neutral-150: #1a1b1d;\n --aia-primitive-neutral-250: #323232;\n --aia-primitive-neutral-300: #333539;\n --aia-primitive-neutral-400: #4a4a4a;\n --aia-primitive-neutral-500: #505050;\n --aia-primitive-neutral-700: #b0b0b0;\n --aia-primitive-neutral-750: #bdbdbd;\n --aia-primitive-neutral-900: #e7e7e7;\n --aia-primitive-neutral-1000: #ffffff;\n --aia-primitive-blue-50: #eef2ff;\n --aia-primitive-neutral-750-a50: rgba(189, 189, 189, 0.51);\n --aia-primitive-neutral-750-a25: rgba(189, 189, 189, 0.25);\n --aia-primitive-neutral-750-a35: rgba(189, 189, 189, 0.35);\n --aia-primitive-neutral-750-a30: rgba(189, 189, 189, 0.3);\n --aia-primitive-neutral-750-a15: rgba(189, 189, 189, 0.15);\n /* a105 is a15 lightened 30% (0.15 -> 0.105) — a fainter tint of the same\n gray, not a new color. Light mode only: over a WHITE surface a weaker\n tint is lighter, but over the dark theme's black surface it would be\n darker, so dark mode keeps a15. */\n --aia-primitive-neutral-750-a105: rgba(189, 189, 189, 0.105);\n --aia-primitive-neutral-700-a40: rgba(176, 176, 176, 0.4);\n /* Exactly 0.5, unlike the older 750-a50 above (0.51). */\n --aia-primitive-neutral-900-a50: rgba(231, 231, 231, 0.5);\n --aia-primitive-neutral-400-a50: rgba(74, 74, 74, 0.5);\n}\n\n/* Light mode defaults (base) — public --aia-* vars resolve to primitives */\n:where(.magicx-aia),\n:where(.magicx-aia[data-mode=\"light\"]) {\n --aia-surface: var(--aia-primitive-neutral-1000);\n --aia-border: rgba(17, 24, 39, 0.14); /* subtle slate hairline (off-palette) */\n /* Elevation for the input container (.inputWrapper). */\n --aia-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 1px 2px rgba(16, 24, 40, 0.05),\n 0 8px 24px rgba(16, 24, 40, 0.08);\n /* Half-strength stroke: neutral-900 (was #e5e7eb — snapped to palette,\n Δ2) at 50% alpha over the surface, so the hairline lands exactly\n halfway between its old value and the white behind it. */\n --aia-dropdown-border: var(--aia-primitive-neutral-900-a50);\n --aia-dropdown-shadow: 0 8px 12px rgba(0, 0, 0, 0.05);\n /* Suggestion pills (Figma \"ParamPill\"): transparent fill, no visible border;\n per-pill opacity via getPillOpacity. */\n --aia-pill-bg: var(--aia-primitive-neutral-750);\n --aia-pill-color: var(--aia-primitive-neutral-300);\n --aia-pill-font-size: 16px;\n\n /* Completed params (Figma \"RichTextPill\"): compact faint-gray chip with\n primary-color regular-weight text. -active is the hover / tapped (re-edit)\n highlight — an alpha over the input background, so one value works in both\n themes. */\n --aia-completed-pill-bg: var(--aia-primitive-neutral-750-a105);\n --aia-completed-pill-bg-active: var(--aia-primitive-neutral-750-a35);\n --aia-completed-pill-color: var(--aia-primitive-neutral-0);\n\n --aia-option-bg: var(--aia-primitive-blue-50);\n /* Options read bigger + darker than the small-caps param labels above them. */\n --aia-option-color: var(--aia-primitive-neutral-150);\n --aia-option-color-selected: var(--aia-primitive-neutral-0);\n --aia-option-font-size: 16px;\n\n --aia-written-text-color: var(--aia-primitive-neutral-0);\n /* Match the option size so the typed query never reads smaller than the\n choices below it. */\n --aia-written-text-font-size: 16px;\n --aia-caret-color: var(--aia-written-text-color, #000000);\n\n --aia-submit-bg: var(--aia-primitive-neutral-0);\n --aia-submit-color: var(--aia-primitive-neutral-1000);\n\n --aia-color-text-muted: #6b7280; /* off shared palette (slate) */\n\n /* Loading bars sit at half the contrast of the surrounding chrome so they\n read as a placeholder, not as content (a50 -> a25 over the light surface). */\n --aia-skeleton-bg: var(--aia-primitive-neutral-750-a25);\n\n --aia-streak-rgb: 99, 102, 241; /* off shared palette (indigo effect) */\n\n --aia-footer-hint-color: var(--aia-primitive-neutral-500);\n --aia-footer-brand-color: var(--aia-primitive-neutral-700);\n --aia-footer-badge-border: var(--aia-primitive-neutral-750-a50);\n}\n\n/* Dark mode defaults */\n:where(.magicx-aia[data-mode=\"dark\"]) {\n --aia-surface: var(--aia-primitive-neutral-0);\n --aia-border: var(--aia-primitive-neutral-500);\n /* Elevation for the input container (.inputWrapper) — tuned for dark surfaces:\n a faint top highlight + deeper ambient shadows. */\n --aia-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 1px 2px rgba(0, 0, 0, 0.2),\n 0 8px 24px rgba(0, 0, 0, 0.25);\n /* Half-strength stroke — neutral-400 (was #484848 — snapped to palette,\n Δ2) at 50% alpha; see the light-mode note above. */\n --aia-dropdown-border: var(--aia-primitive-neutral-400-a50);\n --aia-dropdown-shadow: 0 8px 12px rgba(0, 0, 0, 0.05);\n /* Suggestion pills (Figma \"ParamPill\"): transparent fill, no visible border. */\n --aia-pill-bg: var(--aia-primitive-neutral-750);\n --aia-pill-color: var(--aia-primitive-neutral-700);\n --aia-pill-font-size: 16px;\n\n /* Completed params (Figma \"RichTextPill\") — dark theme (design source):\n white text on a faint-gray chip. -active is the hover / tapped highlight.\n Deliberately still a15 while light mode moved to a105: the fill is a light\n gray tinting the surface, so thinning it lightens over white but DARKENS\n over this theme's black. Lightening the dark chip means a stronger tint,\n which is a design call, not a mechanical one — left for design to make. */\n --aia-completed-pill-bg: var(--aia-primitive-neutral-750-a15);\n --aia-completed-pill-bg-active: var(--aia-primitive-neutral-750-a35);\n --aia-completed-pill-color: var(--aia-primitive-neutral-1000);\n\n --aia-option-bg: var(--aia-primitive-neutral-250);\n /* Options read bigger + darker/brighter than the small-caps param labels. */\n --aia-option-color: var(--aia-primitive-neutral-900);\n --aia-option-color-selected: var(--aia-primitive-neutral-1000);\n --aia-option-font-size: 16px;\n\n --aia-written-text-color: var(--aia-primitive-neutral-1000);\n --aia-written-text-font-size: 16px;\n --aia-caret-color: var(--aia-written-text-color, #ffffff);\n\n --aia-submit-bg: var(--aia-primitive-neutral-1000);\n --aia-submit-color: var(--aia-primitive-neutral-0);\n\n --aia-color-text-muted: #c1c4cb; /* off shared palette (slate) */\n\n /* Half as light against the dark surface as the old neutral-300 fill — the\n dark-mode counterpart of the light theme's a50 -> a25 step-down. */\n --aia-skeleton-bg: var(--aia-primitive-neutral-150);\n\n --aia-streak-rgb: 255, 255, 255;\n\n --aia-footer-hint-color: var(--aia-primitive-neutral-700);\n --aia-footer-brand-color: var(--aia-primitive-neutral-500);\n --aia-footer-badge-border: var(--aia-primitive-neutral-500);\n}\n\n/* Footer band — the option list runs *under* the dropdown footer and dissolves\n into it, instead of being cut off mid-row above it. The band is the footer's\n own height — its top inset (--aia-footer-gap) + --aia-footer-row-height:\n - the options grid reserves it as bottom padding, so the last option can\n still be scrolled fully clear of the footer;\n - --aia-grid-overlap-bottom (the band + the 8px stack gap) pulls the footer\n back up over that band;\n - the footer's background is the fade: transparent at the band's top edge,\n the full dropdown surface at its bottom, so a row dissolves as it passes\n behind. Its hint and branding groups sit on a 65%-opaque fill of their\n own (--aia-footer-chip-bg) so they stay legible across it.\n Lives here rather than with the dropdown's own rules so the\n optionsPosition=\"above\" reset below always follows it in the cascade. */\n[data-aia-dropdown] {\n /* Height of the footer's hint / branding row — the badge is its tallest item\n (the kbd is shorter and centers against it). The band derives from it, so\n restyling the badge's height keeps the overlap in step. */\n --aia-footer-row-height: 23px;\n --aia-footer-band: calc(var(--aia-footer-gap, 8px) + var(--aia-footer-row-height, 23px));\n --aia-grid-scroll-bottom: var(--aia-footer-band);\n --aia-grid-overlap-bottom: calc(-1 * (var(--aia-footer-band) + 8px));\n /* How far above the band the fade starts. */\n --aia-footer-fade-lead: 20px;\n --aia-footer-fade-inset: calc(-1 * var(--aia-footer-fade-lead)) 0 0;\n}\n\n/* In the dropdown, the parameter label reads as a section header for the\n options beneath it — not an outlined chip floating over them. It drops the\n pill's inner horizontal padding and left-aligns its text with the option\n text below, which sits 10px in from the dropdown's content edge. The label's\n own list wrapper carries that 10px so the text lands exactly on the option\n text's left edge.\n\n Selector shape differs from the vanilla/Angular copies (which target the\n \\`.aia-pill-list\\` / \\`.aia-pill\\` class names): the module classes here are\n hash-scoped locals, unreachable from this global stylesheet. The bar's\n direct \\`> span\\` child is the masked scroll wrapper (\\`.pillScroll\\`, tagged\n \\`data-aia-pill-scroll\\`) that holds PillList, so the 10px indent lands on\n the wrapper and the module zeroes PillList's own base padding underneath\n (\\`.pillScroll > span\\` in AIAutocompleteDropdown.module.css — remove one\n only with the other). Pills are matched via \\`[data-aia-pill]\\` (unique to\n ParamPill). Like the sibling structural \\`[data-aia-dropdown]\\` rules below,\n this is deliberately NOT \\`:where()\\`-wrapped — it must win over ParamPill's\n own \\`.pill\\` base rule. */\n[data-aia-dropdown] [data-aia-pillbar] > span {\n padding-inline: 10px;\n}\n[data-aia-dropdown] [data-aia-pillbar] [data-aia-pill] {\n justify-content: flex-start;\n border-inline-width: 0;\n padding-inline: 0;\n}\n\n/* The reserved band the footer overlaps, kept OUT of \\`@layer layout\\` on\n purpose. A consumer reset (\\`* { margin: 0; padding: 0 }\\`, Tailwind's\n preflight, …) is unlayered, and an unlayered declaration beats every layered\n one no matter its specificity — inside the layer this padding and margin\n were silently zeroed and the footer had nothing to sit over. */\n[data-aia-dropdown] .aia-grid[data-scroll] {\n padding-top: var(--aia-grid-scroll-top, 0);\n padding-bottom: var(--aia-grid-scroll-bottom, 0);\n margin-top: var(--aia-grid-overlap-top, 0);\n margin-bottom: var(--aia-grid-overlap-bottom, 0);\n}\n\n/* The fade. Painted on a pseudo-element rather than the footer box so it can\n start --aia-footer-fade-lead above the band's top edge: a row is then already\n dissolving by the time it reaches the hint / branding line, instead of\n crossing it at half strength. --aia-surface is what the dropdown paints\n itself with, so theming the surface retints the fade with it. z-index: -1\n keeps it under the footer's own content but, via the footer's stacking\n context, above the option rows. */\n[data-aia-dropdown] [data-aia-footer]::before {\n content: \"\";\n position: absolute;\n inset: var(--aia-footer-fade-inset, -20px 0 0);\n z-index: -1;\n pointer-events: none;\n background: linear-gradient(to bottom, transparent, var(--aia-surface, #ffffff));\n}\n\n/* The glass surface is translucent — there's no solid color to dissolve into,\n and a fill behind the hint / branding would paint an opaque patch on a\n frosted panel. Both opt out. */\n[data-aia-dropdown][data-aia-surface=\"glass\"] {\n --aia-footer-chip-bg: transparent;\n}\n\n[data-aia-dropdown][data-aia-surface=\"glass\"] [data-aia-footer]::before {\n display: none;\n}\n\n/* optionsPosition: dropdown above the input. The sections live inside the\n dropdown's .aia-stack, so the reversal targets the stack (not the dropdown,\n whose only child is the stack).\n Two forms are supported:\n 1. ancestor form — Tier 1 sets data-options-position on the .magicx-aia\n container and the dropdown is a descendant.\n 2. self form — headless consumers spread \\`optionsPosition\\` from the hook's\n dropdownProps, so the attribute lands on the dropdown element itself.\n This lets the dropdown position above with NO wrapper attribute and no\n hand-copied CSS. */\n:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown],\n[data-aia-dropdown][data-options-position=\"above\"] {\n /* The stack is reversed here (the footer sits on top of the list), so the\n reserved band and the overlap flip to the top edge. */\n --aia-grid-scroll-bottom: 0px;\n --aia-grid-overlap-bottom: 0px;\n --aia-grid-scroll-top: var(--aia-footer-band);\n --aia-grid-overlap-top: calc(-1 * (var(--aia-footer-band) + 8px));\n --aia-footer-fade-inset: 0 0 calc(-1 * var(--aia-footer-fade-lead));\n /* The unfold flips with the stack: the collapsed sliver sits at the panel's\n bottom edge (against the input) and expands upward out of it. */\n transform-origin: 50% 100%;\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: var(--aia-dropdown-offset, 13px);\n}\n\n/* Declared after the optionsPosition=\"above\" block on purpose: that rule's\n second selector ([data-aia-dropdown][data-options-position=\"above\"]) has the\n same two-attribute specificity as this one, so source order is what decides\n which wins when a strip is present in an above-positioned dropdown. */\n/* Product strip present: the footer no longer sits on the scrolling option\n list — the strip is between them — so there is nothing to ride up over and\n nothing to reserve. Zeroing the band HERE, where it is defined, is the fix:\n the pull is a property of \"footer directly over the list\", not of the grid,\n and any section rendered after the grid would otherwise inherit it and land\n on top of the last option row. Both edges are zeroed because\n optionsPosition=\"above\" flips which one is in play. */\n[data-aia-dropdown][data-aia-has-products] {\n --aia-grid-scroll-bottom: 0px;\n --aia-grid-overlap-bottom: 0px;\n --aia-grid-scroll-top: 0px;\n --aia-grid-overlap-top: 0px;\n /* The fade exists to dissolve rows sliding under the footer. With the strip\n in between it has nothing to dissolve and would just wash over the cards. */\n --aia-footer-fade-lead: 0px;\n}\n\n:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] .aia-stack,\n[data-aia-dropdown][data-options-position=\"above\"] .aia-stack {\n flex-direction: column-reverse;\n}\n\n/* The footer now sits on top of the list, so its breathing room flips to the\n bottom edge — the side the option rows scroll under. */\n:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] [data-aia-footer],\n[data-aia-dropdown][data-options-position=\"above\"] [data-aia-footer] {\n padding: 0 0 var(--aia-footer-gap, 8px) 8px;\n}\n\n/* ...and the fade runs the other way, out of the footer and down into the list. */\n:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] [data-aia-footer]::before,\n[data-aia-dropdown][data-options-position=\"above\"] [data-aia-footer]::before {\n background: linear-gradient(to top, transparent, var(--aia-surface, #ffffff));\n}\n\n/* Disable all animations when data-animations=\"off\" */\n:where(.magicx-aia[data-animations=\"off\"]) *,\n:where(.magicx-aia[data-animations=\"off\"]) *::before,\n:where(.magicx-aia[data-animations=\"off\"]) *::after {\n animation-duration: 0s !important;\n transition-duration: 0s !important;\n}\n\n/* Desktop footer is opaque: the option list clips at the footer's edge instead\n of showing through it — the scroll cue lives in the last visible row's own\n text instead (the option scroll-hint rule). Mobile keeps the fade. Declared\n last, and carrying the unwrapped above-position selector some copies use\n (so it ties that rule's higher specificity and wins on cascade order);\n the glass surface still hides this pseudo-element entirely. */\n@media (min-width: 769px) {\n [data-aia-dropdown] [data-aia-footer]::before,\n [data-aia-dropdown][data-options-position=\"above\"] [data-aia-footer]::before,\n :where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] [data-aia-footer]::before {\n inset: 0;\n background: var(--aia-surface, #ffffff);\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport {};","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-3819c762\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-3819c762\";\n s.textContent = `.AIAutocompleteDropdown-module_dropdown_yz2KC {\n position: absolute;\n left: 0;\n right: 0;\n top: 100%;\n max-width: 544px;\n /* Gap between the input box and the dropdown. Tunable via --aia-dropdown-offset. */\n margin-top: var(--aia-dropdown-offset, 13px);\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n padding: 10px 8px;\n overflow: hidden;\n container-type: inline-size;\n z-index: 10;\n opacity: 0;\n pointer-events: none;\n /* Closed, the panel rests as a near-zero-height sliver at the input's edge\n (scaleY only — full width), so opening unfolds it top-to-bottom out of the\n input. The origin flips to the bottom edge for optionsPosition=\"above\" —\n see appearance.css. The transform \"transition\" on THIS side is a delayed\n snap: while closing, the panel holds its full size for the whole 400ms\n fade and only then collapses, ready for the next open. */\n transform-origin: 50% 0;\n transform: scaleY(var(--aia-dropdown-reveal-scale, 0.02));\n transition:\n opacity 400ms cubic-bezier(0.4, 0, 0.2, 1),\n transform 0s 400ms;\n /* Solid surface is the default (matches the Figma components). Opt into the\n frosted-glass look with data-aia-surface=\"glass\". */\n background: var(--aia-surface, #ffffff);\n border: 1px solid var(--aia-dropdown-border, rgba(231, 231, 231, 0.5));\n border-radius: 18px;\n box-shadow: var(--aia-dropdown-shadow, 0 8px 12px rgba(0, 0, 0, 0.05));\n}\n\n/* A calendar has nothing wide to read, so the whole panel narrows with it —\n the option grid's 544px cap leaves a month floating in empty panel. The\n :has() argument is the datepicker's data attribute, which all three packages\n emit identically; only the panel class differs per copy. */\n.AIAutocompleteDropdown-module_dropdown_yz2KC:has([data-aia-datepicker]) {\n max-width: var(--aia-date-panel-width, 312px);\n}\n\n.AIAutocompleteDropdown-module_dropdown_yz2KC[data-aia-surface=\"glass\"] {\n background: transparent;\n border-color: transparent;\n box-shadow:\n hsla(0, 0%, 100%, 1) -3.2px -3.2px 3.2px -3.2px inset,\n hsla(0, 0%, 100%, 1) 6.4px 6.4px 1.6px -8px inset,\n var(--aia-dropdown-bg, transparent) -6.4px 6.4px 1.6px -8px inset, /* same color as bg */\n var(--aia-dropdown-bg, transparent) 6.4px -6.4px 1.6px -8px inset, /* same color as bg */\n hsla(0, 0%, 100%, 0.15) -1.6px 0px 0px -1.6px inset,\n hsla(0, 0%, 100%, 0.15) 0px -1.6px 0px -1.6px inset,\n hsla(0, 0%, 100%, 0.3) 0px 1.6px 0px 0px inset,\n hsla(0, 0%, 100%, 0.3) 1.6px 0px 0px 0px inset,\n inset 0 0 30px 5px hsla(0, 0%, 0%, 0.05),\n hsla(0, 0%, 0%, 0.08) 0px 0px 30px 2px;\n backdrop-filter: blur(30px);\n}\n\n/* Opening: the panel unfolds top-to-bottom out of the input with a single\n spring settle while the option rows cascade in on top of it. Closing keeps\n the longer fade so a populated panel dissolves as one (the base rule above\n delays the transform snap until that fade has finished). */\n.AIAutocompleteDropdown-module_visible_QCoXj {\n opacity: 1;\n pointer-events: auto;\n transform: scaleY(1);\n /* Spring: the easing overshoots full height by a few percent and settles\n once (P1y = 1.28 — one spring, no bounce). Opacity resolves almost\n immediately so the unfold, not a fade, is what reads. */\n transition:\n opacity 100ms cubic-bezier(0.4, 0, 0.2, 1),\n transform 320ms cubic-bezier(0.22, 1.28, 0.36, 1);\n}\n\n/* \"More below\" scroll arrow — see the core's render/scrollArrow.ts. A round\n disc at the bottom-centre of the option list, shown while the list can still\n scroll down. It rests just above the grid's reserved band\n (--aia-scroll-arrow-bottom is measured and set inline by the controller so it\n tracks the grid's bottom edge in every layout) and hides by sliding down past\n the dropdown's lower edge, where the dropdown's overflow clips it — so it\n emerges from behind the footer. z-index 2 puts it over the option rows and\n under the footer (z-index 3). Declarations mirror vanilla's\n .magicx-aia-scroll-arrow and Angular's copy — change all three in the same\n commit. */\n.AIAutocompleteDropdown-module_scrollArrow_uUzV0 {\n position: absolute;\n left: 50%;\n bottom: var(--aia-scroll-arrow-bottom, 8px);\n z-index: 2;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n margin: 0 0 0 -16px;\n padding: 0;\n border: 1px solid\n var(--aia-scroll-arrow-border, var(--aia-dropdown-border, rgba(231, 231, 231, 0.5)));\n border-radius: 50%;\n background: var(--aia-scroll-arrow-bg, var(--aia-surface, #ffffff));\n color: var(\n --aia-scroll-arrow-color,\n var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb))\n );\n box-shadow: var(--aia-scroll-arrow-shadow, 0 2px 8px rgba(0, 0, 0, 0.12));\n cursor: pointer;\n pointer-events: none;\n transform: translateY(calc(100% + var(--aia-scroll-arrow-bottom, 8px) + 4px));\n transition: transform 180ms cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.AIAutocompleteDropdown-module_scrollArrow_uUzV0[data-aia-visible] {\n pointer-events: auto;\n transform: translateY(0);\n}\n\n.AIAutocompleteDropdown-module_scrollArrow_uUzV0:hover {\n color: var(\n --aia-scroll-arrow-color-hover,\n var(--aia-option-color-selected, var(--aia-color-text-default, #fff))\n );\n}\n\n@media (prefers-reduced-motion: reduce) {\n .AIAutocompleteDropdown-module_scrollArrow_uUzV0,\n .AIAutocompleteDropdown-module_dropdown_yz2KC {\n transition-duration: 0s;\n }\n}\n\n/* The dropdown container owns the 10px/8px edge padding and the 8px section\n gaps (matching Figma); the pill row adds none. The horizontal scroll + fade\n live on the inner .pillScroll wrapper, NOT the bar itself: the trailing skip\n button is the bar's other child, and a mask on the bar would fade it out\n along with the overflowing pills it's meant to sit beside. */\n.AIAutocompleteDropdown-module_pillBar_pwTXe {\n overflow: hidden;\n}\n\n/* Scrollable region for the pills. The appearance layer's\n \\`[data-aia-pillbar] > span\\` rule lands here (10px inline padding aligning\n the param label with the option text), so the inner PillList span must not\n add its own base padding on top — see the child rule below. */\n.AIAutocompleteDropdown-module_pillScroll_Tpzus {\n display: inline-flex;\n align-items: center;\n flex: 1 1 auto;\n min-width: 0;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: none;\n mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 48px), transparent 100%);\n -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 48px), transparent 100%);\n}\n\n.AIAutocompleteDropdown-module_pillScroll_Tpzus > span {\n padding-inline: 0;\n}\n\n.AIAutocompleteDropdown-module_pillScroll_Tpzus::-webkit-scrollbar {\n display: none;\n}\n\n/* Trailing \"skip\" button — dismisses the active pill, same action as pressing\n → at the end of the input. Pinned at the bar's far edge (auto inline-start\n margin), outside the masked scroller. Typography follows the footer hint\n (quiet chrome), not the pills. Declarations mirror \\`.magicx-aia-skip\\` in the\n vanilla stylesheet — change both in the same commit. */\n.AIAutocompleteDropdown-module_skip_7-olS {\n display: inline-flex;\n align-items: center;\n margin-inline-start: auto;\n flex-shrink: 0;\n padding: 5px 8px;\n border: none;\n /* Matches the completed-param chip radius, so the hover fill reads as a\n soft rectangle rather than a capsule. */\n border-radius: 6px;\n background: transparent;\n font-family: inherit;\n font-size: var(--aia-skip-font-size, 10px);\n line-height: 18px;\n color: var(--aia-skip-color, var(--aia-footer-hint-color, #505050));\n cursor: pointer;\n white-space: nowrap;\n transition:\n color 150ms ease-out,\n background-color 150ms ease-out;\n}\n\n.AIAutocompleteDropdown-module_skip_7-olS:hover {\n color: var(--aia-skip-color-hover, var(--aia-pill-color, var(--aia-color-text-muted, #c1c4cb)));\n /* Same fill as a highlighted option row (--aia-option-bg), so the hover\n reads with the dropdown's own hover language and stays visible on both\n mode surfaces. */\n background: var(--aia-skip-hover-bg, var(--aia-option-bg, transparent));\n}\n\n.AIAutocompleteDropdown-module_skip_7-olS:disabled {\n pointer-events: none;\n cursor: default;\n opacity: 0.5;\n}\n\n/* --- Fallback loading skeleton (only when no pills/options are cached) --- */\n.AIAutocompleteDropdown-module_skeletonBars_HVr9C {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 7px 8px;\n}\n\n.AIAutocompleteDropdown-module_skeletonBar_O3xIx {\n display: block;\n height: 14px;\n border-radius: 999px;\n background: var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, 0.25)));\n opacity: 0.5;\n animation: AIAutocompleteDropdown-module_aiaSkeletonPulse_G8W7q 1.4s ease-in-out infinite;\n}\n\n.AIAutocompleteDropdown-module_skeletonBar_O3xIx:nth-child(2) {\n animation-delay: 150ms;\n}\n\n.AIAutocompleteDropdown-module_skeletonBar_O3xIx:nth-child(3) {\n animation-delay: 300ms;\n}\n\n@keyframes AIAutocompleteDropdown-module_aiaSkeletonPulse_G8W7q {\n 0%,\n 100% {\n opacity: 0.5;\n }\n 50% {\n opacity: 0.25;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"dropdown\":\"AIAutocompleteDropdown-module_dropdown_yz2KC\",\"visible\":\"AIAutocompleteDropdown-module_visible_QCoXj\",\"scrollArrow\":\"AIAutocompleteDropdown-module_scrollArrow_uUzV0\",\"pillBar\":\"AIAutocompleteDropdown-module_pillBar_pwTXe\",\"pillScroll\":\"AIAutocompleteDropdown-module_pillScroll_Tpzus\",\"skip\":\"AIAutocompleteDropdown-module_skip_7-olS\",\"skeletonBars\":\"AIAutocompleteDropdown-module_skeletonBars_HVr9C\",\"skeletonBar\":\"AIAutocompleteDropdown-module_skeletonBar_O3xIx\",\"aiaSkeletonPulse\":\"AIAutocompleteDropdown-module_aiaSkeletonPulse_G8W7q\"};","import {\n cellDay,\n cellIso,\n type DateMonthView,\n isoDate,\n monthLabel,\n type SuggestionOption,\n WEEKDAY_LABELS,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { useState } from \"react\";\nimport styles from \"./DateGrid.module.css\";\n\n/**\n * Stable keys for the weekday row. The labels themselves repeat (\"S\", \"T\"), so\n * they can't key the list, and the index can't either without tripping\n * `noArrayIndexKey` — the row is static and never reorders, but the linter has\n * no way to know that.\n */\nconst WEEKDAY_KEYS = [\"sunday\", \"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\", \"saturday\"];\n\nexport interface DateGridProps {\n /** The visible month's cells. These ARE `filteredOptions` — see `buildDateOptions`. */\n options: SuggestionOption[];\n activeIndex: number;\n listboxId: string;\n view: DateMonthView;\n /** `YYYY-MM-DD` the param being re-edited already holds, or null. */\n selectedIso: string | null;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n onPreviousMonth: () => void;\n onNextMonth: () => void;\n}\n\n/**\n * The dropdown's calendar body, rendered in place of the options grid when the\n * active parameter is a date. React analogue of vanilla's `renderDateGrid`.\n *\n * The cells carry the same `${listboxId}-option-${i}` ids, `role=\"option\"` and\n * `aria-selected` the options grid emits, and that is load-bearing rather than\n * cosmetic: the keyboard controller lives in the vanilla core for all three\n * packages, navigates by index into `filteredOptions`, and commits by clicking\n * `#${listboxId}-option-${i}`. `getEffectiveColumns` also measures the live\n * `grid-template-columns` of option-0's parent, which is why the 7 columns sit\n * on the cell container itself and not on an ancestor.\n */\nexport function DateGrid({\n options,\n activeIndex,\n listboxId,\n view,\n selectedIso,\n onSelect,\n onHighlight,\n onPreviousMonth,\n onNextMonth,\n}: DateGridProps) {\n const today = isoDate(new Date());\n\n return (\n <div className={styles.datepicker} data-aia-datepicker=\"\">\n <div className={styles.header}>\n <button\n type=\"button\"\n // Out of the tab order for the same reason the skip button is: Tab is\n // already bound to walking the dropdown's options.\n tabIndex={-1}\n className={styles.nav}\n data-aia-date-prev=\"\"\n aria-label=\"Previous month\"\n // Keeps the input focused, which the visibility gate depends on.\n onMouseDown={(e) => e.preventDefault()}\n onClick={onPreviousMonth}\n >\n ‹\n </button>\n <span className={styles.month} data-aia-date-month=\"\" aria-live=\"polite\">\n {monthLabel(view)}\n </span>\n <button\n type=\"button\"\n tabIndex={-1}\n className={styles.nav}\n data-aia-date-next=\"\"\n aria-label=\"Next month\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={onNextMonth}\n >\n ›\n </button>\n </div>\n\n {/* Decorative: each cell announces its own full date, so repeating the\n column letters to AT adds noise — and the duplicate T/S would be\n meaningless read aloud anyway. */}\n <div className={styles.weekdays} aria-hidden=\"true\">\n {WEEKDAY_LABELS.map((label, i) => (\n <span key={WEEKDAY_KEYS[i]} className={styles.weekday}>\n {label}\n </span>\n ))}\n </div>\n\n <div className={styles.grid} data-aia-date-grid=\"\">\n {options.map((option, i) => (\n <DateCell\n // Padding cells have no date of their own, so they key off position.\n key={cellIso(option) ?? `pad-${i}`}\n option={option}\n id={`${listboxId}-option-${i}`}\n index={i}\n isHighlighted={i === activeIndex && option.is_tappable}\n isToday={cellIso(option) === today}\n isPast={cellIso(option) != null && (cellIso(option) as string) < today}\n isSelected={selectedIso != null && cellIso(option) === selectedIso}\n onSelect={onSelect}\n onHighlight={onHighlight}\n />\n ))}\n </div>\n </div>\n );\n}\n\ninterface DateCellProps {\n option: SuggestionOption;\n id: string;\n index: number;\n isHighlighted: boolean;\n isToday: boolean;\n /** Before today: rendered dimmed, but every bit as pickable as the rest. */\n isPast: boolean;\n isSelected: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n}\n\nfunction DateCell({\n option,\n id,\n index,\n isHighlighted,\n isToday,\n isPast,\n isSelected,\n onSelect,\n onHighlight,\n}: DateCellProps) {\n const [pressed, setPressed] = useState(false);\n const day = cellDay(option);\n\n if (day == null) {\n // Padding for the days before the 1st / after the last. Non-tappable, so\n // arrow navigation skips it; hidden from AT so the month reads as its own\n // days and nothing else.\n return (\n <div\n id={id}\n role=\"option\"\n data-aia-option=\"\"\n data-aia-date-cell=\"\"\n aria-hidden=\"true\"\n aria-selected={false}\n tabIndex={-1}\n className={`${styles.cell} ${styles.blank}`}\n />\n );\n }\n\n const handleSelect = () => {\n setPressed(true);\n onSelect(option);\n setTimeout(() => setPressed(false), 500);\n };\n\n const className = [\n styles.cell,\n styles.day,\n isPast ? styles.past : \"\",\n isHighlighted ? styles.highlighted : \"\",\n isToday ? styles.today : \"\",\n isSelected ? styles.selected : \"\",\n pressed ? styles.pressed : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n id={id}\n role=\"option\"\n data-aia-option=\"\"\n data-aia-date-cell=\"\"\n aria-selected={isHighlighted}\n // The cell paints the day number; `option.text` is the full committed\n // value (\"March 23 2026\") and is what AT should announce, since that is\n // what selecting it puts in the input.\n aria-label={option.text}\n tabIndex={0}\n className={className}\n onClick={handleSelect}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleSelect();\n }\n }}\n onMouseEnter={() => onHighlight(index)}\n >\n <span className={styles.number}>{day}</span>\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-f687bd03\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-f687bd03\";\n s.textContent = `/* --- Datepicker (replaces the options grid for date suggestions) ---\n\n One of three hand-maintained copies (vanilla styles.css, this file, Angular's\n date-grid.component.css). Only the class-naming layer differs — the\n declarations must match, and \\`datepickerParity.test.ts\\` fails the build if\n they drift. See CLAUDE.md's duplicated-stylesheet rule.\n\n Every colour resolves through the same --aia-option-* chain the option rows\n use. The dropdown paints a background but sets no \\`color\\`, so anything here\n relying on \\`color: inherit\\` would pick up the HOST page's text colour and go\n black on a dark panel — and \\`prefers-color-scheme\\` can't be used to guess,\n because the panel's darkness comes from --aia-surface, which the media query\n says nothing about. Going through the option chain means one consumer\n override restyles the calendar and the options together. */\n.DateGrid-module_datepicker_6RrTs {\n display: flex;\n flex-direction: column;\n gap: 4px;\n /* Bottom-heavier trim than the top: the compression the compact calendar\n asks for comes out of the bottom edge and the space between cells, never\n the header area or the side gutters. */\n padding: 4px 2px 4px;\n}\n\n.DateGrid-module_header_z4LRk {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 2px 6px 6px;\n}\n\n.DateGrid-module_month_urB2T {\n font-family: inherit;\n font-size: var(--aia-date-month-font-size, 14px);\n font-weight: 500;\n line-height: 20px;\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n}\n\n.DateGrid-module_nav_ap4AN {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n border: none;\n border-radius: 6px;\n background: transparent;\n font-family: inherit;\n font-size: 16px;\n line-height: 1;\n color: var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));\n cursor: pointer;\n transition:\n color 150ms ease-out,\n background-color 150ms ease-out;\n}\n\n.DateGrid-module_nav_ap4AN:hover {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n background: var(--aia-option-bg, transparent);\n}\n\n.DateGrid-module_weekdays_3EA3q,\n.DateGrid-module_grid_mQCgw {\n display: grid;\n /* The 7 columns live on the cell container itself, not on an ancestor:\n KeyboardController.getEffectiveColumns() measures grid-template-columns by\n walking up from option-0's PARENT, and it is this number that makes\n ArrowDown mean \"+1 week\". */\n grid-template-columns: repeat(7, minmax(0, 1fr));\n}\n\n.DateGrid-module_weekday_3lF4B {\n padding: 2px 0;\n text-align: center;\n font-family: inherit;\n font-size: var(--aia-date-weekday-font-size, 11px);\n font-weight: 500;\n line-height: 16px;\n color: var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));\n opacity: 0.7;\n}\n\n.DateGrid-module_cell_59k0y {\n display: flex;\n align-items: center;\n justify-content: center;\n /* Deliberately NOT sized here. Giving the grid item a definite size (an\n aspect-ratio, a width) stops it stretching to its track, so it parks at\n the track's start edge and the whole month drifts left of the weekday\n header above it — the two grids agree on their columns, and only the\n items disagree, which makes it look like a column-count bug. The cell\n fills its track; the square is the number span inside it. */\n min-width: 0;\n /* Keeps a month readable in a narrow dropdown without letting a 6-row month\n grow the panel past the options grid it replaces. */\n height: var(--aia-date-row-height, 28px);\n font-family: inherit;\n font-size: var(--aia-date-cell-font-size, 13px);\n font-weight: 450;\n line-height: 20px;\n color: var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));\n}\n\n/* The visual box: everything a cell paints — fill, ring, press — lands here so\n it reads as a square centred in its column rather than a full-width band. */\n.DateGrid-module_number_aoT01 {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--aia-date-cell-size, 26px);\n height: var(--aia-date-cell-size, 26px);\n border-radius: 6px;\n}\n\n.DateGrid-module_day_cB3u9 {\n cursor: pointer;\n}\n\n.DateGrid-module_blank_ivgRC {\n cursor: default;\n}\n\n/* A day before today: dimmed so the month visibly starts at today, but still\n fully interactive — hover and click behave like any other day. */\n.DateGrid-module_past_CEZsj {\n opacity: 0.35;\n}\n\n.DateGrid-module_day_cB3u9:hover .DateGrid-module_number_aoT01,\n.DateGrid-module_highlighted_YIdtK .DateGrid-module_number_aoT01 {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n background: var(--aia-option-bg, transparent);\n font-weight: 500;\n}\n\n/* Today reads as an outline, the committed answer as a fill — so a re-edited\n date can show both at once without either being ambiguous. */\n.DateGrid-module_today_iI3ME .DateGrid-module_number_aoT01 {\n box-shadow: inset 0 0 0 1px\n var(--aia-date-today-ring, var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb)));\n}\n\n.DateGrid-module_selected_28KDn .DateGrid-module_number_aoT01 {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n background: var(--aia-date-selected-bg, rgba(var(--aia-streak-rgb, 255, 255, 255), 0.12));\n font-weight: 500;\n}\n\n.DateGrid-module_pressed_bEyyN .DateGrid-module_number_aoT01 {\n opacity: 0.8;\n background: rgba(var(--aia-streak-rgb, 255, 255, 255), 0.06);\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"datepicker\":\"DateGrid-module_datepicker_6RrTs\",\"header\":\"DateGrid-module_header_z4LRk\",\"month\":\"DateGrid-module_month_urB2T\",\"nav\":\"DateGrid-module_nav_ap4AN\",\"weekdays\":\"DateGrid-module_weekdays_3EA3q\",\"grid\":\"DateGrid-module_grid_mQCgw\",\"weekday\":\"DateGrid-module_weekday_3lF4B\",\"cell\":\"DateGrid-module_cell_59k0y\",\"number\":\"DateGrid-module_number_aoT01\",\"day\":\"DateGrid-module_day_cB3u9\",\"blank\":\"DateGrid-module_blank_ivgRC\",\"past\":\"DateGrid-module_past_CEZsj\",\"highlighted\":\"DateGrid-module_highlighted_YIdtK\",\"today\":\"DateGrid-module_today_iI3ME\",\"selected\":\"DateGrid-module_selected_28KDn\",\"pressed\":\"DateGrid-module_pressed_bEyyN\"};","import {\n ATTRIBUTION_URL,\n buildAttributionUrl,\n getFooterHint,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { useEffect, useState } from \"react\";\nimport { Cluster } from \"../layout/Cluster\";\nimport styles from \"./DropdownFooter.module.css\";\n\ninterface DropdownFooterProps {\n /**\n * Whether an option is currently highlighted. Takes priority: when true the\n * hint reads \"enter to proceed\".\n */\n isOptionHighlighted?: boolean;\n /**\n * Whether the input has no typed text. When true (and no option is\n * highlighted) the hint reads \"tab to select\" — see {@link getFooterHint}.\n */\n isInputEmpty?: boolean;\n}\n\n// Dropdown chrome: a keyboard hint on the left, AI-Autocomplete branding on the\n// right.\nexport function DropdownFooter({\n isOptionHighlighted = false,\n isInputEmpty = false,\n}: DropdownFooterProps) {\n const { key, hint } = getFooterHint(isOptionHighlighted, isInputEmpty);\n // Initial state is the bare base URL so it matches server-rendered output (no\n // hydration mismatch); the effect appends utm_source after mount on the client.\n const [brandHref, setBrandHref] = useState(ATTRIBUTION_URL);\n useEffect(() => {\n setBrandHref(buildAttributionUrl());\n }, []);\n return (\n <footer className={styles.footer} data-aia-footer=\"\">\n <Cluster justify=\"between\" noWrap className={styles.row}>\n <Cluster gap=\"5px\" className={styles.hintGroup}>\n <kbd className={styles.key}>{key}</kbd>\n <span className={styles.hint}>{hint}</span>\n </Cluster>\n <a className={styles.brandLink} href={brandHref} target=\"_blank\" rel=\"noopener noreferrer\">\n <span className={styles.brand}>AI</span>\n <span className={styles.badge}>Autocomplete</span>\n </a>\n </Cluster>\n </footer>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-5259a217\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-5259a217\";\n s.textContent = `@layer layout {\n .aia-cluster {\n display: flex;\n flex-wrap: wrap;\n gap: var(--aia-cluster-gap, 0.5rem);\n }\n /* Inline-level variant — used when the cluster must sit inline (e.g. inside\n a contentEditable). Rendered on a <span> so it's valid inline content. */\n .aia-cluster[data-inline] {\n display: inline-flex;\n }\n .aia-cluster[data-nowrap] {\n flex-wrap: nowrap;\n }\n .aia-cluster[data-align=\"start\"] {\n align-items: start;\n }\n .aia-cluster[data-align=\"center\"] {\n align-items: center;\n }\n .aia-cluster[data-align=\"end\"] {\n align-items: end;\n }\n .aia-cluster[data-align=\"baseline\"] {\n align-items: baseline;\n }\n .aia-cluster[data-justify=\"start\"] {\n justify-content: start;\n }\n .aia-cluster[data-justify=\"center\"] {\n justify-content: center;\n }\n .aia-cluster[data-justify=\"end\"] {\n justify-content: end;\n }\n .aia-cluster[data-justify=\"between\"] {\n justify-content: space-between;\n }\n .aia-cluster[data-justify=\"around\"] {\n justify-content: space-around;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport {};","import type { ComponentPropsWithoutRef, CSSProperties, ReactNode } from \"react\";\nimport \"./Cluster.css\";\n\ninterface ClusterProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"className\"> {\n /** Gap between children. Any CSS length. Defaults to `0.5rem`. */\n gap?: string;\n /** Cross-axis alignment. Defaults to `center`. */\n align?: \"start\" | \"center\" | \"end\" | \"baseline\";\n /** Main-axis distribution. Defaults to `start`. */\n justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\";\n /** When true, the wrapper does NOT flex-wrap (single-row clusters). */\n noWrap?: boolean;\n /** Render as an inline-level `<span>` (inline-flex) instead of a block `<div>`. */\n inline?: boolean;\n className?: string;\n children: ReactNode;\n}\n\n// Horizontal layout primitive — wraps when out of room. `noWrap` for single-row clusters. Internal.\nexport function Cluster({\n gap,\n align = \"center\",\n justify = \"start\",\n noWrap = false,\n inline = false,\n className,\n children,\n ...rest\n}: ClusterProps) {\n const style = gap ? ({ \"--aia-cluster-gap\": gap } as CSSProperties) : undefined;\n const props = {\n className: className ? `aia-cluster ${className}` : \"aia-cluster\",\n \"data-align\": align,\n \"data-justify\": justify,\n \"data-nowrap\": noWrap || undefined,\n \"data-inline\": inline || undefined,\n style,\n ...rest,\n };\n if (inline) return <span {...props}>{children}</span>;\n return <div {...props}>{children}</div>;\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-56b0c577\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-56b0c577\";\n s.textContent = `/* The footer adds its own 8px horizontal inset so it stays clear of the\n dropdown's rounded edges. The top inset (--aia-footer-gap) adds breathing\n room above the hint/branding row so the footer doesn't butt against the last\n option row — additive to the dropdown's 8px section gap. */\n.DropdownFooter-module_footer_qQQ7x {\n display: flex;\n flex-direction: column;\n gap: 8px;\n /* No right inset: the brand pill's own padding (below) supplies it, so the\n badge sits as far from the right edge as it does from the bottom — 12px\n both ways (dropdown padding 10 + pill 2 down, dropdown padding 8 + pill 4\n across). */\n padding: var(--aia-footer-gap, 8px) 0 0 8px;\n /* The fade itself lives in appearance.css, on the footer's background.\n Paints above the rows it covers: option content sits at z-index 2 (see\n SuggestionItem.module.css) in this same stacking context, so anything\n lower would end up *behind* the rows. */\n position: relative;\n z-index: 3;\n /* Sitting on top of the list would otherwise swallow clicks and hovers on\n the rows scrolling under it — only the branding link needs to be hit. */\n pointer-events: none;\n}\n\n.DropdownFooter-module_hintGroup_ZzbPf {\n min-width: 0;\n}\n\n/* Re-enabled over the footer's \\`pointer-events: none\\`: both groups are visible\n chips sitting on the scroll band, so a click on one must land on the chip\n rather than falling through to the option row behind it. */\n.DropdownFooter-module_hintGroup_ZzbPf,\n.DropdownFooter-module_brandLink_r4f3R {\n pointer-events: auto;\n}\n\n.DropdownFooter-module_brandLink_r4f3R {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n text-decoration: none;\n cursor: pointer;\n transition: opacity 150ms ease-out;\n}\n\n/* The two content groups carry a solid surface fill so the keyboard hint and\n the AI-Autocomplete badge stay fully legible over whatever option row is\n scrolling behind the footer. The inline padding keeps the fill from hugging\n the glyphs. --aia-footer-chip-bg resolves to \\`transparent\\` on the glass\n surface, where there's no solid color to fill with. */\n.DropdownFooter-module_hintGroup_ZzbPf,\n.DropdownFooter-module_brandLink_r4f3R {\n /* Mixed here rather than declared on the container: a custom property\n substitutes var() on the element its declaration applies to, so a mix\n computed upstream would freeze the *theme's* surface and miss a\n dropdown-level --aia-surface retint. Computed on the footer, it picks up\n whichever ancestor set the surface. --aia-footer-chip-bg stays the\n override hook — consumers set it, and the glass surface zeroes it. */\n background: var(\n --aia-footer-chip-bg,\n color-mix(in srgb, var(--aia-surface, #ffffff) 65%, transparent)\n );\n padding-inline: 4px;\n border-radius: 6px;\n}\n\n/* The brand sits at the right edge where option rows scroll under the fade, so\n \"AI\" was getting clipped / washed out. Give the whole brand its own opaque,\n fully-rounded surface pill so it always reads clearly over the fade. Declared\n after the shared .hintGroup/.brandLink chip rule so it wins. */\n.DropdownFooter-module_brandLink_r4f3R {\n background: var(--aia-footer-brand-pill-bg, var(--aia-surface, #ffffff));\n border-radius: 999px;\n padding: 2px 4px;\n gap: 4px;\n}\n\n.DropdownFooter-module_brandLink_r4f3R:hover {\n opacity: 0.7;\n}\n\n.DropdownFooter-module_key_Bz1H- {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 30px;\n height: 22px;\n padding: 2px 6px;\n border: 0.5px solid var(--aia-footer-hint-color, #505050);\n border-radius: 5px;\n font-family: inherit;\n font-size: 11px;\n line-height: 18px;\n color: var(--aia-footer-hint-color, #505050);\n}\n\n.DropdownFooter-module_hint_GKEOH {\n font-family: inherit;\n font-size: 11px;\n line-height: 18px;\n color: var(--aia-footer-hint-color, #505050);\n}\n\n.DropdownFooter-module_brand_Al-lR {\n font-family: inherit;\n font-size: 10px;\n line-height: 18px;\n color: var(--aia-footer-brand-color, #b0b0b0);\n}\n\n.DropdownFooter-module_badge_Fk9vg {\n display: inline-flex;\n align-items: center;\n height: var(--aia-footer-row-height, 23px);\n padding: 2.5px 5.5px;\n border: 0.5px solid var(--aia-footer-badge-border, rgba(189, 189, 189, 0.51));\n border-radius: 999px;\n font-family: inherit;\n font-size: 10px;\n line-height: 18px;\n color: var(--aia-footer-brand-color, #b0b0b0);\n}\n\n/* Mobile footer variant (Figma \"Mobile\"): on phone-width viewports drop the\n keyboard hint (\"tab to select\" is meaningless on touch), leaving only the\n AI-Autocomplete brand pinned to the right. */\n@media (max-width: 768px) {\n .DropdownFooter-module_hintGroup_ZzbPf {\n display: none;\n }\n .DropdownFooter-module_row_BgZ6Q {\n justify-content: flex-end;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"footer\":\"DropdownFooter-module_footer_qQQ7x\",\"hintGroup\":\"DropdownFooter-module_hintGroup_ZzbPf\",\"brandLink\":\"DropdownFooter-module_brandLink_r4f3R\",\"key\":\"DropdownFooter-module_key_Bz1H-\",\"hint\":\"DropdownFooter-module_hint_GKEOH\",\"brand\":\"DropdownFooter-module_brand_Al-lR\",\"badge\":\"DropdownFooter-module_badge_Fk9vg\",\"row\":\"DropdownFooter-module_row_BgZ6Q\"};","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-199d0432\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-199d0432\";\n s.textContent = `/* ParamPill (Figma \"ParamPill\") — unfilled suggestion pill: transparent fill,\n no outline. ~28px via 6px padding + 14px text + the 1px border (border-box).\n The border is kept as a 1px transparent line so the box stays the same size\n as it was when the outline was dashed. */\n.ParamPill-module_pill_6Ga7S {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 5px 8px;\n border: 1px solid transparent;\n border-radius: 7px;\n background: transparent;\n color: var(--aia-pill-color, var(--aia-color-text-muted, #c1c4cb));\n font-family: inherit;\n /* Param labels read as small-caps section headers: distinctly smaller than\n the options they head (0.8× the pill knob), uppercased, and letter-spaced. */\n font-size: calc(var(--aia-pill-font-size, 14px) * 0.8);\n font-weight: 600;\n line-height: normal;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n cursor: pointer;\n white-space: nowrap;\n animation: ParamPill-module_fadeIn_Ux4eQ 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n.ParamPill-module_rounded_y7xA9 {\n border-radius: 999px;\n}\n\n/* Loading skeleton — preserves the pill's exact box (same width and height)\n and hides the text. The base pill is now transparent, so fill the interior\n with the skeleton color (inside the dashed border) and pulse it so it still\n reads as a loading chip. */\n.ParamPill-module_skeleton_57P0T {\n pointer-events: none;\n cursor: default;\n color: transparent;\n background: var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, 0.25)));\n animation: ParamPill-module_skeletonPulse_xGcUy 1.4s ease-in-out infinite;\n}\n\n@keyframes ParamPill-module_skeletonPulse_xGcUy {\n 0%,\n 100% {\n filter: brightness(1);\n }\n 50% {\n filter: brightness(0.55);\n }\n}\n\n@keyframes ParamPill-module_fadeIn_Ux4eQ {\n from {\n opacity: 0;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"pill\":\"ParamPill-module_pill_6Ga7S\",\"fadeIn\":\"ParamPill-module_fadeIn_Ux4eQ\",\"rounded\":\"ParamPill-module_rounded_y7xA9\",\"skeleton\":\"ParamPill-module_skeleton_57P0T\",\"skeletonPulse\":\"ParamPill-module_skeletonPulse_xGcUy\"};","import type { MouseEvent } from \"react\";\nimport styles from \"./ParamPill.module.css\";\n\n/**\n * Visual emphasis tier for a pill. The selected (active) pill renders in the\n * `selected` state; every other pill takes its tier from its position in the\n * upcoming-params sequence — `first`, `next`, then `last` for the rest —\n * progressively de-emphasized.\n */\nexport type PillState = \"selected\" | \"first\" | \"next\" | \"last\";\n\n/** Opacity applied per state. Kept here so `PillList` skeletons stay in sync. */\nexport const PARAM_PILL_OPACITY: Record<PillState, number> = {\n selected: 1,\n first: 0.7,\n next: 0.4,\n last: 0.2,\n};\n\ninterface ParamPillProps {\n /** Pill label text. */\n label: string;\n /** Visual emphasis tier (drives opacity). */\n state: PillState;\n /** Renders the selection outline (the pill at the active index). */\n selected?: boolean;\n /** Capsule shape (fully rounded). Default: false. */\n rounded?: boolean;\n /** Non-interactive shimmering skeleton. */\n loading?: boolean;\n onClick?: () => void;\n}\n\n/**\n * ParamPill — the unfilled suggestion pill (Figma component \"ParamPill\",\n * formerly \"Pill\"). Rendered in the dropdown pill-bar and the inline pill list.\n */\nexport function ParamPill({ label, state, rounded, loading, onClick }: ParamPillProps) {\n const className = [styles.pill, rounded ? styles.rounded : \"\", loading ? styles.skeleton : \"\"]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <button\n type=\"button\"\n data-aia-pill=\"\"\n data-aia-loading={loading ? \"\" : undefined}\n tabIndex={-1}\n contentEditable={false}\n suppressContentEditableWarning\n className={className}\n style={{ opacity: PARAM_PILL_OPACITY[state] }}\n onMouseDown={(e: MouseEvent) => e.preventDefault()}\n onClick={loading ? undefined : onClick}\n disabled={loading}\n >\n {label}\n </button>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-0fcb7940\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-0fcb7940\";\n s.textContent = `.PillList-module_list_qvLqO {\n position: relative;\n z-index: 1;\n pointer-events: auto;\n display: inline-flex;\n gap: 7px;\n padding: 0 8px;\n align-items: center;\n vertical-align: middle;\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"list\":\"PillList-module_list_qvLqO\"};","import type { Suggestion } from \"../types\";\nimport { PARAM_PILL_OPACITY, ParamPill, type PillState } from \"./ParamPill\";\nimport pillStyles from \"./ParamPill.module.css\";\nimport styles from \"./PillList.module.css\";\n\ninterface PillListProps {\n pills: Suggestion[];\n activePillIndex: number;\n onSelectPill: (index: number) => void;\n /**\n * Whether the active pill should render in the `selected` state (full\n * opacity) rather than its positional `first` tier. In `auto` dropdown mode\n * this is true only while a dropdown option is highlighted; in `manual` mode\n * it becomes true once the user taps a pill. Default: false.\n */\n activeSelected?: boolean;\n /** Use capsule-shaped pills (fully rounded). Default: false. */\n rounded?: boolean;\n /**\n * When true, the rendered pills become non-interactive shimmering skeletons.\n * Real pills (with their text) are rendered when provided so widths/positions\n * match the previous state; when `pills` is empty, fixed-width fallback\n * placeholders are rendered instead.\n */\n loading?: boolean;\n}\n\nconst FALLBACK_SKELETON_WIDTHS = [125, 69];\n\n/**\n * Map a pill's index to its positional emphasis tier. The selected (active)\n * pill is handled separately — only the at-most-three positions get a tier\n * here: first, next, then last for everything after.\n */\nfunction pillStateForIndex(index: number): PillState {\n if (index === 0) return \"first\";\n if (index === 1) return \"next\";\n return \"last\";\n}\n\nexport function PillList({\n pills,\n activePillIndex,\n onSelectPill,\n activeSelected,\n rounded,\n loading,\n}: PillListProps) {\n if (loading && pills.length === 0) {\n return (\n <span className={styles.list} data-aia-pill-list-loading=\"\">\n {FALLBACK_SKELETON_WIDTHS.map((w, i) => (\n <span\n key={`skel-${w}`}\n data-aia-pill-skeleton=\"\"\n className={`${pillStyles.pill} ${rounded ? pillStyles.rounded : \"\"} ${pillStyles.skeleton}`}\n style={{ width: w, opacity: PARAM_PILL_OPACITY[pillStateForIndex(i)] }}\n />\n ))}\n </span>\n );\n }\n\n return (\n <span className={styles.list} data-aia-pill-list-loading={loading ? \"\" : undefined}>\n {pills.map((pill, i) => {\n // The active pill is \"selected\" only when activeSelected is set;\n // otherwise it shows its positional tier (first/next/last).\n const selected = Boolean(activeSelected) && i === activePillIndex;\n return (\n <ParamPill\n key={`${pill.type}-${pill.text}`}\n label={pill.text}\n state={selected ? \"selected\" : pillStateForIndex(i)}\n selected={selected}\n rounded={rounded}\n loading={loading}\n onClick={() => onSelectPill(i)}\n />\n );\n })}\n </span>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-fef1688d\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-fef1688d\";\n s.textContent = `/* Product strip — the React counterpart of the vanilla core's strip rules\n (packages/vanilla/src/styles.css). Same tokens, same defaults, so a consumer\n theming one package sees the same result in the other.\n\n Nothing here is allowed to say \\`color: inherit\\`: the dropdown paints a\n background but never sets a \\`color\\`, so an inheriting node would pick up the\n HOST PAGE's text colour and render black text on a dark panel. For the same\n reason there is no \\`prefers-color-scheme\\` rule in this file — the panel's\n darkness comes from --aia-surface, which is independent of the OS setting. */\n\n.ProductStrip-module_section_Hugfg {\n display: flex;\n flex-direction: column;\n gap: 6px;\n /* Matches the grid's own 8px inline padding so the section label lines up\n with the option text above it. */\n padding: 0 8px;\n min-width: 0;\n}\n\n.ProductStrip-module_label_nuc93 {\n font-family: inherit;\n font-size: var(--aia-products-label-font-size, 11px);\n font-weight: 500;\n line-height: 18px;\n letter-spacing: 0.02em;\n color: var(\n --aia-products-label-color,\n var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb))\n );\n}\n\n/* The scroll container. Horizontal overflow is confined here — the dropdown\n itself is \\`overflow: hidden\\`, so the page can never gain a sideways\n scrollbar no matter how many cards there are. \\`overscroll-behavior-x\\` stops\n a trackpad fling at either end from chaining out to the page. */\n.ProductStrip-module_row_WDVBX {\n display: flex;\n gap: var(--aia-product-gap, 8px);\n min-width: 0;\n overflow-x: auto;\n overflow-y: hidden;\n overscroll-behavior-x: contain;\n padding-bottom: 2px;\n /* Hide the scrollbar chrome across all three engines while leaving the box\n scrollable by trackpad, wheel, touch and keyboard. */\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n.ProductStrip-module_row_WDVBX::-webkit-scrollbar {\n display: none;\n}\n\n.ProductStrip-module_card_JBGYT {\n flex: 0 0 auto;\n display: flex;\n flex-direction: column;\n gap: 6px;\n width: var(--aia-product-card-width, 116px);\n padding: 6px;\n border-radius: 10px;\n background: var(--aia-product-bg, transparent);\n /* Explicit, never inherited — see the file header. */\n color: var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));\n text-decoration: none;\n cursor: pointer;\n transition: background-color 150ms ease;\n}\n\n.ProductStrip-module_card_JBGYT:hover {\n background: var(--aia-product-bg-active, var(--aia-option-bg, transparent));\n}\n\n/* Focus is the only cue a keyboard user gets, so it is a real ring rather than\n a background change. Drawn INSIDE the card (negative offset): the row is a\n scroll container with clipped overflow, so an outset ring is cut off on the\n first and last cards and on every card's top and bottom edge. */\n.ProductStrip-module_card_JBGYT:focus-visible {\n outline: 2px solid var(--aia-product-focus-ring, var(--aia-option-color-selected, currentColor));\n outline-offset: -2px;\n}\n\n/* Square media tile. aspect-ratio (not a fixed height) keeps it square at any\n --aia-product-card-width a consumer sets. */\n.ProductStrip-module_media_RrbGe {\n display: block;\n position: relative;\n width: 100%;\n aspect-ratio: 1 / 1;\n border-radius: 8px;\n overflow: hidden;\n background: var(--aia-product-media-bg, var(--aia-skeleton-bg, rgba(189, 189, 189, 0.25)));\n}\n\n.ProductStrip-module_image_5pNL7 {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n/* Placeholder tile for a product with no image — a faint glyph on the same\n media fill, so a card without art reads as \"no photo\" instead of broken. */\n.ProductStrip-module_media_RrbGe[data-aia-product-placeholder]::after {\n content: \"\";\n position: absolute;\n inset: 30%;\n border-radius: 3px;\n border: 1.5px solid var(--aia-product-placeholder-color, var(--aia-option-color, #c1c4cb));\n opacity: 0.35;\n}\n\n/* The text column. Only the title is guaranteed; vendor and price render no\n element at all when absent, so the gap can't reserve space for a missing\n line. */\n.ProductStrip-module_body_ly032 {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.ProductStrip-module_vendor_Gvu7G {\n font-family: inherit;\n font-size: var(--aia-product-vendor-font-size, 10px);\n line-height: 14px;\n color: var(\n --aia-product-vendor-color,\n var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb))\n );\n opacity: 0.8;\n /* Vendor names are frequently long — one line, clipped. */\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.ProductStrip-module_title_gCNmq {\n font-family: inherit;\n font-size: var(--aia-product-title-font-size, 12px);\n font-weight: 400;\n line-height: 16px;\n /* The card's most prominent text uses the same token the *highlighted*\n option text does, so it stays legible on any --aia-surface a consumer\n sets — light or dark — without a second theming control. */\n color: var(\n --aia-product-title-color,\n var(--aia-option-color-selected, var(--aia-color-text-default, #fff))\n );\n display: -webkit-box;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.ProductStrip-module_price_gULcE {\n font-family: inherit;\n font-size: var(--aia-product-price-font-size, 11px);\n font-weight: 500;\n line-height: 15px;\n color: var(\n --aia-product-price-color,\n var(--aia-option-color-selected, var(--aia-color-text-default, #fff))\n );\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"section\":\"ProductStrip-module_section_Hugfg\",\"label\":\"ProductStrip-module_label_nuc93\",\"row\":\"ProductStrip-module_row_WDVBX\",\"card\":\"ProductStrip-module_card_JBGYT\",\"media\":\"ProductStrip-module_media_RrbGe\",\"image\":\"ProductStrip-module_image_5pNL7\",\"body\":\"ProductStrip-module_body_ly032\",\"vendor\":\"ProductStrip-module_vendor_Gvu7G\",\"title\":\"ProductStrip-module_title_gCNmq\",\"price\":\"ProductStrip-module_price_gULcE\"};","import type { MouseEvent as ReactMouseEvent } from \"react\";\nimport type { Product } from \"../types\";\nimport styles from \"./ProductStrip.module.css\";\n\ninterface ProductStripProps {\n products: Product[];\n /** Scopes the section label's id to the owning listbox. */\n listboxId: string;\n onSelect: (product: Product) => void;\n /**\n * Focus moved into / out of the strip. The panel closes on blur by default\n * and the input blurs the moment a card takes focus, so the dropdown reports\n * focus as still-inside rather than shutting out from under the card.\n */\n onFocusChange?: (focused: boolean) => void;\n /**\n * False while the panel is fading out. The closed dropdown keeps rendering\n * its last content for the fade, and focusable cards inside it would still\n * answer Tab.\n */\n focusable?: boolean;\n}\n\n/**\n * The dropdown's product strip: a labelled section holding a horizontally\n * scrolling row of product cards. Sits below the options grid and above the\n * footer, and renders only when there are products — the panel's two halves\n * are independent, so an empty strip leaves no gap and an empty options grid\n * leaves the strip alone.\n *\n * Mirrors the vanilla core's `renderProductStrip` markup and class contract so\n * both packages theme identically. Two layout notes carried over from it:\n *\n * - The dropdown paints a background but never sets `color`, so anything here\n * relying on `color: inherit` would pick up the *host page's* text colour.\n * Every text node resolves its colour through the same `--aia-option-*`\n * chain the options use (see ProductStrip.module.css).\n * - The options grid carries a negative bottom margin so the footer rides up\n * over its reserved band; whatever follows the grid inherits that pull. The\n * dropdown root is marked `data-aia-has-products` and appearance.css zeroes\n * the band at its source rather than the strip cancelling it from here.\n */\nexport function ProductStrip({\n products,\n listboxId,\n onSelect,\n onFocusChange,\n focusable = true,\n}: ProductStripProps) {\n if (products.length === 0) return null;\n\n const labelId = `${listboxId}-products-label`;\n\n return (\n // biome-ignore lint/a11y/useSemanticElements: the rule suggests <fieldset>, which groups form controls and drags in legend semantics and UA styling. `group` is the one role a listbox accepts around a set of options, so the explicit ARIA role is exactly the point.\n <section\n className={styles.section}\n data-aia-products=\"\"\n // `group` is the one role a listbox accepts around a set of options, so\n // the strip stays inside the listbox without breaking its content model.\n role=\"group\"\n aria-labelledby={labelId}\n >\n <div className={styles.label} id={labelId}>\n Products\n </div>\n <div className={styles.row} data-aia-products-row=\"\">\n {products.map((product, i) => (\n <ProductCard\n key={product.id}\n product={product}\n id={`${listboxId}-product-${i}`}\n onSelect={onSelect}\n onFocusChange={onFocusChange}\n focusable={focusable}\n />\n ))}\n </div>\n </section>\n );\n}\n\ninterface ProductCardProps {\n product: Product;\n id: string;\n onSelect: (product: Product) => void;\n onFocusChange?: (focused: boolean) => void;\n focusable: boolean;\n}\n\nfunction ProductCard({ product, id, onSelect, onFocusChange, focusable }: ProductCardProps) {\n const handleClick = (e: ReactMouseEvent<HTMLAnchorElement>) => {\n // Let the browser keep the clicks that mean \"open this somewhere else\" —\n // intercepting them would defeat the point of rendering an <a>. Those are\n // navigations the user asked for explicitly, so they don't emit.\n if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;\n e.preventDefault();\n onSelect(product);\n };\n\n return (\n // A real <a href> rather than a <div>: it keeps the browser's own link\n // affordances — cmd/ctrl-click for a new tab, middle-click, right-click →\n // \"copy link address\". `role=\"option\"` overrides how assistive tech\n // announces it, which is correct inside a listbox; the deliberate trade is\n // that AT no longer calls it a link.\n <a\n id={id}\n className={styles.card}\n data-aia-product=\"\"\n role=\"option\"\n aria-selected={false}\n href={product.url}\n tabIndex={focusable ? 0 : -1}\n onClick={handleClick}\n onKeyDown={(e) => {\n if (e.key !== \"Enter\" && e.key !== \" \") return;\n e.preventDefault();\n onSelect(product);\n }}\n onFocus={() => onFocusChange?.(true)}\n onBlur={(e) => {\n const next = e.relatedTarget as HTMLElement | null;\n if (next?.closest(\"[data-aia-dropdown]\")) return;\n onFocusChange?.(false);\n }}\n >\n <span\n className={styles.media}\n // Catalogues without images are common enough that the placeholder is\n // a first-class state, not an error state.\n data-aia-product-placeholder={product.imageUrl ? undefined : \"\"}\n >\n {product.imageUrl ? (\n <img\n className={styles.image}\n src={product.imageUrl}\n // The title is already the card's accessible name; repeating it\n // here would have a screen reader read it twice.\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\"\n />\n ) : null}\n </span>\n {/* Every field but the title is optional, so absent ones render no\n element at all — the column gap can't leave a hole for a box that\n isn't there. */}\n <span className={styles.body}>\n {product.vendor ? <span className={styles.vendor}>{product.vendor}</span> : null}\n <span className={styles.title}>{product.title}</span>\n {product.price ? <span className={styles.price}>{product.price}</span> : null}\n </span>\n </a>\n );\n}\n","import {\n isOptionsGridMobileViewport,\n measureOptionsGrid,\n needsOptionsGridMeasurement,\n OPTIONS_GRID_MOBILE_QUERY,\n type OptionsGridPlan,\n optionEnterDelayMs,\n planOptionsGrid,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { Grid } from \"../layout/Grid\";\nimport type { SuggestionOption } from \"../types\";\nimport { SuggestionItem } from \"./SuggestionItem\";\n\n/**\n * Tracks the phone-width breakpoint the options grid switches on. The core\n * owns the query itself (and the vanilla/Angular grids watch the same one) so\n * the three packages can't drift onto different breakpoints.\n */\nfunction useIsMobile(): boolean {\n const [isMobile, setIsMobile] = useState(isOptionsGridMobileViewport);\n useEffect(() => {\n if (typeof window === \"undefined\" || !window.matchMedia) return;\n const mq = window.matchMedia(OPTIONS_GRID_MOBILE_QUERY);\n const onChange = () => setIsMobile(mq.matches);\n onChange();\n mq.addEventListener(\"change\", onChange);\n return () => mq.removeEventListener(\"change\", onChange);\n }, []);\n return isMobile;\n}\n\ninterface SuggestionGridProps {\n options: SuggestionOption[];\n activeIndex: number;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n listboxId: string;\n loading?: boolean;\n /**\n * Identity of the suggestion these options belong to. When it changes the\n * grid scrolls back to the top, so the next parameter's options are read\n * from the first one instead of from the previous list's scroll offset.\n */\n groupKey?: string;\n /**\n * Which side of the input the dropdown opens on. The rows' entrance starts\n * from the input's side outward, so \"above\" reverses the order.\n */\n optionsPosition?: \"above\" | \"below\";\n}\n\n/**\n * The dropdown's option grid: a thin wrapper that lays `SuggestionItem`s out\n * with the `Grid` layout primitive. `Grid` owns the auto-fit columns and the\n * capped-height scroll, so this component only wires each option to its\n * highlight/select handlers and listbox-scoped id.\n */\nexport function SuggestionGrid({\n options,\n activeIndex,\n onSelect,\n onHighlight,\n listboxId,\n loading,\n groupKey = \"\",\n optionsPosition = \"below\",\n}: SuggestionGridProps) {\n const isMobile = useIsMobile();\n const gridEl = useRef<HTMLDivElement | null>(null);\n // Two-pass: the first render lays out the measurement-free baseline (one\n // column), then the layout effect measures the rendered rows and upgrades to\n // the two-column plan when they provably fit — same policy as the vanilla\n // and Angular grids, all through `planOptionsGrid`. activeIndex is\n // deliberately not a dependency: highlighting can't change the plan, and\n // measuring clones every row and forces a layout. The needs-measurement gate\n // skips that cost entirely whenever the plan would ignore the result\n // (mobile, fewer than five options). jsdom measures every row at 0, so the\n // upgrade never fires in tests — the fit decision is asserted in the core's\n // own suite.\n const [measuredPlan, setMeasuredPlan] = useState<OptionsGridPlan | null>(null);\n useLayoutEffect(() => {\n const el = gridEl.current;\n const shouldMeasure = el && !loading && needsOptionsGridMeasurement(options.length, isMobile);\n const measured = shouldMeasure ? measureOptionsGrid(el) : null;\n setMeasuredPlan(\n measured\n ? planOptionsGrid(options.length, isMobile, measured.rowWidths, measured.gridWidth)\n : null,\n );\n }, [options, isMobile, loading]);\n const plan = measuredPlan ?? planOptionsGrid(options.length, isMobile, null, null);\n return (\n <Grid\n min=\"250px\"\n max=\"1fr\"\n gap=\"0\"\n scroll\n scrollResetKey={groupKey}\n template={plan.template}\n maxHeight={plan.maxHeight}\n innerRef={(el) => {\n gridEl.current = el;\n }}\n // Read by the scroll arrow to tell a new set of options (rising in)\n // from the same set re-rendered.\n data-aia-group={groupKey}\n >\n {options.map((option, i) => (\n <SuggestionItem\n // The group is part of the key: a new suggestion's options are new\n // rows and get the entrance animation even when one spells the same\n // as a row already on screen.\n key={`${groupKey}\\0${option.text}`}\n option={option}\n isHighlighted={i === activeIndex}\n onSelect={onSelect}\n onHighlight={() => onHighlight(i)}\n id={`${listboxId}-option-${i}`}\n loading={loading}\n scrollHint={!loading && plan.scrollHintIndices.includes(i)}\n // Skeleton rows fade in together — they're placeholders, not content.\n enterDelayMs={\n loading ? 0 : optionEnterDelayMs(i, plan.cols, options.length, optionsPosition)\n }\n />\n ))}\n </Grid>\n );\n}\n","import { optionsGridTemplateColumns } from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport {\n type ComponentPropsWithoutRef,\n type CSSProperties,\n type ReactNode,\n useLayoutEffect,\n useRef,\n} from \"react\";\nimport \"./Grid.css\";\n\ninterface GridProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"className\"> {\n /** Minimum cell width. CSS length, e.g. \"16rem\". Columns auto-fit at runtime. */\n min?: string;\n /** Maximum cell width. CSS length. Defaults to `1fr` (stretch to fill). */\n max?: string;\n /** Gap between cells. Defaults to `0`. */\n gap?: string;\n /** Cap the height and scroll vertically when content overflows. */\n scroll?: boolean;\n /** Max height when `scroll`. CSS length. Defaults to `120px`. */\n maxHeight?: string;\n /** Scroll back to the top whenever this key changes (`scroll` only). */\n scrollResetKey?: string;\n /** Fixed column count. Overrides the intrinsic auto-fit when set; rows fill left-to-right. */\n cols?: number;\n /** Explicit `grid-template-columns` value. Overrides `cols` when set. */\n template?: string;\n /** Also receives the grid element (for callers that measure it). */\n innerRef?: (el: HTMLDivElement | null) => void;\n className?: string;\n children: ReactNode;\n}\n\n// Intrinsic grid — auto-fits as many columns as fit between `min` and `max`\n// wide, wrapping to new rows when there's no more horizontal room. Optionally\n// scrolls (capped height). Internal.\nexport function Grid({\n min = \"16rem\",\n max,\n gap,\n scroll = false,\n maxHeight,\n scrollResetKey,\n cols,\n template,\n innerRef,\n className,\n children,\n ...rest\n}: GridProps) {\n const gridRef = useRef<HTMLDivElement | null>(null);\n\n // A new key means a different content group is being shown (e.g. the next\n // suggestion's options after a selection) — start it from the top instead of\n // inheriting the previous group's scroll offset. Layout effect so the reset\n // lands in the same frame the new content paints.\n useLayoutEffect(() => {\n if (scrollResetKey === undefined) return;\n const el = gridRef.current;\n if (el) el.scrollTop = 0;\n }, [scrollResetKey]);\n\n const style: CSSProperties = { \"--aia-grid-min\": min } as CSSProperties;\n if (max) (style as Record<string, string>)[\"--aia-grid-max\"] = max;\n if (gap) (style as Record<string, string>)[\"--aia-grid-gap\"] = gap;\n if (maxHeight) (style as Record<string, string>)[\"--aia-grid-max-height\"] = maxHeight;\n // Explicit column count overrides the intrinsic auto-fit (inline wins). The\n // track string is built by the core so all three packages emit the same one.\n // An explicit template (the measured two-column split) wins over both.\n if (cols) style.gridTemplateColumns = optionsGridTemplateColumns(cols);\n if (template) style.gridTemplateColumns = template;\n\n return (\n <div\n ref={(el) => {\n gridRef.current = el;\n innerRef?.(el);\n }}\n className={className ? `aia-grid ${className}` : \"aia-grid\"}\n data-scroll={scroll || undefined}\n style={style}\n {...rest}\n >\n {children}\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-948e58da\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-948e58da\";\n s.textContent = `@layer layout {\n .aia-grid {\n display: grid;\n grid-template-columns: repeat(\n auto-fit,\n minmax(min(var(--aia-grid-min), 100%), var(--aia-grid-max, 1fr))\n );\n gap: var(--aia-grid-gap, 0);\n }\n\n /* Scrollable variant — capped height with a styled thin scrollbar. Rows pack\n from the top instead of stretching to fill the container. */\n .aia-grid[data-scroll] {\n grid-auto-rows: min-content;\n align-content: start;\n justify-content: start;\n /* The scroll box's reserved band (--aia-grid-scroll-* / --aia-grid-overlap-*)\n is deliberately NOT declared here — see the unlayered rule in\n appearance.css for why. */\n max-height: var(--aia-grid-max-height, 120px);\n overflow-y: auto;\n scrollbar-width: thin;\n scrollbar-color: var(--aia-scrollbar-thumb, rgba(0, 0, 0, 0.3)) transparent;\n }\n .aia-grid[data-scroll]::-webkit-scrollbar {\n width: 6px;\n }\n .aia-grid[data-scroll]::-webkit-scrollbar-track {\n background: transparent;\n }\n .aia-grid[data-scroll]::-webkit-scrollbar-thumb {\n background: var(--aia-scrollbar-thumb, rgba(0, 0, 0, 0.3));\n border-radius: 3px;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport {};","import { OPTION_ENTER_DELAY_VAR } from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { type CSSProperties, useEffect, useRef, useState } from \"react\";\nimport type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionItem.module.css\";\n\ninterface SuggestionItemProps {\n option: SuggestionOption;\n isHighlighted: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: () => void;\n id: string;\n loading?: boolean;\n /** Fade this option's text toward its bottom edge (last visible row of a scrollable grid). */\n scrollHint?: boolean;\n /**\n * Start delay of this row's entrance animation (ms) — each row rises in a\n * beat after the one nearer the input. Fixed for the row's lifetime: it's\n * read once on mount, so a re-render can't restart a row mid-rise.\n */\n enterDelayMs?: number;\n}\n\nexport function SuggestionItem({\n option,\n isHighlighted,\n onSelect,\n onHighlight,\n id,\n loading,\n scrollHint,\n enterDelayMs = 0,\n}: SuggestionItemProps) {\n const [enterDelay] = useState(enterDelayMs);\n const [pressed, setPressed] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n useEffect(() => {\n return () => clearTimeout(timerRef.current);\n }, []);\n\n const handleSelect = () => {\n if (loading || !option.is_tappable || pressed) return;\n setPressed(true);\n onSelect(option);\n clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setPressed(false), 500);\n };\n\n const className = [\n styles.item,\n isHighlighted && !loading ? styles.highlighted : \"\",\n option.is_tappable ? styles.tappable : styles.nonTappable,\n pressed ? styles.pressed : \"\",\n scrollHint ? styles.scrollHint : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n id={id}\n role=\"option\"\n data-aia-option=\"\"\n data-aia-loading={loading ? \"\" : undefined}\n aria-selected={isHighlighted}\n className={className}\n style={{ [OPTION_ENTER_DELAY_VAR]: `${enterDelay}ms` } as CSSProperties}\n tabIndex={loading || !option.is_tappable ? -1 : 0}\n onClick={handleSelect}\n onKeyDown={(e) => {\n if (!loading && option.is_tappable && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n handleSelect();\n }\n }}\n onMouseEnter={!loading && option.is_tappable ? onHighlight : undefined}\n >\n <span className={styles.content}>\n <span className={styles.text}>\n {option.icon ? `${option.icon} ${option.text}` : option.text}\n </span>\n {option.tag && <span className={styles.tag}>{option.tag}</span>}\n </span>\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-82820da7\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-82820da7\";\n s.textContent = `.SuggestionItem-module_item_d4vpD {\n position: relative;\n overflow: visible;\n display: flex;\n /* Top-align so single-line and multi-line options in the same row share\n the same baseline at the top edge of the cell. */\n align-items: flex-start;\n font-family: inherit;\n font-size: var(--aia-option-font-size, 16px);\n font-weight: 450;\n line-height: 21px;\n color: var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));\n white-space: normal;\n word-break: break-word;\n /* 8px radius on the highlighted fill (--aia-option-bg), matching the Figma\n SuggestionItem selection. The 9px/10px inset is the item's own padding. */\n border-radius: 8px;\n padding: 8px 10px;\n /* Entrance: fade in while rising into place, each row a beat after the one\n before it (--aia-option-enter-delay is set inline per row from the core's\n optionEnterDelayMs). The durations and distance mirror OPTION_ENTER_* in\n the core's derive/optionsEntrance.ts — change both together. */\n animation:\n SuggestionItem-module_fadeIn_I8u35 150ms ease-out both,\n SuggestionItem-module_riseIn_etXZT 280ms cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n animation-delay: var(--aia-option-enter-delay, 0ms);\n}\n\n@keyframes SuggestionItem-module_fadeIn_I8u35 {\n from {\n opacity: 0;\n }\n}\n\n@keyframes SuggestionItem-module_riseIn_etXZT {\n from {\n transform: translateY(16px);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .SuggestionItem-module_item_d4vpD {\n animation-duration: 0s;\n animation-delay: 0s;\n }\n}\n\n.SuggestionItem-module_content_T-Qba {\n position: relative;\n z-index: 2;\n}\n\n.SuggestionItem-module_tappable_70KcX {\n cursor: pointer;\n}\n\n.SuggestionItem-module_tappable_70KcX:hover {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n}\n\n.SuggestionItem-module_nonTappable_xSZM- {\n cursor: default;\n}\n\n.SuggestionItem-module_highlighted_Hb0SU {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n background: var(--aia-option-bg, transparent);\n font-weight: 500;\n}\n\n.SuggestionItem-module_tag_e3Fwe {\n font-size: 11px;\n margin-left: 6px;\n opacity: 0.5;\n}\n\n/* Press feedback: the picked option's text compresses down while every other\n option steps back in opacity — no fill, no glow, the hierarchy carries it. */\n.SuggestionItem-module_pressed_98o-r {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n animation: SuggestionItem-module_pressCompress_ICV3q 500ms ease forwards;\n}\n\n[role=\"listbox\"]:has(.SuggestionItem-module_pressed_98o-r) .SuggestionItem-module_item_d4vpD:not(.SuggestionItem-module_pressed_98o-r) {\n opacity: 0.35;\n transition: opacity 150ms ease;\n}\n\n@keyframes SuggestionItem-module_pressCompress_ICV3q {\n 0% {\n transform: scale(1);\n }\n 25% {\n transform: scale(0.93);\n }\n 60% {\n transform: scale(0.93);\n }\n 100% {\n transform: scale(1);\n }\n}\n\n/* Scroll hint — the last visible row of a scrollable web grid fades toward its\n bottom edge, signalling more options below (the desktop footer is opaque, so\n rows no longer dissolve through it). A mask instead of a color so any themed\n option color fades the same way. */\n.SuggestionItem-module_scrollHint_xKXPt .SuggestionItem-module_content_T-Qba {\n -webkit-mask-image: linear-gradient(to bottom, rgb(0 0 0), rgb(0 0 0 / 0.6));\n mask-image: linear-gradient(to bottom, rgb(0 0 0), rgb(0 0 0 / 0.6));\n}\n\n/* Loading state — preserve the row's exact dimensions. The content stays an\n inline span so the line box and padding match the non-loading state byte\n for byte. Just hide the text and apply a background as a skeleton bar; the\n pulse provides the shimmer. */\n.SuggestionItem-module_item_d4vpD[data-aia-loading] {\n cursor: default;\n animation: SuggestionItem-module_skeletonPulse_plvdD 1.4s ease-in-out infinite;\n}\n\n/* Skeleton fill is on the inner text span (a true inline element) so multi-\n line options wrap into one skeleton bar per line. The outer .content is a\n flex item — blockified by spec — so painting the background there would\n collapse all lines into one tall rectangle. \\`box-decoration-break: clone\\`\n makes the radius render cleanly on each line bar. */\n.SuggestionItem-module_item_d4vpD[data-aia-loading] .SuggestionItem-module_text_yqoh9 {\n color: transparent;\n background: var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, 0.25)));\n border-radius: 999px;\n -webkit-box-decoration-break: clone;\n box-decoration-break: clone;\n}\n\n.SuggestionItem-module_item_d4vpD[data-aia-loading] .SuggestionItem-module_tag_e3Fwe {\n display: none;\n}\n\n@keyframes SuggestionItem-module_skeletonPulse_plvdD {\n 0%,\n 100% {\n filter: brightness(1);\n }\n 50% {\n filter: brightness(0.55);\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"item\":\"SuggestionItem-module_item_d4vpD\",\"fadeIn\":\"SuggestionItem-module_fadeIn_I8u35\",\"riseIn\":\"SuggestionItem-module_riseIn_etXZT\",\"content\":\"SuggestionItem-module_content_T-Qba\",\"tappable\":\"SuggestionItem-module_tappable_70KcX\",\"nonTappable\":\"SuggestionItem-module_nonTappable_xSZM-\",\"highlighted\":\"SuggestionItem-module_highlighted_Hb0SU\",\"tag\":\"SuggestionItem-module_tag_e3Fwe\",\"pressed\":\"SuggestionItem-module_pressed_98o-r\",\"pressCompress\":\"SuggestionItem-module_pressCompress_ICV3q\",\"scrollHint\":\"SuggestionItem-module_scrollHint_xKXPt\",\"skeletonPulse\":\"SuggestionItem-module_skeletonPulse_plvdD\",\"text\":\"SuggestionItem-module_text_yqoh9\"};","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-8414cd5f\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-8414cd5f\";\n s.textContent = `@layer layout {\n .aia-stack {\n display: flex;\n flex-direction: column;\n gap: var(--aia-stack-space, 0.5rem);\n }\n .aia-stack[data-align=\"start\"] {\n align-items: start;\n }\n .aia-stack[data-align=\"center\"] {\n align-items: center;\n }\n .aia-stack[data-align=\"end\"] {\n align-items: end;\n }\n /* data-align=\"stretch\" is the flex default — no rule needed. */\n}\n`;\n document.head.appendChild(s);\n}\nexport {};","import type { ComponentPropsWithoutRef, CSSProperties, ReactNode } from \"react\";\nimport \"./Stack.css\";\n\ninterface StackProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"className\"> {\n /** Gap between children. Any CSS length. Defaults to `0.5rem`. */\n space?: string;\n /** Cross-axis alignment of children. Defaults to `stretch` (full width). */\n align?: \"start\" | \"center\" | \"end\" | \"stretch\";\n className?: string;\n children: ReactNode;\n}\n\n// Vertical layout primitive — children stack top-to-bottom with `space` gap. Internal.\nexport function Stack({ space, align = \"stretch\", className, children, ...rest }: StackProps) {\n const style = space ? ({ \"--aia-stack-space\": space } as CSSProperties) : undefined;\n return (\n <div\n className={className ? `aia-stack ${className}` : \"aia-stack\"}\n data-align={align}\n style={style}\n {...rest}\n >\n {children}\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-fdee06e6\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-fdee06e6\";\n s.textContent = `.SubmitButton-module_submitButton_otz7H {\n flex-shrink: 0;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n border: none;\n background: var(--aia-submit-bg, var(--aia-color-text-default, #fff));\n color: var(--aia-submit-color, var(--aia-color-bg-default, #000));\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n transition: opacity 0.2s ease;\n}\n\n.SubmitButton-module_submitButton_otz7H:hover {\n opacity: 0.85;\n}\n\n/* Disabled (empty input) keeps the solid themed look by default — the disabled\n tokens fall back to the enabled ones, so a consumer's themed color is never\n washed out. Opt into a faded/dimmed rest state by setting\n --aia-submit-bg-disabled / --aia-submit-color-disabled. */\n.SubmitButton-module_submitButton_otz7H:disabled {\n background: var(\n --aia-submit-bg-disabled,\n var(--aia-submit-bg, var(--aia-color-text-default, #fff))\n );\n color: var(\n --aia-submit-color-disabled,\n var(--aia-submit-color, var(--aia-color-bg-default, #000))\n );\n cursor: default;\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"submitButton\":\"SubmitButton-module_submitButton_otz7H\"};","import styles from \"./SubmitButton.module.css\";\n\ninterface SubmitButtonProps {\n /** Disabled when there's nothing to submit. */\n disabled?: boolean;\n onClick: () => void;\n}\n\n/**\n * The default circular submit button (up-arrow). Tier 1 renders this when the\n * consumer doesn't supply a custom `submitButton`. Themed via `--aia-submit-*`.\n */\nexport function SubmitButton({ disabled, onClick }: SubmitButtonProps) {\n return (\n <button\n type=\"button\"\n data-aia-submit=\"\"\n className={styles.submitButton}\n disabled={disabled}\n onClick={(e) => {\n e.stopPropagation();\n onClick();\n }}\n aria-label=\"Submit\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" role=\"img\" aria-label=\"Submit\">\n <path\n d=\"M9 14V4M9 4L4 9M9 4L14 9\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n );\n}\n","import {\n AIAutocomplete as CoreAIAutocomplete,\n type CoreState,\n identifiedParamLabel,\n type Product,\n type Suggestion,\n type SuggestionOption,\n selectedIsoFromText,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport {\n type ChangeEvent,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { UseAIAutocompleteOptions, UseAIAutocompleteReturn } from \"../types\";\nimport { useProductsProxy } from \"./useProductsProxy\";\n\n/**\n * Pre-mount / SSR fallback. Identical shape to the post-mount CoreState so\n * the hook's return is single-shaped — no `if (!instance) return ...` branch.\n * `isLoading: true` matches the historical SSR bail-out: consumers using\n * `isLoading` to render a skeleton see one on the first paint instead of a\n * flash of blank content while the mount effect creates the core instance.\n */\nconst EMPTY_STATE: CoreState = {\n text: \"\",\n completedParams: [],\n identifiedParams: [],\n skippedParams: [],\n pendingSpan: null,\n suggestions: [],\n // Pre-mount there is no core and therefore no product search in flight.\n products: [],\n activeDropdownIndex: -1,\n newParamId: null,\n isLoading: true,\n isReady: false,\n error: null,\n segments: [],\n actionableSuggestions: [],\n filteredOptions: [],\n // Pre-mount there is no active suggestion, so nothing can be a date yet.\n activeFormatType: \"options\",\n dateView: null,\n placeholderText: \"\",\n isDropdownOpen: false,\n isActivePillSelected: false,\n filterBase: 0,\n filterInProgress: false,\n pillTapped: false,\n skipNextFetch: false,\n lastRawQuery: \"\",\n isFocused: false,\n editingParam: null,\n editingIdentified: null,\n editingAnchor: null,\n editingTail: null,\n caretOffset: null,\n inSelectionAnimation: false,\n dateViewMonth: null,\n};\n\ninterface CoreActions {\n handleTextChange: (value: string) => void;\n handleKeyDown: (e: KeyboardEvent<HTMLElement> | globalThis.KeyboardEvent) => void;\n setFocused: (focused: boolean) => void;\n startEditingParam: (paramId: string) => void;\n exitEditMode: () => void;\n handleCaretAfterInput: (offset: number | null) => void;\n handleCaretMove: (offset: number | null) => void;\n replaceEditingRange: (replacement: string) => boolean;\n setActivePill: (index: number) => void;\n skipActivePill: () => void;\n removeLastParam: () => void;\n clearNewParamId: () => void;\n reset: () => void;\n selectOption: (option: SuggestionOption) => void;\n selectProduct: (product: Product) => void;\n setActiveDropdownIndex: (index: number) => void;\n showPreviousMonth: () => void;\n showNextMonth: () => void;\n handleFocus: () => void;\n handleBlur: () => void;\n}\n\nexport function useAIAutocomplete({\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n apiConfig,\n additionalContext,\n columns = 2,\n dropdownTrigger,\n optionsPosition,\n closeDropdownOnBlur,\n showNonTappableOptions,\n showSkipButton,\n onFocus,\n onBlur,\n value: controlledValue,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n products,\n onProductSelect,\n source,\n setCursor,\n}: UseAIAutocompleteOptions): UseAIAutocompleteReturn {\n const instanceRef = useRef<CoreAIAutocomplete | null>(null);\n const [coreState, setCoreState] = useState<CoreState | null>(null);\n\n // Refs for caller-supplied callbacks. The CoreAIAutocomplete instance is\n // mount-only (created once); these refs let the stable proxy callbacks\n // inside it pick up the latest props on every render.\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const onChangeRef = useRef(onChangeProp);\n onChangeRef.current = onChangeProp;\n const onParamsChangeRef = useRef(onParamsChange);\n onParamsChangeRef.current = onParamsChange;\n const onFocusRef = useRef(onFocus);\n onFocusRef.current = onFocus;\n const onBlurRef = useRef(onBlur);\n onBlurRef.current = onBlur;\n const setCursorRef = useRef(setCursor);\n setCursorRef.current = setCursor;\n const onProductSelectRef = useRef(onProductSelect);\n onProductSelectRef.current = onProductSelect;\n\n // Stable proxy so an inline `products={{ … }}` doesn't read as a swapped\n // integration on every render — see useProductsProxy for the full rationale.\n const productsProxy = useProductsProxy(products);\n\n // Create, subscribe, and destroy the core instance in one mount-only effect.\n // Keeping creation out of render (and pairing it with the cleanup) is what\n // makes this StrictMode-safe — otherwise cleanup nulls the ref, render\n // re-creates, and the store subscription drives an infinite setState loop.\n // biome-ignore lint/correctness/useExhaustiveDependencies: initial-opts snapshot; later changes are synced by the update-effect below\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n const instance = new CoreAIAutocomplete(document.createElement(\"div\"), {\n renderMode: \"headless\",\n apiConfig,\n additionalContext,\n optionOverrides,\n maskCompletedText,\n columns,\n dropdownTrigger,\n optionsPosition,\n closeDropdownOnBlur,\n showNonTappableOptions,\n source,\n value: controlledValue,\n completedParams: controlledParams,\n onSubmit: (...args) => onSubmitRef.current?.(...args),\n onError: (...args) => onErrorRef.current?.(...args),\n onChange: (...args) => onChangeRef.current?.(...args),\n onParamsChange: (...args) => onParamsChangeRef.current?.(...args),\n onFocus: () => onFocusRef.current?.(),\n onBlur: () => onBlurRef.current?.(),\n onProductSelect: (product) => onProductSelectRef.current?.(product),\n setCursor: (offset) => setCursorRef.current?.(offset),\n products: productsProxy.config,\n });\n instanceRef.current = instance;\n setCoreState(instance.getState());\n const unsub = instance.subscribe((state) => setCoreState(state));\n return () => {\n unsub();\n instance.destroy();\n if (instanceRef.current === instance) instanceRef.current = null;\n };\n }, []);\n\n // Sync controlled value\n useEffect(() => {\n if (controlledValue !== undefined) instanceRef.current?.setValue(controlledValue);\n }, [controlledValue]);\n\n // Sync controlled params\n useEffect(() => {\n if (controlledParams !== undefined) instanceRef.current?.setCompletedParams(controlledParams);\n }, [controlledParams]);\n\n // Sync apiConfig/optionOverrides/dropdownTrigger when values change\n const apiConfigJson = JSON.stringify(apiConfig ?? null);\n // Unlike apiConfig (a narrow typed shape), additionalContext is consumer-supplied\n // free-form JSON — a circular reference or a BigInt would throw here, which runs\n // during render. Fall back to a constant so a bad value is silently dropped\n // (never synced to the core) instead of crashing the render.\n let additionalContextJson: string;\n try {\n additionalContextJson = JSON.stringify(additionalContext ?? null);\n } catch {\n additionalContextJson = \"[unstringifiable]\";\n }\n const prevOverridesRef = useRef(optionOverrides);\n const overridesVersion = useRef(0);\n if (optionOverrides !== prevOverridesRef.current) {\n const prev = prevOverridesRef.current;\n const next = optionOverrides;\n const prevKeys = Object.keys(prev ?? {});\n const nextKeys = Object.keys(next ?? {});\n if (\n prevKeys.length !== nextKeys.length ||\n nextKeys.some(\n (k) =>\n !(prev as Record<string, unknown>)?.[k] ||\n (next as Record<string, unknown>)[k] !== (prev as Record<string, unknown>)[k],\n )\n ) {\n overridesVersion.current++;\n }\n prevOverridesRef.current = optionOverrides;\n }\n // biome-ignore lint/correctness/useExhaustiveDependencies: overridesVersion tracks shallow changes to fn-valued optionOverrides\n useEffect(() => {\n instanceRef.current?.update({\n apiConfig,\n additionalContext,\n optionOverrides,\n dropdownTrigger,\n optionsPosition,\n closeDropdownOnBlur,\n showNonTappableOptions,\n });\n }, [\n apiConfigJson,\n additionalContextJson,\n overridesVersion.current,\n dropdownTrigger,\n optionsPosition,\n closeDropdownOnBlur,\n showNonTappableOptions,\n ]);\n\n // Toggling the strip on or off is the only products change the core needs to\n // hear about — the proxy handles everything else — and it deliberately\n // clears the cards on the way out. Skips the mount pass: the constructor\n // above already applied the initial value, and a redundant update() here\n // would clear a strip the first fetch had populated.\n //\n // `productsProxy.config` is intentionally not a dependency: its identity is\n // stable by construction, so `enabled` is the only thing that can change.\n const productsMountedRef = useRef(false);\n // biome-ignore lint/correctness/useExhaustiveDependencies: config is stable by construction; `enabled` is the only real change\n useEffect(() => {\n if (!productsMountedRef.current) {\n productsMountedRef.current = true;\n return;\n }\n instanceRef.current?.update({ products: productsProxy.config });\n }, [productsProxy.enabled]);\n\n // Single stable action surface. Built once via the useRef-with-null-init\n // pattern (the idiomatic \"create once, never recreate\" idiom in React — see\n // https://react.dev/reference/react/useRef). Every entry forwards to the\n // current core instance via `instanceRef.current` so the closure picks up\n // the live instance even though the actions object itself never changes.\n const actionsRef = useRef<CoreActions | null>(null);\n if (actionsRef.current === null) {\n actionsRef.current = {\n handleTextChange: (value) => instanceRef.current?.handleTextChange(value),\n handleKeyDown: (e) => {\n const native = \"nativeEvent\" in e ? e.nativeEvent : e;\n instanceRef.current?.handleKeyDown(native);\n },\n setFocused: (focused) => instanceRef.current?.setFocused(focused),\n startEditingParam: (paramId) => instanceRef.current?.startEditingParam(paramId),\n exitEditMode: () => instanceRef.current?.exitEditMode(),\n handleCaretAfterInput: (offset) => instanceRef.current?.handleCaretAfterInput(offset),\n handleCaretMove: (offset) => instanceRef.current?.handleCaretMove(offset),\n replaceEditingRange: (replacement) =>\n instanceRef.current?.replaceEditingRange(replacement) ?? false,\n setActivePill: (index) => instanceRef.current?.setActivePill(index),\n skipActivePill: () => instanceRef.current?.skipActivePill(),\n removeLastParam: () => instanceRef.current?.removeLastParam(),\n clearNewParamId: () => instanceRef.current?.clearNewParamId(),\n reset: () => instanceRef.current?.reset(),\n selectOption: (option) => instanceRef.current?.selectOption(option),\n selectProduct: (product) => instanceRef.current?.selectProduct(product),\n setActiveDropdownIndex: (index) => instanceRef.current?.setActiveDropdownIndex(index),\n showPreviousMonth: () => instanceRef.current?.showPreviousMonth(),\n showNextMonth: () => instanceRef.current?.showNextMonth(),\n handleFocus: () => instanceRef.current?.setFocused(true),\n handleBlur: () => instanceRef.current?.setFocused(false),\n };\n }\n const actions = actionsRef.current;\n\n // textarea-specific adapter — capitalizes the first character on first\n // keystroke. Kept separate from `actions.handleTextChange` because the\n // capitalization rule belongs to the textarea host, not the core.\n const handleChange = useCallback((e: ChangeEvent<HTMLTextAreaElement>) => {\n const raw = e.target.value;\n const shouldCapitalize =\n raw.length > 0 &&\n !(e.nativeEvent as InputEvent)?.isComposing &&\n raw[0] !== raw[0].toUpperCase();\n const newValue = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n instanceRef.current?.handleTextChange(newValue);\n }, []);\n\n const handleKeyDownTextarea = useCallback((e: KeyboardEvent<HTMLTextAreaElement>) => {\n instanceRef.current?.handleKeyDown(e.nativeEvent);\n }, []);\n\n // Snapshot the live instance + state for this render.\n const instance = instanceRef.current;\n const state = coreState ?? EMPTY_STATE;\n const text = controlledValue !== undefined ? controlledValue : state.text;\n const completedParams = controlledParams !== undefined ? controlledParams : state.completedParams;\n\n const actionableSuggestions = state.actionableSuggestions;\n const activeSuggestion: Suggestion | undefined = actionableSuggestions[0];\n const listboxId = instance?.listboxId ?? \"\";\n\n const activeDescendantId =\n state.activeDropdownIndex >= 0 && instance\n ? `${listboxId}-option-${state.activeDropdownIndex}`\n : undefined;\n\n // In re-edit mode, the dropdown's pill bar shows a synthetic pill built\n // from the edited param's cached suggestion metadata. The options grid\n // shows the cached options regardless of the latest server response.\n const editingParam = state.editingParam;\n const editingIdentified = state.editingIdentified;\n const dropdownPill: Suggestion | null = editingParam\n ? {\n type: editingParam.suggestionType,\n text: editingParam.suggestionPlaceholder,\n required: true,\n options: editingParam.options,\n }\n : editingIdentified\n ? // Answering a span the user wrote themselves: the pill names the\n // parameter the server matched it to, so the calendar isn't unlabelled.\n {\n type: editingIdentified.type,\n text: identifiedParamLabel(editingIdentified.type),\n required: true,\n options: [],\n }\n : null;\n const dropdownActivePill = dropdownPill ?? activeSuggestion;\n const dropdownPills = dropdownPill ? [dropdownPill] : actionableSuggestions;\n\n // UI-visible loading — suppressed during the post-select press animation\n // and during re-edit (cached options remain visible there). Pre-mount we\n // report loading=true so SSR / first-paint consumers render a skeleton\n // instead of a flash of blank content while the mount effect runs.\n const uiLoading =\n !instance || (state.isLoading && !state.editingParam && !state.inSelectionAnimation);\n\n return {\n completedParams,\n skippedParams: state.skippedParams,\n suggestionPills: actionableSuggestions,\n setActivePill: actions.setActivePill,\n skipActivePill: actions.skipActivePill,\n removeLastParam: actions.removeLastParam,\n segments: state.segments,\n newParamId: state.newParamId,\n clearNewParamId: actions.clearNewParamId,\n suggestions: state.suggestions,\n activeIndex: state.activeDropdownIndex,\n isReady: state.isReady,\n isLoading: uiLoading,\n isFocused: state.isFocused,\n isDropdownOpen: state.isDropdownOpen,\n isActivePillSelected: state.isActivePillSelected,\n placeholderText: state.placeholderText,\n listboxId,\n error: state.error,\n products: state.products,\n selectProduct: actions.selectProduct,\n handleTextChange: actions.handleTextChange,\n handleKeyDown: actions.handleKeyDown,\n setFocused: actions.setFocused,\n editingParam,\n editingIdentified,\n editingAnchor: state.editingAnchor,\n caretOffset: state.caretOffset,\n startEditingParam: actions.startEditingParam,\n exitEditMode: actions.exitEditMode,\n handleCaretAfterInput: actions.handleCaretAfterInput,\n handleCaretMove: actions.handleCaretMove,\n replaceEditingRange: actions.replaceEditingRange,\n inputProps: {\n value: text,\n placeholder: state.placeholderText || undefined,\n onChange: handleChange,\n onKeyDown: handleKeyDownTextarea,\n onFocus: actions.handleFocus,\n onBlur: actions.handleBlur,\n role: \"combobox\" as const,\n \"aria-expanded\": state.isDropdownOpen,\n \"aria-activedescendant\": activeDescendantId,\n \"aria-autocomplete\": \"list\" as const,\n \"aria-controls\": listboxId,\n },\n reset: actions.reset,\n dropdownProps: {\n suggestions: dropdownActivePill\n ? [{ ...dropdownActivePill, options: state.filteredOptions }]\n : [],\n activeIndex: state.activeDropdownIndex,\n onSelect: actions.selectOption,\n onHighlight: actions.setActiveDropdownIndex,\n isOpen: state.isDropdownOpen,\n id: listboxId,\n pills: dropdownPills,\n activeSelected: state.isActivePillSelected,\n onPillClick: actions.setActivePill,\n onSkip: actions.skipActivePill,\n // Hidden while re-editing: the bar then shows the param being re-edited,\n // and an already answered param isn't skippable.\n showSkipButton: (showSkipButton ?? true) && !editingParam && !editingIdentified,\n // uiLoading is suppressed during the selection animation, but\n // skipActivePill no-ops in that window — mirror the guard visually.\n skipDisabled: state.inSelectionAnimation,\n isLoading: uiLoading,\n isInputEmpty: text.trim().length === 0,\n products: state.products,\n onProductSelect: actions.selectProduct,\n // A card taking focus blurs the input, which would otherwise close the\n // panel out from under the card the user just tabbed to.\n onProductFocusChange: actions.setFocused,\n // Datepicker. `filteredOptions` above already carries the visible month's\n // cells rather than the suggestion's own options when this is \"date\" —\n // the core swapped them in its derive layer, so the dropdown only has to\n // know which body to draw.\n formatType: state.activeFormatType,\n dateView: state.dateView,\n selectedDateIso: editingIdentified\n ? editingIdentified.iso\n : selectedIsoFromText(editingParam?.text),\n onPreviousMonth: actions.showPreviousMonth,\n onNextMonth: actions.showNextMonth,\n // Flow the configured position into the dropdown so a headless consumer\n // who spreads `dropdownProps` gets above/below placement + layout reversal\n // automatically — no wrapper attribute or hand-copied CSS required.\n optionsPosition: optionsPosition ?? \"below\",\n },\n };\n}\n","import type { ProductsConfig } from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { useRef } from \"react\";\n\nexport interface ProductsProxy {\n /**\n * Stable object to hand the core. Identity never changes for the lifetime of\n * the hook, so `update()` never mistakes a re-render for a swapped\n * integration. `undefined` while the consumer hasn't configured `products` —\n * the core must see exactly that to stay completely inert.\n */\n config: ProductsConfig | undefined;\n /**\n * Whether `products` is configured. The only products change worth an\n * `update()` call, and therefore the only sane effect dependency: everything\n * else is picked up live through the proxy.\n */\n enabled: boolean;\n}\n\n/**\n * Forwards a `products` config to the core through a **stable proxy**.\n *\n * Consumers write the config inline (`products={{ fetch, transform }}`), so the\n * object and its function members get a fresh identity on every render. Handing\n * that straight to the core would look like a swapped integration on each\n * keystroke and clear the strip — so calls are forwarded through a ref instead,\n * exactly as the hook's `on*` callbacks already are. `limit` is a **getter**\n * because it's a value rather than a function: without one it would freeze at\n * whatever the first render passed.\n *\n * Note the trade this makes deliberately: identity can no longer distinguish\n * \"same integration, new object literal\" from \"genuinely different\n * integration\", so swapping one live config for another does NOT clear the\n * previous integration's cards — they're replaced when the next request lands.\n * Documented on the `products` prop.\n */\nexport function useProductsProxy(products: ProductsConfig | undefined): ProductsProxy {\n const productsRef = useRef(products);\n productsRef.current = products;\n\n const proxyRef = useRef<ProductsConfig | null>(null);\n if (proxyRef.current === null) {\n proxyRef.current = {\n fetch: (query, signal) => {\n const config = productsRef.current;\n // Unreachable while configured; a rejected promise (rather than a\n // throw) keeps the failure on the path the core already treats as\n // \"silent failure\" if the config is torn down mid-flight.\n if (!config) return Promise.reject(new Error(\"products config removed\"));\n return config.fetch(query, signal);\n },\n transform: (raw) => productsRef.current?.transform(raw) ?? [],\n get limit() {\n return productsRef.current?.limit;\n },\n };\n }\n\n const enabled = products !== undefined;\n return { config: enabled ? proxyRef.current : undefined, enabled };\n}\n","import {\n type CompletedParamState,\n extractPlainText,\n getCursorOffset,\n plainTextLength,\n renderEditableContent,\n type Segment,\n setCursorOffset,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport {\n type ClipboardEvent as ReactClipboardEvent,\n type KeyboardEvent as ReactKeyboardEvent,\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n} from \"react\";\n\nlet plaintextOnlyCache: boolean | undefined;\nfunction supportsPlaintextOnly(): boolean {\n if (plaintextOnlyCache !== undefined) return plaintextOnlyCache;\n if (typeof document === \"undefined\") return false;\n const probe = document.createElement(\"div\");\n probe.setAttribute(\"contenteditable\", \"plaintext-only\");\n plaintextOnlyCache = probe.contentEditable === \"plaintext-only\";\n return plaintextOnlyCache;\n}\n\nexport interface UseContentEditableEditorOptions {\n /** Derived segments (text + bold completed-param runs) for the editor body. */\n segments: readonly Segment[];\n /** The most recently promoted param — shimmer + post-promote refocus key. */\n newParamId: string | null;\n /** The bold param currently being re-edited (or null). */\n editingParam: CompletedParamState | null;\n /** Set while picking a date for a span the server identified as one. */\n editingIdentified: { id: string } | null;\n /** Plain-text offset where re-edit started; caret parks here on entry. */\n editingAnchor: number | null;\n /** Live caret offset within the editor, used by post-promote refocus. */\n caretOffset: number | null;\n /** Server-suggested placeholder (rendered via ::before when empty). */\n placeholderText: string;\n /** Whether the editor currently has focus — passes through to segment renderer. */\n isFocused: boolean;\n /** ARIA `aria-expanded` value for the input. */\n isDropdownOpen: boolean;\n /** ARIA `aria-controls` value pointing at the listbox. */\n listboxId: string;\n /** ARIA `aria-activedescendant` value pointing at the highlighted option (or undefined). */\n activeDescendantId: string | undefined;\n /** Focus the editor on mount (Tier 1 default). */\n autoFocus: boolean;\n /** Forwarded to the core whenever the plain-text content changes. */\n handleTextChange: (value: string) => void;\n /** Forwarded to the core for keyboard handling. */\n handleKeyDown: (e: ReactKeyboardEvent<HTMLElement> | globalThis.KeyboardEvent) => void;\n /** Forwarded to the core after each input event (extends edit tail, etc.). */\n handleCaretAfterInput: (offset: number | null) => void;\n /** Forwarded to the core on selectionchange (exits re-edit when caret leaves). */\n handleCaretMove: (offset: number | null) => void;\n /** Forwarded to the core when the caret lands inside a bold param's strong. */\n startEditingParam: (id: string) => void;\n /** Forwarded to the core during a `beforeinput` — atomic re-edit replacement. */\n replaceEditingRange: (replacement: string) => boolean;\n /** Forwarded to the core on native focus/blur. */\n setFocused: (focused: boolean) => void;\n}\n\nexport interface UseContentEditableEditorReturn {\n inputRef: React.RefObject<HTMLDivElement>;\n // Spread onto the contentEditable element; consumer supplies className.\n editorProps: {\n ref: React.RefObject<HTMLDivElement>;\n contentEditable: boolean;\n suppressContentEditableWarning: true;\n tabIndex: 0;\n role: \"combobox\";\n \"aria-autocomplete\": \"list\";\n \"aria-haspopup\": \"listbox\";\n \"aria-controls\": string;\n \"aria-expanded\": boolean;\n \"aria-activedescendant\": string | undefined;\n spellCheck: true;\n enterKeyHint: \"send\";\n onInput: () => void;\n onKeyDown: (e: ReactKeyboardEvent<HTMLDivElement>) => void;\n onCompositionStart: () => void;\n onCompositionEnd: () => void;\n onPaste: (e: ReactClipboardEvent<HTMLDivElement>) => void;\n onFocus: () => void;\n onBlur: () => void;\n };\n /** Current plain-text content of the editor (used by submit). */\n getPlainText: () => string;\n /** Imperative focus / blur (used by the parent's imperative handle). */\n focus: () => void;\n blur: () => void;\n}\n\n/**\n * Owns every concern that's specific to running the autocomplete on top of a\n * contentEditable host: composition state, caret tracking, selectionchange,\n * `beforeinput` interception, paste sanitization, plaintext-only feature\n * detection, segment rendering, post-promote refocus, and re-edit caret park.\n *\n * The hook stays React-agnostic above the contentEditable adapter — see\n * `core/render/renderEditable.ts` for the underlying DOM mutations. Callers\n * spread `editorProps` onto a `<div>` (className is theirs to provide).\n */\nexport function useContentEditableEditor(\n opts: UseContentEditableEditorOptions,\n): UseContentEditableEditorReturn {\n const {\n segments,\n newParamId,\n editingParam,\n editingIdentified,\n editingAnchor,\n caretOffset,\n placeholderText,\n isFocused,\n isDropdownOpen,\n listboxId,\n activeDescendantId,\n autoFocus,\n handleTextChange,\n handleKeyDown,\n handleCaretAfterInput,\n handleCaretMove,\n startEditingParam,\n replaceEditingRange,\n setFocused,\n } = opts;\n\n const inputRef = useRef<HTMLDivElement>(null);\n const composingRef = useRef(false);\n const lastSeenParamIdRef = useRef(\"\");\n const lastEditingIdRef = useRef(\"\");\n const caretOffsetRef = useRef<number | null>(null);\n // Set in the input event handler; selectionchange suppresses post-input\n // caret-move tracking within this window so typing doesn't get treated\n // as navigation.\n const lastInputAtRef = useRef(0);\n\n caretOffsetRef.current = caretOffset;\n\n // Auto-focus on mount once the host element is mounted.\n useEffect(() => {\n if (!autoFocus) return;\n const el = inputRef.current;\n if (!el) return;\n if (document.activeElement === el) {\n setFocused(true);\n } else {\n el.focus();\n }\n // Focusing an empty contentEditable doesn't always create a selection\n // Range, so no caret blinks until the user clicks. Place a collapsed caret\n // at the start so the field is visibly ready immediately. Skip if the caret\n // already sits inside the editor (e.g. the user clicked before this ran).\n const doc = el.ownerDocument ?? document;\n const sel = doc.getSelection();\n const caretInside = sel && sel.rangeCount > 0 && el.contains(sel.anchorNode);\n if (sel && !caretInside) {\n const range = doc.createRange();\n range.selectNodeContents(el);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n }\n }, [autoFocus, setFocused]);\n\n // `selectionchange` is the canonical signal for \"caret moved\" in\n // contentEditable land. Anchored inside the editor: a caret that lands\n // inside a `<strong>` triggers re-edit mode; a caret that leaves the\n // current editing region exits it.\n useEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n const doc = el.ownerDocument ?? document;\n const onSelectionChange = () => {\n const sel = doc.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n if (!sel.anchorNode || !el.contains(sel.anchorNode)) return;\n const anchor = sel.anchorNode;\n const startEl =\n anchor.nodeType === Node.ELEMENT_NODE ? (anchor as Element) : anchor.parentElement;\n // Only a COLLAPSED selection means \"the caret landed in a chip\". A range\n // selection (Cmd+A, shift-arrow, drag) anchors at its start, which lands\n // inside the first `<strong>` whenever the input begins with a chip —\n // starting re-edit there parks the caret on that chip and destroys the\n // user's selection.\n const strong = sel.isCollapsed\n ? // Both chip kinds report here. The core decides what a tap means — a\n // completed param re-opens its options, an identified date opens the\n // calendar, anything else is inert.\n startEl?.closest<HTMLElement>(\"strong[data-param-id]\")\n : null;\n const enclosing = strong?.dataset.paramId ?? null;\n // Either kind counts as \"already open on this chip\" — without the\n // identified id here, every caret tick inside a date span would re-enter\n // the pick it is already in.\n const openChipId = editingParam?.id ?? editingIdentified?.id ?? null;\n if (enclosing && enclosing !== openChipId) {\n startEditingParam(enclosing);\n return;\n }\n if (performance.now() - lastInputAtRef.current < 50) return;\n handleCaretMove(getCursorOffset(el));\n };\n doc.addEventListener(\"selectionchange\", onSelectionChange);\n return () => doc.removeEventListener(\"selectionchange\", onSelectionChange);\n }, [editingParam, editingIdentified, startEditingParam, handleCaretMove]);\n\n // Render segments imperatively into the contentEditable. useLayoutEffect\n // runs before paint so the caret is restored without a one-frame flicker.\n // MUST run before the post-promote refocus + re-edit caret park effects\n // below — keep this declaration order.\n useLayoutEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n renderEditableContent({\n input: el,\n segments: segments as Segment[],\n newParamId,\n editingParamId: editingParam?.id ?? null,\n placeholderText: placeholderText ?? \"\",\n isFocused,\n });\n }, [segments, newParamId, editingParam, placeholderText, isFocused]);\n\n // After a fresh option selection (newParamId changed), refocus the editor\n // and place the caret at the end of the just-promoted segment. Mirrors the\n // vanilla core's `justSelected` logic in renderInput.ts.\n useLayoutEffect(() => {\n const previous = lastSeenParamIdRef.current;\n const current = newParamId ?? \"\";\n lastSeenParamIdRef.current = current;\n if (!current || current === previous) return;\n const el = inputRef.current;\n if (!el) return;\n el.focus();\n // Every promote path stamps `caretOffset` with the position right after\n // the new param's trailing space, so use it. Read via ref so the effect\n // stays gated on newParamId (not every caret-move).\n const desired = caretOffsetRef.current ?? plainTextLength(el);\n setCursorOffset(el, desired);\n }, [newParamId]);\n\n // On re-edit-mode entry, park the caret just BEFORE the bold strong so\n // typing/backspace via the `beforeinput` intercept replaces the param\n // cleanly (instead of inserting mid-letter inside the bold span).\n useLayoutEffect(() => {\n const previous = lastEditingIdRef.current;\n const current = editingParam?.id ?? \"\";\n lastEditingIdRef.current = current;\n if (!current || current === previous || editingAnchor == null) return;\n const el = inputRef.current;\n if (!el) return;\n setCursorOffset(el, editingAnchor);\n }, [editingParam, editingAnchor]);\n\n const fireInput = useCallback(() => {\n if (composingRef.current) return;\n const el = inputRef.current;\n if (!el) return;\n const raw = extractPlainText(el);\n const shouldCapitalize = raw.length > 0 && raw[0] !== raw[0].toUpperCase();\n const next = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n handleTextChange(next);\n }, [handleTextChange]);\n\n const handleInputEvent = useCallback(() => {\n lastInputAtRef.current = performance.now();\n fireInput();\n const el = inputRef.current;\n if (el) handleCaretAfterInput(getCursorOffset(el));\n }, [fireInput, handleCaretAfterInput]);\n\n // React's synthetic `onBeforeInput` is wired to the legacy `textInput`\n // event and doesn't reliably fire for `delete*` input types, so we attach\n // a native `beforeinput` listener directly on the editor.\n useEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n const onBeforeInput = (e: Event) => {\n const inputEvent = e as InputEvent;\n const t = inputEvent.inputType;\n if (t === \"insertParagraph\" || t === \"insertLineBreak\" || t === \"insertFromDrop\") {\n e.preventDefault();\n return;\n }\n if (t.startsWith(\"insert\") || t.startsWith(\"delete\")) {\n const replacement = t.startsWith(\"delete\") ? \"\" : (inputEvent.data ?? \"\");\n if (replaceEditingRange(replacement)) {\n e.preventDefault();\n }\n }\n };\n el.addEventListener(\"beforeinput\", onBeforeInput);\n return () => el.removeEventListener(\"beforeinput\", onBeforeInput);\n }, [replaceEditingRange]);\n\n const handleCompositionStart = useCallback(() => {\n composingRef.current = true;\n }, []);\n\n const handleCompositionEnd = useCallback(() => {\n composingRef.current = false;\n fireInput();\n }, [fireInput]);\n\n const handlePaste = useCallback(\n (e: ReactClipboardEvent<HTMLDivElement>) => {\n e.preventDefault();\n const el = inputRef.current;\n if (!el) return;\n const text = (e.clipboardData.getData(\"text/plain\") ?? \"\").replace(/\\r?\\n/g, \" \");\n if (!text) return;\n const doc = el.ownerDocument ?? document;\n const sel = doc.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n if (!el.contains(range.startContainer)) return;\n range.deleteContents();\n const node = doc.createTextNode(text);\n range.insertNode(node);\n range.setStartAfter(node);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n fireInput();\n },\n [fireInput],\n );\n\n const handleKeyDownReact = useCallback(\n (e: ReactKeyboardEvent<HTMLDivElement>) => handleKeyDown(e),\n [handleKeyDown],\n );\n\n const handleFocus = useCallback(() => setFocused(true), [setFocused]);\n const handleBlur = useCallback(() => setFocused(false), [setFocused]);\n\n const focus = useCallback(() => inputRef.current?.focus(), []);\n const blur = useCallback(() => inputRef.current?.blur(), []);\n const getPlainText = useCallback(() => {\n const el = inputRef.current;\n return el ? extractPlainText(el) : \"\";\n }, []);\n\n const ceMode = supportsPlaintextOnly() ? \"plaintext-only\" : \"true\";\n\n return {\n inputRef,\n editorProps: {\n ref: inputRef,\n contentEditable: ceMode as unknown as boolean,\n suppressContentEditableWarning: true,\n tabIndex: 0,\n role: \"combobox\",\n \"aria-autocomplete\": \"list\",\n \"aria-haspopup\": \"listbox\",\n \"aria-controls\": listboxId,\n \"aria-expanded\": isDropdownOpen,\n \"aria-activedescendant\": activeDescendantId,\n spellCheck: true,\n enterKeyHint: \"send\",\n onInput: handleInputEvent,\n onKeyDown: handleKeyDownReact,\n onCompositionStart: handleCompositionStart,\n onCompositionEnd: handleCompositionEnd,\n onPaste: handlePaste,\n onFocus: handleFocus,\n onBlur: handleBlur,\n },\n getPlainText,\n focus,\n blur,\n };\n}\n"],"mappings":"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","names":["index_exports","__export","AIAutocomplete","AIAutocompleteDropdown","useAIAutocomplete","__toCommonJS","import_ai_autocomplete_vanilla","import_react","s","AIAutocomplete_module_css_default","import_ai_autocomplete_vanilla","import_react","s","s","AIAutocompleteDropdown_module_css_default","import_ai_autocomplete_vanilla","import_react","s","DateGrid_module_css_default","import_jsx_runtime","WEEKDAY_KEYS","DateGrid","options","activeIndex","listboxId","view","selectedIso","onSelect","onHighlight","onPreviousMonth","onNextMonth","today","DateGrid_module_css_default","e","label","i","option","DateCell","id","index","isHighlighted","isToday","isPast","isSelected","pressed","setPressed","day","handleSelect","className","import_ai_autocomplete_vanilla","import_react","s","import_jsx_runtime","Cluster","gap","align","justify","noWrap","inline","className","children","rest","style","props","s","DropdownFooter_module_css_default","import_jsx_runtime","DropdownFooter","isOptionHighlighted","isInputEmpty","key","hint","brandHref","setBrandHref","DropdownFooter_module_css_default","Cluster","s","ParamPill_module_css_default","import_jsx_runtime","PARAM_PILL_OPACITY","ParamPill","label","state","rounded","loading","onClick","className","ParamPill_module_css_default","e","s","PillList_module_css_default","import_jsx_runtime","FALLBACK_SKELETON_WIDTHS","pillStateForIndex","index","PillList","pills","activePillIndex","onSelectPill","activeSelected","rounded","loading","PillList_module_css_default","w","i","ParamPill_module_css_default","PARAM_PILL_OPACITY","pill","selected","ParamPill","s","ProductStrip_module_css_default","import_jsx_runtime","ProductStrip","products","listboxId","onSelect","onFocusChange","focusable","labelId","ProductStrip_module_css_default","product","i","ProductCard","id","handleClick","e","import_ai_autocomplete_vanilla","import_react","import_ai_autocomplete_vanilla","import_react","s","import_jsx_runtime","Grid","min","max","gap","scroll","maxHeight","scrollResetKey","cols","template","innerRef","className","children","rest","gridRef","el","style","import_ai_autocomplete_vanilla","import_react","s","SuggestionItem_module_css_default","import_jsx_runtime","SuggestionItem","option","isHighlighted","onSelect","onHighlight","id","loading","scrollHint","enterDelayMs","enterDelay","pressed","setPressed","timerRef","handleSelect","className","SuggestionItem_module_css_default","e","import_jsx_runtime","useIsMobile","isMobile","setIsMobile","mq","onChange","SuggestionGrid","options","activeIndex","onSelect","onHighlight","listboxId","loading","groupKey","optionsPosition","gridEl","measuredPlan","setMeasuredPlan","el","measured","plan","Grid","option","i","SuggestionItem","s","import_jsx_runtime","Stack","space","align","className","children","rest","style","import_jsx_runtime","FALLBACK_SKELETON_BAR_WIDTHS","NOOP_PRODUCT_SELECT","NOOP_MONTH","useResolvedMode","mode","prefersDark","systemDark","setSystemDark","mq","onChange","useScrollArrow","rootRef","buttonRef","boundRef","root","button","grid","AIAutocompleteDropdown","suggestions","activeIndex","onSelect","onHighlight","isOpen","id","className","pills","onPillClick","showPills","onSkip","showSkipButton","skipDisabled","activeSelected","isLoading","isInputEmpty","products","onProductSelect","onProductFocusChange","formatType","dateView","selectedDateIso","onPreviousMonth","onNextMonth","optionsPosition","resolvedMode","selfScope","scrollArrowRef","liveOptions","liveHasRealPills","liveHasProducts","isVisible","snapshot","lastVisibleRef","content","activeSuggestion","options","isOptionHighlighted","hasRealPills","showsRealPills","showsLoadingPills","showsPillBar","showsSkip","activePillLabel","isDate","showsOptions","showsDateGrid","showsFallbackSkeleton","stripProducts","AIAutocompleteDropdown_module_css_default","e","Stack","Cluster","PillList","SuggestionGrid","DateGrid","w","ProductStrip","DropdownFooter","import_ai_autocomplete_vanilla","s","SubmitButton_module_css_default","import_jsx_runtime","SubmitButton","disabled","onClick","SubmitButton_module_css_default","e","import_ai_autocomplete_vanilla","import_react","import_react","useProductsProxy","products","productsRef","proxyRef","query","signal","config","raw","enabled","EMPTY_STATE","useAIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","apiConfig","additionalContext","columns","dropdownTrigger","optionsPosition","closeDropdownOnBlur","showNonTappableOptions","showSkipButton","onFocus","onBlur","controlledValue","controlledParams","onChangeProp","onParamsChange","products","onProductSelect","source","setCursor","instanceRef","coreState","setCoreState","onSubmitRef","onErrorRef","onChangeRef","onParamsChangeRef","onFocusRef","onBlurRef","setCursorRef","onProductSelectRef","productsProxy","useProductsProxy","instance","CoreAIAutocomplete","args","product","offset","unsub","state","apiConfigJson","additionalContextJson","prevOverridesRef","overridesVersion","prev","next","prevKeys","nextKeys","k","productsMountedRef","actionsRef","value","e","native","focused","paramId","replacement","index","option","actions","handleChange","raw","newValue","handleKeyDownTextarea","text","completedParams","actionableSuggestions","activeSuggestion","listboxId","activeDescendantId","editingParam","editingIdentified","dropdownPill","dropdownActivePill","dropdownPills","uiLoading","import_ai_autocomplete_vanilla","import_react","plaintextOnlyCache","supportsPlaintextOnly","probe","useContentEditableEditor","opts","segments","newParamId","editingParam","editingIdentified","editingAnchor","caretOffset","placeholderText","isFocused","isDropdownOpen","listboxId","activeDescendantId","autoFocus","handleTextChange","handleKeyDown","handleCaretAfterInput","handleCaretMove","startEditingParam","replaceEditingRange","setFocused","inputRef","composingRef","lastSeenParamIdRef","lastEditingIdRef","caretOffsetRef","lastInputAtRef","el","doc","sel","caretInside","range","onSelectionChange","anchor","startEl","enclosing","openChipId","previous","current","desired","fireInput","raw","next","handleInputEvent","onBeforeInput","e","inputEvent","t","replacement","handleCompositionStart","handleCompositionEnd","handlePaste","text","node","handleKeyDownReact","handleFocus","handleBlur","focus","blur","getPlainText","ceMode","import_jsx_runtime","resolveInitialMode","mode","AIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","className","apiConfig","additionalContext","columns","pillPlacement","optionsPosition","animations","dropdownTrigger","closeDropdownOnBlur","showNonTappableOptions","showSkipButton","autoFocus","onFocus","onBlur","value","controlledParams","onChangeProp","onParamsChange","products","onProductSelect","submitButton","ref","containerRef","pillContainerRef","handleSubmitRef","modeControllerRef","editorInputRefHolder","el","handleSetCursor","offset","completedParams","skippedParams","suggestionPills","setActivePill","skipActivePill","segments","newParamId","clearNewParamId","placeholderText","isFocused","isDropdownOpen","isActivePillSelected","isLoading","activeIndex","listboxId","handleTextChange","handleKeyDown","setFocused","editingParam","editingIdentified","editingAnchor","caretOffset","startEditingParam","handleCaretAfterInput","handleCaretMove","replaceEditingRange","dropdownProps","reset","useAIAutocomplete","result","t","activeDescendantId","inputRef","editorProps","focus","blur","getPlainText","useContentEditableEditor","container","editor","update","inner","cRect","eRect","ro","m","canSubmit","handleSubmit","text","handleWrapperClick","e","showInlinePills","showDropdownPills","AIAutocomplete_module_css_default","AIAutocompleteDropdown","PillList","SubmitButton"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/AIAutocomplete.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/AIAutocomplete.module.css.js","../src/AIAutocompleteDropdown.tsx","plain-css:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/appearance.css.js","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/AIAutocompleteDropdown.module.css.js","../src/components/DateGrid.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/DateGrid.module.css.js","../src/components/DropdownFooter.tsx","plain-css:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/layout/Cluster.css.js","../src/layout/Cluster.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/DropdownFooter.module.css.js","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/ParamPill.module.css.js","../src/components/ParamPill.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/PillList.module.css.js","../src/components/PillList.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/ProductStrip.module.css.js","../src/components/ProductStrip.tsx","../src/components/SuggestionGrid.tsx","../src/layout/Grid.tsx","plain-css:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/layout/Grid.css.js","../src/components/SuggestionItem.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/SuggestionItem.module.css.js","plain-css:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/layout/Stack.css.js","../src/layout/Stack.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/SubmitButton.module.css.js","../src/components/SubmitButton.tsx","../src/hooks/useAIAutocomplete.ts","../src/hooks/useOptionOverridesProxy.ts","../src/hooks/useProductsProxy.ts","../src/hooks/useContentEditableEditor.ts"],"sourcesContent":["export {\n buildSubmitResult,\n // Date helpers, for turning a committed date back into a `Date` and for\n // rendering a custom calendar in Tier 3.\n cellDay,\n cellIso,\n formatDate,\n isoDate,\n monthLabel,\n parseDate,\n parseLooseDate,\n WEEKDAY_LABELS,\n withSkippedParams,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nexport { AIAutocomplete } from \"./AIAutocomplete\";\nexport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nexport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nexport type {\n AccessTokenConfig,\n AccessTokenResult,\n AIAutocompleteDropdownProps,\n AIAutocompleteHandle,\n AIAutocompleteProps,\n APIConfig,\n APIKeyConfig,\n AppearanceMode,\n AutocompleteResult,\n CompletedParam,\n CompletedParamState,\n DateMonthView,\n FormatType,\n IdentifiedParam,\n IdentifiedParamState,\n OptionOverrides,\n Product,\n ProductsConfig,\n Segment,\n SkippedParamState,\n SubmitResultExtras,\n Suggestion,\n SuggestionOption,\n TaskKind,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"./types\";\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n} from \"react\";\nimport styles from \"./AIAutocomplete.module.css\";\nimport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nimport \"./appearance.css\";\nimport {\n type AppearanceMode,\n type AutocompleteResult,\n buildSubmitResult,\n ModeController,\n setCursorOffset,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { PillList } from \"./components/PillList\";\nimport { SubmitButton } from \"./components/SubmitButton\";\nimport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nimport { useContentEditableEditor } from \"./hooks/useContentEditableEditor\";\nimport type { AIAutocompleteHandle, AIAutocompleteProps } from \"./types\";\n\nfunction resolveInitialMode(mode: AppearanceMode): \"light\" | \"dark\" {\n if (mode !== \"auto\") return mode;\n if (typeof window === \"undefined\") return \"dark\";\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\";\n}\n\nexport const AIAutocomplete = forwardRef<AIAutocompleteHandle, AIAutocompleteProps>(\n function AIAutocomplete(\n {\n onSubmit,\n onResult,\n onError,\n optionOverrides,\n maskCompletedText,\n className,\n apiConfig,\n additionalContext,\n columns,\n pillPlacement = \"dropdown\",\n mode = \"auto\",\n optionsPosition = \"below\",\n animations = true,\n dropdownTrigger,\n closeDropdownOnBlur,\n showNonTappableOptions,\n showSkipButton,\n autoFocus = true,\n onFocus,\n onBlur,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n products,\n onProductSelect,\n submitButton,\n },\n ref,\n ) {\n const containerRef = useRef<HTMLDivElement>(null);\n const pillContainerRef = useRef<HTMLSpanElement>(null);\n const handleSubmitRef = useRef<(result: AutocompleteResult) => void>(() => {});\n const modeControllerRef = useRef<ModeController | null>(null);\n // Holds the editor's input *ref object* (not its current value) so the\n // setCursor callback — defined before useContentEditableEditor runs — can\n // dereference the live DOM element at call time without a one-render lag.\n const editorInputRefHolder = useRef<React.RefObject<HTMLDivElement> | null>(null);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n if (modeControllerRef.current) {\n modeControllerRef.current.setMode(mode);\n } else {\n modeControllerRef.current = new ModeController(el, mode);\n }\n return () => {\n modeControllerRef.current?.destroy();\n modeControllerRef.current = null;\n };\n }, [mode]);\n\n const handleSetCursor = useCallback((offset: number) => {\n const el = editorInputRefHolder.current?.current;\n if (!el) return;\n el.focus();\n setCursorOffset(el, offset);\n }, []);\n\n const {\n completedParams,\n skippedParams,\n identifiedParams,\n isReady,\n suggestionPills,\n setActivePill,\n skipActivePill,\n segments,\n newParamId,\n clearNewParamId,\n placeholderText,\n isFocused,\n isDropdownOpen,\n isActivePillSelected,\n isLoading,\n activeIndex,\n listboxId,\n handleTextChange,\n handleKeyDown,\n setFocused,\n editingParam,\n editingIdentified,\n editingAnchor,\n caretOffset,\n startEditingParam,\n handleCaretAfterInput,\n handleCaretMove,\n replaceEditingRange,\n dropdownProps,\n reset,\n } = useAIAutocomplete({\n onSubmit: (result) => handleSubmitRef.current(result),\n onResult,\n onError,\n optionOverrides,\n maskCompletedText,\n apiConfig,\n additionalContext,\n columns,\n dropdownTrigger,\n optionsPosition,\n closeDropdownOnBlur,\n showNonTappableOptions,\n showSkipButton,\n onFocus,\n onBlur,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n products,\n onProductSelect,\n source: \"full-sdk\",\n setCursor: handleSetCursor,\n });\n\n // Shimmer auto-clear after the animation finishes.\n useEffect(() => {\n if (!newParamId) return;\n const t = window.setTimeout(() => clearNewParamId(), 650);\n return () => window.clearTimeout(t);\n }, [newParamId, clearNewParamId]);\n\n const activeDescendantId = activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : undefined;\n\n const { inputRef, editorProps, focus, blur, getPlainText } = useContentEditableEditor({\n segments,\n newParamId,\n editingParam,\n editingIdentified,\n editingAnchor,\n caretOffset,\n placeholderText,\n isFocused,\n isDropdownOpen,\n listboxId,\n activeDescendantId,\n autoFocus,\n handleTextChange,\n handleKeyDown,\n handleCaretAfterInput,\n handleCaretMove,\n startEditingParam,\n replaceEditingRange,\n setFocused,\n });\n\n // Wire the holder to the hook's ref. The ref *object* is stable across\n // renders, so this assignment is idempotent and reaches the live DOM\n // element via `.current` without snapshotting null on the first render.\n editorInputRefHolder.current = inputRef;\n\n // The pill list sits inline-adjacent to the editor and carries an 8px\n // left margin so it doesn't butt against the editor's text. When the\n // editor's text fills its line and the pill list wraps to a new line,\n // that margin becomes a stray indent at the start of the wrapped line —\n // detect that case and drop the margin via a data attribute the CSS\n // keys off. The wrap detection (pill row's top vs editor's bottom)\n // already handles the placeholder-only case correctly: the placeholder\n // still occupies the editor's line box, so pills sitting beside it are\n // NOT wrapped and the margin stays.\n // biome-ignore lint/correctness/useExhaustiveDependencies: segments/suggestionPills/isLoading are intentional re-measure triggers, not reads\n useLayoutEffect(() => {\n const container = pillContainerRef.current;\n const editor = inputRef.current;\n if (!container || !editor) return;\n\n const update = () => {\n const inner = container.firstElementChild as HTMLElement | null;\n if (!inner) return;\n const cRect = inner.getBoundingClientRect();\n const eRect = editor.getBoundingClientRect();\n const wrapped = cRect.top >= eRect.bottom - 2;\n if (wrapped) container.setAttribute(\"data-aia-pill-wrapped\", \"\");\n else container.removeAttribute(\"data-aia-pill-wrapped\");\n };\n\n update();\n const ro = new ResizeObserver(update);\n ro.observe(editor);\n return () => ro.disconnect();\n }, [segments, suggestionPills.length, isLoading, inputRef]);\n\n useImperativeHandle(\n ref,\n () => ({\n focus,\n blur,\n reset,\n setMode: (m) => modeControllerRef.current?.setMode(m),\n skipActivePill,\n }),\n [focus, blur, reset, skipActivePill],\n );\n\n const canSubmit = !!segments.length || completedParams.length > 0;\n\n const handleSubmit = useCallback(() => {\n if (!canSubmit) return;\n const text = getPlainText();\n onSubmit(\n buildSubmitResult(text, completedParams, skippedParams, { identifiedParams, isReady }),\n );\n reset();\n }, [\n canSubmit,\n completedParams,\n skippedParams,\n identifiedParams,\n isReady,\n onSubmit,\n reset,\n getPlainText,\n ]);\n\n handleSubmitRef.current = handleSubmit;\n\n const handleWrapperClick = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n // Clicking a pill activates it; don't steal focus away from where it lands.\n const target = e.target as HTMLElement | null;\n if (target?.closest(\"[data-aia-pill]\")) return;\n focus();\n },\n [focus],\n );\n\n const showInlinePills = pillPlacement === \"inline\";\n const showDropdownPills = pillPlacement === \"dropdown\";\n\n return (\n <div\n ref={containerRef}\n className={`magicx-aia ${styles.container} ${className ?? \"\"}`}\n data-pill-placement={pillPlacement}\n data-options-position={optionsPosition}\n data-animations={animations ? \"on\" : \"off\"}\n data-mode={resolveInitialMode(mode)}\n >\n <AIAutocompleteDropdown {...dropdownProps} showPills={showDropdownPills} />\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: container click delegates to editor focus */}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: wrapper delegates focus to editor */}\n <div className={styles.inputWrapper} onClick={handleWrapperClick}>\n <div className={styles.editorArea} data-aia-editor=\"\">\n <div {...editorProps} className={styles.input} data-aia-input=\"\" />\n {showInlinePills && (isLoading || suggestionPills.length > 0) && (\n <span\n ref={pillContainerRef}\n className={styles.pillListContainer}\n data-aia-pill-list-container=\"\"\n >\n <PillList\n pills={suggestionPills}\n activePillIndex={0}\n activeSelected={isActivePillSelected}\n onSelectPill={setActivePill}\n loading={isLoading}\n />\n </span>\n )}\n </div>\n {submitButton === null ? null : submitButton === undefined ? (\n <SubmitButton disabled={!canSubmit} onClick={handleSubmit} />\n ) : (\n // biome-ignore lint/a11y/useKeyWithClickEvents: consumer-provided element handles its own keyboard interaction\n // biome-ignore lint/a11y/noStaticElementInteractions: transparent slot — click bubbles from consumer's element\n <span\n data-aia-submit=\"\"\n className={styles.submitSlot}\n onClick={(e) => {\n if (!canSubmit) return;\n e.stopPropagation();\n handleSubmit();\n }}\n >\n {submitButton}\n </span>\n )}\n </div>\n </div>\n );\n },\n);\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-67791514\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-67791514\";\n s.textContent = `.AIAutocomplete-module_container_KKjFU {\n position: relative;\n /* Inherits the host page's font by default. Consumers can pin a specific\n font on the library via \\`--aia-font-family: 'Custom Font'\\` without\n affecting the surrounding page. */\n font-family: var(--aia-font-family, inherit);\n container-type: inline-size;\n}\n\n.AIAutocomplete-module_inputWrapper_FLq1b {\n padding: 12px 16px;\n border: 1px solid var(--aia-border, #b0b0b0);\n border-radius: 20px;\n background: var(--aia-surface, #ffffff);\n box-shadow: var(--aia-shadow, none);\n overflow: hidden;\n display: flex;\n /* Top-align so the submit button stays by the first line while the editor\n grows downward and then scrolls internally. */\n align-items: flex-start;\n gap: 12px;\n}\n\n.AIAutocomplete-module_editorArea_7rBWq {\n position: relative;\n flex: 1;\n min-width: 0;\n min-height: 22px;\n /* Airy line box so wrapped rows of chips (and plain text) don't touch. */\n line-height: var(--aia-editor-line-height, 1.9);\n font-family: inherit;\n font-size: var(--aia-written-text-font-size, 14px);\n white-space: pre-wrap;\n word-break: break-word;\n overflow-wrap: anywhere;\n /* Grow with content up to a cap of five rows, then hold height and scroll\n internally — the caret stays in view as the text is pushed up. The\n scrollbar is hidden so the box reads as a clean growing field. The cap is\n five line boxes rather than a fixed pixel height so it still lands on a\n whole row when a consumer resizes the text via\n --aia-written-text-font-size (\\`em\\` here resolves against this element's\n own font-size, which is that token). */\n max-height: var(--aia-editor-max-height, calc(var(--aia-editor-line-height, 1.9) * 5em));\n overflow-y: auto;\n scrollbar-width: none;\n}\n\n.AIAutocomplete-module_editorArea_7rBWq::-webkit-scrollbar {\n display: none;\n}\n\n.AIAutocomplete-module_input_IW-P- {\n display: inline;\n outline: none;\n background: transparent;\n color: var(--aia-written-text-color, var(--aia-color-text-default, #fff));\n caret-color: var(\n --aia-caret-color,\n var(--aia-written-text-color, var(--aia-color-text-default, #fff))\n );\n font-weight: 300;\n /* Align the text's inline box with the pill list (also vertical-align: middle)\n so they share a vertical center when pills stretch the line box to ~36px. */\n vertical-align: middle;\n}\n\n/* Completed params render as inline pills (Figma \"RichTextPill\") — a compact\n ~26px chip with regular-weight primary-color text on a faint-gray fill.\n inline-block gives the padding/radius a box while the text stays part of the\n editable plain text (the caret system counts characters inside this\n <strong>). The completed class is stamped by the shared renderer as a global\n string, so match it via [class~=] to bypass CSS Modules' hashing. */\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--completed\"] {\n /* inline (not inline-block) so a chip too wide for the line breaks across two\n lines; box-decoration-break: clone gives each fragment its own padding /\n radius / fill, so an over-long recognized phrase renders as two little\n rounded blocks instead of overflowing the field. */\n display: inline;\n padding: 3px 6px;\n /* Rounded rectangle, not a full capsule. */\n border-radius: 6px;\n -webkit-box-decoration-break: clone;\n box-decoration-break: clone;\n background: var(--aia-completed-pill-bg, rgba(189, 189, 189, 0.105));\n color: var(--aia-completed-pill-color, var(--aia-written-text-color, #fff));\n font-size: var(--aia-pill-font-size, 14px);\n font-weight: 400;\n line-height: normal;\n white-space: normal;\n /* Tighten the tracking so the chip's horizontal padding doesn't make the\n recognized phrase read wider than the same words as plain text. The exact\n per-chip amount is set inline by the renderer (renderEditable); this is a\n fallback for any chip the renderer didn't stamp. */\n letter-spacing: var(--aia-completed-pill-tracking, -0.02em);\n cursor: pointer;\n /* Smooth hover fade. Neutralized by the data-animations=\"off\" block. */\n transition: background-color 150ms ease;\n}\n\n/* Hover highlight — a slightly stronger fill so a pointed-at pill reads as\n tappable. Declared between the base and editing rules so editing wins. */\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--completed\"]:hover {\n background: var(--aia-completed-pill-bg-active, rgba(189, 189, 189, 0.35));\n}\n\n/* Re-edit highlight — applied to the completed pill being re-edited (after a\n tap). Reuses the exact hover fill so the highlight persists from tap until an\n option is selected. Hides the native caret; cursor switches to text since the\n pill is in text-replacement mode. The editing class is written by the shared\n renderer (a global string), so target it via an attribute selector to bypass\n CSS Modules' hashing. Declared last so it wins on a strong carrying both\n classes. */\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--editing\"] {\n background: var(--aia-completed-pill-bg-active, rgba(189, 189, 189, 0.35));\n caret-color: transparent;\n cursor: text;\n}\n\n/* In re-edit mode the caret is parked just *before* the bold strong (see\n useContentEditableEditor.ts) — that means it sits in the parent .input, not\n inside the strong, so the rule above doesn't hide it. Use :has() to hide\n the caret on the whole editor while any completed param is selected. */\n.AIAutocomplete-module_input_IW-P-:has(strong[class~=\"magicx-aia-segment--editing\"]) {\n caret-color: transparent;\n}\n\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--editing\"]::selection {\n background: transparent;\n color: inherit;\n}\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--editing\"]::-moz-selection {\n background: transparent;\n color: inherit;\n}\n\n/* Placeholder via ::before so it doesn't enter the editable DOM. The text is\n typed in one character at a time by the core's typewriter (the attribute\n holds the typed prefix); the only fade is the outgoing phrase when the\n placeholder changes — its duration mirrors PLACEHOLDER_FADE_OUT_MS. */\n.AIAutocomplete-module_input_IW-P-[data-aia-empty=\"true\"][data-placeholder]::before {\n content: attr(data-placeholder);\n color: var(--aia-color-text-muted, #c1c4cb);\n opacity: 0.7;\n pointer-events: none;\n transition: opacity var(--aia-placeholder-fade, 120ms) ease-out;\n}\n\n.AIAutocomplete-module_input_IW-P-[data-aia-placeholder-leaving]::before {\n opacity: 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .AIAutocomplete-module_input_IW-P-[data-aia-empty=\"true\"][data-placeholder]::before {\n transition-duration: 0s;\n }\n}\n\n/* Empty inline contentEditables have no inline box for the caret to render\n in. Switch to inline-block (min-width matches the caret line) when empty,\n so the caret stays visible while focused. */\n.AIAutocomplete-module_input_IW-P-[data-aia-empty=\"true\"] {\n display: inline-block;\n min-width: 1px;\n}\n\n.AIAutocomplete-module_pillListContainer_h92IA {\n display: inline;\n margin-left: 8px;\n}\n\n.AIAutocomplete-module_pillListContainer_h92IA:empty,\n.AIAutocomplete-module_pillListContainer_h92IA[data-aia-pill-wrapped] {\n margin-left: 0;\n}\n\n.AIAutocomplete-module_submitSlot_GhuCM {\n display: contents;\n}\n\n/* Promotion reveal on a newly promoted completed param. The shared renderer\n (core/render/renderEditable.ts) stamps the global shimmer classes onto the\n just-added <strong>; we match them via [class~=] to bypass CSS Modules'\n hashing. Completed params are now pills with a solid background, so the old\n text-clip gradient shimmer can't be used (background-clip: text would wipe\n the pill background). The reveal is a simple fade-in of the whole pill,\n riding on shimmer-sweep so it only plays on genuine promotions. */\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-shimmer-sweep\"] {\n animation: AIAutocomplete-module_aiaPillReveal_wf05b 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n@keyframes AIAutocomplete-module_aiaPillReveal_wf05b {\n from {\n opacity: 0;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"container\":\"AIAutocomplete-module_container_KKjFU\",\"inputWrapper\":\"AIAutocomplete-module_inputWrapper_FLq1b\",\"editorArea\":\"AIAutocomplete-module_editorArea_7rBWq\",\"input\":\"AIAutocomplete-module_input_IW-P-\",\"pillListContainer\":\"AIAutocomplete-module_pillListContainer_h92IA\",\"submitSlot\":\"AIAutocomplete-module_submitSlot_GhuCM\",\"aiaPillReveal\":\"AIAutocomplete-module_aiaPillReveal_wf05b\"};","import {\n attachScrollArrow,\n SCROLL_ARROW_LABEL,\n type ScrollArrowController,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { type RefObject, useEffect, useRef, useState } from \"react\";\n// Self-inject the appearance layer (design tokens, box-sizing reset, and the\n// optionsPosition=\"above\" layout-reversal rules). Tier 1 already imports this,\n// but headless consumers render only this dropdown — importing it here means\n// they get correct styling and a working `optionsPosition` with no extra setup.\nimport \"./appearance.css\";\nimport styles from \"./AIAutocompleteDropdown.module.css\";\nimport { DateGrid } from \"./components/DateGrid\";\nimport { DropdownFooter } from \"./components/DropdownFooter\";\nimport { PillList } from \"./components/PillList\";\nimport { ProductStrip } from \"./components/ProductStrip\";\nimport { SuggestionGrid } from \"./components/SuggestionGrid\";\nimport { Cluster } from \"./layout/Cluster\";\nimport { Stack } from \"./layout/Stack\";\nimport type { AIAutocompleteDropdownProps } from \"./types\";\n\nconst FALLBACK_SKELETON_BAR_WIDTHS = [159, 119, 164];\n\n// Module constant, not an inline arrow: a fresh closure per render would defeat\n// ProductStrip's prop stability for no reason. Reached only by a Tier 2\n// consumer who renders products without wiring onProductSelect.\nconst NOOP_PRODUCT_SELECT = () => {};\n/** A Tier 2 consumer who renders the dropdown without wiring month paging gets inert arrows, not a crash. */\nconst NOOP_MONTH = () => {};\n\n/**\n * Resolve the `mode` prop to a concrete `\"light\" | \"dark\"` (or `undefined` when\n * unset, meaning \"don't self-scope — inherit from a `.magicx-aia` ancestor\").\n * `\"auto\"` tracks `prefers-color-scheme` live.\n */\nfunction useResolvedMode(\n mode: \"light\" | \"dark\" | \"auto\" | undefined,\n): \"light\" | \"dark\" | undefined {\n const prefersDark = () =>\n typeof window !== \"undefined\" &&\n typeof window.matchMedia === \"function\" &&\n window.matchMedia(\"(prefers-color-scheme: dark)\").matches;\n const [systemDark, setSystemDark] = useState(prefersDark);\n\n useEffect(() => {\n if (\n mode !== \"auto\" ||\n typeof window === \"undefined\" ||\n typeof window.matchMedia !== \"function\"\n ) {\n return;\n }\n const mq = window.matchMedia(\"(prefers-color-scheme: dark)\");\n const onChange = () => setSystemDark(mq.matches);\n mq.addEventListener(\"change\", onChange);\n return () => mq.removeEventListener(\"change\", onChange);\n }, [mode]);\n\n if (mode === undefined) return undefined;\n if (mode === \"auto\") return systemDark ? \"dark\" : \"light\";\n return mode;\n}\n\n/**\n * Keeps the core's \"more below\" arrow controller bound to whichever options\n * grid the dropdown currently renders. The controller owns the behaviour\n * (measuring, visibility, the page-scroll on click — see the core's\n * scrollArrow.ts); this hook only hands it the live elements and tells it to\n * re-measure after every render, re-attaching when the grid element is\n * replaced and tearing down when there is no grid.\n */\nfunction useScrollArrow(\n rootRef: RefObject<HTMLDivElement>,\n buttonRef: RefObject<HTMLButtonElement>,\n): void {\n const boundRef = useRef<{ grid: HTMLElement; controller: ScrollArrowController } | null>(null);\n\n // No dependency array on purpose: the grid can come and go with any render,\n // and update() is a cheap attribute compare when nothing changed. This\n // effect deliberately returns no cleanup — a cleanup here would run before\n // every re-run and tear the controller down on each render (re-arming its\n // \"new group\" gate every time). The controller's lifetime is instead tied to\n // the grid element (destroyed when the grid is replaced or gone, below) and\n // to the component (the mount-only effect after this one), which also\n // survives StrictMode's mount → cleanup → mount pass.\n // biome-ignore lint/correctness/useExhaustiveDependencies: runs after every render by design\n useEffect(() => {\n const root = rootRef.current;\n const button = buttonRef.current;\n if (!root || !button) return;\n const grid = root.querySelector<HTMLElement>(\".aia-grid[data-scroll]\");\n if (boundRef.current && boundRef.current.grid !== grid) {\n boundRef.current.controller.destroy();\n boundRef.current = null;\n }\n if (grid && !boundRef.current) {\n boundRef.current = {\n grid,\n controller: attachScrollArrow({ dropdown: root, grid, button }),\n };\n return; // attach() runs the first update itself\n }\n boundRef.current?.controller.update();\n });\n\n useEffect(\n () => () => {\n boundRef.current?.controller.destroy();\n boundRef.current = null;\n },\n [],\n );\n}\n\nexport function AIAutocompleteDropdown({\n suggestions,\n activeIndex,\n onSelect,\n onHighlight,\n isOpen,\n id,\n className,\n pills,\n onPillClick,\n showPills = true,\n onSkip,\n showSkipButton = true,\n skipDisabled = false,\n activeSelected = false,\n isLoading = false,\n isInputEmpty = false,\n products,\n onProductSelect,\n onProductFocusChange,\n formatType = \"options\",\n dateView = null,\n selectedDateIso = null,\n onPreviousMonth,\n onNextMonth,\n optionsPosition = \"below\",\n mode,\n}: AIAutocompleteDropdownProps) {\n // When `mode` is set, self-scope: add `magicx-aia` + `data-mode` to our own\n // root so the dropdown is styled without a `.magicx-aia` wrapper. When unset,\n // stay class-less and inherit from an ancestor (Tier 1 / a custom wrapper).\n const resolvedMode = useResolvedMode(mode);\n const selfScope = resolvedMode !== undefined;\n\n const rootRef = useRef<HTMLDivElement>(null);\n const scrollArrowRef = useRef<HTMLButtonElement>(null);\n useScrollArrow(rootRef, scrollArrowRef);\n\n // Visibility is computed from the CURRENT props and drives the opacity fade.\n const liveOptions = suggestions[0]?.options ?? [];\n const liveHasRealPills = Boolean(pills && pills.length > 0 && onPillClick);\n // Either half is enough to keep the panel up: products render with no\n // suggestions, suggestions render with no products.\n const liveHasProducts = Boolean(products && products.length > 0);\n const isVisible =\n isOpen &&\n (liveOptions.length > 0 || (showPills && liveHasRealPills) || isLoading || liveHasProducts);\n\n // Freeze the content-driving values while the dropdown is open. When it\n // closes we render this frozen snapshot during the 400ms opacity fade, so the\n // whole populated dropdown fades out as one. Otherwise the pills/options\n // unmount the instant the underlying state empties (e.g. skipping the last\n // pill with →), leaving the always-present footer alone for a flash of a\n // footer-only \"no options\" box. Content is refreshed on the next open.\n const snapshot = {\n suggestions,\n activeIndex,\n pills,\n showPills,\n showSkipButton,\n skipDisabled,\n activeSelected,\n isLoading,\n isInputEmpty,\n products,\n formatType,\n dateView,\n selectedDateIso,\n };\n const lastVisibleRef = useRef(snapshot);\n if (isVisible) lastVisibleRef.current = snapshot;\n const content = isVisible ? snapshot : lastVisibleRef.current;\n\n const activeSuggestion = content.suggestions[0];\n const options = activeSuggestion?.options ?? [];\n const isOptionHighlighted =\n content.activeIndex >= 0 && Boolean(options[content.activeIndex]?.is_tappable);\n const hasRealPills = Boolean(content.pills && content.pills.length > 0 && onPillClick);\n // Guarantee at least one option bar during loading — if the cached state\n // had no options, render the fallback skeleton bars regardless of whether\n // pills are present, so the dropdown never shows pills with an empty body.\n const showsRealPills = content.showPills && hasRealPills;\n const showsLoadingPills = content.showPills && !hasRealPills && content.isLoading;\n const showsPillBar = showsRealPills || showsLoadingPills;\n // The trailing \"skip\" button only makes sense next to a real, skippable\n // pill — the fallback skeleton bar has nothing to skip. Requires onSkip:\n // a Tier 2 consumer rendering the dropdown without wiring it gets no\n // dead button. Deliberately NOT gated on showPills: with pills rendered\n // elsewhere (pillPlacement \"inline\"/\"hidden\") the bar renders as a\n // skip-only row holding just the button. Hidden while the input is empty —\n // the footer hint doesn't advertise \"→ to skip\" until the user has typed,\n // so the pristine starting state stays free of the affordance too.\n const showsSkip =\n hasRealPills && content.showSkipButton && !content.isInputEmpty && Boolean(onSkip);\n const activePillLabel = content.pills?.[0]?.text;\n // Exactly one body renders. `options` above already holds the visible\n // month's cells when this is a date — the core swapped them in its derive\n // layer — so the two are the same list drawn two different ways, and never\n // both at once (two elements answering to `#${id}-option-0` would break\n // keyboard commit).\n const isDate = content.formatType === \"date\" && content.dateView != null;\n const showsOptions = options.length > 0 && !isDate;\n const showsDateGrid = options.length > 0 && isDate;\n const showsFallbackSkeleton = content.isLoading && !showsOptions && !showsDateGrid;\n // `data-aia-has-products` below is the layout hook: the band the footer\n // rides up over only makes sense when the footer sits directly on the\n // scrolling option list, and appearance.css reads the attribute to zero it\n // at the source when a strip is in between.\n const stripProducts = content.products ?? [];\n\n return (\n <div\n ref={rootRef}\n id={id}\n role=\"listbox\"\n data-aia-dropdown=\"\"\n data-options-position={optionsPosition}\n data-mode={resolvedMode}\n data-aia-loading={content.isLoading ? \"\" : undefined}\n data-aia-has-products={stripProducts.length > 0 ? \"\" : undefined}\n className={`${selfScope ? \"magicx-aia \" : \"\"}${styles.dropdown} ${isVisible ? styles.visible : \"\"} ${className ?? \"\"}`}\n onMouseDown={(e) => e.preventDefault()}\n >\n <Stack space=\"8px\">\n {(showsPillBar || showsSkip) && (\n <Cluster noWrap className={styles.pillBar} data-aia-pillbar=\"\">\n {/* The scroll + right-edge fade live on this wrapper (not the bar)\n so the skip button stays outside the masked region — pinned and\n fully opaque while overflowing pills fade under it. The\n data-aia-pill-scroll attribute is the public styling hook for\n the mask, since the module class hash isn't part of the API.\n Absent in a skip-only row (pills rendered elsewhere). */}\n {showsPillBar && (\n <span className={styles.pillScroll} data-aia-pill-scroll=\"\">\n <PillList\n pills={content.pills ?? []}\n activePillIndex={0}\n activeSelected={content.activeSelected}\n onSelectPill={onPillClick ?? (() => {})}\n rounded\n loading={content.isLoading}\n />\n </span>\n )}\n {showsSkip && (\n <button\n type=\"button\"\n tabIndex={-1}\n className={styles.skip}\n data-aia-skip=\"\"\n disabled={content.isLoading || content.skipDisabled}\n aria-label={activePillLabel ? `Skip ${activePillLabel}` : \"Skip\"}\n onClick={onSkip}\n >\n skip\n </button>\n )}\n </Cluster>\n )}\n {showsOptions && (\n <SuggestionGrid\n options={options}\n activeIndex={content.activeIndex}\n onSelect={onSelect}\n onHighlight={onHighlight}\n listboxId={id}\n loading={content.isLoading}\n groupKey={activeSuggestion ? `${activeSuggestion.type} ${activeSuggestion.text}` : \"\"}\n optionsPosition={optionsPosition}\n />\n )}\n {showsDateGrid && content.dateView && (\n <DateGrid\n options={options}\n activeIndex={content.activeIndex}\n listboxId={id}\n view={content.dateView}\n selectedIso={content.selectedDateIso ?? null}\n onSelect={onSelect}\n onHighlight={onHighlight}\n onPreviousMonth={onPreviousMonth ?? NOOP_MONTH}\n onNextMonth={onNextMonth ?? NOOP_MONTH}\n />\n )}\n {showsFallbackSkeleton && (\n <div className={styles.skeletonBars} data-aia-skeleton-bars=\"\">\n {FALLBACK_SKELETON_BAR_WIDTHS.map((w) => (\n <span key={`bar-${w}`} className={styles.skeletonBar} style={{ width: w }} />\n ))}\n </div>\n )}\n <ProductStrip\n products={stripProducts}\n listboxId={id}\n onSelect={onProductSelect ?? NOOP_PRODUCT_SELECT}\n onFocusChange={onProductFocusChange}\n focusable={isVisible}\n />\n <DropdownFooter\n isOptionHighlighted={isOptionHighlighted}\n isInputEmpty={content.isInputEmpty}\n />\n </Stack>\n {/* \"More below\" arrow — an overlay on the panel, not a section of the\n stack. Shown/positioned by the core's controller (useScrollArrow);\n markup mirrors vanilla's createScrollArrowButton. */}\n <button\n ref={scrollArrowRef}\n type=\"button\"\n tabIndex={-1}\n className={styles.scrollArrow}\n data-aia-scroll-arrow=\"\"\n aria-label={SCROLL_ARROW_LABEL}\n aria-hidden=\"true\"\n >\n <svg\n viewBox=\"0 0 16 16\"\n width=\"14\"\n height=\"14\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"1.75\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path d=\"M4 6.5 8 10.5l4-4\" />\n </svg>\n </button>\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-0ae03977\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-0ae03977\";\n s.textContent = `/*\n * Built-in appearance defaults — zero specificity via :where().\n * Consumer CSS always wins without !important.\n *\n * Resolution priority (highest wins):\n * 1. Consumer CSS targeting new vars (--aia-pill-bg, etc.)\n * 2. Consumer CSS targeting legacy vars (--aia-color-*, via fallback chain)\n * 3. These built-in defaults\n */\n\n/*\n * Library-scoped box-sizing reset. The SDK's pill / option / wrapper styles\n * mix explicit dimensions with padding (e.g. .magicx-aia-pill has height:36px\n * + padding:13px) and were authored assuming \\`border-box\\`. In consumer apps\n * without a global \\`* { box-sizing: border-box }\\` reset the pill rendered\n * ~62px tall instead of 36px. Scoping the reset to \\`.magicx-aia\\` descendants\n * keeps the library self-contained without leaking onto consumer markup.\n */\n:where(.magicx-aia, .magicx-aia *, .magicx-aia *::before, .magicx-aia *::after) {\n box-sizing: border-box;\n}\n\n/*\n * Primitive color ramp — single source of truth, mirroring the Figma\n * \"Primitives\" collection. INTERNAL: theme via the public --aia-* vars below,\n * not these. Mode-independent (raw values; the same in light and dark).\n */\n:where(.magicx-aia) {\n --aia-primitive-neutral-0: #000000;\n --aia-primitive-neutral-150: #1a1b1d;\n --aia-primitive-neutral-250: #323232;\n --aia-primitive-neutral-300: #333539;\n --aia-primitive-neutral-400: #4a4a4a;\n --aia-primitive-neutral-500: #505050;\n --aia-primitive-neutral-700: #b0b0b0;\n --aia-primitive-neutral-750: #bdbdbd;\n --aia-primitive-neutral-900: #e7e7e7;\n --aia-primitive-neutral-1000: #ffffff;\n --aia-primitive-blue-50: #eef2ff;\n --aia-primitive-neutral-750-a50: rgba(189, 189, 189, 0.51);\n --aia-primitive-neutral-750-a25: rgba(189, 189, 189, 0.25);\n --aia-primitive-neutral-750-a35: rgba(189, 189, 189, 0.35);\n --aia-primitive-neutral-750-a30: rgba(189, 189, 189, 0.3);\n --aia-primitive-neutral-750-a15: rgba(189, 189, 189, 0.15);\n /* a105 is a15 lightened 30% (0.15 -> 0.105) — a fainter tint of the same\n gray, not a new color. Light mode only: over a WHITE surface a weaker\n tint is lighter, but over the dark theme's black surface it would be\n darker, so dark mode keeps a15. */\n --aia-primitive-neutral-750-a105: rgba(189, 189, 189, 0.105);\n --aia-primitive-neutral-700-a40: rgba(176, 176, 176, 0.4);\n /* Exactly 0.5, unlike the older 750-a50 above (0.51). */\n --aia-primitive-neutral-900-a50: rgba(231, 231, 231, 0.5);\n --aia-primitive-neutral-400-a50: rgba(74, 74, 74, 0.5);\n}\n\n/* Light mode defaults (base) — public --aia-* vars resolve to primitives */\n:where(.magicx-aia),\n:where(.magicx-aia[data-mode=\"light\"]) {\n --aia-surface: var(--aia-primitive-neutral-1000);\n --aia-border: rgba(17, 24, 39, 0.14); /* subtle slate hairline (off-palette) */\n /* Elevation for the input container (.inputWrapper). */\n --aia-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 1px 2px rgba(16, 24, 40, 0.05),\n 0 8px 24px rgba(16, 24, 40, 0.08);\n /* Half-strength stroke: neutral-900 (was #e5e7eb — snapped to palette,\n Δ2) at 50% alpha over the surface, so the hairline lands exactly\n halfway between its old value and the white behind it. */\n --aia-dropdown-border: var(--aia-primitive-neutral-900-a50);\n --aia-dropdown-shadow: 0 8px 12px rgba(0, 0, 0, 0.05);\n /* Suggestion pills (Figma \"ParamPill\"): transparent fill, no visible border;\n per-pill opacity via getPillOpacity. */\n --aia-pill-bg: var(--aia-primitive-neutral-750);\n --aia-pill-color: var(--aia-primitive-neutral-300);\n --aia-pill-font-size: 16px;\n\n /* Completed params (Figma \"RichTextPill\"): compact faint-gray chip with\n primary-color regular-weight text. -active is the hover / tapped (re-edit)\n highlight — an alpha over the input background, so one value works in both\n themes. */\n --aia-completed-pill-bg: var(--aia-primitive-neutral-750-a105);\n --aia-completed-pill-bg-active: var(--aia-primitive-neutral-750-a35);\n --aia-completed-pill-color: var(--aia-primitive-neutral-0);\n\n --aia-option-bg: var(--aia-primitive-blue-50);\n /* Options read bigger + darker than the small-caps param labels above them. */\n --aia-option-color: var(--aia-primitive-neutral-150);\n --aia-option-color-selected: var(--aia-primitive-neutral-0);\n --aia-option-font-size: 16px;\n\n --aia-written-text-color: var(--aia-primitive-neutral-0);\n /* Match the option size so the typed query never reads smaller than the\n choices below it. */\n --aia-written-text-font-size: 16px;\n --aia-caret-color: var(--aia-written-text-color, #000000);\n\n --aia-submit-bg: var(--aia-primitive-neutral-0);\n --aia-submit-color: var(--aia-primitive-neutral-1000);\n\n --aia-color-text-muted: #6b7280; /* off shared palette (slate) */\n\n /* Loading bars sit at half the contrast of the surrounding chrome so they\n read as a placeholder, not as content (a50 -> a25 over the light surface). */\n --aia-skeleton-bg: var(--aia-primitive-neutral-750-a25);\n\n --aia-streak-rgb: 99, 102, 241; /* off shared palette (indigo effect) */\n\n --aia-footer-hint-color: var(--aia-primitive-neutral-500);\n --aia-footer-brand-color: var(--aia-primitive-neutral-700);\n --aia-footer-badge-border: var(--aia-primitive-neutral-750-a50);\n}\n\n/* Dark mode defaults */\n:where(.magicx-aia[data-mode=\"dark\"]) {\n --aia-surface: var(--aia-primitive-neutral-0);\n --aia-border: var(--aia-primitive-neutral-500);\n /* Elevation for the input container (.inputWrapper) — tuned for dark surfaces:\n a faint top highlight + deeper ambient shadows. */\n --aia-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 1px 2px rgba(0, 0, 0, 0.2),\n 0 8px 24px rgba(0, 0, 0, 0.25);\n /* Half-strength stroke — neutral-400 (was #484848 — snapped to palette,\n Δ2) at 50% alpha; see the light-mode note above. */\n --aia-dropdown-border: var(--aia-primitive-neutral-400-a50);\n --aia-dropdown-shadow: 0 8px 12px rgba(0, 0, 0, 0.05);\n /* Suggestion pills (Figma \"ParamPill\"): transparent fill, no visible border. */\n --aia-pill-bg: var(--aia-primitive-neutral-750);\n --aia-pill-color: var(--aia-primitive-neutral-700);\n --aia-pill-font-size: 16px;\n\n /* Completed params (Figma \"RichTextPill\") — dark theme (design source):\n white text on a faint-gray chip. -active is the hover / tapped highlight.\n Deliberately still a15 while light mode moved to a105: the fill is a light\n gray tinting the surface, so thinning it lightens over white but DARKENS\n over this theme's black. Lightening the dark chip means a stronger tint,\n which is a design call, not a mechanical one — left for design to make. */\n --aia-completed-pill-bg: var(--aia-primitive-neutral-750-a15);\n --aia-completed-pill-bg-active: var(--aia-primitive-neutral-750-a35);\n --aia-completed-pill-color: var(--aia-primitive-neutral-1000);\n\n --aia-option-bg: var(--aia-primitive-neutral-250);\n /* Options read bigger + darker/brighter than the small-caps param labels. */\n --aia-option-color: var(--aia-primitive-neutral-900);\n --aia-option-color-selected: var(--aia-primitive-neutral-1000);\n --aia-option-font-size: 16px;\n\n --aia-written-text-color: var(--aia-primitive-neutral-1000);\n --aia-written-text-font-size: 16px;\n --aia-caret-color: var(--aia-written-text-color, #ffffff);\n\n --aia-submit-bg: var(--aia-primitive-neutral-1000);\n --aia-submit-color: var(--aia-primitive-neutral-0);\n\n --aia-color-text-muted: #c1c4cb; /* off shared palette (slate) */\n\n /* Half as light against the dark surface as the old neutral-300 fill — the\n dark-mode counterpart of the light theme's a50 -> a25 step-down. */\n --aia-skeleton-bg: var(--aia-primitive-neutral-150);\n\n --aia-streak-rgb: 255, 255, 255;\n\n --aia-footer-hint-color: var(--aia-primitive-neutral-700);\n --aia-footer-brand-color: var(--aia-primitive-neutral-500);\n --aia-footer-badge-border: var(--aia-primitive-neutral-500);\n}\n\n/* Footer band — the option list runs *under* the dropdown footer and dissolves\n into it, instead of being cut off mid-row above it. The band is the footer's\n own height — its top inset (--aia-footer-gap) + --aia-footer-row-height:\n - the options grid reserves it as bottom padding, so the last option can\n still be scrolled fully clear of the footer;\n - --aia-grid-overlap-bottom (the band + the 8px stack gap) pulls the footer\n back up over that band;\n - the footer's background is the fade: transparent at the band's top edge,\n the full dropdown surface at its bottom, so a row dissolves as it passes\n behind. Its hint and branding groups sit on a 65%-opaque fill of their\n own (--aia-footer-chip-bg) so they stay legible across it.\n Lives here rather than with the dropdown's own rules so the\n optionsPosition=\"above\" reset below always follows it in the cascade. */\n[data-aia-dropdown] {\n /* Height of the footer's hint / branding row — the badge is its tallest item\n (the kbd is shorter and centers against it). The band derives from it, so\n restyling the badge's height keeps the overlap in step. */\n --aia-footer-row-height: 23px;\n --aia-footer-band: calc(var(--aia-footer-gap, 8px) + var(--aia-footer-row-height, 23px));\n --aia-grid-scroll-bottom: var(--aia-footer-band);\n --aia-grid-overlap-bottom: calc(-1 * (var(--aia-footer-band) + 8px));\n /* How far above the band the fade starts. */\n --aia-footer-fade-lead: 20px;\n --aia-footer-fade-inset: calc(-1 * var(--aia-footer-fade-lead)) 0 0;\n}\n\n/* In the dropdown, the parameter label reads as a section header for the\n options beneath it — not an outlined chip floating over them. It drops the\n pill's inner horizontal padding and left-aligns its text with the option\n text below, which sits 10px in from the dropdown's content edge. The label's\n own list wrapper carries that 10px so the text lands exactly on the option\n text's left edge.\n\n Selector shape differs from the vanilla/Angular copies (which target the\n \\`.aia-pill-list\\` / \\`.aia-pill\\` class names): the module classes here are\n hash-scoped locals, unreachable from this global stylesheet. The bar's\n direct \\`> span\\` child is the masked scroll wrapper (\\`.pillScroll\\`, tagged\n \\`data-aia-pill-scroll\\`) that holds PillList, so the 10px indent lands on\n the wrapper and the module zeroes PillList's own base padding underneath\n (\\`.pillScroll > span\\` in AIAutocompleteDropdown.module.css — remove one\n only with the other). Pills are matched via \\`[data-aia-pill]\\` (unique to\n ParamPill). Like the sibling structural \\`[data-aia-dropdown]\\` rules below,\n this is deliberately NOT \\`:where()\\`-wrapped — it must win over ParamPill's\n own \\`.pill\\` base rule. */\n[data-aia-dropdown] [data-aia-pillbar] > span {\n padding-inline: 10px;\n}\n[data-aia-dropdown] [data-aia-pillbar] [data-aia-pill] {\n justify-content: flex-start;\n border-inline-width: 0;\n padding-inline: 0;\n}\n\n/* The reserved band the footer overlaps, kept OUT of \\`@layer layout\\` on\n purpose. A consumer reset (\\`* { margin: 0; padding: 0 }\\`, Tailwind's\n preflight, …) is unlayered, and an unlayered declaration beats every layered\n one no matter its specificity — inside the layer this padding and margin\n were silently zeroed and the footer had nothing to sit over. */\n[data-aia-dropdown] .aia-grid[data-scroll] {\n padding-top: var(--aia-grid-scroll-top, 0);\n padding-bottom: var(--aia-grid-scroll-bottom, 0);\n margin-top: var(--aia-grid-overlap-top, 0);\n margin-bottom: var(--aia-grid-overlap-bottom, 0);\n}\n\n/* The fade. Painted on a pseudo-element rather than the footer box so it can\n start --aia-footer-fade-lead above the band's top edge: a row is then already\n dissolving by the time it reaches the hint / branding line, instead of\n crossing it at half strength. --aia-surface is what the dropdown paints\n itself with, so theming the surface retints the fade with it. z-index: -1\n keeps it under the footer's own content but, via the footer's stacking\n context, above the option rows. */\n[data-aia-dropdown] [data-aia-footer]::before {\n content: \"\";\n position: absolute;\n inset: var(--aia-footer-fade-inset, -20px 0 0);\n z-index: -1;\n pointer-events: none;\n background: linear-gradient(to bottom, transparent, var(--aia-surface, #ffffff));\n}\n\n/* The glass surface is translucent — there's no solid color to dissolve into,\n and a fill behind the hint / branding would paint an opaque patch on a\n frosted panel. Both opt out. */\n[data-aia-dropdown][data-aia-surface=\"glass\"] {\n --aia-footer-chip-bg: transparent;\n}\n\n[data-aia-dropdown][data-aia-surface=\"glass\"] [data-aia-footer]::before {\n display: none;\n}\n\n/* optionsPosition: dropdown above the input. The sections live inside the\n dropdown's .aia-stack, so the reversal targets the stack (not the dropdown,\n whose only child is the stack).\n Two forms are supported:\n 1. ancestor form — Tier 1 sets data-options-position on the .magicx-aia\n container and the dropdown is a descendant.\n 2. self form — headless consumers spread \\`optionsPosition\\` from the hook's\n dropdownProps, so the attribute lands on the dropdown element itself.\n This lets the dropdown position above with NO wrapper attribute and no\n hand-copied CSS. */\n:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown],\n[data-aia-dropdown][data-options-position=\"above\"] {\n /* The stack is reversed here (the footer sits on top of the list), so the\n reserved band and the overlap flip to the top edge. */\n --aia-grid-scroll-bottom: 0px;\n --aia-grid-overlap-bottom: 0px;\n --aia-grid-scroll-top: var(--aia-footer-band);\n --aia-grid-overlap-top: calc(-1 * (var(--aia-footer-band) + 8px));\n --aia-footer-fade-inset: 0 0 calc(-1 * var(--aia-footer-fade-lead));\n /* The unfold flips with the stack: the collapsed sliver sits at the panel's\n bottom edge (against the input) and expands upward out of it. */\n transform-origin: 50% 100%;\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: var(--aia-dropdown-offset, 13px);\n}\n\n/* Declared after the optionsPosition=\"above\" block on purpose: that rule's\n second selector ([data-aia-dropdown][data-options-position=\"above\"]) has the\n same two-attribute specificity as this one, so source order is what decides\n which wins when a strip is present in an above-positioned dropdown. */\n/* Product strip present: the footer no longer sits on the scrolling option\n list — the strip is between them — so there is nothing to ride up over and\n nothing to reserve. Zeroing the band HERE, where it is defined, is the fix:\n the pull is a property of \"footer directly over the list\", not of the grid,\n and any section rendered after the grid would otherwise inherit it and land\n on top of the last option row. Both edges are zeroed because\n optionsPosition=\"above\" flips which one is in play. */\n[data-aia-dropdown][data-aia-has-products] {\n --aia-grid-scroll-bottom: 0px;\n --aia-grid-overlap-bottom: 0px;\n --aia-grid-scroll-top: 0px;\n --aia-grid-overlap-top: 0px;\n /* The fade exists to dissolve rows sliding under the footer. With the strip\n in between it has nothing to dissolve and would just wash over the cards. */\n --aia-footer-fade-lead: 0px;\n}\n\n:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] .aia-stack,\n[data-aia-dropdown][data-options-position=\"above\"] .aia-stack {\n flex-direction: column-reverse;\n}\n\n/* The footer now sits on top of the list, so its breathing room flips to the\n bottom edge — the side the option rows scroll under. */\n:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] [data-aia-footer],\n[data-aia-dropdown][data-options-position=\"above\"] [data-aia-footer] {\n padding: 0 0 var(--aia-footer-gap, 8px) 8px;\n}\n\n/* ...and the fade runs the other way, out of the footer and down into the list. */\n:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] [data-aia-footer]::before,\n[data-aia-dropdown][data-options-position=\"above\"] [data-aia-footer]::before {\n background: linear-gradient(to top, transparent, var(--aia-surface, #ffffff));\n}\n\n/* Disable all animations when data-animations=\"off\" */\n:where(.magicx-aia[data-animations=\"off\"]) *,\n:where(.magicx-aia[data-animations=\"off\"]) *::before,\n:where(.magicx-aia[data-animations=\"off\"]) *::after {\n animation-duration: 0s !important;\n transition-duration: 0s !important;\n}\n\n/* Desktop footer is opaque: the option list clips at the footer's edge instead\n of showing through it — the scroll cue lives in the last visible row's own\n text instead (the option scroll-hint rule). Mobile keeps the fade. Declared\n last, and carrying the unwrapped above-position selector some copies use\n (so it ties that rule's higher specificity and wins on cascade order);\n the glass surface still hides this pseudo-element entirely. */\n@media (min-width: 769px) {\n [data-aia-dropdown] [data-aia-footer]::before,\n [data-aia-dropdown][data-options-position=\"above\"] [data-aia-footer]::before,\n :where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] [data-aia-footer]::before {\n inset: 0;\n background: var(--aia-surface, #ffffff);\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport {};","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-3819c762\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-3819c762\";\n s.textContent = `.AIAutocompleteDropdown-module_dropdown_yz2KC {\n position: absolute;\n left: 0;\n right: 0;\n top: 100%;\n max-width: 544px;\n /* Gap between the input box and the dropdown. Tunable via --aia-dropdown-offset. */\n margin-top: var(--aia-dropdown-offset, 13px);\n display: flex;\n flex-direction: column;\n box-sizing: border-box;\n padding: 10px 8px;\n overflow: hidden;\n container-type: inline-size;\n z-index: 10;\n opacity: 0;\n pointer-events: none;\n /* Closed, the panel rests as a near-zero-height sliver at the input's edge\n (scaleY only — full width), so opening unfolds it top-to-bottom out of the\n input. The origin flips to the bottom edge for optionsPosition=\"above\" —\n see appearance.css. The transform \"transition\" on THIS side is a delayed\n snap: while closing, the panel holds its full size for the whole 400ms\n fade and only then collapses, ready for the next open. */\n transform-origin: 50% 0;\n transform: scaleY(var(--aia-dropdown-reveal-scale, 0.02));\n transition:\n opacity 400ms cubic-bezier(0.4, 0, 0.2, 1),\n transform 0s 400ms;\n /* Solid surface is the default (matches the Figma components). Opt into the\n frosted-glass look with data-aia-surface=\"glass\". */\n background: var(--aia-surface, #ffffff);\n border: 1px solid var(--aia-dropdown-border, rgba(231, 231, 231, 0.5));\n border-radius: 18px;\n box-shadow: var(--aia-dropdown-shadow, 0 8px 12px rgba(0, 0, 0, 0.05));\n}\n\n/* A calendar has nothing wide to read, so the whole panel narrows with it —\n the option grid's 544px cap leaves a month floating in empty panel. The\n :has() argument is the datepicker's data attribute, which all three packages\n emit identically; only the panel class differs per copy. */\n.AIAutocompleteDropdown-module_dropdown_yz2KC:has([data-aia-datepicker]) {\n max-width: var(--aia-date-panel-width, 312px);\n}\n\n.AIAutocompleteDropdown-module_dropdown_yz2KC[data-aia-surface=\"glass\"] {\n background: transparent;\n border-color: transparent;\n box-shadow:\n hsla(0, 0%, 100%, 1) -3.2px -3.2px 3.2px -3.2px inset,\n hsla(0, 0%, 100%, 1) 6.4px 6.4px 1.6px -8px inset,\n var(--aia-dropdown-bg, transparent) -6.4px 6.4px 1.6px -8px inset, /* same color as bg */\n var(--aia-dropdown-bg, transparent) 6.4px -6.4px 1.6px -8px inset, /* same color as bg */\n hsla(0, 0%, 100%, 0.15) -1.6px 0px 0px -1.6px inset,\n hsla(0, 0%, 100%, 0.15) 0px -1.6px 0px -1.6px inset,\n hsla(0, 0%, 100%, 0.3) 0px 1.6px 0px 0px inset,\n hsla(0, 0%, 100%, 0.3) 1.6px 0px 0px 0px inset,\n inset 0 0 30px 5px hsla(0, 0%, 0%, 0.05),\n hsla(0, 0%, 0%, 0.08) 0px 0px 30px 2px;\n backdrop-filter: blur(30px);\n}\n\n/* Opening: the panel unfolds top-to-bottom out of the input with a single\n spring settle while the option rows cascade in on top of it. Closing keeps\n the longer fade so a populated panel dissolves as one (the base rule above\n delays the transform snap until that fade has finished). */\n.AIAutocompleteDropdown-module_visible_QCoXj {\n opacity: 1;\n pointer-events: auto;\n transform: scaleY(1);\n /* Spring: the easing overshoots full height by a few percent and settles\n once (P1y = 1.28 — one spring, no bounce). Opacity resolves almost\n immediately so the unfold, not a fade, is what reads. */\n transition:\n opacity 100ms cubic-bezier(0.4, 0, 0.2, 1),\n transform 320ms cubic-bezier(0.22, 1.28, 0.36, 1);\n}\n\n/* \"More below\" scroll arrow — see the core's render/scrollArrow.ts. A round\n disc at the bottom-centre of the option list, shown while the list can still\n scroll down. It rests just above the grid's reserved band\n (--aia-scroll-arrow-bottom is measured and set inline by the controller so it\n tracks the grid's bottom edge in every layout). Its two moves differ on\n purpose: it ENTERS by rising from below the dropdown's lower edge, where the\n dropdown's overflow clips it — so it emerges from behind the footer — and it\n LEAVES by dissolving in place under data-aia-leaving (see below). z-index 2\n puts it over the option rows and under the footer (z-index 3). Declarations\n mirror vanilla's .magicx-aia-scroll-arrow and Angular's copy — change all\n three in the same commit. */\n.AIAutocompleteDropdown-module_scrollArrow_uUzV0 {\n position: absolute;\n left: 50%;\n bottom: var(--aia-scroll-arrow-bottom, 8px);\n z-index: 2;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n margin: 0 0 0 -16px;\n padding: 0;\n border: 1px solid\n var(--aia-scroll-arrow-border, var(--aia-dropdown-border, rgba(231, 231, 231, 0.5)));\n border-radius: 50%;\n background: var(--aia-scroll-arrow-bg, var(--aia-surface, #ffffff));\n color: var(\n --aia-scroll-arrow-color,\n var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb))\n );\n box-shadow: var(--aia-scroll-arrow-shadow, 0 2px 8px rgba(0, 0, 0, 0.12));\n cursor: pointer;\n pointer-events: none;\n /* Parked: below the panel's edge (clipped), and transparent so the re-park\n after a fade — scale back out to here — never shows. Only the transform\n transitions here, so the disc rises at full strength instead of fading\n in on the way up. */\n opacity: 0;\n transform: translateY(calc(100% + var(--aia-scroll-arrow-bottom, 8px) + 4px));\n transition: transform 180ms cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.AIAutocompleteDropdown-module_scrollArrow_uUzV0[data-aia-visible] {\n pointer-events: auto;\n opacity: 1;\n transform: translateY(0);\n}\n\n/* Leaving: dissolve where it stands — no travel. Ease-out so most of the fade\n happens at once and the last of it lingers; the shrink keeps it from reading\n as a flat cut. The controller holds this attribute for SCROLL_ARROW_LEAVE_MS\n (scrollArrow.ts) — keep the two durations equal. */\n.AIAutocompleteDropdown-module_scrollArrow_uUzV0[data-aia-leaving] {\n pointer-events: none;\n opacity: 0;\n transform: translateY(0) scale(0.86);\n transition:\n opacity 240ms cubic-bezier(0.22, 0.61, 0.36, 1),\n transform 240ms cubic-bezier(0.22, 0.61, 0.36, 1);\n}\n\n.AIAutocompleteDropdown-module_scrollArrow_uUzV0:hover {\n color: var(\n --aia-scroll-arrow-color-hover,\n var(--aia-option-color-selected, var(--aia-color-text-default, #fff))\n );\n}\n\n@media (prefers-reduced-motion: reduce) {\n .AIAutocompleteDropdown-module_scrollArrow_uUzV0,\n .AIAutocompleteDropdown-module_scrollArrow_uUzV0[data-aia-leaving],\n .AIAutocompleteDropdown-module_dropdown_yz2KC {\n transition-duration: 0s;\n }\n}\n\n/* The dropdown container owns the 10px/8px edge padding and the 8px section\n gaps (matching Figma); the pill row adds none. The horizontal scroll + fade\n live on the inner .pillScroll wrapper, NOT the bar itself: the trailing skip\n button is the bar's other child, and a mask on the bar would fade it out\n along with the overflowing pills it's meant to sit beside. */\n.AIAutocompleteDropdown-module_pillBar_pwTXe {\n overflow: hidden;\n}\n\n/* Scrollable region for the pills. The appearance layer's\n \\`[data-aia-pillbar] > span\\` rule lands here (10px inline padding aligning\n the param label with the option text), so the inner PillList span must not\n add its own base padding on top — see the child rule below. */\n.AIAutocompleteDropdown-module_pillScroll_Tpzus {\n display: inline-flex;\n align-items: center;\n flex: 1 1 auto;\n min-width: 0;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: none;\n mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 48px), transparent 100%);\n -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 48px), transparent 100%);\n}\n\n.AIAutocompleteDropdown-module_pillScroll_Tpzus > span {\n padding-inline: 0;\n}\n\n.AIAutocompleteDropdown-module_pillScroll_Tpzus::-webkit-scrollbar {\n display: none;\n}\n\n/* Trailing \"skip\" button — dismisses the active pill, same action as pressing\n → at the end of the input. Pinned at the bar's far edge (auto inline-start\n margin), outside the masked scroller. Typography follows the footer hint\n (quiet chrome), not the pills. Declarations mirror \\`.magicx-aia-skip\\` in the\n vanilla stylesheet — change both in the same commit. */\n.AIAutocompleteDropdown-module_skip_7-olS {\n display: inline-flex;\n align-items: center;\n margin-inline-start: auto;\n flex-shrink: 0;\n padding: 5px 8px;\n border: none;\n /* Matches the completed-param chip radius, so the hover fill reads as a\n soft rectangle rather than a capsule. */\n border-radius: 6px;\n background: transparent;\n font-family: inherit;\n font-size: var(--aia-skip-font-size, 10px);\n line-height: 18px;\n color: var(--aia-skip-color, var(--aia-footer-hint-color, #505050));\n cursor: pointer;\n white-space: nowrap;\n transition:\n color 150ms ease-out,\n background-color 150ms ease-out;\n}\n\n.AIAutocompleteDropdown-module_skip_7-olS:hover {\n color: var(--aia-skip-color-hover, var(--aia-pill-color, var(--aia-color-text-muted, #c1c4cb)));\n /* Same fill as a highlighted option row (--aia-option-bg), so the hover\n reads with the dropdown's own hover language and stays visible on both\n mode surfaces. */\n background: var(--aia-skip-hover-bg, var(--aia-option-bg, transparent));\n}\n\n.AIAutocompleteDropdown-module_skip_7-olS:disabled {\n pointer-events: none;\n cursor: default;\n opacity: 0.5;\n}\n\n/* --- Fallback loading skeleton (only when no pills/options are cached) --- */\n.AIAutocompleteDropdown-module_skeletonBars_HVr9C {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 7px 8px;\n}\n\n.AIAutocompleteDropdown-module_skeletonBar_O3xIx {\n display: block;\n height: 14px;\n border-radius: 999px;\n background: var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, 0.25)));\n opacity: 0.5;\n animation: AIAutocompleteDropdown-module_aiaSkeletonPulse_G8W7q 1.4s ease-in-out infinite;\n}\n\n.AIAutocompleteDropdown-module_skeletonBar_O3xIx:nth-child(2) {\n animation-delay: 150ms;\n}\n\n.AIAutocompleteDropdown-module_skeletonBar_O3xIx:nth-child(3) {\n animation-delay: 300ms;\n}\n\n@keyframes AIAutocompleteDropdown-module_aiaSkeletonPulse_G8W7q {\n 0%,\n 100% {\n opacity: 0.5;\n }\n 50% {\n opacity: 0.25;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"dropdown\":\"AIAutocompleteDropdown-module_dropdown_yz2KC\",\"visible\":\"AIAutocompleteDropdown-module_visible_QCoXj\",\"scrollArrow\":\"AIAutocompleteDropdown-module_scrollArrow_uUzV0\",\"pillBar\":\"AIAutocompleteDropdown-module_pillBar_pwTXe\",\"pillScroll\":\"AIAutocompleteDropdown-module_pillScroll_Tpzus\",\"skip\":\"AIAutocompleteDropdown-module_skip_7-olS\",\"skeletonBars\":\"AIAutocompleteDropdown-module_skeletonBars_HVr9C\",\"skeletonBar\":\"AIAutocompleteDropdown-module_skeletonBar_O3xIx\",\"aiaSkeletonPulse\":\"AIAutocompleteDropdown-module_aiaSkeletonPulse_G8W7q\"};","import {\n cellDay,\n cellIso,\n type DateMonthView,\n isoDate,\n monthLabel,\n type SuggestionOption,\n WEEKDAY_LABELS,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { useState } from \"react\";\nimport styles from \"./DateGrid.module.css\";\n\n/**\n * Stable keys for the weekday row. The labels themselves repeat (\"S\", \"T\"), so\n * they can't key the list, and the index can't either without tripping\n * `noArrayIndexKey` — the row is static and never reorders, but the linter has\n * no way to know that.\n */\nconst WEEKDAY_KEYS = [\"sunday\", \"monday\", \"tuesday\", \"wednesday\", \"thursday\", \"friday\", \"saturday\"];\n\nexport interface DateGridProps {\n /** The visible month's cells. These ARE `filteredOptions` — see `buildDateOptions`. */\n options: SuggestionOption[];\n activeIndex: number;\n listboxId: string;\n view: DateMonthView;\n /** `YYYY-MM-DD` the param being re-edited already holds, or null. */\n selectedIso: string | null;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n onPreviousMonth: () => void;\n onNextMonth: () => void;\n}\n\n/**\n * The dropdown's calendar body, rendered in place of the options grid when the\n * active parameter is a date. React analogue of vanilla's `renderDateGrid`.\n *\n * The cells carry the same `${listboxId}-option-${i}` ids, `role=\"option\"` and\n * `aria-selected` the options grid emits, and that is load-bearing rather than\n * cosmetic: the keyboard controller lives in the vanilla core for all three\n * packages, navigates by index into `filteredOptions`, and commits by clicking\n * `#${listboxId}-option-${i}`. `getEffectiveColumns` also measures the live\n * `grid-template-columns` of option-0's parent, which is why the 7 columns sit\n * on the cell container itself and not on an ancestor.\n */\nexport function DateGrid({\n options,\n activeIndex,\n listboxId,\n view,\n selectedIso,\n onSelect,\n onHighlight,\n onPreviousMonth,\n onNextMonth,\n}: DateGridProps) {\n const today = isoDate(new Date());\n\n return (\n <div className={styles.datepicker} data-aia-datepicker=\"\">\n <div className={styles.header}>\n <button\n type=\"button\"\n // Out of the tab order for the same reason the skip button is: Tab is\n // already bound to walking the dropdown's options.\n tabIndex={-1}\n className={styles.nav}\n data-aia-date-prev=\"\"\n aria-label=\"Previous month\"\n // Keeps the input focused, which the visibility gate depends on.\n onMouseDown={(e) => e.preventDefault()}\n onClick={onPreviousMonth}\n >\n ‹\n </button>\n <span className={styles.month} data-aia-date-month=\"\" aria-live=\"polite\">\n {monthLabel(view)}\n </span>\n <button\n type=\"button\"\n tabIndex={-1}\n className={styles.nav}\n data-aia-date-next=\"\"\n aria-label=\"Next month\"\n onMouseDown={(e) => e.preventDefault()}\n onClick={onNextMonth}\n >\n ›\n </button>\n </div>\n\n {/* Decorative: each cell announces its own full date, so repeating the\n column letters to AT adds noise — and the duplicate T/S would be\n meaningless read aloud anyway. */}\n <div className={styles.weekdays} aria-hidden=\"true\">\n {WEEKDAY_LABELS.map((label, i) => (\n <span key={WEEKDAY_KEYS[i]} className={styles.weekday}>\n {label}\n </span>\n ))}\n </div>\n\n <div className={styles.grid} data-aia-date-grid=\"\">\n {options.map((option, i) => (\n <DateCell\n // Padding cells have no date of their own, so they key off position.\n key={cellIso(option) ?? `pad-${i}`}\n option={option}\n id={`${listboxId}-option-${i}`}\n index={i}\n isHighlighted={i === activeIndex && option.is_tappable}\n isToday={cellIso(option) === today}\n isPast={cellIso(option) != null && (cellIso(option) as string) < today}\n isSelected={selectedIso != null && cellIso(option) === selectedIso}\n onSelect={onSelect}\n onHighlight={onHighlight}\n />\n ))}\n </div>\n </div>\n );\n}\n\ninterface DateCellProps {\n option: SuggestionOption;\n id: string;\n index: number;\n isHighlighted: boolean;\n isToday: boolean;\n /** Before today: rendered dimmed, but every bit as pickable as the rest. */\n isPast: boolean;\n isSelected: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n}\n\nfunction DateCell({\n option,\n id,\n index,\n isHighlighted,\n isToday,\n isPast,\n isSelected,\n onSelect,\n onHighlight,\n}: DateCellProps) {\n const [pressed, setPressed] = useState(false);\n const day = cellDay(option);\n\n if (day == null) {\n // Padding for the days before the 1st / after the last. Non-tappable, so\n // arrow navigation skips it; hidden from AT so the month reads as its own\n // days and nothing else.\n return (\n <div\n id={id}\n role=\"option\"\n data-aia-option=\"\"\n data-aia-date-cell=\"\"\n aria-hidden=\"true\"\n aria-selected={false}\n tabIndex={-1}\n className={`${styles.cell} ${styles.blank}`}\n />\n );\n }\n\n const handleSelect = () => {\n setPressed(true);\n onSelect(option);\n setTimeout(() => setPressed(false), 170);\n };\n\n const className = [\n styles.cell,\n styles.day,\n isPast ? styles.past : \"\",\n isHighlighted ? styles.highlighted : \"\",\n isToday ? styles.today : \"\",\n isSelected ? styles.selected : \"\",\n pressed ? styles.pressed : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n id={id}\n role=\"option\"\n data-aia-option=\"\"\n data-aia-date-cell=\"\"\n aria-selected={isHighlighted}\n // The cell paints the day number; `option.text` is the full committed\n // value (\"March 23 2026\") and is what AT should announce, since that is\n // what selecting it puts in the input.\n aria-label={option.text}\n tabIndex={0}\n className={className}\n onClick={handleSelect}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleSelect();\n }\n }}\n onMouseEnter={() => onHighlight(index)}\n >\n <span className={styles.number}>{day}</span>\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-f687bd03\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-f687bd03\";\n s.textContent = `/* --- Datepicker (replaces the options grid for date suggestions) ---\n\n One of three hand-maintained copies (vanilla styles.css, this file, Angular's\n date-grid.component.css). Only the class-naming layer differs — the\n declarations must match, and \\`datepickerParity.test.ts\\` fails the build if\n they drift. See CLAUDE.md's duplicated-stylesheet rule.\n\n Every colour resolves through the same --aia-option-* chain the option rows\n use. The dropdown paints a background but sets no \\`color\\`, so anything here\n relying on \\`color: inherit\\` would pick up the HOST page's text colour and go\n black on a dark panel — and \\`prefers-color-scheme\\` can't be used to guess,\n because the panel's darkness comes from --aia-surface, which the media query\n says nothing about. Going through the option chain means one consumer\n override restyles the calendar and the options together. */\n.DateGrid-module_datepicker_6RrTs {\n display: flex;\n flex-direction: column;\n gap: 4px;\n /* Bottom-heavier trim than the top: the compression the compact calendar\n asks for comes out of the bottom edge and the space between cells, never\n the header area or the side gutters. */\n padding: 4px 2px 4px;\n}\n\n.DateGrid-module_header_z4LRk {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 2px 6px 6px;\n}\n\n.DateGrid-module_month_urB2T {\n font-family: inherit;\n font-size: var(--aia-date-month-font-size, 14px);\n font-weight: 500;\n line-height: 20px;\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n}\n\n.DateGrid-module_nav_ap4AN {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n padding: 0;\n border: none;\n border-radius: 6px;\n background: transparent;\n font-family: inherit;\n font-size: 16px;\n line-height: 1;\n color: var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));\n cursor: pointer;\n transition:\n color 150ms ease-out,\n background-color 150ms ease-out;\n}\n\n.DateGrid-module_nav_ap4AN:hover {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n background: var(--aia-option-bg, transparent);\n}\n\n.DateGrid-module_weekdays_3EA3q,\n.DateGrid-module_grid_mQCgw {\n display: grid;\n /* The 7 columns live on the cell container itself, not on an ancestor:\n KeyboardController.getEffectiveColumns() measures grid-template-columns by\n walking up from option-0's PARENT, and it is this number that makes\n ArrowDown mean \"+1 week\". */\n grid-template-columns: repeat(7, minmax(0, 1fr));\n}\n\n.DateGrid-module_weekday_3lF4B {\n padding: 2px 0;\n text-align: center;\n font-family: inherit;\n font-size: var(--aia-date-weekday-font-size, 11px);\n font-weight: 500;\n line-height: 16px;\n color: var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));\n opacity: 0.7;\n}\n\n.DateGrid-module_cell_59k0y {\n display: flex;\n align-items: center;\n justify-content: center;\n /* Deliberately NOT sized here. Giving the grid item a definite size (an\n aspect-ratio, a width) stops it stretching to its track, so it parks at\n the track's start edge and the whole month drifts left of the weekday\n header above it — the two grids agree on their columns, and only the\n items disagree, which makes it look like a column-count bug. The cell\n fills its track; the square is the number span inside it. */\n min-width: 0;\n /* Keeps a month readable in a narrow dropdown without letting a 6-row month\n grow the panel past the options grid it replaces. */\n height: var(--aia-date-row-height, 28px);\n font-family: inherit;\n font-size: var(--aia-date-cell-font-size, 13px);\n font-weight: 450;\n line-height: 20px;\n color: var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));\n}\n\n/* The visual box: everything a cell paints — fill, ring, press — lands here so\n it reads as a square centred in its column rather than a full-width band. */\n.DateGrid-module_number_aoT01 {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--aia-date-cell-size, 26px);\n height: var(--aia-date-cell-size, 26px);\n border-radius: 6px;\n}\n\n.DateGrid-module_day_cB3u9 {\n cursor: pointer;\n}\n\n.DateGrid-module_blank_ivgRC {\n cursor: default;\n}\n\n/* A day before today: dimmed so the month visibly starts at today, but still\n fully interactive — hover and click behave like any other day. */\n.DateGrid-module_past_CEZsj {\n opacity: 0.35;\n}\n\n.DateGrid-module_day_cB3u9:hover .DateGrid-module_number_aoT01,\n.DateGrid-module_highlighted_YIdtK .DateGrid-module_number_aoT01 {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n background: var(--aia-option-bg, transparent);\n font-weight: 500;\n}\n\n/* Today reads as an outline, the committed answer as a fill — so a re-edited\n date can show both at once without either being ambiguous. */\n.DateGrid-module_today_iI3ME .DateGrid-module_number_aoT01 {\n box-shadow: inset 0 0 0 1px\n var(--aia-date-today-ring, var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb)));\n}\n\n.DateGrid-module_selected_28KDn .DateGrid-module_number_aoT01 {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n background: var(--aia-date-selected-bg, rgba(var(--aia-streak-rgb, 255, 255, 255), 0.12));\n font-weight: 500;\n}\n\n.DateGrid-module_pressed_bEyyN .DateGrid-module_number_aoT01 {\n opacity: 0.8;\n background: rgba(var(--aia-streak-rgb, 255, 255, 255), 0.06);\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"datepicker\":\"DateGrid-module_datepicker_6RrTs\",\"header\":\"DateGrid-module_header_z4LRk\",\"month\":\"DateGrid-module_month_urB2T\",\"nav\":\"DateGrid-module_nav_ap4AN\",\"weekdays\":\"DateGrid-module_weekdays_3EA3q\",\"grid\":\"DateGrid-module_grid_mQCgw\",\"weekday\":\"DateGrid-module_weekday_3lF4B\",\"cell\":\"DateGrid-module_cell_59k0y\",\"number\":\"DateGrid-module_number_aoT01\",\"day\":\"DateGrid-module_day_cB3u9\",\"blank\":\"DateGrid-module_blank_ivgRC\",\"past\":\"DateGrid-module_past_CEZsj\",\"highlighted\":\"DateGrid-module_highlighted_YIdtK\",\"today\":\"DateGrid-module_today_iI3ME\",\"selected\":\"DateGrid-module_selected_28KDn\",\"pressed\":\"DateGrid-module_pressed_bEyyN\"};","import {\n ATTRIBUTION_URL,\n buildAttributionUrl,\n getFooterHint,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { useEffect, useState } from \"react\";\nimport { Cluster } from \"../layout/Cluster\";\nimport styles from \"./DropdownFooter.module.css\";\n\ninterface DropdownFooterProps {\n /**\n * Whether an option is currently highlighted. Takes priority: when true the\n * hint reads \"enter to proceed\".\n */\n isOptionHighlighted?: boolean;\n /**\n * Whether the input has no typed text. When true (and no option is\n * highlighted) the hint reads \"tab to select\" — see {@link getFooterHint}.\n */\n isInputEmpty?: boolean;\n}\n\n// Dropdown chrome: a keyboard hint on the left, AI-Autocomplete branding on the\n// right.\nexport function DropdownFooter({\n isOptionHighlighted = false,\n isInputEmpty = false,\n}: DropdownFooterProps) {\n const { key, hint } = getFooterHint(isOptionHighlighted, isInputEmpty);\n // Initial state is the bare base URL so it matches server-rendered output (no\n // hydration mismatch); the effect appends utm_source after mount on the client.\n const [brandHref, setBrandHref] = useState(ATTRIBUTION_URL);\n useEffect(() => {\n setBrandHref(buildAttributionUrl());\n }, []);\n return (\n <footer className={styles.footer} data-aia-footer=\"\">\n <Cluster justify=\"between\" noWrap className={styles.row}>\n <Cluster gap=\"5px\" className={styles.hintGroup}>\n <kbd className={styles.key}>{key}</kbd>\n <span className={styles.hint}>{hint}</span>\n </Cluster>\n <a className={styles.brandLink} href={brandHref} target=\"_blank\" rel=\"noopener noreferrer\">\n <span className={styles.brand}>AI</span>\n <span className={styles.badge}>Autocomplete</span>\n </a>\n </Cluster>\n </footer>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-5259a217\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-5259a217\";\n s.textContent = `@layer layout {\n .aia-cluster {\n display: flex;\n flex-wrap: wrap;\n gap: var(--aia-cluster-gap, 0.5rem);\n }\n /* Inline-level variant — used when the cluster must sit inline (e.g. inside\n a contentEditable). Rendered on a <span> so it's valid inline content. */\n .aia-cluster[data-inline] {\n display: inline-flex;\n }\n .aia-cluster[data-nowrap] {\n flex-wrap: nowrap;\n }\n .aia-cluster[data-align=\"start\"] {\n align-items: start;\n }\n .aia-cluster[data-align=\"center\"] {\n align-items: center;\n }\n .aia-cluster[data-align=\"end\"] {\n align-items: end;\n }\n .aia-cluster[data-align=\"baseline\"] {\n align-items: baseline;\n }\n .aia-cluster[data-justify=\"start\"] {\n justify-content: start;\n }\n .aia-cluster[data-justify=\"center\"] {\n justify-content: center;\n }\n .aia-cluster[data-justify=\"end\"] {\n justify-content: end;\n }\n .aia-cluster[data-justify=\"between\"] {\n justify-content: space-between;\n }\n .aia-cluster[data-justify=\"around\"] {\n justify-content: space-around;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport {};","import type { ComponentPropsWithoutRef, CSSProperties, ReactNode } from \"react\";\nimport \"./Cluster.css\";\n\ninterface ClusterProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"className\"> {\n /** Gap between children. Any CSS length. Defaults to `0.5rem`. */\n gap?: string;\n /** Cross-axis alignment. Defaults to `center`. */\n align?: \"start\" | \"center\" | \"end\" | \"baseline\";\n /** Main-axis distribution. Defaults to `start`. */\n justify?: \"start\" | \"center\" | \"end\" | \"between\" | \"around\";\n /** When true, the wrapper does NOT flex-wrap (single-row clusters). */\n noWrap?: boolean;\n /** Render as an inline-level `<span>` (inline-flex) instead of a block `<div>`. */\n inline?: boolean;\n className?: string;\n children: ReactNode;\n}\n\n// Horizontal layout primitive — wraps when out of room. `noWrap` for single-row clusters. Internal.\nexport function Cluster({\n gap,\n align = \"center\",\n justify = \"start\",\n noWrap = false,\n inline = false,\n className,\n children,\n ...rest\n}: ClusterProps) {\n const style = gap ? ({ \"--aia-cluster-gap\": gap } as CSSProperties) : undefined;\n const props = {\n className: className ? `aia-cluster ${className}` : \"aia-cluster\",\n \"data-align\": align,\n \"data-justify\": justify,\n \"data-nowrap\": noWrap || undefined,\n \"data-inline\": inline || undefined,\n style,\n ...rest,\n };\n if (inline) return <span {...props}>{children}</span>;\n return <div {...props}>{children}</div>;\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-56b0c577\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-56b0c577\";\n s.textContent = `/* The footer adds its own 8px horizontal inset so it stays clear of the\n dropdown's rounded edges. The top inset (--aia-footer-gap) adds breathing\n room above the hint/branding row so the footer doesn't butt against the last\n option row — additive to the dropdown's 8px section gap. */\n.DropdownFooter-module_footer_qQQ7x {\n display: flex;\n flex-direction: column;\n gap: 8px;\n /* No right inset: the brand pill's own padding (below) supplies it, so the\n badge sits as far from the right edge as it does from the bottom — 12px\n both ways (dropdown padding 10 + pill 2 down, dropdown padding 8 + pill 4\n across). */\n padding: var(--aia-footer-gap, 8px) 0 0 8px;\n /* The fade itself lives in appearance.css, on the footer's background.\n Paints above the rows it covers: option content sits at z-index 2 (see\n SuggestionItem.module.css) in this same stacking context, so anything\n lower would end up *behind* the rows. */\n position: relative;\n z-index: 3;\n /* Sitting on top of the list would otherwise swallow clicks and hovers on\n the rows scrolling under it — only the branding link needs to be hit. */\n pointer-events: none;\n}\n\n.DropdownFooter-module_hintGroup_ZzbPf {\n min-width: 0;\n}\n\n/* Re-enabled over the footer's \\`pointer-events: none\\`: both groups are visible\n chips sitting on the scroll band, so a click on one must land on the chip\n rather than falling through to the option row behind it. */\n.DropdownFooter-module_hintGroup_ZzbPf,\n.DropdownFooter-module_brandLink_r4f3R {\n pointer-events: auto;\n}\n\n.DropdownFooter-module_brandLink_r4f3R {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n text-decoration: none;\n cursor: pointer;\n transition: opacity 150ms ease-out;\n}\n\n/* The two content groups carry a solid surface fill so the keyboard hint and\n the AI-Autocomplete badge stay fully legible over whatever option row is\n scrolling behind the footer. The inline padding keeps the fill from hugging\n the glyphs. --aia-footer-chip-bg resolves to \\`transparent\\` on the glass\n surface, where there's no solid color to fill with. */\n.DropdownFooter-module_hintGroup_ZzbPf,\n.DropdownFooter-module_brandLink_r4f3R {\n /* Mixed here rather than declared on the container: a custom property\n substitutes var() on the element its declaration applies to, so a mix\n computed upstream would freeze the *theme's* surface and miss a\n dropdown-level --aia-surface retint. Computed on the footer, it picks up\n whichever ancestor set the surface. --aia-footer-chip-bg stays the\n override hook — consumers set it, and the glass surface zeroes it. */\n background: var(\n --aia-footer-chip-bg,\n color-mix(in srgb, var(--aia-surface, #ffffff) 65%, transparent)\n );\n padding-inline: 4px;\n border-radius: 6px;\n}\n\n/* The brand sits at the right edge where option rows scroll under the fade, so\n \"AI\" was getting clipped / washed out. Give the whole brand its own opaque,\n fully-rounded surface pill so it always reads clearly over the fade. Declared\n after the shared .hintGroup/.brandLink chip rule so it wins. */\n.DropdownFooter-module_brandLink_r4f3R {\n background: var(--aia-footer-brand-pill-bg, var(--aia-surface, #ffffff));\n border-radius: 999px;\n padding: 2px 4px;\n gap: 4px;\n}\n\n.DropdownFooter-module_brandLink_r4f3R:hover {\n opacity: 0.7;\n}\n\n.DropdownFooter-module_key_Bz1H- {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 30px;\n height: 22px;\n padding: 2px 6px;\n border: 0.5px solid var(--aia-footer-hint-color, #505050);\n border-radius: 5px;\n font-family: inherit;\n font-size: 11px;\n line-height: 18px;\n color: var(--aia-footer-hint-color, #505050);\n}\n\n.DropdownFooter-module_hint_GKEOH {\n font-family: inherit;\n font-size: 11px;\n line-height: 18px;\n color: var(--aia-footer-hint-color, #505050);\n}\n\n.DropdownFooter-module_brand_Al-lR {\n font-family: inherit;\n font-size: 10px;\n line-height: 18px;\n color: var(--aia-footer-brand-color, #b0b0b0);\n}\n\n.DropdownFooter-module_badge_Fk9vg {\n display: inline-flex;\n align-items: center;\n height: var(--aia-footer-row-height, 23px);\n padding: 2.5px 5.5px;\n border: 0.5px solid var(--aia-footer-badge-border, rgba(189, 189, 189, 0.51));\n border-radius: 999px;\n font-family: inherit;\n font-size: 10px;\n line-height: 18px;\n color: var(--aia-footer-brand-color, #b0b0b0);\n}\n\n/* Mobile footer variant (Figma \"Mobile\"): on phone-width viewports drop the\n keyboard hint (\"tab to select\" is meaningless on touch), leaving only the\n AI-Autocomplete brand pinned to the right. */\n@media (max-width: 768px) {\n .DropdownFooter-module_hintGroup_ZzbPf {\n display: none;\n }\n .DropdownFooter-module_row_BgZ6Q {\n justify-content: flex-end;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"footer\":\"DropdownFooter-module_footer_qQQ7x\",\"hintGroup\":\"DropdownFooter-module_hintGroup_ZzbPf\",\"brandLink\":\"DropdownFooter-module_brandLink_r4f3R\",\"key\":\"DropdownFooter-module_key_Bz1H-\",\"hint\":\"DropdownFooter-module_hint_GKEOH\",\"brand\":\"DropdownFooter-module_brand_Al-lR\",\"badge\":\"DropdownFooter-module_badge_Fk9vg\",\"row\":\"DropdownFooter-module_row_BgZ6Q\"};","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-199d0432\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-199d0432\";\n s.textContent = `/* ParamPill (Figma \"ParamPill\") — unfilled suggestion pill: transparent fill,\n no outline. ~28px via 6px padding + 14px text + the 1px border (border-box).\n The border is kept as a 1px transparent line so the box stays the same size\n as it was when the outline was dashed. */\n.ParamPill-module_pill_6Ga7S {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 5px 8px;\n border: 1px solid transparent;\n border-radius: 7px;\n background: transparent;\n color: var(--aia-pill-color, var(--aia-color-text-muted, #c1c4cb));\n font-family: inherit;\n /* Param labels read as small-caps section headers: distinctly smaller than\n the options they head (0.8× the pill knob), uppercased, and letter-spaced. */\n font-size: calc(var(--aia-pill-font-size, 14px) * 0.8);\n font-weight: 600;\n line-height: normal;\n text-transform: uppercase;\n letter-spacing: 0.06em;\n cursor: pointer;\n white-space: nowrap;\n animation: ParamPill-module_fadeIn_Ux4eQ 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n.ParamPill-module_rounded_y7xA9 {\n border-radius: 999px;\n}\n\n/* Loading skeleton — preserves the pill's exact box (same width and height)\n and hides the text. The base pill is now transparent, so fill the interior\n with the skeleton color (inside the dashed border) and pulse it so it still\n reads as a loading chip. */\n.ParamPill-module_skeleton_57P0T {\n pointer-events: none;\n cursor: default;\n color: transparent;\n background: var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, 0.25)));\n animation: ParamPill-module_skeletonPulse_xGcUy 1.4s ease-in-out infinite;\n}\n\n@keyframes ParamPill-module_skeletonPulse_xGcUy {\n 0%,\n 100% {\n filter: brightness(1);\n }\n 50% {\n filter: brightness(0.55);\n }\n}\n\n@keyframes ParamPill-module_fadeIn_Ux4eQ {\n from {\n opacity: 0;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"pill\":\"ParamPill-module_pill_6Ga7S\",\"fadeIn\":\"ParamPill-module_fadeIn_Ux4eQ\",\"rounded\":\"ParamPill-module_rounded_y7xA9\",\"skeleton\":\"ParamPill-module_skeleton_57P0T\",\"skeletonPulse\":\"ParamPill-module_skeletonPulse_xGcUy\"};","import type { MouseEvent } from \"react\";\nimport styles from \"./ParamPill.module.css\";\n\n/**\n * Visual emphasis tier for a pill. The selected (active) pill renders in the\n * `selected` state; every other pill takes its tier from its position in the\n * upcoming-params sequence — `first`, `next`, then `last` for the rest —\n * progressively de-emphasized.\n */\nexport type PillState = \"selected\" | \"first\" | \"next\" | \"last\";\n\n/** Opacity applied per state. Kept here so `PillList` skeletons stay in sync. */\nexport const PARAM_PILL_OPACITY: Record<PillState, number> = {\n selected: 1,\n first: 0.7,\n next: 0.4,\n last: 0.2,\n};\n\ninterface ParamPillProps {\n /** Pill label text. */\n label: string;\n /** Visual emphasis tier (drives opacity). */\n state: PillState;\n /** Renders the selection outline (the pill at the active index). */\n selected?: boolean;\n /** Capsule shape (fully rounded). Default: false. */\n rounded?: boolean;\n /** Non-interactive shimmering skeleton. */\n loading?: boolean;\n onClick?: () => void;\n}\n\n/**\n * ParamPill — the unfilled suggestion pill (Figma component \"ParamPill\",\n * formerly \"Pill\"). Rendered in the dropdown pill-bar and the inline pill list.\n */\nexport function ParamPill({ label, state, rounded, loading, onClick }: ParamPillProps) {\n const className = [styles.pill, rounded ? styles.rounded : \"\", loading ? styles.skeleton : \"\"]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <button\n type=\"button\"\n data-aia-pill=\"\"\n data-aia-loading={loading ? \"\" : undefined}\n tabIndex={-1}\n contentEditable={false}\n suppressContentEditableWarning\n className={className}\n style={{ opacity: PARAM_PILL_OPACITY[state] }}\n onMouseDown={(e: MouseEvent) => e.preventDefault()}\n onClick={loading ? undefined : onClick}\n disabled={loading}\n >\n {label}\n </button>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-0fcb7940\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-0fcb7940\";\n s.textContent = `.PillList-module_list_qvLqO {\n position: relative;\n z-index: 1;\n pointer-events: auto;\n display: inline-flex;\n gap: 7px;\n padding: 0 8px;\n align-items: center;\n vertical-align: middle;\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"list\":\"PillList-module_list_qvLqO\"};","import type { Suggestion } from \"../types\";\nimport { PARAM_PILL_OPACITY, ParamPill, type PillState } from \"./ParamPill\";\nimport pillStyles from \"./ParamPill.module.css\";\nimport styles from \"./PillList.module.css\";\n\ninterface PillListProps {\n pills: Suggestion[];\n activePillIndex: number;\n onSelectPill: (index: number) => void;\n /**\n * Whether the active pill should render in the `selected` state (full\n * opacity) rather than its positional `first` tier. In `auto` dropdown mode\n * this is true only while a dropdown option is highlighted; in `manual` mode\n * it becomes true once the user taps a pill. Default: false.\n */\n activeSelected?: boolean;\n /** Use capsule-shaped pills (fully rounded). Default: false. */\n rounded?: boolean;\n /**\n * When true, the rendered pills become non-interactive shimmering skeletons.\n * Real pills (with their text) are rendered when provided so widths/positions\n * match the previous state; when `pills` is empty, fixed-width fallback\n * placeholders are rendered instead.\n */\n loading?: boolean;\n}\n\nconst FALLBACK_SKELETON_WIDTHS = [125, 69];\n\n/**\n * Map a pill's index to its positional emphasis tier. The selected (active)\n * pill is handled separately — only the at-most-three positions get a tier\n * here: first, next, then last for everything after.\n */\nfunction pillStateForIndex(index: number): PillState {\n if (index === 0) return \"first\";\n if (index === 1) return \"next\";\n return \"last\";\n}\n\nexport function PillList({\n pills,\n activePillIndex,\n onSelectPill,\n activeSelected,\n rounded,\n loading,\n}: PillListProps) {\n if (loading && pills.length === 0) {\n return (\n <span className={styles.list} data-aia-pill-list-loading=\"\">\n {FALLBACK_SKELETON_WIDTHS.map((w, i) => (\n <span\n key={`skel-${w}`}\n data-aia-pill-skeleton=\"\"\n className={`${pillStyles.pill} ${rounded ? pillStyles.rounded : \"\"} ${pillStyles.skeleton}`}\n style={{ width: w, opacity: PARAM_PILL_OPACITY[pillStateForIndex(i)] }}\n />\n ))}\n </span>\n );\n }\n\n return (\n <span className={styles.list} data-aia-pill-list-loading={loading ? \"\" : undefined}>\n {pills.map((pill, i) => {\n // The active pill is \"selected\" only when activeSelected is set;\n // otherwise it shows its positional tier (first/next/last).\n const selected = Boolean(activeSelected) && i === activePillIndex;\n return (\n <ParamPill\n key={`${pill.type}-${pill.text}`}\n label={pill.text}\n state={selected ? \"selected\" : pillStateForIndex(i)}\n selected={selected}\n rounded={rounded}\n loading={loading}\n onClick={() => onSelectPill(i)}\n />\n );\n })}\n </span>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-fef1688d\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-fef1688d\";\n s.textContent = `/* Product strip — the React counterpart of the vanilla core's strip rules\n (packages/vanilla/src/styles.css). Same tokens, same defaults, so a consumer\n theming one package sees the same result in the other.\n\n Nothing here is allowed to say \\`color: inherit\\`: the dropdown paints a\n background but never sets a \\`color\\`, so an inheriting node would pick up the\n HOST PAGE's text colour and render black text on a dark panel. For the same\n reason there is no \\`prefers-color-scheme\\` rule in this file — the panel's\n darkness comes from --aia-surface, which is independent of the OS setting. */\n\n.ProductStrip-module_section_Hugfg {\n display: flex;\n flex-direction: column;\n gap: 6px;\n /* Matches the grid's own 8px inline padding so the section label lines up\n with the option text above it. */\n padding: 0 8px;\n min-width: 0;\n}\n\n.ProductStrip-module_label_nuc93 {\n font-family: inherit;\n font-size: var(--aia-products-label-font-size, 11px);\n font-weight: 500;\n line-height: 18px;\n letter-spacing: 0.02em;\n color: var(\n --aia-products-label-color,\n var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb))\n );\n}\n\n/* The scroll container. Horizontal overflow is confined here — the dropdown\n itself is \\`overflow: hidden\\`, so the page can never gain a sideways\n scrollbar no matter how many cards there are. \\`overscroll-behavior-x\\` stops\n a trackpad fling at either end from chaining out to the page. */\n.ProductStrip-module_row_WDVBX {\n display: flex;\n gap: var(--aia-product-gap, 8px);\n min-width: 0;\n overflow-x: auto;\n overflow-y: hidden;\n overscroll-behavior-x: contain;\n padding-bottom: 2px;\n /* Hide the scrollbar chrome across all three engines while leaving the box\n scrollable by trackpad, wheel, touch and keyboard. */\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n\n.ProductStrip-module_row_WDVBX::-webkit-scrollbar {\n display: none;\n}\n\n.ProductStrip-module_card_JBGYT {\n flex: 0 0 auto;\n display: flex;\n flex-direction: column;\n gap: 6px;\n width: var(--aia-product-card-width, 116px);\n padding: 6px;\n border-radius: 10px;\n background: var(--aia-product-bg, transparent);\n /* Explicit, never inherited — see the file header. */\n color: var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));\n text-decoration: none;\n cursor: pointer;\n transition: background-color 150ms ease;\n}\n\n.ProductStrip-module_card_JBGYT:hover {\n background: var(--aia-product-bg-active, var(--aia-option-bg, transparent));\n}\n\n/* Focus is the only cue a keyboard user gets, so it is a real ring rather than\n a background change. Drawn INSIDE the card (negative offset): the row is a\n scroll container with clipped overflow, so an outset ring is cut off on the\n first and last cards and on every card's top and bottom edge. */\n.ProductStrip-module_card_JBGYT:focus-visible {\n outline: 2px solid var(--aia-product-focus-ring, var(--aia-option-color-selected, currentColor));\n outline-offset: -2px;\n}\n\n/* Square media tile. aspect-ratio (not a fixed height) keeps it square at any\n --aia-product-card-width a consumer sets. */\n.ProductStrip-module_media_RrbGe {\n display: block;\n position: relative;\n width: 100%;\n aspect-ratio: 1 / 1;\n border-radius: 8px;\n overflow: hidden;\n background: var(--aia-product-media-bg, var(--aia-skeleton-bg, rgba(189, 189, 189, 0.25)));\n}\n\n.ProductStrip-module_image_5pNL7 {\n display: block;\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\n/* Placeholder tile for a product with no image — a faint glyph on the same\n media fill, so a card without art reads as \"no photo\" instead of broken. */\n.ProductStrip-module_media_RrbGe[data-aia-product-placeholder]::after {\n content: \"\";\n position: absolute;\n inset: 30%;\n border-radius: 3px;\n border: 1.5px solid var(--aia-product-placeholder-color, var(--aia-option-color, #c1c4cb));\n opacity: 0.35;\n}\n\n/* The text column. Only the title is guaranteed; vendor and price render no\n element at all when absent, so the gap can't reserve space for a missing\n line. */\n.ProductStrip-module_body_ly032 {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.ProductStrip-module_vendor_Gvu7G {\n font-family: inherit;\n font-size: var(--aia-product-vendor-font-size, 10px);\n line-height: 14px;\n color: var(\n --aia-product-vendor-color,\n var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb))\n );\n opacity: 0.8;\n /* Vendor names are frequently long — one line, clipped. */\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n\n.ProductStrip-module_title_gCNmq {\n font-family: inherit;\n font-size: var(--aia-product-title-font-size, 12px);\n font-weight: 400;\n line-height: 16px;\n /* The card's most prominent text uses the same token the *highlighted*\n option text does, so it stays legible on any --aia-surface a consumer\n sets — light or dark — without a second theming control. */\n color: var(\n --aia-product-title-color,\n var(--aia-option-color-selected, var(--aia-color-text-default, #fff))\n );\n display: -webkit-box;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.ProductStrip-module_price_gULcE {\n font-family: inherit;\n font-size: var(--aia-product-price-font-size, 11px);\n font-weight: 500;\n line-height: 15px;\n color: var(\n --aia-product-price-color,\n var(--aia-option-color-selected, var(--aia-color-text-default, #fff))\n );\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"section\":\"ProductStrip-module_section_Hugfg\",\"label\":\"ProductStrip-module_label_nuc93\",\"row\":\"ProductStrip-module_row_WDVBX\",\"card\":\"ProductStrip-module_card_JBGYT\",\"media\":\"ProductStrip-module_media_RrbGe\",\"image\":\"ProductStrip-module_image_5pNL7\",\"body\":\"ProductStrip-module_body_ly032\",\"vendor\":\"ProductStrip-module_vendor_Gvu7G\",\"title\":\"ProductStrip-module_title_gCNmq\",\"price\":\"ProductStrip-module_price_gULcE\"};","import type { MouseEvent as ReactMouseEvent } from \"react\";\nimport type { Product } from \"../types\";\nimport styles from \"./ProductStrip.module.css\";\n\ninterface ProductStripProps {\n products: Product[];\n /** Scopes the section label's id to the owning listbox. */\n listboxId: string;\n onSelect: (product: Product) => void;\n /**\n * Focus moved into / out of the strip. The panel closes on blur by default\n * and the input blurs the moment a card takes focus, so the dropdown reports\n * focus as still-inside rather than shutting out from under the card.\n */\n onFocusChange?: (focused: boolean) => void;\n /**\n * False while the panel is fading out. The closed dropdown keeps rendering\n * its last content for the fade, and focusable cards inside it would still\n * answer Tab.\n */\n focusable?: boolean;\n}\n\n/**\n * The dropdown's product strip: a labelled section holding a horizontally\n * scrolling row of product cards. Sits below the options grid and above the\n * footer, and renders only when there are products — the panel's two halves\n * are independent, so an empty strip leaves no gap and an empty options grid\n * leaves the strip alone.\n *\n * Mirrors the vanilla core's `renderProductStrip` markup and class contract so\n * both packages theme identically. Two layout notes carried over from it:\n *\n * - The dropdown paints a background but never sets `color`, so anything here\n * relying on `color: inherit` would pick up the *host page's* text colour.\n * Every text node resolves its colour through the same `--aia-option-*`\n * chain the options use (see ProductStrip.module.css).\n * - The options grid carries a negative bottom margin so the footer rides up\n * over its reserved band; whatever follows the grid inherits that pull. The\n * dropdown root is marked `data-aia-has-products` and appearance.css zeroes\n * the band at its source rather than the strip cancelling it from here.\n */\nexport function ProductStrip({\n products,\n listboxId,\n onSelect,\n onFocusChange,\n focusable = true,\n}: ProductStripProps) {\n if (products.length === 0) return null;\n\n const labelId = `${listboxId}-products-label`;\n\n return (\n // biome-ignore lint/a11y/useSemanticElements: the rule suggests <fieldset>, which groups form controls and drags in legend semantics and UA styling. `group` is the one role a listbox accepts around a set of options, so the explicit ARIA role is exactly the point.\n <section\n className={styles.section}\n data-aia-products=\"\"\n // `group` is the one role a listbox accepts around a set of options, so\n // the strip stays inside the listbox without breaking its content model.\n role=\"group\"\n aria-labelledby={labelId}\n >\n <div className={styles.label} id={labelId}>\n Products\n </div>\n <div className={styles.row} data-aia-products-row=\"\">\n {products.map((product, i) => (\n <ProductCard\n key={product.id}\n product={product}\n id={`${listboxId}-product-${i}`}\n onSelect={onSelect}\n onFocusChange={onFocusChange}\n focusable={focusable}\n />\n ))}\n </div>\n </section>\n );\n}\n\ninterface ProductCardProps {\n product: Product;\n id: string;\n onSelect: (product: Product) => void;\n onFocusChange?: (focused: boolean) => void;\n focusable: boolean;\n}\n\nfunction ProductCard({ product, id, onSelect, onFocusChange, focusable }: ProductCardProps) {\n const handleClick = (e: ReactMouseEvent<HTMLAnchorElement>) => {\n // Let the browser keep the clicks that mean \"open this somewhere else\" —\n // intercepting them would defeat the point of rendering an <a>. Those are\n // navigations the user asked for explicitly, so they don't emit.\n if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || e.button !== 0) return;\n e.preventDefault();\n onSelect(product);\n };\n\n return (\n // A real <a href> rather than a <div>: it keeps the browser's own link\n // affordances — cmd/ctrl-click for a new tab, middle-click, right-click →\n // \"copy link address\". `role=\"option\"` overrides how assistive tech\n // announces it, which is correct inside a listbox; the deliberate trade is\n // that AT no longer calls it a link.\n <a\n id={id}\n className={styles.card}\n data-aia-product=\"\"\n role=\"option\"\n aria-selected={false}\n href={product.url}\n tabIndex={focusable ? 0 : -1}\n onClick={handleClick}\n onKeyDown={(e) => {\n if (e.key !== \"Enter\" && e.key !== \" \") return;\n e.preventDefault();\n onSelect(product);\n }}\n onFocus={() => onFocusChange?.(true)}\n onBlur={(e) => {\n const next = e.relatedTarget as HTMLElement | null;\n if (next?.closest(\"[data-aia-dropdown]\")) return;\n onFocusChange?.(false);\n }}\n >\n <span\n className={styles.media}\n // Catalogues without images are common enough that the placeholder is\n // a first-class state, not an error state.\n data-aia-product-placeholder={product.imageUrl ? undefined : \"\"}\n >\n {product.imageUrl ? (\n <img\n className={styles.image}\n src={product.imageUrl}\n // The title is already the card's accessible name; repeating it\n // here would have a screen reader read it twice.\n alt=\"\"\n loading=\"lazy\"\n decoding=\"async\"\n />\n ) : null}\n </span>\n {/* Every field but the title is optional, so absent ones render no\n element at all — the column gap can't leave a hole for a box that\n isn't there. */}\n <span className={styles.body}>\n {product.vendor ? <span className={styles.vendor}>{product.vendor}</span> : null}\n <span className={styles.title}>{product.title}</span>\n {product.price ? <span className={styles.price}>{product.price}</span> : null}\n </span>\n </a>\n );\n}\n","import {\n isOptionsGridMobileViewport,\n measureOptionsGrid,\n needsOptionsGridMeasurement,\n OPTIONS_GRID_MOBILE_QUERY,\n type OptionsGridPlan,\n optionEnterDelayMs,\n planOptionsGrid,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport { Grid } from \"../layout/Grid\";\nimport type { SuggestionOption } from \"../types\";\nimport { SuggestionItem } from \"./SuggestionItem\";\n\n/**\n * Tracks the phone-width breakpoint the options grid switches on. The core\n * owns the query itself (and the vanilla/Angular grids watch the same one) so\n * the three packages can't drift onto different breakpoints.\n */\nfunction useIsMobile(): boolean {\n const [isMobile, setIsMobile] = useState(isOptionsGridMobileViewport);\n useEffect(() => {\n if (typeof window === \"undefined\" || !window.matchMedia) return;\n const mq = window.matchMedia(OPTIONS_GRID_MOBILE_QUERY);\n const onChange = () => setIsMobile(mq.matches);\n onChange();\n mq.addEventListener(\"change\", onChange);\n return () => mq.removeEventListener(\"change\", onChange);\n }, []);\n return isMobile;\n}\n\ninterface SuggestionGridProps {\n options: SuggestionOption[];\n activeIndex: number;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n listboxId: string;\n loading?: boolean;\n /**\n * Identity of the suggestion these options belong to. When it changes the\n * grid scrolls back to the top, so the next parameter's options are read\n * from the first one instead of from the previous list's scroll offset.\n */\n groupKey?: string;\n /**\n * Which side of the input the dropdown opens on. The rows' entrance starts\n * from the input's side outward, so \"above\" reverses the order.\n */\n optionsPosition?: \"above\" | \"below\";\n}\n\n/**\n * The dropdown's option grid: a thin wrapper that lays `SuggestionItem`s out\n * with the `Grid` layout primitive. `Grid` owns the auto-fit columns and the\n * capped-height scroll, so this component only wires each option to its\n * highlight/select handlers and listbox-scoped id.\n */\nexport function SuggestionGrid({\n options,\n activeIndex,\n onSelect,\n onHighlight,\n listboxId,\n loading,\n groupKey = \"\",\n optionsPosition = \"below\",\n}: SuggestionGridProps) {\n const isMobile = useIsMobile();\n const gridEl = useRef<HTMLDivElement | null>(null);\n // Two-pass: the first render lays out the measurement-free baseline (one\n // column), then the layout effect measures the rendered rows and upgrades to\n // the two-column plan when they provably fit — same policy as the vanilla\n // and Angular grids, all through `planOptionsGrid`. activeIndex is\n // deliberately not a dependency: highlighting can't change the plan, and\n // measuring clones every row and forces a layout. The needs-measurement gate\n // skips that cost entirely whenever the plan would ignore the result\n // (mobile, fewer than five options). jsdom measures every row at 0, so the\n // upgrade never fires in tests — the fit decision is asserted in the core's\n // own suite.\n const [measuredPlan, setMeasuredPlan] = useState<OptionsGridPlan | null>(null);\n useLayoutEffect(() => {\n const el = gridEl.current;\n const shouldMeasure = el && !loading && needsOptionsGridMeasurement(options.length, isMobile);\n const measured = shouldMeasure ? measureOptionsGrid(el) : null;\n setMeasuredPlan(\n measured\n ? planOptionsGrid(options.length, isMobile, measured.rowWidths, measured.gridWidth)\n : null,\n );\n }, [options, isMobile, loading]);\n const plan = measuredPlan ?? planOptionsGrid(options.length, isMobile, null, null);\n return (\n <Grid\n min=\"250px\"\n max=\"1fr\"\n gap=\"0\"\n scroll\n scrollResetKey={groupKey}\n template={plan.template}\n maxHeight={plan.maxHeight}\n innerRef={(el) => {\n gridEl.current = el;\n }}\n // Read by the scroll arrow to tell a new set of options (rising in)\n // from the same set re-rendered.\n data-aia-group={groupKey}\n >\n {options.map((option, i) => (\n <SuggestionItem\n // The group is part of the key: a new suggestion's options are new\n // rows and get the entrance animation even when one spells the same\n // as a row already on screen.\n key={`${groupKey}\\0${option.text}`}\n option={option}\n isHighlighted={i === activeIndex}\n onSelect={onSelect}\n onHighlight={() => onHighlight(i)}\n id={`${listboxId}-option-${i}`}\n loading={loading}\n scrollHint={!loading && plan.scrollHintIndices.includes(i)}\n // Skeleton rows fade in together — they're placeholders, not content.\n enterDelayMs={\n loading ? 0 : optionEnterDelayMs(i, plan.cols, options.length, optionsPosition)\n }\n />\n ))}\n </Grid>\n );\n}\n","import { optionsGridTemplateColumns } from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport {\n type ComponentPropsWithoutRef,\n type CSSProperties,\n type ReactNode,\n useLayoutEffect,\n useRef,\n} from \"react\";\nimport \"./Grid.css\";\n\ninterface GridProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"className\"> {\n /** Minimum cell width. CSS length, e.g. \"16rem\". Columns auto-fit at runtime. */\n min?: string;\n /** Maximum cell width. CSS length. Defaults to `1fr` (stretch to fill). */\n max?: string;\n /** Gap between cells. Defaults to `0`. */\n gap?: string;\n /** Cap the height and scroll vertically when content overflows. */\n scroll?: boolean;\n /** Max height when `scroll`. CSS length. Defaults to `120px`. */\n maxHeight?: string;\n /** Scroll back to the top whenever this key changes (`scroll` only). */\n scrollResetKey?: string;\n /** Fixed column count. Overrides the intrinsic auto-fit when set; rows fill left-to-right. */\n cols?: number;\n /** Explicit `grid-template-columns` value. Overrides `cols` when set. */\n template?: string;\n /** Also receives the grid element (for callers that measure it). */\n innerRef?: (el: HTMLDivElement | null) => void;\n className?: string;\n children: ReactNode;\n}\n\n// Intrinsic grid — auto-fits as many columns as fit between `min` and `max`\n// wide, wrapping to new rows when there's no more horizontal room. Optionally\n// scrolls (capped height). Internal.\nexport function Grid({\n min = \"16rem\",\n max,\n gap,\n scroll = false,\n maxHeight,\n scrollResetKey,\n cols,\n template,\n innerRef,\n className,\n children,\n ...rest\n}: GridProps) {\n const gridRef = useRef<HTMLDivElement | null>(null);\n\n // A new key means a different content group is being shown (e.g. the next\n // suggestion's options after a selection) — start it from the top instead of\n // inheriting the previous group's scroll offset. Layout effect so the reset\n // lands in the same frame the new content paints.\n useLayoutEffect(() => {\n if (scrollResetKey === undefined) return;\n const el = gridRef.current;\n if (el) el.scrollTop = 0;\n }, [scrollResetKey]);\n\n const style: CSSProperties = { \"--aia-grid-min\": min } as CSSProperties;\n if (max) (style as Record<string, string>)[\"--aia-grid-max\"] = max;\n if (gap) (style as Record<string, string>)[\"--aia-grid-gap\"] = gap;\n if (maxHeight) (style as Record<string, string>)[\"--aia-grid-max-height\"] = maxHeight;\n // Explicit column count overrides the intrinsic auto-fit (inline wins). The\n // track string is built by the core so all three packages emit the same one.\n // An explicit template (the measured two-column split) wins over both.\n if (cols) style.gridTemplateColumns = optionsGridTemplateColumns(cols);\n if (template) style.gridTemplateColumns = template;\n\n return (\n <div\n ref={(el) => {\n gridRef.current = el;\n innerRef?.(el);\n }}\n className={className ? `aia-grid ${className}` : \"aia-grid\"}\n data-scroll={scroll || undefined}\n style={style}\n {...rest}\n >\n {children}\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-948e58da\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-948e58da\";\n s.textContent = `@layer layout {\n .aia-grid {\n display: grid;\n grid-template-columns: repeat(\n auto-fit,\n minmax(min(var(--aia-grid-min), 100%), var(--aia-grid-max, 1fr))\n );\n gap: var(--aia-grid-gap, 0);\n }\n\n /* Scrollable variant — capped height with a styled thin scrollbar. Rows pack\n from the top instead of stretching to fill the container. */\n .aia-grid[data-scroll] {\n grid-auto-rows: min-content;\n align-content: start;\n justify-content: start;\n /* The scroll box's reserved band (--aia-grid-scroll-* / --aia-grid-overlap-*)\n is deliberately NOT declared here — see the unlayered rule in\n appearance.css for why. */\n max-height: var(--aia-grid-max-height, 120px);\n overflow-y: auto;\n scrollbar-width: thin;\n scrollbar-color: var(--aia-scrollbar-thumb, rgba(0, 0, 0, 0.3)) transparent;\n }\n .aia-grid[data-scroll]::-webkit-scrollbar {\n width: 6px;\n }\n .aia-grid[data-scroll]::-webkit-scrollbar-track {\n background: transparent;\n }\n .aia-grid[data-scroll]::-webkit-scrollbar-thumb {\n background: var(--aia-scrollbar-thumb, rgba(0, 0, 0, 0.3));\n border-radius: 3px;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport {};","import { OPTION_ENTER_DELAY_VAR } from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { type CSSProperties, useEffect, useRef, useState } from \"react\";\nimport type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionItem.module.css\";\n\ninterface SuggestionItemProps {\n option: SuggestionOption;\n isHighlighted: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: () => void;\n id: string;\n loading?: boolean;\n /** Fade this option's text toward its bottom edge (last visible row of a scrollable grid). */\n scrollHint?: boolean;\n /**\n * Start delay of this row's entrance animation (ms) — each row rises in a\n * beat after the one nearer the input. Fixed for the row's lifetime: it's\n * read once on mount, so a re-render can't restart a row mid-rise.\n */\n enterDelayMs?: number;\n}\n\nexport function SuggestionItem({\n option,\n isHighlighted,\n onSelect,\n onHighlight,\n id,\n loading,\n scrollHint,\n enterDelayMs = 0,\n}: SuggestionItemProps) {\n const [enterDelay] = useState(enterDelayMs);\n const [pressed, setPressed] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n useEffect(() => {\n return () => clearTimeout(timerRef.current);\n }, []);\n\n const handleSelect = () => {\n if (loading || !option.is_tappable || pressed) return;\n setPressed(true);\n onSelect(option);\n clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setPressed(false), 170);\n };\n\n const className = [\n styles.item,\n isHighlighted && !loading ? styles.highlighted : \"\",\n option.is_tappable ? styles.tappable : styles.nonTappable,\n pressed ? styles.pressed : \"\",\n scrollHint ? styles.scrollHint : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n id={id}\n role=\"option\"\n data-aia-option=\"\"\n data-aia-loading={loading ? \"\" : undefined}\n aria-selected={isHighlighted}\n className={className}\n style={{ [OPTION_ENTER_DELAY_VAR]: `${enterDelay}ms` } as CSSProperties}\n tabIndex={loading || !option.is_tappable ? -1 : 0}\n onClick={handleSelect}\n onKeyDown={(e) => {\n if (!loading && option.is_tappable && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n handleSelect();\n }\n }}\n onMouseEnter={!loading && option.is_tappable ? onHighlight : undefined}\n >\n <span className={styles.content}>\n <span className={styles.text}>\n {option.icon ? `${option.icon} ${option.text}` : option.text}\n </span>\n {option.tag && <span className={styles.tag}>{option.tag}</span>}\n </span>\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-82820da7\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-82820da7\";\n s.textContent = `.SuggestionItem-module_item_d4vpD {\n position: relative;\n overflow: visible;\n display: flex;\n /* Top-align so single-line and multi-line options in the same row share\n the same baseline at the top edge of the cell. */\n align-items: flex-start;\n font-family: inherit;\n font-size: var(--aia-option-font-size, 16px);\n font-weight: 450;\n line-height: 21px;\n color: var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));\n white-space: normal;\n word-break: break-word;\n /* 8px radius on the highlighted fill (--aia-option-bg), matching the Figma\n SuggestionItem selection. The 9px/10px inset is the item's own padding. */\n border-radius: 8px;\n padding: 8px 10px;\n /* Entrance: fade in while rising into place, each row a beat after the one\n before it (--aia-option-enter-delay is set inline per row from the core's\n optionEnterDelayMs). The durations and distance mirror OPTION_ENTER_* in\n the core's derive/optionsEntrance.ts — change both together. */\n animation:\n SuggestionItem-module_fadeIn_I8u35 150ms ease-out both,\n SuggestionItem-module_riseIn_etXZT 280ms cubic-bezier(0.25, 0.46, 0.45, 0.94) both;\n animation-delay: var(--aia-option-enter-delay, 0ms);\n}\n\n@keyframes SuggestionItem-module_fadeIn_I8u35 {\n from {\n opacity: 0;\n }\n}\n\n@keyframes SuggestionItem-module_riseIn_etXZT {\n from {\n transform: translateY(16px);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .SuggestionItem-module_item_d4vpD {\n animation-duration: 0s;\n animation-delay: 0s;\n }\n}\n\n.SuggestionItem-module_content_T-Qba {\n position: relative;\n z-index: 2;\n}\n\n.SuggestionItem-module_tappable_70KcX {\n cursor: pointer;\n}\n\n.SuggestionItem-module_tappable_70KcX:hover {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n}\n\n.SuggestionItem-module_nonTappable_xSZM- {\n cursor: default;\n}\n\n.SuggestionItem-module_highlighted_Hb0SU {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n background: var(--aia-option-bg, transparent);\n font-weight: 500;\n}\n\n.SuggestionItem-module_tag_e3Fwe {\n font-size: 11px;\n margin-left: 6px;\n opacity: 0.5;\n}\n\n/* Press feedback: the picked option's text compresses down while every other\n option steps back in opacity — no fill, no glow, the hierarchy carries it. */\n.SuggestionItem-module_pressed_98o-r {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n animation: SuggestionItem-module_pressCompress_ICV3q 170ms ease forwards;\n}\n\n[role=\"listbox\"]:has(.SuggestionItem-module_pressed_98o-r) .SuggestionItem-module_item_d4vpD:not(.SuggestionItem-module_pressed_98o-r) {\n opacity: 0.35;\n transition: opacity 60ms ease;\n}\n\n@keyframes SuggestionItem-module_pressCompress_ICV3q {\n 0% {\n transform: scale(1);\n }\n 25% {\n transform: scale(0.93);\n }\n 60% {\n transform: scale(0.93);\n }\n 100% {\n transform: scale(1);\n }\n}\n\n/* Scroll hint — the last visible row of a scrollable web grid fades toward its\n bottom edge, signalling more options below (the desktop footer is opaque, so\n rows no longer dissolve through it). A mask instead of a color so any themed\n option color fades the same way. */\n.SuggestionItem-module_scrollHint_xKXPt .SuggestionItem-module_content_T-Qba {\n -webkit-mask-image: linear-gradient(to bottom, rgb(0 0 0), rgb(0 0 0 / 0.6));\n mask-image: linear-gradient(to bottom, rgb(0 0 0), rgb(0 0 0 / 0.6));\n}\n\n/* Loading state — preserve the row's exact dimensions. The content stays an\n inline span so the line box and padding match the non-loading state byte\n for byte. Just hide the text and apply a background as a skeleton bar; the\n pulse provides the shimmer. */\n.SuggestionItem-module_item_d4vpD[data-aia-loading] {\n cursor: default;\n animation: SuggestionItem-module_skeletonPulse_plvdD 1.4s ease-in-out infinite;\n}\n\n/* Skeleton fill is on the inner text span (a true inline element) so multi-\n line options wrap into one skeleton bar per line. The outer .content is a\n flex item — blockified by spec — so painting the background there would\n collapse all lines into one tall rectangle. \\`box-decoration-break: clone\\`\n makes the radius render cleanly on each line bar. */\n.SuggestionItem-module_item_d4vpD[data-aia-loading] .SuggestionItem-module_text_yqoh9 {\n color: transparent;\n background: var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, 0.25)));\n border-radius: 999px;\n -webkit-box-decoration-break: clone;\n box-decoration-break: clone;\n}\n\n.SuggestionItem-module_item_d4vpD[data-aia-loading] .SuggestionItem-module_tag_e3Fwe {\n display: none;\n}\n\n@keyframes SuggestionItem-module_skeletonPulse_plvdD {\n 0%,\n 100% {\n filter: brightness(1);\n }\n 50% {\n filter: brightness(0.55);\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"item\":\"SuggestionItem-module_item_d4vpD\",\"fadeIn\":\"SuggestionItem-module_fadeIn_I8u35\",\"riseIn\":\"SuggestionItem-module_riseIn_etXZT\",\"content\":\"SuggestionItem-module_content_T-Qba\",\"tappable\":\"SuggestionItem-module_tappable_70KcX\",\"nonTappable\":\"SuggestionItem-module_nonTappable_xSZM-\",\"highlighted\":\"SuggestionItem-module_highlighted_Hb0SU\",\"tag\":\"SuggestionItem-module_tag_e3Fwe\",\"pressed\":\"SuggestionItem-module_pressed_98o-r\",\"pressCompress\":\"SuggestionItem-module_pressCompress_ICV3q\",\"scrollHint\":\"SuggestionItem-module_scrollHint_xKXPt\",\"skeletonPulse\":\"SuggestionItem-module_skeletonPulse_plvdD\",\"text\":\"SuggestionItem-module_text_yqoh9\"};","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-8414cd5f\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-8414cd5f\";\n s.textContent = `@layer layout {\n .aia-stack {\n display: flex;\n flex-direction: column;\n gap: var(--aia-stack-space, 0.5rem);\n }\n .aia-stack[data-align=\"start\"] {\n align-items: start;\n }\n .aia-stack[data-align=\"center\"] {\n align-items: center;\n }\n .aia-stack[data-align=\"end\"] {\n align-items: end;\n }\n /* data-align=\"stretch\" is the flex default — no rule needed. */\n}\n`;\n document.head.appendChild(s);\n}\nexport {};","import type { ComponentPropsWithoutRef, CSSProperties, ReactNode } from \"react\";\nimport \"./Stack.css\";\n\ninterface StackProps extends Omit<ComponentPropsWithoutRef<\"div\">, \"className\"> {\n /** Gap between children. Any CSS length. Defaults to `0.5rem`. */\n space?: string;\n /** Cross-axis alignment of children. Defaults to `stretch` (full width). */\n align?: \"start\" | \"center\" | \"end\" | \"stretch\";\n className?: string;\n children: ReactNode;\n}\n\n// Vertical layout primitive — children stack top-to-bottom with `space` gap. Internal.\nexport function Stack({ space, align = \"stretch\", className, children, ...rest }: StackProps) {\n const style = space ? ({ \"--aia-stack-space\": space } as CSSProperties) : undefined;\n return (\n <div\n className={className ? `aia-stack ${className}` : \"aia-stack\"}\n data-align={align}\n style={style}\n {...rest}\n >\n {children}\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-fdee06e6\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-fdee06e6\";\n s.textContent = `.SubmitButton-module_submitButton_otz7H {\n flex-shrink: 0;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n border: none;\n background: var(--aia-submit-bg, var(--aia-color-text-default, #fff));\n color: var(--aia-submit-color, var(--aia-color-bg-default, #000));\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n transition: opacity 0.2s ease;\n}\n\n.SubmitButton-module_submitButton_otz7H:hover {\n opacity: 0.85;\n}\n\n/* Disabled (empty input) keeps the solid themed look by default — the disabled\n tokens fall back to the enabled ones, so a consumer's themed color is never\n washed out. Opt into a faded/dimmed rest state by setting\n --aia-submit-bg-disabled / --aia-submit-color-disabled. */\n.SubmitButton-module_submitButton_otz7H:disabled {\n background: var(\n --aia-submit-bg-disabled,\n var(--aia-submit-bg, var(--aia-color-text-default, #fff))\n );\n color: var(\n --aia-submit-color-disabled,\n var(--aia-submit-color, var(--aia-color-bg-default, #000))\n );\n cursor: default;\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"submitButton\":\"SubmitButton-module_submitButton_otz7H\"};","import styles from \"./SubmitButton.module.css\";\n\ninterface SubmitButtonProps {\n /** Disabled when there's nothing to submit. */\n disabled?: boolean;\n onClick: () => void;\n}\n\n/**\n * The default circular submit button (up-arrow). Tier 1 renders this when the\n * consumer doesn't supply a custom `submitButton`. Themed via `--aia-submit-*`.\n */\nexport function SubmitButton({ disabled, onClick }: SubmitButtonProps) {\n return (\n <button\n type=\"button\"\n data-aia-submit=\"\"\n className={styles.submitButton}\n disabled={disabled}\n onClick={(e) => {\n e.stopPropagation();\n onClick();\n }}\n aria-label=\"Submit\"\n >\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" role=\"img\" aria-label=\"Submit\">\n <path\n d=\"M9 14V4M9 4L4 9M9 4L14 9\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n );\n}\n","import {\n AIAutocomplete as CoreAIAutocomplete,\n type CoreState,\n identifiedParamLabel,\n type Product,\n type Suggestion,\n type SuggestionOption,\n selectedIsoFromText,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport {\n type ChangeEvent,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { UseAIAutocompleteOptions, UseAIAutocompleteReturn } from \"../types\";\nimport { useOptionOverridesProxy } from \"./useOptionOverridesProxy\";\nimport { useProductsProxy } from \"./useProductsProxy\";\n\n/**\n * Pre-mount / SSR fallback. Identical shape to the post-mount CoreState so\n * the hook's return is single-shaped — no `if (!instance) return ...` branch.\n * `isLoading: true` matches the historical SSR bail-out: consumers using\n * `isLoading` to render a skeleton see one on the first paint instead of a\n * flash of blank content while the mount effect creates the core instance.\n */\nconst EMPTY_STATE: CoreState = {\n text: \"\",\n completedParams: [],\n identifiedParams: [],\n skippedParams: [],\n pendingSpan: null,\n suggestions: [],\n // Pre-mount there is no core and therefore no product search in flight.\n products: [],\n // …nor an option override being asked.\n optionSearch: null,\n activeDropdownIndex: -1,\n newParamId: null,\n isLoading: true,\n isReady: false,\n error: null,\n segments: [],\n actionableSuggestions: [],\n filteredOptions: [],\n // Pre-mount there is no active suggestion, so nothing can be a date yet.\n activeFormatType: \"options\",\n dateView: null,\n placeholderText: \"\",\n optionQuery: \"\",\n isSearchingOptions: false,\n isDropdownOpen: false,\n isActivePillSelected: false,\n filterBase: 0,\n filterInProgress: false,\n pillTapped: false,\n skipNextFetch: false,\n lastRawQuery: \"\",\n isFocused: false,\n editingParam: null,\n editingIdentified: null,\n editingAnchor: null,\n editingTail: null,\n caretOffset: null,\n inSelectionAnimation: false,\n dateViewMonth: null,\n};\n\ninterface CoreActions {\n handleTextChange: (value: string) => void;\n handleKeyDown: (e: KeyboardEvent<HTMLElement> | globalThis.KeyboardEvent) => void;\n setFocused: (focused: boolean) => void;\n startEditingParam: (paramId: string) => void;\n exitEditMode: () => void;\n handleCaretAfterInput: (offset: number | null) => void;\n handleCaretMove: (offset: number | null) => void;\n replaceEditingRange: (replacement: string) => boolean;\n setActivePill: (index: number) => void;\n skipActivePill: () => void;\n removeLastParam: () => void;\n clearNewParamId: () => void;\n reset: () => void;\n selectOption: (option: SuggestionOption) => void;\n selectProduct: (product: Product) => void;\n setActiveDropdownIndex: (index: number) => void;\n showPreviousMonth: () => void;\n showNextMonth: () => void;\n handleFocus: () => void;\n handleBlur: () => void;\n}\n\nexport function useAIAutocomplete({\n onSubmit,\n onResult,\n onError,\n optionOverrides,\n maskCompletedText,\n apiConfig,\n additionalContext,\n columns = 2,\n dropdownTrigger,\n optionsPosition,\n closeDropdownOnBlur,\n showNonTappableOptions,\n showSkipButton,\n onFocus,\n onBlur,\n value: controlledValue,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n products,\n onProductSelect,\n source,\n setCursor,\n}: UseAIAutocompleteOptions): UseAIAutocompleteReturn {\n const instanceRef = useRef<CoreAIAutocomplete | null>(null);\n const [coreState, setCoreState] = useState<CoreState | null>(null);\n\n // Refs for caller-supplied callbacks. The CoreAIAutocomplete instance is\n // mount-only (created once); these refs let the stable proxy callbacks\n // inside it pick up the latest props on every render.\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n const onResultRef = useRef(onResult);\n onResultRef.current = onResult;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const onChangeRef = useRef(onChangeProp);\n onChangeRef.current = onChangeProp;\n const onParamsChangeRef = useRef(onParamsChange);\n onParamsChangeRef.current = onParamsChange;\n const onFocusRef = useRef(onFocus);\n onFocusRef.current = onFocus;\n const onBlurRef = useRef(onBlur);\n onBlurRef.current = onBlur;\n const setCursorRef = useRef(setCursor);\n setCursorRef.current = setCursor;\n const onProductSelectRef = useRef(onProductSelect);\n onProductSelectRef.current = onProductSelect;\n\n // Stable proxy so an inline `products={{ … }}` doesn't read as a swapped\n // integration on every render — see useProductsProxy for the full rationale.\n const productsProxy = useProductsProxy(products);\n // Same treatment for `optionOverrides`: the core would read a fresh inline\n // record as a swap and re-ask the pill on screen — see useOptionOverridesProxy.\n const overridesProxy = useOptionOverridesProxy(optionOverrides);\n\n // Create, subscribe, and destroy the core instance in one mount-only effect.\n // Keeping creation out of render (and pairing it with the cleanup) is what\n // makes this StrictMode-safe — otherwise cleanup nulls the ref, render\n // re-creates, and the store subscription drives an infinite setState loop.\n // biome-ignore lint/correctness/useExhaustiveDependencies: initial-opts snapshot; later changes are synced by the update-effect below\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n const instance = new CoreAIAutocomplete(document.createElement(\"div\"), {\n renderMode: \"headless\",\n apiConfig,\n additionalContext,\n optionOverrides: overridesProxy.overrides,\n maskCompletedText,\n columns,\n dropdownTrigger,\n optionsPosition,\n closeDropdownOnBlur,\n showNonTappableOptions,\n source,\n value: controlledValue,\n completedParams: controlledParams,\n onSubmit: (...args) => onSubmitRef.current?.(...args),\n onResult: (...args) => onResultRef.current?.(...args),\n onError: (...args) => onErrorRef.current?.(...args),\n onChange: (...args) => onChangeRef.current?.(...args),\n onParamsChange: (...args) => onParamsChangeRef.current?.(...args),\n onFocus: () => onFocusRef.current?.(),\n onBlur: () => onBlurRef.current?.(),\n onProductSelect: (product) => onProductSelectRef.current?.(product),\n setCursor: (offset) => setCursorRef.current?.(offset),\n products: productsProxy.config,\n });\n instanceRef.current = instance;\n setCoreState(instance.getState());\n const unsub = instance.subscribe((state) => setCoreState(state));\n return () => {\n unsub();\n instance.destroy();\n if (instanceRef.current === instance) instanceRef.current = null;\n };\n }, []);\n\n // Sync controlled value\n useEffect(() => {\n if (controlledValue !== undefined) instanceRef.current?.setValue(controlledValue);\n }, [controlledValue]);\n\n // Sync controlled params\n useEffect(() => {\n if (controlledParams !== undefined) instanceRef.current?.setCompletedParams(controlledParams);\n }, [controlledParams]);\n\n // Sync apiConfig/optionOverrides/dropdownTrigger when values change\n const apiConfigJson = JSON.stringify(apiConfig ?? null);\n // Unlike apiConfig (a narrow typed shape), additionalContext is consumer-supplied\n // free-form JSON — a circular reference or a BigInt would throw here, which runs\n // during render. Fall back to a constant so a bad value is silently dropped\n // (never synced to the core) instead of crashing the render.\n let additionalContextJson: string;\n try {\n additionalContextJson = JSON.stringify(additionalContext ?? null);\n } catch {\n additionalContextJson = \"[unstringifiable]\";\n }\n // biome-ignore lint/correctness/useExhaustiveDependencies: overridesProxy.key is the only optionOverrides change worth an update — the proxy reads the rest live\n useEffect(() => {\n instanceRef.current?.update({\n apiConfig,\n additionalContext,\n optionOverrides: overridesProxy.overrides,\n dropdownTrigger,\n optionsPosition,\n closeDropdownOnBlur,\n showNonTappableOptions,\n });\n }, [\n apiConfigJson,\n additionalContextJson,\n overridesProxy.key,\n dropdownTrigger,\n optionsPosition,\n closeDropdownOnBlur,\n showNonTappableOptions,\n ]);\n\n // Toggling the strip on or off is the only products change the core needs to\n // hear about — the proxy handles everything else — and it deliberately\n // clears the cards on the way out. Skips the mount pass: the constructor\n // above already applied the initial value, and a redundant update() here\n // would clear a strip the first fetch had populated.\n //\n // `productsProxy.config` is intentionally not a dependency: its identity is\n // stable by construction, so `enabled` is the only thing that can change.\n const productsMountedRef = useRef(false);\n // biome-ignore lint/correctness/useExhaustiveDependencies: config is stable by construction; `enabled` is the only real change\n useEffect(() => {\n if (!productsMountedRef.current) {\n productsMountedRef.current = true;\n return;\n }\n instanceRef.current?.update({ products: productsProxy.config });\n }, [productsProxy.enabled]);\n\n // Single stable action surface. Built once via the useRef-with-null-init\n // pattern (the idiomatic \"create once, never recreate\" idiom in React — see\n // https://react.dev/reference/react/useRef). Every entry forwards to the\n // current core instance via `instanceRef.current` so the closure picks up\n // the live instance even though the actions object itself never changes.\n const actionsRef = useRef<CoreActions | null>(null);\n if (actionsRef.current === null) {\n actionsRef.current = {\n handleTextChange: (value) => instanceRef.current?.handleTextChange(value),\n handleKeyDown: (e) => {\n const native = \"nativeEvent\" in e ? e.nativeEvent : e;\n instanceRef.current?.handleKeyDown(native);\n },\n setFocused: (focused) => instanceRef.current?.setFocused(focused),\n startEditingParam: (paramId) => instanceRef.current?.startEditingParam(paramId),\n exitEditMode: () => instanceRef.current?.exitEditMode(),\n handleCaretAfterInput: (offset) => instanceRef.current?.handleCaretAfterInput(offset),\n handleCaretMove: (offset) => instanceRef.current?.handleCaretMove(offset),\n replaceEditingRange: (replacement) =>\n instanceRef.current?.replaceEditingRange(replacement) ?? false,\n setActivePill: (index) => instanceRef.current?.setActivePill(index),\n skipActivePill: () => instanceRef.current?.skipActivePill(),\n removeLastParam: () => instanceRef.current?.removeLastParam(),\n clearNewParamId: () => instanceRef.current?.clearNewParamId(),\n reset: () => instanceRef.current?.reset(),\n selectOption: (option) => instanceRef.current?.selectOption(option),\n selectProduct: (product) => instanceRef.current?.selectProduct(product),\n setActiveDropdownIndex: (index) => instanceRef.current?.setActiveDropdownIndex(index),\n showPreviousMonth: () => instanceRef.current?.showPreviousMonth(),\n showNextMonth: () => instanceRef.current?.showNextMonth(),\n handleFocus: () => instanceRef.current?.setFocused(true),\n handleBlur: () => instanceRef.current?.setFocused(false),\n };\n }\n const actions = actionsRef.current;\n\n // textarea-specific adapter — capitalizes the first character on first\n // keystroke. Kept separate from `actions.handleTextChange` because the\n // capitalization rule belongs to the textarea host, not the core.\n const handleChange = useCallback((e: ChangeEvent<HTMLTextAreaElement>) => {\n const raw = e.target.value;\n const shouldCapitalize =\n raw.length > 0 &&\n !(e.nativeEvent as InputEvent)?.isComposing &&\n raw[0] !== raw[0].toUpperCase();\n const newValue = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n instanceRef.current?.handleTextChange(newValue);\n }, []);\n\n const handleKeyDownTextarea = useCallback((e: KeyboardEvent<HTMLTextAreaElement>) => {\n instanceRef.current?.handleKeyDown(e.nativeEvent);\n }, []);\n\n // Snapshot the live instance + state for this render.\n const instance = instanceRef.current;\n const state = coreState ?? EMPTY_STATE;\n const text = controlledValue !== undefined ? controlledValue : state.text;\n const completedParams = controlledParams !== undefined ? controlledParams : state.completedParams;\n\n const actionableSuggestions = state.actionableSuggestions;\n const activeSuggestion: Suggestion | undefined = actionableSuggestions[0];\n const listboxId = instance?.listboxId ?? \"\";\n\n const activeDescendantId =\n state.activeDropdownIndex >= 0 && instance\n ? `${listboxId}-option-${state.activeDropdownIndex}`\n : undefined;\n\n // In re-edit mode, the dropdown's pill bar shows a synthetic pill built\n // from the edited param's cached suggestion metadata. The options grid\n // shows the cached options regardless of the latest server response.\n const editingParam = state.editingParam;\n const editingIdentified = state.editingIdentified;\n const dropdownPill: Suggestion | null = editingParam\n ? {\n type: editingParam.suggestionType,\n text: editingParam.suggestionPlaceholder,\n required: true,\n options: editingParam.options,\n }\n : editingIdentified\n ? // Answering a span the user wrote themselves: the pill names the\n // parameter the server matched it to, so the calendar isn't unlabelled.\n {\n type: editingIdentified.type,\n text: identifiedParamLabel(editingIdentified.type),\n required: true,\n options: [],\n }\n : null;\n const dropdownActivePill = dropdownPill ?? activeSuggestion;\n const dropdownPills = dropdownPill ? [dropdownPill] : actionableSuggestions;\n\n // UI-visible loading — suppressed during the post-select press animation\n // and during re-edit (cached options remain visible there). Pre-mount we\n // report loading=true so SSR / first-paint consumers render a skeleton\n // instead of a flash of blank content while the mount effect runs. An\n // `optionOverrides` entry still answering shows the skeleton in any mode —\n // its pill has nothing else to show yet.\n const uiLoading =\n !instance ||\n (state.isLoading && !state.editingParam && !state.inSelectionAnimation) ||\n state.isSearchingOptions;\n\n return {\n completedParams,\n skippedParams: state.skippedParams,\n identifiedParams: state.identifiedParams,\n suggestionPills: actionableSuggestions,\n setActivePill: actions.setActivePill,\n skipActivePill: actions.skipActivePill,\n removeLastParam: actions.removeLastParam,\n segments: state.segments,\n newParamId: state.newParamId,\n clearNewParamId: actions.clearNewParamId,\n suggestions: state.suggestions,\n activeIndex: state.activeDropdownIndex,\n isReady: state.isReady,\n isLoading: uiLoading,\n isFocused: state.isFocused,\n isDropdownOpen: state.isDropdownOpen,\n isActivePillSelected: state.isActivePillSelected,\n placeholderText: state.placeholderText,\n listboxId,\n error: state.error,\n products: state.products,\n selectProduct: actions.selectProduct,\n handleTextChange: actions.handleTextChange,\n handleKeyDown: actions.handleKeyDown,\n setFocused: actions.setFocused,\n editingParam,\n editingIdentified,\n editingAnchor: state.editingAnchor,\n caretOffset: state.caretOffset,\n startEditingParam: actions.startEditingParam,\n exitEditMode: actions.exitEditMode,\n handleCaretAfterInput: actions.handleCaretAfterInput,\n handleCaretMove: actions.handleCaretMove,\n replaceEditingRange: actions.replaceEditingRange,\n inputProps: {\n value: text,\n placeholder: state.placeholderText || undefined,\n onChange: handleChange,\n onKeyDown: handleKeyDownTextarea,\n onFocus: actions.handleFocus,\n onBlur: actions.handleBlur,\n role: \"combobox\" as const,\n \"aria-expanded\": state.isDropdownOpen,\n \"aria-activedescendant\": activeDescendantId,\n \"aria-autocomplete\": \"list\" as const,\n \"aria-controls\": listboxId,\n },\n reset: actions.reset,\n dropdownProps: {\n suggestions: dropdownActivePill\n ? [{ ...dropdownActivePill, options: state.filteredOptions }]\n : [],\n activeIndex: state.activeDropdownIndex,\n onSelect: actions.selectOption,\n onHighlight: actions.setActiveDropdownIndex,\n isOpen: state.isDropdownOpen,\n id: listboxId,\n pills: dropdownPills,\n activeSelected: state.isActivePillSelected,\n onPillClick: actions.setActivePill,\n onSkip: actions.skipActivePill,\n // Hidden while re-editing: the bar then shows the param being re-edited,\n // and an already answered param isn't skippable.\n showSkipButton: (showSkipButton ?? true) && !editingParam && !editingIdentified,\n // uiLoading is suppressed during the selection animation, but\n // skipActivePill no-ops in that window — mirror the guard visually.\n skipDisabled: state.inSelectionAnimation,\n isLoading: uiLoading,\n isInputEmpty: text.trim().length === 0,\n products: state.products,\n onProductSelect: actions.selectProduct,\n // A card taking focus blurs the input, which would otherwise close the\n // panel out from under the card the user just tabbed to.\n onProductFocusChange: actions.setFocused,\n // Datepicker. `filteredOptions` above already carries the visible month's\n // cells rather than the suggestion's own options when this is \"date\" —\n // the core swapped them in its derive layer, so the dropdown only has to\n // know which body to draw.\n formatType: state.activeFormatType,\n dateView: state.dateView,\n selectedDateIso: editingIdentified\n ? editingIdentified.iso\n : selectedIsoFromText(editingParam?.text),\n onPreviousMonth: actions.showPreviousMonth,\n onNextMonth: actions.showNextMonth,\n // Flow the configured position into the dropdown so a headless consumer\n // who spreads `dropdownProps` gets above/below placement + layout reversal\n // automatically — no wrapper attribute or hand-copied CSS required.\n optionsPosition: optionsPosition ?? \"below\",\n },\n };\n}\n","import type { OptionOverride, OptionOverrides } from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { useRef } from \"react\";\n\nexport interface OptionOverridesProxy {\n /**\n * Stable record to hand the core. Its identity changes only when the SET of\n * overridden types changes, so `update()` sees a swap — and re-asks the pill\n * on screen — for a real change, never for a re-render.\n */\n overrides: OptionOverrides | undefined;\n /** The overridden types, joined — the only change worth an `update()` call. */\n key: string;\n}\n\n/**\n * Forwards `optionOverrides` to the core through a **stable proxy**.\n *\n * Consumers write the record inline, so the object and every function in it\n * get a fresh identity on each render. Handing that to the core would look\n * like a swapped record on every render, and the core answers a swap by\n * abandoning the ask in flight and asking again — with an inline record that\n * is a re-ask per render, and each answer re-renders. So calls go through a\n * ref instead, exactly as the hook's `on*` callbacks and `products` do: the\n * function the core calls is always the latest one rendered.\n *\n * The proxy is rebuilt only when the set of types changes, which is the one\n * change the core has to hear about (a pill of a newly overridden type may be\n * on screen).\n */\nexport function useOptionOverridesProxy(\n optionOverrides: OptionOverrides | undefined,\n): OptionOverridesProxy {\n const liveRef = useRef(optionOverrides);\n liveRef.current = optionOverrides;\n\n const key = Object.keys(optionOverrides ?? {})\n .sort()\n .join(\"\\u0000\");\n const proxyRef = useRef<{ key: string; overrides: OptionOverrides | undefined }>({\n key: \"\\u0001\",\n overrides: undefined,\n });\n if (proxyRef.current.key !== key) {\n const overrides: OptionOverrides = {};\n for (const type of Object.keys(optionOverrides ?? {})) {\n const forward: OptionOverride = (query, signal, suggestion) => {\n const fn = liveRef.current?.[type];\n // Unreachable while the type is overridden; an empty answer keeps a\n // torn-down entry on the path the core already treats as \"no options\".\n return fn ? fn(query, signal, suggestion) : [];\n };\n overrides[type] = forward;\n }\n proxyRef.current = { key, overrides: optionOverrides ? overrides : undefined };\n }\n return { overrides: proxyRef.current.overrides, key };\n}\n","import type { ProductsConfig } from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { useRef } from \"react\";\n\nexport interface ProductsProxy {\n /**\n * Stable object to hand the core. Identity never changes for the lifetime of\n * the hook, so `update()` never mistakes a re-render for a swapped\n * integration. `undefined` while the consumer hasn't configured `products` —\n * the core must see exactly that to stay completely inert.\n */\n config: ProductsConfig | undefined;\n /**\n * Whether `products` is configured. The only products change worth an\n * `update()` call, and therefore the only sane effect dependency: everything\n * else is picked up live through the proxy.\n */\n enabled: boolean;\n}\n\n/**\n * Forwards a `products` config to the core through a **stable proxy**.\n *\n * Consumers write the config inline (`products={{ fetch, transform }}`), so the\n * object and its function members get a fresh identity on every render. Handing\n * that straight to the core would look like a swapped integration on each\n * keystroke and clear the strip — so calls are forwarded through a ref instead,\n * exactly as the hook's `on*` callbacks already are. `limit` is a **getter**\n * because it's a value rather than a function: without one it would freeze at\n * whatever the first render passed.\n *\n * Note the trade this makes deliberately: identity can no longer distinguish\n * \"same integration, new object literal\" from \"genuinely different\n * integration\", so swapping one live config for another does NOT clear the\n * previous integration's cards — they're replaced when the next request lands.\n * Documented on the `products` prop.\n */\nexport function useProductsProxy(products: ProductsConfig | undefined): ProductsProxy {\n const productsRef = useRef(products);\n productsRef.current = products;\n\n const proxyRef = useRef<ProductsConfig | null>(null);\n if (proxyRef.current === null) {\n proxyRef.current = {\n fetch: (query, signal) => {\n const config = productsRef.current;\n // Unreachable while configured; a rejected promise (rather than a\n // throw) keeps the failure on the path the core already treats as\n // \"silent failure\" if the config is torn down mid-flight.\n if (!config) return Promise.reject(new Error(\"products config removed\"));\n return config.fetch(query, signal);\n },\n transform: (raw) => productsRef.current?.transform(raw) ?? [],\n get limit() {\n return productsRef.current?.limit;\n },\n };\n }\n\n const enabled = products !== undefined;\n return { config: enabled ? proxyRef.current : undefined, enabled };\n}\n","import {\n type CompletedParamState,\n extractPlainText,\n getCursorOffset,\n plainTextLength,\n renderEditableContent,\n type Segment,\n setCursorOffset,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport {\n type ClipboardEvent as ReactClipboardEvent,\n type KeyboardEvent as ReactKeyboardEvent,\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n} from \"react\";\n\nlet plaintextOnlyCache: boolean | undefined;\nfunction supportsPlaintextOnly(): boolean {\n if (plaintextOnlyCache !== undefined) return plaintextOnlyCache;\n if (typeof document === \"undefined\") return false;\n const probe = document.createElement(\"div\");\n probe.setAttribute(\"contenteditable\", \"plaintext-only\");\n plaintextOnlyCache = probe.contentEditable === \"plaintext-only\";\n return plaintextOnlyCache;\n}\n\nexport interface UseContentEditableEditorOptions {\n /** Derived segments (text + bold completed-param runs) for the editor body. */\n segments: readonly Segment[];\n /** The most recently promoted param — shimmer + post-promote refocus key. */\n newParamId: string | null;\n /** The bold param currently being re-edited (or null). */\n editingParam: CompletedParamState | null;\n /** Set while picking a date for a span the server identified as one. */\n editingIdentified: { id: string } | null;\n /** Plain-text offset where re-edit started; caret parks here on entry. */\n editingAnchor: number | null;\n /** Live caret offset within the editor, used by post-promote refocus. */\n caretOffset: number | null;\n /** Server-suggested placeholder (rendered via ::before when empty). */\n placeholderText: string;\n /** Whether the editor currently has focus — passes through to segment renderer. */\n isFocused: boolean;\n /** ARIA `aria-expanded` value for the input. */\n isDropdownOpen: boolean;\n /** ARIA `aria-controls` value pointing at the listbox. */\n listboxId: string;\n /** ARIA `aria-activedescendant` value pointing at the highlighted option (or undefined). */\n activeDescendantId: string | undefined;\n /** Focus the editor on mount (Tier 1 default). */\n autoFocus: boolean;\n /** Forwarded to the core whenever the plain-text content changes. */\n handleTextChange: (value: string) => void;\n /** Forwarded to the core for keyboard handling. */\n handleKeyDown: (e: ReactKeyboardEvent<HTMLElement> | globalThis.KeyboardEvent) => void;\n /** Forwarded to the core after each input event (extends edit tail, etc.). */\n handleCaretAfterInput: (offset: number | null) => void;\n /** Forwarded to the core on selectionchange (exits re-edit when caret leaves). */\n handleCaretMove: (offset: number | null) => void;\n /** Forwarded to the core when the caret lands inside a bold param's strong. */\n startEditingParam: (id: string) => void;\n /** Forwarded to the core during a `beforeinput` — atomic re-edit replacement. */\n replaceEditingRange: (replacement: string) => boolean;\n /** Forwarded to the core on native focus/blur. */\n setFocused: (focused: boolean) => void;\n}\n\nexport interface UseContentEditableEditorReturn {\n inputRef: React.RefObject<HTMLDivElement>;\n // Spread onto the contentEditable element; consumer supplies className.\n editorProps: {\n ref: React.RefObject<HTMLDivElement>;\n contentEditable: boolean;\n suppressContentEditableWarning: true;\n tabIndex: 0;\n role: \"combobox\";\n \"aria-autocomplete\": \"list\";\n \"aria-haspopup\": \"listbox\";\n \"aria-controls\": string;\n \"aria-expanded\": boolean;\n \"aria-activedescendant\": string | undefined;\n spellCheck: true;\n enterKeyHint: \"send\";\n onInput: () => void;\n onKeyDown: (e: ReactKeyboardEvent<HTMLDivElement>) => void;\n onCompositionStart: () => void;\n onCompositionEnd: () => void;\n onPaste: (e: ReactClipboardEvent<HTMLDivElement>) => void;\n onFocus: () => void;\n onBlur: () => void;\n };\n /** Current plain-text content of the editor (used by submit). */\n getPlainText: () => string;\n /** Imperative focus / blur (used by the parent's imperative handle). */\n focus: () => void;\n blur: () => void;\n}\n\n/**\n * Owns every concern that's specific to running the autocomplete on top of a\n * contentEditable host: composition state, caret tracking, selectionchange,\n * `beforeinput` interception, paste sanitization, plaintext-only feature\n * detection, segment rendering, post-promote refocus, and re-edit caret park.\n *\n * The hook stays React-agnostic above the contentEditable adapter — see\n * `core/render/renderEditable.ts` for the underlying DOM mutations. Callers\n * spread `editorProps` onto a `<div>` (className is theirs to provide).\n */\nexport function useContentEditableEditor(\n opts: UseContentEditableEditorOptions,\n): UseContentEditableEditorReturn {\n const {\n segments,\n newParamId,\n editingParam,\n editingIdentified,\n editingAnchor,\n caretOffset,\n placeholderText,\n isFocused,\n isDropdownOpen,\n listboxId,\n activeDescendantId,\n autoFocus,\n handleTextChange,\n handleKeyDown,\n handleCaretAfterInput,\n handleCaretMove,\n startEditingParam,\n replaceEditingRange,\n setFocused,\n } = opts;\n\n const inputRef = useRef<HTMLDivElement>(null);\n const composingRef = useRef(false);\n const lastSeenParamIdRef = useRef(\"\");\n const lastEditingIdRef = useRef(\"\");\n const caretOffsetRef = useRef<number | null>(null);\n // Set in the input event handler; selectionchange suppresses post-input\n // caret-move tracking within this window so typing doesn't get treated\n // as navigation.\n const lastInputAtRef = useRef(0);\n\n caretOffsetRef.current = caretOffset;\n\n // Auto-focus on mount once the host element is mounted.\n useEffect(() => {\n if (!autoFocus) return;\n const el = inputRef.current;\n if (!el) return;\n if (document.activeElement === el) {\n setFocused(true);\n } else {\n el.focus();\n }\n // Focusing an empty contentEditable doesn't always create a selection\n // Range, so no caret blinks until the user clicks. Place a collapsed caret\n // at the start so the field is visibly ready immediately. Skip if the caret\n // already sits inside the editor (e.g. the user clicked before this ran).\n const doc = el.ownerDocument ?? document;\n const sel = doc.getSelection();\n const caretInside = sel && sel.rangeCount > 0 && el.contains(sel.anchorNode);\n if (sel && !caretInside) {\n const range = doc.createRange();\n range.selectNodeContents(el);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n }\n }, [autoFocus, setFocused]);\n\n // `selectionchange` is the canonical signal for \"caret moved\" in\n // contentEditable land. Anchored inside the editor: a caret that lands\n // inside a `<strong>` triggers re-edit mode; a caret that leaves the\n // current editing region exits it.\n useEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n const doc = el.ownerDocument ?? document;\n const onSelectionChange = () => {\n const sel = doc.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n if (!sel.anchorNode || !el.contains(sel.anchorNode)) return;\n const anchor = sel.anchorNode;\n const startEl =\n anchor.nodeType === Node.ELEMENT_NODE ? (anchor as Element) : anchor.parentElement;\n // Only a COLLAPSED selection means \"the caret landed in a chip\". A range\n // selection (Cmd+A, shift-arrow, drag) anchors at its start, which lands\n // inside the first `<strong>` whenever the input begins with a chip —\n // starting re-edit there parks the caret on that chip and destroys the\n // user's selection.\n const strong = sel.isCollapsed\n ? // Both chip kinds report here. The core decides what a tap means — a\n // completed param re-opens its options, an identified date opens the\n // calendar, anything else is inert.\n startEl?.closest<HTMLElement>(\"strong[data-param-id]\")\n : null;\n const enclosing = strong?.dataset.paramId ?? null;\n // Either kind counts as \"already open on this chip\" — without the\n // identified id here, every caret tick inside a date span would re-enter\n // the pick it is already in.\n const openChipId = editingParam?.id ?? editingIdentified?.id ?? null;\n if (enclosing && enclosing !== openChipId) {\n startEditingParam(enclosing);\n return;\n }\n if (performance.now() - lastInputAtRef.current < 50) return;\n handleCaretMove(getCursorOffset(el));\n };\n doc.addEventListener(\"selectionchange\", onSelectionChange);\n return () => doc.removeEventListener(\"selectionchange\", onSelectionChange);\n }, [editingParam, editingIdentified, startEditingParam, handleCaretMove]);\n\n // Render segments imperatively into the contentEditable. useLayoutEffect\n // runs before paint so the caret is restored without a one-frame flicker.\n // MUST run before the post-promote refocus + re-edit caret park effects\n // below — keep this declaration order.\n useLayoutEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n renderEditableContent({\n input: el,\n segments: segments as Segment[],\n newParamId,\n editingParamId: editingParam?.id ?? null,\n placeholderText: placeholderText ?? \"\",\n isFocused,\n });\n }, [segments, newParamId, editingParam, placeholderText, isFocused]);\n\n // After a fresh option selection (newParamId changed), refocus the editor\n // and place the caret at the end of the just-promoted segment. Mirrors the\n // vanilla core's `justSelected` logic in renderInput.ts.\n useLayoutEffect(() => {\n const previous = lastSeenParamIdRef.current;\n const current = newParamId ?? \"\";\n lastSeenParamIdRef.current = current;\n if (!current || current === previous) return;\n const el = inputRef.current;\n if (!el) return;\n el.focus();\n // Every promote path stamps `caretOffset` with the position right after\n // the new param's trailing space, so use it. Read via ref so the effect\n // stays gated on newParamId (not every caret-move).\n const desired = caretOffsetRef.current ?? plainTextLength(el);\n setCursorOffset(el, desired);\n }, [newParamId]);\n\n // On re-edit-mode entry, park the caret just BEFORE the bold strong so\n // typing/backspace via the `beforeinput` intercept replaces the param\n // cleanly (instead of inserting mid-letter inside the bold span).\n useLayoutEffect(() => {\n const previous = lastEditingIdRef.current;\n const current = editingParam?.id ?? \"\";\n lastEditingIdRef.current = current;\n if (!current || current === previous || editingAnchor == null) return;\n const el = inputRef.current;\n if (!el) return;\n setCursorOffset(el, editingAnchor);\n }, [editingParam, editingAnchor]);\n\n const fireInput = useCallback(() => {\n if (composingRef.current) return;\n const el = inputRef.current;\n if (!el) return;\n const raw = extractPlainText(el);\n const shouldCapitalize = raw.length > 0 && raw[0] !== raw[0].toUpperCase();\n const next = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n handleTextChange(next);\n }, [handleTextChange]);\n\n const handleInputEvent = useCallback(() => {\n lastInputAtRef.current = performance.now();\n fireInput();\n const el = inputRef.current;\n if (el) handleCaretAfterInput(getCursorOffset(el));\n }, [fireInput, handleCaretAfterInput]);\n\n // React's synthetic `onBeforeInput` is wired to the legacy `textInput`\n // event and doesn't reliably fire for `delete*` input types, so we attach\n // a native `beforeinput` listener directly on the editor.\n useEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n const onBeforeInput = (e: Event) => {\n const inputEvent = e as InputEvent;\n const t = inputEvent.inputType;\n if (t === \"insertParagraph\" || t === \"insertLineBreak\" || t === \"insertFromDrop\") {\n e.preventDefault();\n return;\n }\n if (t.startsWith(\"insert\") || t.startsWith(\"delete\")) {\n const replacement = t.startsWith(\"delete\") ? \"\" : (inputEvent.data ?? \"\");\n if (replaceEditingRange(replacement)) {\n e.preventDefault();\n }\n }\n };\n el.addEventListener(\"beforeinput\", onBeforeInput);\n return () => el.removeEventListener(\"beforeinput\", onBeforeInput);\n }, [replaceEditingRange]);\n\n const handleCompositionStart = useCallback(() => {\n composingRef.current = true;\n }, []);\n\n const handleCompositionEnd = useCallback(() => {\n composingRef.current = false;\n fireInput();\n }, [fireInput]);\n\n const handlePaste = useCallback(\n (e: ReactClipboardEvent<HTMLDivElement>) => {\n e.preventDefault();\n const el = inputRef.current;\n if (!el) return;\n const text = (e.clipboardData.getData(\"text/plain\") ?? \"\").replace(/\\r?\\n/g, \" \");\n if (!text) return;\n const doc = el.ownerDocument ?? document;\n const sel = doc.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n if (!el.contains(range.startContainer)) return;\n range.deleteContents();\n const node = doc.createTextNode(text);\n range.insertNode(node);\n range.setStartAfter(node);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n fireInput();\n },\n [fireInput],\n );\n\n const handleKeyDownReact = useCallback(\n (e: ReactKeyboardEvent<HTMLDivElement>) => handleKeyDown(e),\n [handleKeyDown],\n );\n\n const handleFocus = useCallback(() => setFocused(true), [setFocused]);\n const handleBlur = useCallback(() => setFocused(false), [setFocused]);\n\n const focus = useCallback(() => inputRef.current?.focus(), []);\n const blur = useCallback(() => inputRef.current?.blur(), []);\n const getPlainText = useCallback(() => {\n const el = inputRef.current;\n return el ? extractPlainText(el) : \"\";\n }, []);\n\n const ceMode = supportsPlaintextOnly() ? \"plaintext-only\" : \"true\";\n\n return {\n inputRef,\n editorProps: {\n ref: inputRef,\n contentEditable: ceMode as unknown as boolean,\n suppressContentEditableWarning: true,\n tabIndex: 0,\n role: \"combobox\",\n \"aria-autocomplete\": \"list\",\n \"aria-haspopup\": \"listbox\",\n \"aria-controls\": listboxId,\n \"aria-expanded\": isDropdownOpen,\n \"aria-activedescendant\": activeDescendantId,\n spellCheck: true,\n enterKeyHint: \"send\",\n onInput: handleInputEvent,\n onKeyDown: handleKeyDownReact,\n onCompositionStart: handleCompositionStart,\n onCompositionEnd: handleCompositionEnd,\n onPaste: handlePaste,\n onFocus: handleFocus,\n onBlur: handleBlur,\n },\n getPlainText,\n focus,\n blur,\n };\n}\n"],"mappings":"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","names":["index_exports","__export","AIAutocomplete","AIAutocompleteDropdown","useAIAutocomplete","__toCommonJS","import_ai_autocomplete_vanilla","import_react","s","AIAutocomplete_module_css_default","import_ai_autocomplete_vanilla","import_react","s","s","AIAutocompleteDropdown_module_css_default","import_ai_autocomplete_vanilla","import_react","s","DateGrid_module_css_default","import_jsx_runtime","WEEKDAY_KEYS","DateGrid","options","activeIndex","listboxId","view","selectedIso","onSelect","onHighlight","onPreviousMonth","onNextMonth","today","DateGrid_module_css_default","e","label","i","option","DateCell","id","index","isHighlighted","isToday","isPast","isSelected","pressed","setPressed","day","handleSelect","className","import_ai_autocomplete_vanilla","import_react","s","import_jsx_runtime","Cluster","gap","align","justify","noWrap","inline","className","children","rest","style","props","s","DropdownFooter_module_css_default","import_jsx_runtime","DropdownFooter","isOptionHighlighted","isInputEmpty","key","hint","brandHref","setBrandHref","DropdownFooter_module_css_default","Cluster","s","ParamPill_module_css_default","import_jsx_runtime","PARAM_PILL_OPACITY","ParamPill","label","state","rounded","loading","onClick","className","ParamPill_module_css_default","e","s","PillList_module_css_default","import_jsx_runtime","FALLBACK_SKELETON_WIDTHS","pillStateForIndex","index","PillList","pills","activePillIndex","onSelectPill","activeSelected","rounded","loading","PillList_module_css_default","w","i","ParamPill_module_css_default","PARAM_PILL_OPACITY","pill","selected","ParamPill","s","ProductStrip_module_css_default","import_jsx_runtime","ProductStrip","products","listboxId","onSelect","onFocusChange","focusable","labelId","ProductStrip_module_css_default","product","i","ProductCard","id","handleClick","e","import_ai_autocomplete_vanilla","import_react","import_ai_autocomplete_vanilla","import_react","s","import_jsx_runtime","Grid","min","max","gap","scroll","maxHeight","scrollResetKey","cols","template","innerRef","className","children","rest","gridRef","el","style","import_ai_autocomplete_vanilla","import_react","s","SuggestionItem_module_css_default","import_jsx_runtime","SuggestionItem","option","isHighlighted","onSelect","onHighlight","id","loading","scrollHint","enterDelayMs","enterDelay","pressed","setPressed","timerRef","handleSelect","className","SuggestionItem_module_css_default","e","import_jsx_runtime","useIsMobile","isMobile","setIsMobile","mq","onChange","SuggestionGrid","options","activeIndex","onSelect","onHighlight","listboxId","loading","groupKey","optionsPosition","gridEl","measuredPlan","setMeasuredPlan","el","measured","plan","Grid","option","i","SuggestionItem","s","import_jsx_runtime","Stack","space","align","className","children","rest","style","import_jsx_runtime","FALLBACK_SKELETON_BAR_WIDTHS","NOOP_PRODUCT_SELECT","NOOP_MONTH","useResolvedMode","mode","prefersDark","systemDark","setSystemDark","mq","onChange","useScrollArrow","rootRef","buttonRef","boundRef","root","button","grid","AIAutocompleteDropdown","suggestions","activeIndex","onSelect","onHighlight","isOpen","id","className","pills","onPillClick","showPills","onSkip","showSkipButton","skipDisabled","activeSelected","isLoading","isInputEmpty","products","onProductSelect","onProductFocusChange","formatType","dateView","selectedDateIso","onPreviousMonth","onNextMonth","optionsPosition","resolvedMode","selfScope","scrollArrowRef","liveOptions","liveHasRealPills","liveHasProducts","isVisible","snapshot","lastVisibleRef","content","activeSuggestion","options","isOptionHighlighted","hasRealPills","showsRealPills","showsLoadingPills","showsPillBar","showsSkip","activePillLabel","isDate","showsOptions","showsDateGrid","showsFallbackSkeleton","stripProducts","AIAutocompleteDropdown_module_css_default","e","Stack","Cluster","PillList","SuggestionGrid","DateGrid","w","ProductStrip","DropdownFooter","import_ai_autocomplete_vanilla","s","SubmitButton_module_css_default","import_jsx_runtime","SubmitButton","disabled","onClick","SubmitButton_module_css_default","e","import_ai_autocomplete_vanilla","import_react","import_react","useOptionOverridesProxy","optionOverrides","liveRef","key","proxyRef","overrides","type","forward","query","signal","suggestion","fn","import_react","useProductsProxy","products","productsRef","proxyRef","query","signal","config","raw","enabled","EMPTY_STATE","useAIAutocomplete","onSubmit","onResult","onError","optionOverrides","maskCompletedText","apiConfig","additionalContext","columns","dropdownTrigger","optionsPosition","closeDropdownOnBlur","showNonTappableOptions","showSkipButton","onFocus","onBlur","controlledValue","controlledParams","onChangeProp","onParamsChange","products","onProductSelect","source","setCursor","instanceRef","coreState","setCoreState","onSubmitRef","onResultRef","onErrorRef","onChangeRef","onParamsChangeRef","onFocusRef","onBlurRef","setCursorRef","onProductSelectRef","productsProxy","useProductsProxy","overridesProxy","useOptionOverridesProxy","instance","CoreAIAutocomplete","args","product","offset","unsub","state","apiConfigJson","additionalContextJson","productsMountedRef","actionsRef","value","e","native","focused","paramId","replacement","index","option","actions","handleChange","raw","newValue","handleKeyDownTextarea","text","completedParams","actionableSuggestions","activeSuggestion","listboxId","activeDescendantId","editingParam","editingIdentified","dropdownPill","dropdownActivePill","dropdownPills","uiLoading","import_ai_autocomplete_vanilla","import_react","plaintextOnlyCache","supportsPlaintextOnly","probe","useContentEditableEditor","opts","segments","newParamId","editingParam","editingIdentified","editingAnchor","caretOffset","placeholderText","isFocused","isDropdownOpen","listboxId","activeDescendantId","autoFocus","handleTextChange","handleKeyDown","handleCaretAfterInput","handleCaretMove","startEditingParam","replaceEditingRange","setFocused","inputRef","composingRef","lastSeenParamIdRef","lastEditingIdRef","caretOffsetRef","lastInputAtRef","el","doc","sel","caretInside","range","onSelectionChange","anchor","startEl","enclosing","openChipId","previous","current","desired","fireInput","raw","next","handleInputEvent","onBeforeInput","e","inputEvent","t","replacement","handleCompositionStart","handleCompositionEnd","handlePaste","text","node","handleKeyDownReact","handleFocus","handleBlur","focus","blur","getPlainText","ceMode","import_jsx_runtime","resolveInitialMode","mode","AIAutocomplete","onSubmit","onResult","onError","optionOverrides","maskCompletedText","className","apiConfig","additionalContext","columns","pillPlacement","optionsPosition","animations","dropdownTrigger","closeDropdownOnBlur","showNonTappableOptions","showSkipButton","autoFocus","onFocus","onBlur","value","controlledParams","onChangeProp","onParamsChange","products","onProductSelect","submitButton","ref","containerRef","pillContainerRef","handleSubmitRef","modeControllerRef","editorInputRefHolder","el","handleSetCursor","offset","completedParams","skippedParams","identifiedParams","isReady","suggestionPills","setActivePill","skipActivePill","segments","newParamId","clearNewParamId","placeholderText","isFocused","isDropdownOpen","isActivePillSelected","isLoading","activeIndex","listboxId","handleTextChange","handleKeyDown","setFocused","editingParam","editingIdentified","editingAnchor","caretOffset","startEditingParam","handleCaretAfterInput","handleCaretMove","replaceEditingRange","dropdownProps","reset","useAIAutocomplete","result","t","activeDescendantId","inputRef","editorProps","focus","blur","getPlainText","useContentEditableEditor","container","editor","update","inner","cRect","eRect","ro","m","canSubmit","handleSubmit","text","handleWrapperClick","e","showInlinePills","showDropdownPills","AIAutocomplete_module_css_default","AIAutocompleteDropdown","PillList","SubmitButton"]}