WidgetPosition (default bottom-right). Color from PrimaryColor. The unread badge shows when the bot has proactively pinged the user (v1.1).WelcomeMessage. Quick-reply chips are derived from top FAQ topics indexed in the KB (v1.1 — static fallback for v1.0). Typing indicator shows while SSE stream from /AiChatBot/Send is opening.WidgetPosition setting.env(safe-area-inset-bottom) on the input bar.AiChatBotViewComponent outputs the PublicInfo.cshtml partial inside a widget zone (likely body_end_html_tag_before). The partial reads runtime settings from the controller and emits the launcher + chat panel HTML scoped under a single root element.--bot-primary: @Model.PrimaryColor;) so it doesn't need a build step. Avatar gradient uses color-mix(in srgb, var(--bot-primary) 92%, black).WidgetPosition ∈ {bottom-right, bottom-left, top-right, top-left} maps to CSS classes .pos-br, .pos-bl, etc. Default bottom-right./AiChatBot/Send with { sessionGuid, message } returns an SSE stream (token-by-token). Existing AiChatBotPublicController + ChatRequestModel/ChatResponseModel covers this; add streaming response shape if not present.sessionGuid persisted in localStorage (key ai-chatbot-session) so refreshes preserve history. Server-side history truncated to MaxHistoryTurns pairs.sources: [{ url, title, contentType }]. Shown collapsed by default; expanded on click.product (AiChatBotDefaults.ContentTypes.Product), enrich the response with thumbnail + price + product URL from the chunk metadata. Falls back to a plain text source if metadata is missing.role="dialog" aria-modal="false" aria-label="Store Assistant chat". Launcher is a button with aria-expanded. Messages list is role="log" aria-live="polite"./AiChatBot/Feedback; proactive prompts after N seconds idle on a product page; "Email me this conversation" CTA.