@syntrologie/adapt-chatbot 2.8.0-canary.406 → 2.8.0-canary.408

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.
@@ -1 +1 @@
1
- {"version":3,"file":"AdaptiveChatBar.d.ts","sourceRoot":"","sources":["../src/AdaptiveChatBar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAQ,UAAU,EAAW,MAAM,KAAK,CAAC;AAGhD,OAAO,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAM3F,qBAAa,eAAgB,SAAQ,UAAU;IAC7C,OAAgB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAaxB;IAEF,QAAQ,EAAE,YAAY,EAAE,CAAM;IAC9B,SAAS,UAAS;IAClB,YAAY,EAAE,WAAW,EAAE,CAAM;IACjC;yEACqE;IACrE,aAAa,EAAE,iBAAiB,EAAE,CAAM;IAExC;;;;;;;OAOG;IACH,YAAY,SAAM;IAClB;;;;;OAKG;IACH,eAAe,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAa;IAE3E;;;uDAGmD;IACnD,aAAa,UAAS;IACtB,WAAW,SAAuB;IAClC;;;;;OAKG;IACH,aAAa,SAA0B;IACvC;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAa;IACzC;;;;;;OAMG;IACH,QAAQ,UAAS;IACjB,MAAM,SAAM;IAEH,gBAAgB,IAAI,WAAW;IAI/B,iBAAiB,IAAI,IAAI;IASzB,oBAAoB,IAAI,IAAI;IAYrC,OAAO,CAAC,QAAQ,CAEd;IAEF,OAAO,CAAC,UAAU,CAShB;IAKF,OAAO,CAAC,kBAAkB,CAMxB;IAEF,OAAO,CAAC,sBAAsB,CAM5B;IAEF,OAAO,CAAC,uBAAuB,CAK7B;IAEF,OAAO,CAAC,iBAAiB,CAEvB;IAEF,OAAO,CAAC,KAAK;IAoBb;;;;;;;OAOG;IACH,OAAO,CAAC,kBAAkB,CAmBxB;IAEF;;;;;;;OAOG;IACH,OAAO,CAAC,iBAAiB,CAiBvB;IAEO,MAAM;CAiDhB;AA2PD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,mBAAmB,EAAE,eAAe,CAAC;KACtC;CACF"}
1
+ {"version":3,"file":"AdaptiveChatBar.d.ts","sourceRoot":"","sources":["../src/AdaptiveChatBar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAQ,UAAU,EAAW,MAAM,KAAK,CAAC;AAGhD,OAAO,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAM3F,qBAAa,eAAgB,SAAQ,UAAU;IAC7C,OAAgB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAaxB;IAEF,QAAQ,EAAE,YAAY,EAAE,CAAM;IAC9B,SAAS,UAAS;IAClB,YAAY,EAAE,WAAW,EAAE,CAAM;IACjC;yEACqE;IACrE,aAAa,EAAE,iBAAiB,EAAE,CAAM;IAExC;;;;;;;OAOG;IACH,YAAY,SAAM;IAClB;;;;;OAKG;IACH,eAAe,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAa;IAE3E;;;uDAGmD;IACnD,aAAa,UAAS;IACtB,WAAW,SAAuB;IAClC;;;;;OAKG;IACH,aAAa,SAA0B;IACvC;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAa;IACzC;;;;;;OAMG;IACH,QAAQ,UAAS;IACjB,MAAM,SAAM;IAEH,gBAAgB,IAAI,WAAW;IAI/B,iBAAiB,IAAI,IAAI;IASzB,oBAAoB,IAAI,IAAI;IAYrC,OAAO,CAAC,QAAQ,CAEd;IAEF,OAAO,CAAC,UAAU,CAShB;IAKF,OAAO,CAAC,kBAAkB,CAMxB;IAEF,OAAO,CAAC,sBAAsB,CAM5B;IAEF,OAAO,CAAC,uBAAuB,CAK7B;IAEF,OAAO,CAAC,iBAAiB,CAEvB;IAEF,OAAO,CAAC,KAAK;IAoBb;;;;;;;OAOG;IACH,OAAO,CAAC,kBAAkB,CAmBxB;IAEF;;;;;;;OAOG;IACH,OAAO,CAAC,iBAAiB,CAiBvB;IAEO,MAAM;CAiDhB;AA8OD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,mBAAmB,EAAE,eAAe,CAAC;KACtC;CACF"}
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  AdaptiveChatBar
3
- } from "./chunk-G2DSOWTP.js";
3
+ } from "./chunk-L3LR2J3L.js";
4
4
  import "./chunk-EWPPVPJ4.js";
5
- import "./chunk-ZPN3HRYX.js";
5
+ import "./chunk-NWSIOIQ3.js";
6
6
  import "./chunk-5PW6T3QF.js";
7
7
  import "./chunk-UVKRO5ER.js";
8
8
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"AdaptiveChatTrail.d.ts","sourceRoot":"","sources":["../src/AdaptiveChatTrail.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"AdaptiveChatTrail.d.ts","sourceRoot":"","sources":["../src/AdaptiveChatTrail.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  AdaptiveChatTrail,
3
3
  looksLikeSerializedModelResponse
4
- } from "./chunk-ZPN3HRYX.js";
4
+ } from "./chunk-NWSIOIQ3.js";
5
5
  import "./chunk-5PW6T3QF.js";
6
6
  import "./chunk-UVKRO5ER.js";
7
7
  export {
@@ -270,14 +270,20 @@ function rootStyles(forceExpanded) {
270
270
  color: "var(--sc-tile-title-color, inherit)",
271
271
  fontFamily: "var(--sc-font-family, inherit)",
272
272
  // Override the trail's host-layout tokens so the trail (a flex item
273
- // of this column) shrinks to 0 first when space is tight — letting
274
- // the header and absolute-positioned input pill stay pinned. The
275
- // SDK-level rule in SmartCanvasElementLit consumes these tokens on
273
+ // of this column) fills a definite-height parent AND contributes its
274
+ // content height in an indefinite one. basis AUTO (not 0) is
275
+ // load-bearing: grow:1 still fills a full-screen panel, but basis auto
276
+ // also lets the trail's content height propagate up the fill chain so a
277
+ // SHRINK-WRAP host (velvet's bottom sheet) hugs the content with no void.
278
+ // A basis-0 layer anywhere in the chain reports 0 min-content and
279
+ // collapses the sheet to header+input. shrink:1 + min-height:0 still lets
280
+ // the trail yield first when space is tight (input is absolute-pinned).
281
+ // The SDK-level rule in SmartCanvasElementLit consumes these tokens on
276
282
  // adaptive-chat-trail's host element. Containers OWN host styling
277
283
  // via tokens; the adaptive never sets inline styles on its host.
278
284
  ["--sc-chat-trail-host-display"]: "flex",
279
285
  ["--sc-chat-trail-host-flex-direction"]: "column",
280
- ["--sc-chat-trail-host-flex"]: "1 1 0",
286
+ ["--sc-chat-trail-host-flex"]: "1 1 auto",
281
287
  ["--sc-chat-trail-host-min-height"]: "0",
282
288
  ["--sc-chat-trail-host-overflow"]: "hidden"
283
289
  };
@@ -398,30 +404,10 @@ function renderHeader(assistantName) {
398
404
  lineHeight: "1.2",
399
405
  flexShrink: "0"
400
406
  };
401
- const statusDot = {
402
- width: "6px",
403
- height: "6px",
404
- borderRadius: "9999px",
405
- background: "var(--sc-tile-title-color, #3d8275)",
406
- display: "inline-block",
407
- flexShrink: "0"
408
- };
409
- const status = {
410
- fontSize: "0.68rem",
411
- color: "var(--sc-tile-title-color, #3d8275)",
412
- lineHeight: "1.2",
413
- // Ellipsize on narrow surfaces instead of wrapping to a second line.
414
- whiteSpace: "nowrap",
415
- overflow: "hidden",
416
- textOverflow: "ellipsis",
417
- minWidth: "0"
418
- };
419
407
  return html`
420
408
  <div style=${styleMap(headerStyles)} data-chat-header>
421
409
  <span style=${styleMap(avatar)} aria-hidden="true">✦</span>
422
410
  <span style=${styleMap(name)}>${assistantName}</span>
423
- <span style=${styleMap(statusDot)} aria-hidden="true"></span>
424
- <span style=${styleMap(status)}>Online · understands your session</span>
425
411
  </div>
426
412
  `;
427
413
  }
@@ -432,4 +418,4 @@ if (!customElements.get("adaptive-chat-bar")) {
432
418
  export {
433
419
  AdaptiveChatBar
434
420
  };
435
- //# sourceMappingURL=chunk-G2DSOWTP.js.map
421
+ //# sourceMappingURL=chunk-L3LR2J3L.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/AdaptiveChatBar.ts"],
4
- "sourcesContent": ["/**\n * AdaptiveChatBar \u2014 the canvas lid composition for the chat-canvas\n * experience. Renders the bubble-up trail on top and an always-visible\n * input row below.\n *\n * Wiring contract (events out):\n * - `chat-message-sent` ({ text }): the user submitted text via Enter\n * or the send button. The owning code is responsible for pushing\n * this into the conversation history and producing a reply.\n *\n * Wiring contract (props in):\n * - `messages`: the conversation trail, passed straight through to\n * `<adaptive-chat-trail>`.\n * - `placeholder`: input placeholder copy. Defaults to a generic\n * \"Ask, find, or navigate\u2026\" \u2014 the host (typically the slot's lid\n * widget mount) can override to a context-specific string.\n *\n * Light DOM. Glassmorphism is applied at the input-row level so the\n * trail above floats over the host page without chrome. See PRD \u00A74.4.\n */\n\nimport { html, LitElement, nothing } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\n\nimport './AdaptiveChatTrail.js';\nimport type { InlineTrailWidget, TileReceipt, TrailMessage } from './AdaptiveChatTrail.js';\nimport { getElementInstanceStore } from './elements/store-singleton.js';\n\nconst DEFAULT_PLACEHOLDER = 'Ask, find, or navigate\u2026';\nconst DEFAULT_ASSISTANT_NAME = 'Assistant';\n\nexport class AdaptiveChatBar extends LitElement {\n static override properties = {\n messages: { attribute: false },\n placeholder: { type: String },\n assistantName: { type: String },\n greeting: { type: String },\n inFlight: { type: Boolean, reflect: true },\n thinkingText: { attribute: false },\n introSuggestion: { attribute: false },\n forceExpanded: { type: Boolean, reflect: true },\n maximized: { type: Boolean },\n tileReceipts: { attribute: false },\n inlineWidgets: { attribute: false },\n _input: { state: true },\n };\n\n messages: TrailMessage[] = [];\n maximized = false;\n tileReceipts: TileReceipt[] = [];\n /** Widgets rendered inline in the trail (reco carousel), sourced from\n * the store's `chat-inline` slot mounts. Forwarded to the trail. */\n inlineWidgets: InlineTrailWidget[] = [];\n\n /**\n * Live reasoning narration from the model \u2014 streamed in via\n * AG-UI THINKING_TEXT_MESSAGE_CONTENT events and forwarded by\n * the ChatSession subscription on the host (mountable).\n * Forwarded verbatim to the trail, which renders it in place of\n * the silent loading dots between turns. Empty string when no\n * thinking turn is active.\n */\n thinkingText = '';\n /**\n * Pre-conversation suggestion button \u2014 forwarded to the trail's\n * empty-state pane. When the visitor clicks it the trail emits\n * `trail-intro-suggestion`; we catch that here and submit the\n * configured prompt through the normal send path.\n */\n introSuggestion: { label: string; prompt: string } | undefined = undefined;\n\n /** Pass-through to {@link AdaptiveChatTrail}'s ``forceExpanded`` prop.\n * Hosts that mount the chat-bar in a full-screen surface (mobile\n * panel, agent app, etc.) set this to skip the collapse affordance\n * \u2014 there is no smaller state to fall back to. */\n forceExpanded = false;\n placeholder = DEFAULT_PLACEHOLDER;\n /**\n * Name shown in the (forceExpanded) header. Defaults to a generic\n * \"Assistant\". Hosts can override per-workspace (e.g. Vela sets\n * \"Vela Concierge\") without inventing new SDK surface \u2014 it threads\n * through the same mount config the placeholder does.\n */\n assistantName = DEFAULT_ASSISTANT_NAME;\n /**\n * Initial assistant message shown before any real conversation\n * starts. Renders inside the trail as a phantom assistant chip\n * when messages.length === 0; auto-disappears as soon as the\n * first user message lands. Mirrors ChatAssistantLit's greeting.\n */\n greeting: string | undefined = undefined;\n /**\n * Whether a chat round-trip is in flight (request sent, awaiting\n * reply). The single send/stop button morphs accordingly: \u2191 when\n * ready, \u23F9 when in-flight. Parent owns this state \u2014 set true after\n * `chat-message-sent` fires, false when the reply lands or the\n * request is aborted. Enter is inert while in-flight.\n */\n inFlight = false;\n _input = '';\n\n override createRenderRoot(): HTMLElement {\n return this;\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Listen on the host element so that `tile-receipt-activate` events\n // dispatched directly on this element (as well as bubbling up from the\n // trail child) are handled in one place.\n this.addEventListener('tile-receipt-activate', this._onTileReceiptActivate);\n this.addEventListener('alert-receipt-activate', this._onAlertReceiptActivate);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('tile-receipt-activate', this._onTileReceiptActivate);\n this.removeEventListener('alert-receipt-activate', this._onAlertReceiptActivate);\n }\n\n // Host-level styling (display, width, height, flex, etc.) is owned\n // by the container \u2014 SDK shadow root provides default rules, panel\n // overrides via design tokens (--sc-chat-bar-host-*). This adaptive\n // never sets inline styles on itself. See SmartCanvasElementLit's\n // static styles for the rule.\n\n private _onInput = (e: Event): void => {\n this._input = (e.target as HTMLInputElement).value;\n };\n\n private _onKeyDown = (e: KeyboardEvent): void => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n // Enter is the send affordance \u2014 while in-flight there's nothing\n // to send, so it's a no-op. Interrupt requires the explicit\n // \u23F9 click to avoid surprise-aborting on a stray keystroke.\n if (this.inFlight) return;\n this._send();\n }\n };\n\n // Single button. Click delegates to send-or-interrupt based on\n // current state. Same DOM node, different behavior \u2014 discoverability\n // wins from the user not having to scan for which control is active.\n private _onSendOrInterrupt = (): void => {\n if (this.inFlight) {\n this.dispatchEvent(new CustomEvent('chat-interrupt', { bubbles: true, composed: true }));\n return;\n }\n this._send();\n };\n\n private _onTileReceiptActivate = (e: Event): void => {\n const { instanceId } = (e as CustomEvent<{ instanceId: string }>).detail;\n getElementInstanceStore()?.recreate(instanceId);\n this.dispatchEvent(\n new CustomEvent('tile-recall', { detail: { instanceId }, bubbles: true, composed: true })\n );\n };\n\n private _onAlertReceiptActivate = (e: Event): void => {\n const { instanceId } = (e as CustomEvent<{ instanceId: string }>).detail;\n this.dispatchEvent(\n new CustomEvent('alert-recall', { detail: { instanceId }, bubbles: true, composed: true })\n );\n };\n\n private _onMaximizeToggle = (): void => {\n this.dispatchEvent(new CustomEvent('chat-maximize-toggle', { bubbles: true, composed: true }));\n };\n\n private _send(): void {\n const text = this._input.trim();\n if (!text) return;\n this.dispatchEvent(\n new CustomEvent<{ text: string }>('chat-message-sent', {\n detail: { text },\n bubbles: true,\n composed: true,\n })\n );\n this._input = '';\n // Drop the input value too \u2014 the input's bound value is `this._input`\n // via the render, but jsdom's two-way binding via property only takes\n // effect after the next render, so set it imperatively for the test\n // and for browser symmetry (most browsers do the right thing here\n // anyway because Lit re-renders on the state change).\n const input = this.querySelector<HTMLInputElement>('input[data-chat-input]');\n if (input) input.value = '';\n }\n\n /**\n * Visitor tapped the intro suggestion button in the empty-state\n * trail. Submit the configured prompt through the same channel as\n * a typed message so listeners (mountable \u2192 chatSession.send) see\n * a uniform shape \u2014 no need for a parallel \"suggestion-sent\" path.\n * The trail's intro pane auto-disappears the moment the first\n * message lands, so this also closes the empty state in one go.\n */\n private _onIntroSuggestion = (e: Event): void => {\n const detail = (e as CustomEvent<{ prompt: string }>).detail;\n if (!detail?.prompt) return;\n e.stopPropagation();\n if (this.inFlight) return;\n // Latch in-flight optimistically. `inFlight` is owned by the parent\n // mountable and only pushed back down after it handles\n // `chat-message-sent` + a Lit render cycle. Two taps in the same frame\n // both see inFlight===false otherwise, double-dispatching one intended\n // reply (C3). Set it true synchronously here; the parent confirms/owns\n // it from the next render and clears it when the reply lands.\n this.inFlight = true;\n this.dispatchEvent(\n new CustomEvent<{ text: string }>('chat-message-sent', {\n detail: { text: detail.prompt },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n /**\n * Visitor tapped an inline `suggest_replies` chip in the trail. Submit\n * the chip text through the SAME `chat-message-sent` channel a typed\n * message uses, so the reply rides the existing send path (mountable \u2192\n * chatSession.send \u2192 transport) \u2014 no fabricated AG-UI events. The\n * trail clears the chips on its own once the reply lands and a newer\n * assistant turn becomes the latest.\n */\n private _onSuggestedReply = (e: Event): void => {\n const detail = (e as CustomEvent<{ text: string }>).detail;\n if (!detail?.text) return;\n e.stopPropagation();\n if (this.inFlight) return;\n // Latch in-flight optimistically \u2014 same race as `_onIntroSuggestion`\n // (C3). The parent owns `inFlight` and only re-asserts it after a render\n // cycle, so a same-frame double tap would otherwise fire two\n // `chat-message-sent` events for one chip.\n this.inFlight = true;\n this.dispatchEvent(\n new CustomEvent<{ text: string }>('chat-message-sent', {\n detail: { text: detail.text },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n override render() {\n return html`\n <div style=${styleMap(rootStyles(this.forceExpanded))}>\n ${this.forceExpanded ? renderHeader(this.assistantName) : nothing}\n <adaptive-chat-trail\n .messages=${this.messages}\n .greeting=${this.greeting}\n .forceExpanded=${this.forceExpanded}\n .inFlight=${this.inFlight}\n .thinkingText=${this.thinkingText}\n .introSuggestion=${this.introSuggestion}\n .tileReceipts=${this.tileReceipts}\n .inlineWidgets=${this.inlineWidgets}\n @trail-intro-suggestion=${this._onIntroSuggestion}\n @trail-suggested-reply=${this._onSuggestedReply}\n ></adaptive-chat-trail>\n <div style=${styleMap(rowStyles(this.forceExpanded))} data-chat-row>\n <button\n type=\"button\"\n data-chat-maximize\n @click=${this._onMaximizeToggle}\n aria-label=${this.maximized ? 'Exit full screen' : 'Maximize chat'}\n title=${this.maximized ? 'Normal' : 'Maximize'}\n aria-pressed=${this.maximized ? 'true' : 'false'}\n style=${styleMap(maximizeStyles(this.maximized))}\n >${this.maximized ? '\u2921' : '\u2922'}</button>\n <input\n data-chat-input\n type=\"text\"\n placeholder=${this.placeholder}\n .value=${this._input}\n @input=${this._onInput}\n @keydown=${this._onKeyDown}\n style=${styleMap(inputStyles())}\n aria-label=\"Chat input\"\n />\n <button\n type=\"button\"\n data-chat-send\n data-state=${this.inFlight ? 'in-flight' : 'ready'}\n @click=${this._onSendOrInterrupt}\n aria-label=${this.inFlight ? 'Stop' : 'Send message'}\n title=${this.inFlight ? 'Interrupt' : 'Send'}\n style=${styleMap(sendStyles(this.inFlight))}\n >${this.inFlight ? '\u25A0' : '\u2191'}</button>\n </div>\n </div>\n `;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Styles \u2014 kept inline (Lit styleMap) so they participate in light-DOM\n// rendering and pick up host CSS variables (e.g. --sc-tile-background).\n// ---------------------------------------------------------------------------\n\nfunction rootStyles(forceExpanded: boolean): Record<string, string> {\n // When the host expects the chat to fill its container (full-screen\n // panel, agent app), we grow vertically AND wrap the whole widget in\n // its own chrome card \u2014 trail + input read as one cohesive surface\n // instead of a naked trail above a chrome'd input. Floating mounts\n // (bottom-right pinned, etc.) stay chrome-less here because their\n // chrome is owned by the host's positioned wrapper.\n if (!forceExpanded) {\n return {\n display: 'flex',\n flexDirection: 'column',\n gap: '6px',\n width: '100%',\n pointerEvents: 'auto',\n };\n }\n // Input is ABSOLUTELY positioned at the bottom of this chrome card\n // (see rowStyles forceExpanded mode). That guarantees the input is\n // always visible \u2014 even when the lid region is tighter than the\n // chat-bar would naturally want. The flex column above holds\n // header + trail; padding-bottom reserves the input's footprint so\n // trail content can never overlap.\n //\n // Priority of \"what disappears when space is tight\":\n // Trail (shrinks to 0 first via flex: 1 1 0)\n // Header (can shrink via default flex: 0 1 auto)\n // Input (NEVER \u2014 it's positioned absolute, always at the bottom)\n return {\n position: 'relative',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n width: '100%',\n height: '100%',\n boxSizing: 'border-box',\n flex: '1 1 auto',\n minHeight: '0',\n overflow: 'hidden',\n pointerEvents: 'auto',\n background: 'var(--sc-tile-background, rgba(255, 255, 255, 0.92))',\n border: 'var(--sc-tile-border, 1px solid rgba(0, 0, 0, 0.06))',\n borderRadius: 'var(--sc-tile-border-radius, 14px)',\n boxShadow: 'var(--sc-tile-shadow, 0 12px 32px -16px rgba(0, 0, 0, 0.18))',\n // Reserves room for the absolute-positioned input pill (36px high\n // + 12px from bottom) plus a 16px visual gap above the input.\n padding: '0.75rem 0.75rem calc(36px + 1.75rem)',\n color: 'var(--sc-tile-title-color, inherit)',\n fontFamily: 'var(--sc-font-family, inherit)',\n // Override the trail's host-layout tokens so the trail (a flex item\n // of this column) shrinks to 0 first when space is tight \u2014 letting\n // the header and absolute-positioned input pill stay pinned. The\n // SDK-level rule in SmartCanvasElementLit consumes these tokens on\n // adaptive-chat-trail's host element. Containers OWN host styling\n // via tokens; the adaptive never sets inline styles on its host.\n ['--sc-chat-trail-host-display']: 'flex',\n ['--sc-chat-trail-host-flex-direction']: 'column',\n ['--sc-chat-trail-host-flex']: '1 1 0',\n ['--sc-chat-trail-host-min-height']: '0',\n ['--sc-chat-trail-host-overflow']: 'hidden',\n };\n}\n\nfunction rowStyles(forceExpanded: boolean): Record<string, string> {\n // forceExpanded \u2014 root container already carries the chrome; row\n // becomes a flat input-pill inside that chrome (subtle border + soft\n // background, no shadow/blur).\n if (forceExpanded) {\n // Absolute-pinned to the chrome card's bottom edge so it never\n // disappears under any container size. The chrome reserves\n // padding-bottom equal to this row's footprint so flex content\n // above (header + trail) can't overlap.\n return {\n position: 'absolute',\n left: '0.75rem',\n right: '0.75rem',\n bottom: '0.75rem',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '6px 14px',\n borderRadius: '9999px',\n background: 'rgba(0, 0, 0, 0.04)',\n border: '1px solid rgba(0, 0, 0, 0.10)',\n color: 'var(--sc-content-text-color, inherit)',\n fontFamily: 'var(--sc-font-family, inherit)',\n minHeight: '36px',\n };\n }\n // Floating mount \u2014 keeps the original tile-chrome look.\n return {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '10px 12px',\n borderRadius: 'var(--sc-tile-border-radius, 14px)',\n background: 'var(--sc-tile-background, rgba(15, 19, 24, 0.6))',\n backdropFilter: 'var(--sc-chat-bar-blur, blur(24px) saturate(140%))',\n WebkitBackdropFilter: 'var(--sc-chat-bar-blur, blur(24px) saturate(140%))',\n border: 'var(--sc-tile-border, 1px solid rgba(255, 255, 255, 0.08))',\n boxShadow: 'var(--sc-tile-shadow, 0 2px 12px rgba(0, 0, 0, 0.3))',\n color: 'var(--sc-tile-title-color, #fafafa)',\n fontFamily: 'var(--sc-font-family, inherit)',\n };\n}\n\n// Maximize / restore toggle in the chat bar. Legibility matters: the old\n// treatment reused the decorative avatar chip then stripped its background and\n// border and let `font: inherit` shrink the glyph \u2014 leaving a faint, ghosted\n// (0.95-alpha) character that read as \"barely visible\" and gave no visual\n// signal of its on/off state. This mirrors the sibling send button (28px,\n// filled-accent affordance) and makes the ACTIVE (maximized) state a filled\n// chip so the toggle state is obvious at a glance.\nfunction maximizeStyles(maximized: boolean): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '28px',\n height: '28px',\n borderRadius: '9999px',\n // Active (maximized): filled accent chip. Idle: subtle accent chip with a\n // visible ring. Colour is full-opacity in both states (no 0.95 ghosting).\n background: maximized\n ? 'hsl(var(--sc-accent-color) / 0.85)'\n : 'hsl(var(--sc-accent-color) / 0.15)',\n border: maximized ? 'none' : '1px solid hsl(var(--sc-accent-color) / 0.45)',\n color: maximized ? 'var(--sc-accent-foreground, #fff)' : 'hsl(var(--sc-accent-color))',\n flexShrink: '0',\n fontSize: '16px',\n lineHeight: '1',\n padding: '0',\n cursor: 'pointer',\n transition: 'background 150ms ease, color 150ms ease, border-color 150ms ease',\n };\n}\n\nfunction inputStyles(): Record<string, string> {\n return {\n flex: '1',\n minWidth: '0',\n background: 'transparent',\n border: 'none',\n outline: 'none',\n color: 'inherit',\n fontSize: '13px',\n };\n}\n\nfunction sendStyles(inFlight: boolean): Record<string, string> {\n return {\n width: '28px',\n height: '28px',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: '9999px',\n // Ready: filled accent (send is the affordance). In-flight: hollow\n // ring + accent ring (stop is a one-of-a-kind disruptive action,\n // styled differently so the user reads \"this isn't just send\").\n background: inFlight ? 'transparent' : 'hsl(var(--sc-accent-color) / 0.85)',\n color: inFlight ? 'hsl(var(--sc-accent-color) / 0.95)' : 'var(--sc-accent-foreground, #fff)',\n border: inFlight ? '1px solid hsl(var(--sc-accent-color) / 0.55)' : 'none',\n cursor: 'pointer',\n flexShrink: '0',\n transition: 'background 150ms ease, color 150ms ease, border-color 150ms ease',\n };\n}\n\n/**\n * Compact single-line chat header. Prior version stacked the name over a\n * two-line status block inside a flex-column wrapper with a 28px avatar and\n * `padding: 4px 4px 12px`, which wasted a lot of vertical space (user\n * feedback: \"bad use of vertical space\"). This is now ONE inline row \u2014\n * small avatar dot \u00B7 name \u00B7 live-status dot \u00B7 short status \u2014 at roughly half\n * the height. All surfaces share this chrome.\n */\nfunction renderHeader(assistantName: string) {\n const headerStyles: Record<string, string> = {\n display: 'flex',\n alignItems: 'center',\n gap: '7px',\n // Halved vertical footprint: 6px total block padding vs the old 16px\n // (4px top + 12px bottom). Horizontal padding unchanged.\n padding: '3px 4px',\n borderBottom: '1px solid var(--sc-content-divider-color, rgba(0, 0, 0, 0.08))',\n flex: '0 0 auto',\n };\n // Small brand dot \u2014 shrunk from a 28px avatar to a 16px chip so the\n // whole header collapses to a single text line. Still tracks the\n // workspace brand primary so it matches the rest of the canvas chrome.\n const avatar: Record<string, string> = {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '16px',\n height: '16px',\n borderRadius: '9999px',\n background:\n 'var(--sc-tile-icon-background, linear-gradient(135deg, var(--sc-color-primary, #5faf7d) 0%, var(--sc-color-primary-hover, #3d8a5e) 100%))',\n color: '#fff',\n flexShrink: '0',\n fontSize: '9px',\n lineHeight: '1',\n };\n const name: Record<string, string> = {\n fontSize: '0.8rem',\n fontWeight: '600',\n color: 'var(--sc-content-text-color, inherit)',\n lineHeight: '1.2',\n flexShrink: '0',\n };\n // Live-status dot, inline with the name (was nested in a stacked column).\n const statusDot: Record<string, string> = {\n width: '6px',\n height: '6px',\n borderRadius: '9999px',\n background: 'var(--sc-tile-title-color, #3d8275)',\n display: 'inline-block',\n flexShrink: '0',\n };\n const status: Record<string, string> = {\n fontSize: '0.68rem',\n color: 'var(--sc-tile-title-color, #3d8275)',\n lineHeight: '1.2',\n // Ellipsize on narrow surfaces instead of wrapping to a second line.\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n minWidth: '0',\n };\n return html`\n <div style=${styleMap(headerStyles)} data-chat-header>\n <span style=${styleMap(avatar)} aria-hidden=\"true\">\u2726</span>\n <span style=${styleMap(name)}>${assistantName}</span>\n <span style=${styleMap(statusDot)} aria-hidden=\"true\"></span>\n <span style=${styleMap(status)}>Online \u00B7 understands your session</span>\n </div>\n `;\n}\n\nif (!customElements.get('adaptive-chat-bar')) {\n customElements.define('adaptive-chat-bar', AdaptiveChatBar);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'adaptive-chat-bar': AdaptiveChatBar;\n }\n}\n"],
5
- "mappings": ";;;;;AAqBA,SAAS,MAAM,YAAY,eAAe;AAC1C,SAAS,gBAAgB;AAMzB,IAAM,sBAAsB;AAC5B,IAAM,yBAAyB;AAExB,IAAM,kBAAN,cAA8B,WAAW;AAAA,EAAzC;AAAA;AAgBL,oBAA2B,CAAC;AAC5B,qBAAY;AACZ,wBAA8B,CAAC;AAG/B;AAAA;AAAA,yBAAqC,CAAC;AAUtC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAe;AAOf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAiE;AAMjE;AAAA;AAAA;AAAA;AAAA,yBAAgB;AAChB,uBAAc;AAOd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAgB;AAOhB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA+B;AAQ/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAW;AACX,kBAAS;AA2BT;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,WAAW,CAAC,MAAmB;AACrC,WAAK,SAAU,EAAE,OAA4B;AAAA,IAC/C;AAEA,SAAQ,aAAa,CAAC,MAA2B;AAC/C,UAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,UAAU;AACpC,UAAE,eAAe;AAIjB,YAAI,KAAK,SAAU;AACnB,aAAK,MAAM;AAAA,MACb;AAAA,IACF;AAKA;AAAA;AAAA;AAAA,SAAQ,qBAAqB,MAAY;AACvC,UAAI,KAAK,UAAU;AACjB,aAAK,cAAc,IAAI,YAAY,kBAAkB,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AACvF;AAAA,MACF;AACA,WAAK,MAAM;AAAA,IACb;AAEA,SAAQ,yBAAyB,CAAC,MAAmB;AACnD,YAAM,EAAE,WAAW,IAAK,EAA0C;AAClE,8BAAwB,GAAG,SAAS,UAAU;AAC9C,WAAK;AAAA,QACH,IAAI,YAAY,eAAe,EAAE,QAAQ,EAAE,WAAW,GAAG,SAAS,MAAM,UAAU,KAAK,CAAC;AAAA,MAC1F;AAAA,IACF;AAEA,SAAQ,0BAA0B,CAAC,MAAmB;AACpD,YAAM,EAAE,WAAW,IAAK,EAA0C;AAClE,WAAK;AAAA,QACH,IAAI,YAAY,gBAAgB,EAAE,QAAQ,EAAE,WAAW,GAAG,SAAS,MAAM,UAAU,KAAK,CAAC;AAAA,MAC3F;AAAA,IACF;AAEA,SAAQ,oBAAoB,MAAY;AACtC,WAAK,cAAc,IAAI,YAAY,wBAAwB,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,IAC/F;AA8BA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,qBAAqB,CAAC,MAAmB;AAC/C,YAAM,SAAU,EAAsC;AACtD,UAAI,CAAC,QAAQ,OAAQ;AACrB,QAAE,gBAAgB;AAClB,UAAI,KAAK,SAAU;AAOnB,WAAK,WAAW;AAChB,WAAK;AAAA,QACH,IAAI,YAA8B,qBAAqB;AAAA,UACrD,QAAQ,EAAE,MAAM,OAAO,OAAO;AAAA,UAC9B,SAAS;AAAA,UACT,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF;AAUA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,oBAAoB,CAAC,MAAmB;AAC9C,YAAM,SAAU,EAAoC;AACpD,UAAI,CAAC,QAAQ,KAAM;AACnB,QAAE,gBAAgB;AAClB,UAAI,KAAK,SAAU;AAKnB,WAAK,WAAW;AAChB,WAAK;AAAA,QACH,IAAI,YAA8B,qBAAqB;AAAA,UACrD,QAAQ,EAAE,MAAM,OAAO,KAAK;AAAA,UAC5B,SAAS;AAAA,UACT,UAAU;AAAA,QACZ,CAAC;AAAA,MACH;AAAA,IACF;AAAA;AAAA,EAhJS,mBAAgC;AACvC,WAAO;AAAA,EACT;AAAA,EAES,oBAA0B;AACjC,UAAM,kBAAkB;AAIxB,SAAK,iBAAiB,yBAAyB,KAAK,sBAAsB;AAC1E,SAAK,iBAAiB,0BAA0B,KAAK,uBAAuB;AAAA,EAC9E;AAAA,EAES,uBAA6B;AACpC,UAAM,qBAAqB;AAC3B,SAAK,oBAAoB,yBAAyB,KAAK,sBAAsB;AAC7E,SAAK,oBAAoB,0BAA0B,KAAK,uBAAuB;AAAA,EACjF;AAAA,EAqDQ,QAAc;AACpB,UAAM,OAAO,KAAK,OAAO,KAAK;AAC9B,QAAI,CAAC,KAAM;AACX,SAAK;AAAA,MACH,IAAI,YAA8B,qBAAqB;AAAA,QACrD,QAAQ,EAAE,KAAK;AAAA,QACf,SAAS;AAAA,QACT,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AACA,SAAK,SAAS;AAMd,UAAM,QAAQ,KAAK,cAAgC,wBAAwB;AAC3E,QAAI,MAAO,OAAM,QAAQ;AAAA,EAC3B;AAAA,EA0DS,SAAS;AAChB,WAAO;AAAA,mBACQ,SAAS,WAAW,KAAK,aAAa,CAAC,CAAC;AAAA,UACjD,KAAK,gBAAgB,aAAa,KAAK,aAAa,IAAI,OAAO;AAAA;AAAA,sBAEnD,KAAK,QAAQ;AAAA,sBACb,KAAK,QAAQ;AAAA,2BACR,KAAK,aAAa;AAAA,sBACvB,KAAK,QAAQ;AAAA,0BACT,KAAK,YAAY;AAAA,6BACd,KAAK,eAAe;AAAA,0BACvB,KAAK,YAAY;AAAA,2BAChB,KAAK,aAAa;AAAA,oCACT,KAAK,kBAAkB;AAAA,mCACxB,KAAK,iBAAiB;AAAA;AAAA,qBAEpC,SAAS,UAAU,KAAK,aAAa,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA,qBAIvC,KAAK,iBAAiB;AAAA,yBAClB,KAAK,YAAY,qBAAqB,eAAe;AAAA,oBAC1D,KAAK,YAAY,WAAW,UAAU;AAAA,2BAC/B,KAAK,YAAY,SAAS,OAAO;AAAA,oBACxC,SAAS,eAAe,KAAK,SAAS,CAAC,CAAC;AAAA,aAC/C,KAAK,YAAY,WAAM,QAAG;AAAA;AAAA;AAAA;AAAA,0BAIb,KAAK,WAAW;AAAA,qBACrB,KAAK,MAAM;AAAA,qBACX,KAAK,QAAQ;AAAA,uBACX,KAAK,UAAU;AAAA,oBAClB,SAAS,YAAY,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAMlB,KAAK,WAAW,cAAc,OAAO;AAAA,qBACzC,KAAK,kBAAkB;AAAA,yBACnB,KAAK,WAAW,SAAS,cAAc;AAAA,oBAC5C,KAAK,WAAW,cAAc,MAAM;AAAA,oBACpC,SAAS,WAAW,KAAK,QAAQ,CAAC,CAAC;AAAA,aAC1C,KAAK,WAAW,WAAM,QAAG;AAAA;AAAA;AAAA;AAAA,EAIpC;AACF;AAzQa,gBACK,aAAa;AAAA,EAC3B,UAAU,EAAE,WAAW,MAAM;AAAA,EAC7B,aAAa,EAAE,MAAM,OAAO;AAAA,EAC5B,eAAe,EAAE,MAAM,OAAO;AAAA,EAC9B,UAAU,EAAE,MAAM,OAAO;AAAA,EACzB,UAAU,EAAE,MAAM,SAAS,SAAS,KAAK;AAAA,EACzC,cAAc,EAAE,WAAW,MAAM;AAAA,EACjC,iBAAiB,EAAE,WAAW,MAAM;AAAA,EACpC,eAAe,EAAE,MAAM,SAAS,SAAS,KAAK;AAAA,EAC9C,WAAW,EAAE,MAAM,QAAQ;AAAA,EAC3B,cAAc,EAAE,WAAW,MAAM;AAAA,EACjC,eAAe,EAAE,WAAW,MAAM;AAAA,EAClC,QAAQ,EAAE,OAAO,KAAK;AACxB;AAkQF,SAAS,WAAW,eAAgD;AAOlE,MAAI,CAAC,eAAe;AAClB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,eAAe;AAAA,MACf,KAAK;AAAA,MACL,OAAO;AAAA,MACP,eAAe;AAAA,IACjB;AAAA,EACF;AAYA,SAAO;AAAA,IACL,UAAU;AAAA,IACV,SAAS;AAAA,IACT,eAAe;AAAA,IACf,KAAK;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,WAAW;AAAA;AAAA;AAAA,IAGX,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOZ,CAAC,8BAA8B,GAAG;AAAA,IAClC,CAAC,qCAAqC,GAAG;AAAA,IACzC,CAAC,2BAA2B,GAAG;AAAA,IAC/B,CAAC,iCAAiC,GAAG;AAAA,IACrC,CAAC,+BAA+B,GAAG;AAAA,EACrC;AACF;AAEA,SAAS,UAAU,eAAgD;AAIjE,MAAI,eAAe;AAKjB,WAAO;AAAA,MACL,UAAU;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,KAAK;AAAA,MACL,SAAS;AAAA,MACT,cAAc;AAAA,MACd,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,WAAW;AAAA,IACb;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,SAAS;AAAA,IACT,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,IACtB,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AACF;AASA,SAAS,eAAe,WAA4C;AAClE,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA;AAAA;AAAA,IAGd,YAAY,YACR,uCACA;AAAA,IACJ,QAAQ,YAAY,SAAS;AAAA,IAC7B,OAAO,YAAY,sCAAsC;AAAA,IACzD,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,YAAY;AAAA,EACd;AACF;AAEA,SAAS,cAAsC;AAC7C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA,IACP,UAAU;AAAA,EACZ;AACF;AAEA,SAAS,WAAW,UAA2C;AAC7D,SAAO;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,cAAc;AAAA;AAAA;AAAA;AAAA,IAId,YAAY,WAAW,gBAAgB;AAAA,IACvC,OAAO,WAAW,uCAAuC;AAAA,IACzD,QAAQ,WAAW,iDAAiD;AAAA,IACpE,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,YAAY;AAAA,EACd;AACF;AAUA,SAAS,aAAa,eAAuB;AAC3C,QAAM,eAAuC;AAAA,IAC3C,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA;AAAA;AAAA,IAGL,SAAS;AAAA,IACT,cAAc;AAAA,IACd,MAAM;AAAA,EACR;AAIA,QAAM,SAAiC;AAAA,IACrC,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YACE;AAAA,IACF,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACA,QAAM,OAA+B;AAAA,IACnC,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,YAAY;AAAA,EACd;AAEA,QAAM,YAAoC;AAAA,IACxC,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,YAAY;AAAA,EACd;AACA,QAAM,SAAiC;AAAA,IACrC,UAAU;AAAA,IACV,OAAO;AAAA,IACP,YAAY;AAAA;AAAA,IAEZ,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,cAAc;AAAA,IACd,UAAU;AAAA,EACZ;AACA,SAAO;AAAA,iBACQ,SAAS,YAAY,CAAC;AAAA,oBACnB,SAAS,MAAM,CAAC;AAAA,oBAChB,SAAS,IAAI,CAAC,IAAI,aAAa;AAAA,oBAC/B,SAAS,SAAS,CAAC;AAAA,oBACnB,SAAS,MAAM,CAAC;AAAA;AAAA;AAGpC;AAEA,IAAI,CAAC,eAAe,IAAI,mBAAmB,GAAG;AAC5C,iBAAe,OAAO,qBAAqB,eAAe;AAC5D;",
4
+ "sourcesContent": ["/**\n * AdaptiveChatBar \u2014 the canvas lid composition for the chat-canvas\n * experience. Renders the bubble-up trail on top and an always-visible\n * input row below.\n *\n * Wiring contract (events out):\n * - `chat-message-sent` ({ text }): the user submitted text via Enter\n * or the send button. The owning code is responsible for pushing\n * this into the conversation history and producing a reply.\n *\n * Wiring contract (props in):\n * - `messages`: the conversation trail, passed straight through to\n * `<adaptive-chat-trail>`.\n * - `placeholder`: input placeholder copy. Defaults to a generic\n * \"Ask, find, or navigate\u2026\" \u2014 the host (typically the slot's lid\n * widget mount) can override to a context-specific string.\n *\n * Light DOM. Glassmorphism is applied at the input-row level so the\n * trail above floats over the host page without chrome. See PRD \u00A74.4.\n */\n\nimport { html, LitElement, nothing } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\n\nimport './AdaptiveChatTrail.js';\nimport type { InlineTrailWidget, TileReceipt, TrailMessage } from './AdaptiveChatTrail.js';\nimport { getElementInstanceStore } from './elements/store-singleton.js';\n\nconst DEFAULT_PLACEHOLDER = 'Ask, find, or navigate\u2026';\nconst DEFAULT_ASSISTANT_NAME = 'Assistant';\n\nexport class AdaptiveChatBar extends LitElement {\n static override properties = {\n messages: { attribute: false },\n placeholder: { type: String },\n assistantName: { type: String },\n greeting: { type: String },\n inFlight: { type: Boolean, reflect: true },\n thinkingText: { attribute: false },\n introSuggestion: { attribute: false },\n forceExpanded: { type: Boolean, reflect: true },\n maximized: { type: Boolean },\n tileReceipts: { attribute: false },\n inlineWidgets: { attribute: false },\n _input: { state: true },\n };\n\n messages: TrailMessage[] = [];\n maximized = false;\n tileReceipts: TileReceipt[] = [];\n /** Widgets rendered inline in the trail (reco carousel), sourced from\n * the store's `chat-inline` slot mounts. Forwarded to the trail. */\n inlineWidgets: InlineTrailWidget[] = [];\n\n /**\n * Live reasoning narration from the model \u2014 streamed in via\n * AG-UI THINKING_TEXT_MESSAGE_CONTENT events and forwarded by\n * the ChatSession subscription on the host (mountable).\n * Forwarded verbatim to the trail, which renders it in place of\n * the silent loading dots between turns. Empty string when no\n * thinking turn is active.\n */\n thinkingText = '';\n /**\n * Pre-conversation suggestion button \u2014 forwarded to the trail's\n * empty-state pane. When the visitor clicks it the trail emits\n * `trail-intro-suggestion`; we catch that here and submit the\n * configured prompt through the normal send path.\n */\n introSuggestion: { label: string; prompt: string } | undefined = undefined;\n\n /** Pass-through to {@link AdaptiveChatTrail}'s ``forceExpanded`` prop.\n * Hosts that mount the chat-bar in a full-screen surface (mobile\n * panel, agent app, etc.) set this to skip the collapse affordance\n * \u2014 there is no smaller state to fall back to. */\n forceExpanded = false;\n placeholder = DEFAULT_PLACEHOLDER;\n /**\n * Name shown in the (forceExpanded) header. Defaults to a generic\n * \"Assistant\". Hosts can override per-workspace (e.g. Vela sets\n * \"Vela Concierge\") without inventing new SDK surface \u2014 it threads\n * through the same mount config the placeholder does.\n */\n assistantName = DEFAULT_ASSISTANT_NAME;\n /**\n * Initial assistant message shown before any real conversation\n * starts. Renders inside the trail as a phantom assistant chip\n * when messages.length === 0; auto-disappears as soon as the\n * first user message lands. Mirrors ChatAssistantLit's greeting.\n */\n greeting: string | undefined = undefined;\n /**\n * Whether a chat round-trip is in flight (request sent, awaiting\n * reply). The single send/stop button morphs accordingly: \u2191 when\n * ready, \u23F9 when in-flight. Parent owns this state \u2014 set true after\n * `chat-message-sent` fires, false when the reply lands or the\n * request is aborted. Enter is inert while in-flight.\n */\n inFlight = false;\n _input = '';\n\n override createRenderRoot(): HTMLElement {\n return this;\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Listen on the host element so that `tile-receipt-activate` events\n // dispatched directly on this element (as well as bubbling up from the\n // trail child) are handled in one place.\n this.addEventListener('tile-receipt-activate', this._onTileReceiptActivate);\n this.addEventListener('alert-receipt-activate', this._onAlertReceiptActivate);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('tile-receipt-activate', this._onTileReceiptActivate);\n this.removeEventListener('alert-receipt-activate', this._onAlertReceiptActivate);\n }\n\n // Host-level styling (display, width, height, flex, etc.) is owned\n // by the container \u2014 SDK shadow root provides default rules, panel\n // overrides via design tokens (--sc-chat-bar-host-*). This adaptive\n // never sets inline styles on itself. See SmartCanvasElementLit's\n // static styles for the rule.\n\n private _onInput = (e: Event): void => {\n this._input = (e.target as HTMLInputElement).value;\n };\n\n private _onKeyDown = (e: KeyboardEvent): void => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n // Enter is the send affordance \u2014 while in-flight there's nothing\n // to send, so it's a no-op. Interrupt requires the explicit\n // \u23F9 click to avoid surprise-aborting on a stray keystroke.\n if (this.inFlight) return;\n this._send();\n }\n };\n\n // Single button. Click delegates to send-or-interrupt based on\n // current state. Same DOM node, different behavior \u2014 discoverability\n // wins from the user not having to scan for which control is active.\n private _onSendOrInterrupt = (): void => {\n if (this.inFlight) {\n this.dispatchEvent(new CustomEvent('chat-interrupt', { bubbles: true, composed: true }));\n return;\n }\n this._send();\n };\n\n private _onTileReceiptActivate = (e: Event): void => {\n const { instanceId } = (e as CustomEvent<{ instanceId: string }>).detail;\n getElementInstanceStore()?.recreate(instanceId);\n this.dispatchEvent(\n new CustomEvent('tile-recall', { detail: { instanceId }, bubbles: true, composed: true })\n );\n };\n\n private _onAlertReceiptActivate = (e: Event): void => {\n const { instanceId } = (e as CustomEvent<{ instanceId: string }>).detail;\n this.dispatchEvent(\n new CustomEvent('alert-recall', { detail: { instanceId }, bubbles: true, composed: true })\n );\n };\n\n private _onMaximizeToggle = (): void => {\n this.dispatchEvent(new CustomEvent('chat-maximize-toggle', { bubbles: true, composed: true }));\n };\n\n private _send(): void {\n const text = this._input.trim();\n if (!text) return;\n this.dispatchEvent(\n new CustomEvent<{ text: string }>('chat-message-sent', {\n detail: { text },\n bubbles: true,\n composed: true,\n })\n );\n this._input = '';\n // Drop the input value too \u2014 the input's bound value is `this._input`\n // via the render, but jsdom's two-way binding via property only takes\n // effect after the next render, so set it imperatively for the test\n // and for browser symmetry (most browsers do the right thing here\n // anyway because Lit re-renders on the state change).\n const input = this.querySelector<HTMLInputElement>('input[data-chat-input]');\n if (input) input.value = '';\n }\n\n /**\n * Visitor tapped the intro suggestion button in the empty-state\n * trail. Submit the configured prompt through the same channel as\n * a typed message so listeners (mountable \u2192 chatSession.send) see\n * a uniform shape \u2014 no need for a parallel \"suggestion-sent\" path.\n * The trail's intro pane auto-disappears the moment the first\n * message lands, so this also closes the empty state in one go.\n */\n private _onIntroSuggestion = (e: Event): void => {\n const detail = (e as CustomEvent<{ prompt: string }>).detail;\n if (!detail?.prompt) return;\n e.stopPropagation();\n if (this.inFlight) return;\n // Latch in-flight optimistically. `inFlight` is owned by the parent\n // mountable and only pushed back down after it handles\n // `chat-message-sent` + a Lit render cycle. Two taps in the same frame\n // both see inFlight===false otherwise, double-dispatching one intended\n // reply (C3). Set it true synchronously here; the parent confirms/owns\n // it from the next render and clears it when the reply lands.\n this.inFlight = true;\n this.dispatchEvent(\n new CustomEvent<{ text: string }>('chat-message-sent', {\n detail: { text: detail.prompt },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n /**\n * Visitor tapped an inline `suggest_replies` chip in the trail. Submit\n * the chip text through the SAME `chat-message-sent` channel a typed\n * message uses, so the reply rides the existing send path (mountable \u2192\n * chatSession.send \u2192 transport) \u2014 no fabricated AG-UI events. The\n * trail clears the chips on its own once the reply lands and a newer\n * assistant turn becomes the latest.\n */\n private _onSuggestedReply = (e: Event): void => {\n const detail = (e as CustomEvent<{ text: string }>).detail;\n if (!detail?.text) return;\n e.stopPropagation();\n if (this.inFlight) return;\n // Latch in-flight optimistically \u2014 same race as `_onIntroSuggestion`\n // (C3). The parent owns `inFlight` and only re-asserts it after a render\n // cycle, so a same-frame double tap would otherwise fire two\n // `chat-message-sent` events for one chip.\n this.inFlight = true;\n this.dispatchEvent(\n new CustomEvent<{ text: string }>('chat-message-sent', {\n detail: { text: detail.text },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n override render() {\n return html`\n <div style=${styleMap(rootStyles(this.forceExpanded))}>\n ${this.forceExpanded ? renderHeader(this.assistantName) : nothing}\n <adaptive-chat-trail\n .messages=${this.messages}\n .greeting=${this.greeting}\n .forceExpanded=${this.forceExpanded}\n .inFlight=${this.inFlight}\n .thinkingText=${this.thinkingText}\n .introSuggestion=${this.introSuggestion}\n .tileReceipts=${this.tileReceipts}\n .inlineWidgets=${this.inlineWidgets}\n @trail-intro-suggestion=${this._onIntroSuggestion}\n @trail-suggested-reply=${this._onSuggestedReply}\n ></adaptive-chat-trail>\n <div style=${styleMap(rowStyles(this.forceExpanded))} data-chat-row>\n <button\n type=\"button\"\n data-chat-maximize\n @click=${this._onMaximizeToggle}\n aria-label=${this.maximized ? 'Exit full screen' : 'Maximize chat'}\n title=${this.maximized ? 'Normal' : 'Maximize'}\n aria-pressed=${this.maximized ? 'true' : 'false'}\n style=${styleMap(maximizeStyles(this.maximized))}\n >${this.maximized ? '\u2921' : '\u2922'}</button>\n <input\n data-chat-input\n type=\"text\"\n placeholder=${this.placeholder}\n .value=${this._input}\n @input=${this._onInput}\n @keydown=${this._onKeyDown}\n style=${styleMap(inputStyles())}\n aria-label=\"Chat input\"\n />\n <button\n type=\"button\"\n data-chat-send\n data-state=${this.inFlight ? 'in-flight' : 'ready'}\n @click=${this._onSendOrInterrupt}\n aria-label=${this.inFlight ? 'Stop' : 'Send message'}\n title=${this.inFlight ? 'Interrupt' : 'Send'}\n style=${styleMap(sendStyles(this.inFlight))}\n >${this.inFlight ? '\u25A0' : '\u2191'}</button>\n </div>\n </div>\n `;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Styles \u2014 kept inline (Lit styleMap) so they participate in light-DOM\n// rendering and pick up host CSS variables (e.g. --sc-tile-background).\n// ---------------------------------------------------------------------------\n\nfunction rootStyles(forceExpanded: boolean): Record<string, string> {\n // When the host expects the chat to fill its container (full-screen\n // panel, agent app), we grow vertically AND wrap the whole widget in\n // its own chrome card \u2014 trail + input read as one cohesive surface\n // instead of a naked trail above a chrome'd input. Floating mounts\n // (bottom-right pinned, etc.) stay chrome-less here because their\n // chrome is owned by the host's positioned wrapper.\n if (!forceExpanded) {\n return {\n display: 'flex',\n flexDirection: 'column',\n gap: '6px',\n width: '100%',\n pointerEvents: 'auto',\n };\n }\n // Input is ABSOLUTELY positioned at the bottom of this chrome card\n // (see rowStyles forceExpanded mode). That guarantees the input is\n // always visible \u2014 even when the lid region is tighter than the\n // chat-bar would naturally want. The flex column above holds\n // header + trail; padding-bottom reserves the input's footprint so\n // trail content can never overlap.\n //\n // Priority of \"what disappears when space is tight\":\n // Trail (shrinks to 0 first via flex: 1 1 0)\n // Header (can shrink via default flex: 0 1 auto)\n // Input (NEVER \u2014 it's positioned absolute, always at the bottom)\n return {\n position: 'relative',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n width: '100%',\n height: '100%',\n boxSizing: 'border-box',\n flex: '1 1 auto',\n minHeight: '0',\n overflow: 'hidden',\n pointerEvents: 'auto',\n background: 'var(--sc-tile-background, rgba(255, 255, 255, 0.92))',\n border: 'var(--sc-tile-border, 1px solid rgba(0, 0, 0, 0.06))',\n borderRadius: 'var(--sc-tile-border-radius, 14px)',\n boxShadow: 'var(--sc-tile-shadow, 0 12px 32px -16px rgba(0, 0, 0, 0.18))',\n // Reserves room for the absolute-positioned input pill (36px high\n // + 12px from bottom) plus a 16px visual gap above the input.\n padding: '0.75rem 0.75rem calc(36px + 1.75rem)',\n color: 'var(--sc-tile-title-color, inherit)',\n fontFamily: 'var(--sc-font-family, inherit)',\n // Override the trail's host-layout tokens so the trail (a flex item\n // of this column) fills a definite-height parent AND contributes its\n // content height in an indefinite one. basis AUTO (not 0) is\n // load-bearing: grow:1 still fills a full-screen panel, but basis auto\n // also lets the trail's content height propagate up the fill chain so a\n // SHRINK-WRAP host (velvet's bottom sheet) hugs the content with no void.\n // A basis-0 layer anywhere in the chain reports 0 min-content and\n // collapses the sheet to header+input. shrink:1 + min-height:0 still lets\n // the trail yield first when space is tight (input is absolute-pinned).\n // The SDK-level rule in SmartCanvasElementLit consumes these tokens on\n // adaptive-chat-trail's host element. Containers OWN host styling\n // via tokens; the adaptive never sets inline styles on its host.\n ['--sc-chat-trail-host-display']: 'flex',\n ['--sc-chat-trail-host-flex-direction']: 'column',\n ['--sc-chat-trail-host-flex']: '1 1 auto',\n ['--sc-chat-trail-host-min-height']: '0',\n ['--sc-chat-trail-host-overflow']: 'hidden',\n };\n}\n\nfunction rowStyles(forceExpanded: boolean): Record<string, string> {\n // forceExpanded \u2014 root container already carries the chrome; row\n // becomes a flat input-pill inside that chrome (subtle border + soft\n // background, no shadow/blur).\n if (forceExpanded) {\n // Absolute-pinned to the chrome card's bottom edge so it never\n // disappears under any container size. The chrome reserves\n // padding-bottom equal to this row's footprint so flex content\n // above (header + trail) can't overlap.\n return {\n position: 'absolute',\n left: '0.75rem',\n right: '0.75rem',\n bottom: '0.75rem',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '6px 14px',\n borderRadius: '9999px',\n background: 'rgba(0, 0, 0, 0.04)',\n border: '1px solid rgba(0, 0, 0, 0.10)',\n color: 'var(--sc-content-text-color, inherit)',\n fontFamily: 'var(--sc-font-family, inherit)',\n minHeight: '36px',\n };\n }\n // Floating mount \u2014 keeps the original tile-chrome look.\n return {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '10px 12px',\n borderRadius: 'var(--sc-tile-border-radius, 14px)',\n background: 'var(--sc-tile-background, rgba(15, 19, 24, 0.6))',\n backdropFilter: 'var(--sc-chat-bar-blur, blur(24px) saturate(140%))',\n WebkitBackdropFilter: 'var(--sc-chat-bar-blur, blur(24px) saturate(140%))',\n border: 'var(--sc-tile-border, 1px solid rgba(255, 255, 255, 0.08))',\n boxShadow: 'var(--sc-tile-shadow, 0 2px 12px rgba(0, 0, 0, 0.3))',\n color: 'var(--sc-tile-title-color, #fafafa)',\n fontFamily: 'var(--sc-font-family, inherit)',\n };\n}\n\n// Maximize / restore toggle in the chat bar. Legibility matters: the old\n// treatment reused the decorative avatar chip then stripped its background and\n// border and let `font: inherit` shrink the glyph \u2014 leaving a faint, ghosted\n// (0.95-alpha) character that read as \"barely visible\" and gave no visual\n// signal of its on/off state. This mirrors the sibling send button (28px,\n// filled-accent affordance) and makes the ACTIVE (maximized) state a filled\n// chip so the toggle state is obvious at a glance.\nfunction maximizeStyles(maximized: boolean): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '28px',\n height: '28px',\n borderRadius: '9999px',\n // Active (maximized): filled accent chip. Idle: subtle accent chip with a\n // visible ring. Colour is full-opacity in both states (no 0.95 ghosting).\n background: maximized\n ? 'hsl(var(--sc-accent-color) / 0.85)'\n : 'hsl(var(--sc-accent-color) / 0.15)',\n border: maximized ? 'none' : '1px solid hsl(var(--sc-accent-color) / 0.45)',\n color: maximized ? 'var(--sc-accent-foreground, #fff)' : 'hsl(var(--sc-accent-color))',\n flexShrink: '0',\n fontSize: '16px',\n lineHeight: '1',\n padding: '0',\n cursor: 'pointer',\n transition: 'background 150ms ease, color 150ms ease, border-color 150ms ease',\n };\n}\n\nfunction inputStyles(): Record<string, string> {\n return {\n flex: '1',\n minWidth: '0',\n background: 'transparent',\n border: 'none',\n outline: 'none',\n color: 'inherit',\n fontSize: '13px',\n };\n}\n\nfunction sendStyles(inFlight: boolean): Record<string, string> {\n return {\n width: '28px',\n height: '28px',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: '9999px',\n // Ready: filled accent (send is the affordance). In-flight: hollow\n // ring + accent ring (stop is a one-of-a-kind disruptive action,\n // styled differently so the user reads \"this isn't just send\").\n background: inFlight ? 'transparent' : 'hsl(var(--sc-accent-color) / 0.85)',\n color: inFlight ? 'hsl(var(--sc-accent-color) / 0.95)' : 'var(--sc-accent-foreground, #fff)',\n border: inFlight ? '1px solid hsl(var(--sc-accent-color) / 0.55)' : 'none',\n cursor: 'pointer',\n flexShrink: '0',\n transition: 'background 150ms ease, color 150ms ease, border-color 150ms ease',\n };\n}\n\n/**\n * Compact single-line chat header. Prior version stacked the name over a\n * two-line status block inside a flex-column wrapper with a 28px avatar and\n * `padding: 4px 4px 12px`, which wasted a lot of vertical space (user\n * feedback: \"bad use of vertical space\"). This is now ONE inline row \u2014\n * small avatar dot \u00B7 name \u00B7 live-status dot \u00B7 short status \u2014 at roughly half\n * the height. All surfaces share this chrome.\n */\nfunction renderHeader(assistantName: string) {\n const headerStyles: Record<string, string> = {\n display: 'flex',\n alignItems: 'center',\n gap: '7px',\n // Halved vertical footprint: 6px total block padding vs the old 16px\n // (4px top + 12px bottom). Horizontal padding unchanged.\n padding: '3px 4px',\n borderBottom: '1px solid var(--sc-content-divider-color, rgba(0, 0, 0, 0.08))',\n flex: '0 0 auto',\n };\n // Small brand dot \u2014 shrunk from a 28px avatar to a 16px chip so the\n // whole header collapses to a single text line. Still tracks the\n // workspace brand primary so it matches the rest of the canvas chrome.\n const avatar: Record<string, string> = {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '16px',\n height: '16px',\n borderRadius: '9999px',\n background:\n 'var(--sc-tile-icon-background, linear-gradient(135deg, var(--sc-color-primary, #5faf7d) 0%, var(--sc-color-primary-hover, #3d8a5e) 100%))',\n color: '#fff',\n flexShrink: '0',\n fontSize: '9px',\n lineHeight: '1',\n };\n const name: Record<string, string> = {\n fontSize: '0.8rem',\n fontWeight: '600',\n color: 'var(--sc-content-text-color, inherit)',\n lineHeight: '1.2',\n flexShrink: '0',\n };\n // No status line or presence dot (\"Online \u00B7 understands your session\") \u2014\n // user feedback: that's chrome a visitor doesn't need. Avatar + name only.\n return html`\n <div style=${styleMap(headerStyles)} data-chat-header>\n <span style=${styleMap(avatar)} aria-hidden=\"true\">\u2726</span>\n <span style=${styleMap(name)}>${assistantName}</span>\n </div>\n `;\n}\n\nif (!customElements.get('adaptive-chat-bar')) {\n customElements.define('adaptive-chat-bar', AdaptiveChatBar);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'adaptive-chat-bar': AdaptiveChatBar;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -394,12 +394,18 @@ var AdaptiveChatTrail = class extends LitElement {
394
394
  };
395
395
  const modeStyles = this.forceExpanded ? {
396
396
  // Full-screen host: fill all available vertical space and
397
- // scroll the overflow. ``flex: 1 1 0`` (basis 0, not auto)
398
- // makes the trail shrink to 0 first when the parent runs
399
- // out of space — so the header above and the input row
400
- // below stay pinned at their natural sizes instead of one
401
- // of them being pushed off-screen.
402
- flex: "1 1 0",
397
+ // scroll the overflow. ``flex: 1 1 auto`` (basis AUTO, not 0)
398
+ // in a DEFINITE-height parent (full-screen panel) grow:1 still
399
+ // fills all free space and margin-top:auto bottom-anchors, so
400
+ // fill behavior is unchanged; but basis auto also lets the trail
401
+ // report its CONTENT height as its natural size, so in an
402
+ // INDEFINITE-height parent (velvet's shrink-wrap bottom sheet)
403
+ // the trail contributes real content height instead of collapsing
404
+ // to 0 — which is what lets the sheet hug its content with no void.
405
+ // shrink:1 + min-height:0 still lets the trail shrink first when
406
+ // the parent runs out of room; the input row is absolute-pinned
407
+ // (never pushed off) and the header shrinks after the trail.
408
+ flex: "1 1 auto",
403
409
  minHeight: "0",
404
410
  overflowY: "auto",
405
411
  // ``contain`` prevents scroll from bubbling out to the host
@@ -436,7 +442,11 @@ var AdaptiveChatTrail = class extends LitElement {
436
442
  width: "100%",
437
443
  display: "flex",
438
444
  flexDirection: "column",
439
- flex: "1 1 0",
445
+ // basis AUTO (see the scroller's modeStyles note): fills a definite
446
+ // parent, contributes content height in an indefinite one (velvet
447
+ // shrink-wrap). Every fill layer in the chain must be basis-auto or
448
+ // the min-content of a basis-0 layer collapses the whole chain to 0.
449
+ flex: "1 1 auto",
440
450
  minHeight: "0"
441
451
  } : {
442
452
  position: "relative",
@@ -1265,4 +1275,4 @@ export {
1265
1275
  AdaptiveChatTrail,
1266
1276
  looksLikeSerializedModelResponse
1267
1277
  };
1268
- //# sourceMappingURL=chunk-ZPN3HRYX.js.map
1278
+ //# sourceMappingURL=chunk-NWSIOIQ3.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/AdaptiveChatTrail.ts"],
4
+ "sourcesContent": ["/**\n * AdaptiveChatTrail \u2014 the \"bubble-up\" message column that sits above the\n * chat bar in the canvas lid.\n *\n * Messages appear immediately above the chat bar and drift upward as\n * newer ones arrive. Each stack position carries an opacity + blur\n * falloff so older messages read as fading from the page. Beyond a\n * `visibleCount` cap (default 3) the trail collapses into an \"N more \u00B7\n * expand\" affordance \u2014 clicking emits `trail-expand`.\n *\n * Shadow DOM (default Lit open root) so chip styles, markdown reset\n * rules, and animation @keyframes are scoped to this element's tree.\n * Theme CSS variables (--sc-tile-text-color, --sc-content-bubble-*,\n * etc.) inherit through the shadow boundary, so canvas-level theming\n * still reaches the chips. The earlier light-DOM render-root override\n * silently broke @keyframes lookup once the trail was hosted inside\n * any shadow root (sc-mount, velvet-mobile, etc.) \u2014 keyframes injected\n * into `document.head` aren't visible from another tree scope.\n *\n * See PRD \u00A74.3 (chat trail) for the canonical motion + falloff spec.\n */\n\nimport { renderMarkdown } from '@syntrologie/chat';\nimport { css, html, LitElement, nothing } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\n\nexport interface TrailToolCall {\n id: string;\n name: string;\n status: 'args-streaming' | 'pending' | 'running' | 'done' | 'error';\n /**\n * Parsed tool-call arguments, when available. Threaded through from\n * the AG-UI `ToolCall.args` so the trail can render argument-derived\n * affordances WITHOUT a new transport: an activity receipt for a\n * `primary_response_action` mount (derives type + label from\n * `template_id` / `content.title`) and inline reply chips for a\n * `suggest_replies` call (reads the `replies` array). Undefined while\n * args are still streaming or for tools whose args we don't surface.\n */\n args?: Record<string, unknown>;\n}\n\nexport interface TrailMessage {\n /** Stable identity for keyed rendering (must be unique within the trail). */\n id: number | string;\n role: 'user' | 'assistant' | 'system';\n text: string;\n /** Streaming \u2192 assistant text still arriving from backend. Complete \u2192 final. Error \u2192 fatal during stream. */\n status?: 'streaming' | 'complete' | 'error';\n /** Tool calls attached to an assistant message (rendered as compact chips). */\n toolCalls?: TrailToolCall[];\n}\n\nexport type TileReceipt =\n | { kind: 'tile'; instanceId: string; title: string; dismissed: boolean }\n | { kind: 'alert'; instanceId: string; title: string };\n\n/**\n * A widget the backend wants rendered INLINE IN THE CHAT TRAIL (in the\n * conversation flow, like a rich message) \u2014 currently the reco carousel.\n * Sourced from `ElementInstanceStore.listInlineWidgets()` (backend\n * `chat-inline` slot mounts) and forwarded by AdaptiveChatBar.\n *\n * The trail mounts `tag` by name via `document.createElement` and assigns\n * `props` onto the element \u2014 it never imports the widget package (the\n * element self-defines when its own bundle loads; on demos both bundles\n * are present). If `tag` is not a defined custom element, the trail\n * renders NOTHING for it (no broken box).\n */\nexport interface InlineTrailWidget {\n instanceId: string;\n /** Custom-element tag (e.g. `syntro-product-reco-carousel`). */\n tag: string;\n props: Record<string, unknown>;\n}\n\n/** PRD \u00A74.3 constants. */\nconst DEFAULT_VISIBLE = 3;\n/**\n * Shared max-width for EVERY message bubble in the trail (user,\n * assistant, streaming, pending, error). Single source of truth so\n * bubbles never drift to different widths across rendering paths \u2014 the\n * user reported chat tiles at inconsistent widths. Paired with\n * `width: fit-content` in `chipStyles`, short replies stay tight while\n * long ones cap here.\n */\nconst TRAIL_MAX_WIDTH = '88%';\nconst OPACITY_STEP = 0.22;\nconst OPACITY_FLOOR = 0.18;\nconst Y_DRIFT_PX = -2;\n/**\n * Height of the absolute blur veil at the top of the trail's scroll\n * area. Pixel-based, NOT message-count-based: with the old per-chip\n * `filter: blur(pos * step)` model, a single long markdown response\n * at pos=1 would have its entire body uniformly blurred \u2014 including\n * the chunk visually adjacent to the crisp newest message \u2014 because\n * blur is a property of the chip element, not of pixels. Switching\n * to a fixed-height backdrop-blur veil keeps the bottom of the\n * visible area (newest content) crisp regardless of message length.\n */\nconst TRAIL_BLUR_VEIL_PX = 72;\n/** Max blur applied at the very top of the veil; tapers to 0 at the bottom edge. */\nconst TRAIL_BLUR_MAX_PX = 5;\n\nexport class AdaptiveChatTrail extends LitElement {\n // Trail-local styles. The chat-trail used to render into light DOM\n // (`createRenderRoot() { return this }`) and inject these rules into\n // `document.head` so chip + markdown styles could find their selectors.\n // That broke the moment the trail was hosted inside any shadow root\n // (sc-mount \u2192 custom-canvas \u2192 velvet-mobile \u2192 sc-mount \u2192 chat-bar \u2192\n // chat-trail is the production chain): CSS animations require the\n // @keyframes rule to be in the SAME TreeScope as the element using\n // it, and document-level keyframes don't cross a shadow boundary.\n // Result was silent \u2014 `animation-name` parsed fine, the property got\n // the right resolved value, but the browser never instantiated an\n // Animation object because no matching keyframe was visible from\n // inside the shadow tree. `getAnimations()` returned `[]`, dots sat\n // frozen at base scale, the typing indicator looked dead.\n //\n // Shadow DOM with `static styles` is the right architecture here.\n // CSS custom properties (--sc-tile-text-color, --sc-content-bubble-*,\n // etc.) inherit through shadow boundaries by default, so the canvas\n // theme cascade still reaches the chips without the light-DOM\n // workaround. As a bonus the markdown reset rules can't leak out\n // onto the host page, and the keyframes are owned by the trail's\n // own tree scope where the chip + dot elements live.\n static override styles = css`\n [data-syntro-chat-trail] > :first-child {\n margin-top: auto;\n }\n [data-trail-chip] > p:first-child {\n margin-top: 0;\n }\n [data-trail-chip] > p:last-child {\n margin-bottom: 0;\n }\n [data-trail-chip] p {\n margin: 4px 0;\n }\n [data-trail-chip] br + br {\n display: none;\n }\n [data-trail-chip] ul,\n [data-trail-chip] ol {\n margin: 4px 0;\n padding-left: 1.1em;\n }\n [data-trail-chip] li {\n margin: 0;\n }\n [data-trail-chip] li + li {\n margin-top: 1px;\n }\n [data-trail-chip] pre {\n margin: 6px 0;\n padding: 6px 8px;\n background: var(--sc-content-code-background-block, rgba(0, 0, 0, 0.35));\n border-radius: 6px;\n overflow-x: auto;\n font-size: 11px;\n }\n [data-trail-chip] code {\n font-family: ui-monospace, SF Mono, Menlo, monospace;\n font-size: 11px;\n background: var(--sc-content-code-background, rgba(0, 0, 0, 0.25));\n padding: 1px 4px;\n border-radius: 3px;\n }\n [data-trail-chip] pre code {\n background: transparent;\n padding: 0;\n }\n [data-trail-chip] a {\n color: var(--sc-content-link-color, var(--sc-color-primary, #b72e2a));\n text-decoration: underline;\n }\n [data-trail-chip] strong {\n font-weight: 600;\n }\n /* Streaming-caret blink for in-progress assistant chips. */\n @keyframes syntro-trail-caret {\n 0% {\n opacity: 1;\n }\n 50% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n }\n /* Thinking-dot scale + opacity pulse. The naked-dots redesign\n relies entirely on this motion to signal \"alive\" \u2014 there's no\n chip frame around the dots, so a subtle animation reads as\n broken. 0.4 \u2192 1.0 scale with 0.25 \u2192 1.0 opacity gives an\n unmistakable breathing cue. */\n @keyframes syntro-trail-thinking-pulse {\n 0%,\n 100% {\n transform: scale(0.4);\n opacity: 0.25;\n }\n 45% {\n transform: scale(1);\n opacity: 1;\n }\n }\n /* Chip entrance \u2014 fades a freshly-mounted chip up from below\n so the thinking \u2192 first-streaming-chip handoff feels like one\n continuous motion instead of an element swap. */\n @keyframes syntro-trail-chip-enter {\n from {\n opacity: 0;\n transform: translateY(6px) scale(0.97);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n `;\n\n static override properties = {\n messages: { attribute: false },\n visibleCount: { type: Number },\n expanded: { type: Boolean },\n greeting: { type: String },\n /** When true: trail renders fully expanded AND the\n * expand/collapse affordance is hidden. Used by hosts that mount\n * the chat in a full-screen surface (the mobile panel) where\n * collapse makes no sense \u2014 there's nothing to collapse INTO. */\n forceExpanded: { type: Boolean },\n /**\n * Mirrors `chatSession.inFlight` \u2014 true between `send()` and the\n * assistant's first `receiveStart`/`receiveDelta`, OR while a\n * stream is in progress. Drives the \"thinking\" indicator that\n * fills the gap between the user's just-sent message and the\n * first assistant token. Wired through AdaptiveChatBar (it owns\n * the chatSession subscription and forwards inFlight as a prop).\n */\n inFlight: { type: Boolean },\n /**\n * Live reasoning narration streamed from the model via AG-UI\n * `THINKING_TEXT_MESSAGE_CONTENT`. When non-empty, the thinking\n * chip renders this in place of the bouncing dots so the visitor\n * sees what the model is actually doing instead of staring at\n * silent loading state during a tool-call gap.\n */\n thinkingText: { attribute: false },\n /**\n * Pre-conversation suggestion chip. When the visitor opens the\n * chat and `messages` is empty, the trail renders this as a\n * button beneath the greeting. Clicking it dispatches a\n * `trail-intro-suggestion` event with the configured prompt \u2014\n * the parent (chat-bar) forwards that to chatSession.send().\n * Disappears the moment the first message lands.\n */\n introSuggestion: { attribute: false },\n /**\n * Tappable tile-receipt chips rendered once at the end of the\n * trail. Produced from the store by Task 3 (AdaptiveChatBar).\n * Each chip emits `tile-receipt-activate` with its instanceId.\n */\n tileReceipts: { attribute: false },\n /**\n * Widgets rendered INLINE in the trail (reco carousel etc.),\n * anchored to a message position like receipts. Sourced from the\n * store's `chat-inline` slot mounts via AdaptiveChatBar.\n */\n inlineWidgets: { attribute: false },\n };\n\n messages: TrailMessage[] = [];\n tileReceipts: TileReceipt[] = [];\n inlineWidgets: InlineTrailWidget[] = [];\n visibleCount = DEFAULT_VISIBLE;\n expanded = false;\n forceExpanded = false;\n inFlight = false;\n thinkingText = '';\n introSuggestion: { label: string; prompt: string } | undefined = undefined;\n /**\n * Pre-conversation phantom assistant message. Rendered only when\n * `messages` is empty. NOT injected into chatSession state \u2014 the\n * greeting is configuration, not conversation, so it disappears\n * automatically when the first real message arrives.\n */\n greeting: string | undefined = undefined;\n\n // No `createRenderRoot()` override \u2192 default open shadow root. CSS\n // custom properties (--sc-tile-text-color, --sc-content-bubble-*,\n // etc.) inherit through the shadow boundary, so canvas-level theming\n // continues to cascade into the chips without the light-DOM hack.\n // See the `static styles` block above for the in-shadow stylesheet.\n\n private _onExpand = (): void => {\n // Self-manage: clicking the inline link expands the trail in place.\n // We still dispatch the event so any parent that wants to react\n // (telemetry, mirror state to a side panel, etc.) can listen.\n this.expanded = true;\n this.dispatchEvent(new CustomEvent('trail-expand', { bubbles: true, composed: true }));\n };\n\n /**\n * Approve a pending client tool call. The trail emits a generic\n * event so the host can decide whether to forward to chatSession\n * (the common path) or override. Keeps the trail itself free of\n * direct chatSession coupling \u2014 it's a pure view component.\n */\n private _onToolCallClick = (tc: TrailToolCall): void => {\n if (tc.status !== 'pending') return;\n this.dispatchEvent(\n new CustomEvent<{ toolCallId: string; approved: boolean }>('trail-toolcall-approved', {\n detail: { toolCallId: tc.id, approved: true },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n private _onCollapse = (): void => {\n // Mirror of _onExpand for the minimize affordance shown while\n // expanded. Self-manages + dispatches `trail-collapse` for parent\n // observers (telemetry, side-panel mirrors).\n this.expanded = false;\n this.dispatchEvent(new CustomEvent('trail-collapse', { bubbles: true, composed: true }));\n };\n\n /**\n * Whether to render the thinking-dots chip after the last message.\n * True iff a request is in flight AND the assistant hasn't started\n * streaming a reply yet \u2014 once the first delta lands, the streaming\n * chip's caret takes over and the thinking indicator hides so the\n * visitor isn't shown both at once. Also hidden when the last\n * message is an error/system message, because the request that\n * \"errored\" is already over from the user's perspective.\n */\n private _shouldShowThinking(): boolean {\n if (!this.inFlight) return false;\n const last = this.messages[this.messages.length - 1];\n if (!last) return true;\n // A streaming assistant message with no text yet is a PLACEHOLDER\n // (time-to-first-token window, or a tool phase before the first token).\n // It is not rendered as a bubble (see the `renderable` filter below) \u2014\n // keep the in-place thinking indicator showing until the first real\n // token lands, then hand off to the streaming chip. Without this the\n // indicator vanished at message-start and the visitor saw a blank bubble.\n if (last.role === 'assistant' && last.status === 'streaming') {\n return (last.text ?? '').trim().length === 0;\n }\n if (last.role === 'system' || last.status === 'error') return false;\n return true;\n }\n\n /**\n * instanceId \u2192 id of the message that was newest when the receipt first\n * appeared. This is what makes a receipt read like a chat bubble: it renders\n * inline right after its anchor message, so newer messages push it up into\n * history instead of it staying pinned below everything. Assigned once per\n * instanceId (in willUpdate, the only place that sees both `messages` and\n * `tileReceipts` at the moment a tile mounts) and never re-homed \u2014 a\n * dismiss/bring-back keeps the chip where it was created. `null` = the tile\n * mounted before the first chat message (canvas replay); those fall to the\n * tail strip (see render).\n */\n private readonly _receiptAnchors = new Map<string, TrailMessage['id'] | null>();\n\n /**\n * instanceId \u2192 anchor message id for inline widgets \u2014 same mechanism as\n * `_receiptAnchors`. The inline carousel renders right after the message\n * that was newest when it mounted, so it reads like a rich reply and\n * drifts up into history as later messages append.\n */\n private readonly _inlineAnchors = new Map<string, TrailMessage['id'] | null>();\n\n /**\n * instanceId \u2192 the live custom element mounted for an inline widget.\n * Cached so a prop patch (same instanceId, new props) updates the\n * EXISTING element instead of tearing it down and re-creating it \u2014\n * which would reset the carousel's scroll position + internal state.\n * The element is created lazily via `document.createElement(tag)` the\n * first time we see a defined tag; an undefined tag caches `null` so\n * the fail-safe renders nothing without re-checking the registry.\n */\n private readonly _inlineElements = new Map<string, HTMLElement | null>();\n\n override willUpdate(changed: Map<string, unknown>): void {\n // Only (re)compute anchors when the receipt set itself changes. A plain\n // message update must NOT re-home existing receipts \u2014 that's exactly how\n // they scroll up: their anchor stays put while new messages append below.\n if (changed.has('tileReceipts')) {\n const lastId = this.messages.length > 0 ? this.messages[this.messages.length - 1].id : null;\n const live = new Set<string>();\n for (const r of this.tileReceipts) {\n live.add(r.instanceId);\n if (!this._receiptAnchors.has(r.instanceId)) {\n this._receiptAnchors.set(r.instanceId, lastId);\n }\n }\n // Drop anchors for receipts that are gone (unmounted/expired) so the map\n // stays bounded over a long session.\n for (const key of this._receiptAnchors.keys()) {\n if (!live.has(key)) this._receiptAnchors.delete(key);\n }\n }\n // Same anchoring pass for inline widgets. Also reconcile the element\n // cache: create/refresh the element for each live widget, drop cached\n // elements + anchors for widgets that are gone.\n if (changed.has('inlineWidgets')) {\n const lastId = this.messages.length > 0 ? this.messages[this.messages.length - 1].id : null;\n const live = new Set<string>();\n for (const w of this.inlineWidgets) {\n live.add(w.instanceId);\n if (!this._inlineAnchors.has(w.instanceId)) {\n this._inlineAnchors.set(w.instanceId, lastId);\n }\n this._ensureInlineElement(w);\n }\n for (const key of this._inlineAnchors.keys()) {\n if (!live.has(key)) this._inlineAnchors.delete(key);\n }\n for (const key of this._inlineElements.keys()) {\n if (!live.has(key)) this._inlineElements.delete(key);\n }\n }\n }\n\n /**\n * Create (once) or refresh the cached custom element for an inline\n * widget. Mounts by tag name so the chat bundle never imports the\n * widget package. Fail-safe: if the tag is not a defined custom\n * element, cache `null` and render nothing (no broken box).\n */\n private _ensureInlineElement(w: InlineTrailWidget): void {\n let el = this._inlineElements.get(w.instanceId);\n if (el === undefined) {\n if (!customElements.get(w.tag)) {\n this._inlineElements.set(w.instanceId, null);\n return;\n }\n el = document.createElement(w.tag);\n el.setAttribute('data-inline-widget-el', '');\n this._inlineElements.set(w.instanceId, el);\n }\n if (!el) return; // previously-cached undefined tag \u2192 nothing to update\n // Assign props onto the element (not attributes) so complex values\n // (arrays/objects) reach the widget intact.\n for (const [k, v] of Object.entries(w.props)) {\n (el as unknown as Record<string, unknown>)[k] = v;\n }\n }\n\n override updated(changed: Map<string, unknown>): void {\n // Anchor the scroll to the bottom whenever:\n // - the trail flips into expanded mode (UX continuity), OR\n // - new messages or text deltas arrive (so a long streaming chip\n // stays pinned to the latest line, not the start of the chip).\n // Skip when the user has manually scrolled UP into history \u2014 we'd\n // rather lose pinning than yank them out of what they're reading.\n if (changed.has('expanded') || changed.has('messages')) {\n requestAnimationFrame(() => {\n const container = this.renderRoot.querySelector<HTMLElement>('[data-syntro-chat-trail]');\n if (!container) return;\n const distanceFromBottom =\n container.scrollHeight - container.scrollTop - container.clientHeight;\n // 200px tolerance \u2014 streaming deltas can append a paragraph in\n // one update, easily 80-150px. A tighter window would strand\n // the viewer at the top of the chip mid-stream because the\n // first delta blew past the threshold. User-driven scroll-up\n // of >200px disables auto-pin until they scroll back down.\n if (distanceFromBottom < 200 || changed.has('expanded')) {\n container.scrollTop = container.scrollHeight;\n }\n });\n }\n }\n\n private _onTileReceiptClick = (instanceId: string): void => {\n this.dispatchEvent(\n new CustomEvent('tile-receipt-activate', {\n detail: { instanceId },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n private _onAlertReceiptClick = (instanceId: string): void => {\n this.dispatchEvent(\n new CustomEvent('alert-receipt-activate', {\n detail: { instanceId },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n /** Render a set of inline widgets (reco carousel etc.) as\n * `[data-trail-widget]` blocks, anchored to a message position like\n * receipts. Each block hosts the cached custom element for that\n * instanceId \u2014 a defined tag mounts inline; an undefined tag renders\n * nothing (fail-safe). Rendered at every trail site (inline per anchor,\n * tail, empty-state) so placement can't diverge. */\n private _renderInlineWidgetStrip(list: InlineTrailWidget[]) {\n if (list.length === 0) return nothing;\n const blocks = list\n .map((w) => {\n const el = this._inlineElements.get(w.instanceId);\n if (!el) return nothing; // undefined tag / not yet created \u2192 nothing\n // Key the block by instanceId so Lit re-uses the same wrapper (and\n // therefore the same cached element child) across patches.\n return html`<div\n data-trail-widget\n data-instance-id=${w.instanceId}\n style=${styleMap(inlineWidgetBlockStyles())}\n >${el}</div>`;\n })\n .filter((b) => b !== nothing);\n if (blocks.length === 0) return nothing;\n return html`${blocks}`;\n }\n\n /** A row of receipt chips, used at every trail render site (inline per\n * anchor message, the tail fallback, and the empty-state branches) so the\n * markup + styling can never diverge. Returns `nothing` for an empty list. */\n private _renderReceiptStrip(list: TileReceipt[]) {\n if (list.length === 0) return nothing;\n return html`<div data-trail-tile-receipts style=${styleMap(replyChipStripStyles())}>\n ${list.map((tr) => this._renderReceiptChip(tr))}\n </div>`;\n }\n\n /** One receipt chip \u2014 a single, unified, single-line design for both kinds\n * (nav \"alert\" + mounted \"tile\"). Same container/title/action style so they\n * read as one chip family; the icon + action label carry the kind. No\n * subtitle: the old \"Brought up earlier\" line was hardcoded (wrong for\n * same-turn mounts) and made the chip taller \u2014 dropping it is the \"shorter\"\n * chip. Rendered at every trail site so the kinds can't diverge. */\n private _renderReceiptChip(tr: TileReceipt) {\n if (tr.kind === 'alert') {\n return html`<button\n type=\"button\"\n data-trail-alert-receipt\n data-instance-id=${tr.instanceId}\n @click=${() => this._onAlertReceiptClick(tr.instanceId)}\n style=${styleMap(tileReceiptChipStyles())}\n >\n <span style=${styleMap(alertReceiptIconStyles())} aria-hidden=\"true\">\u26A1</span>\n <span style=${styleMap(receiptChipTitleStyles('alert'))}>${tr.title}</span>\n <span style=${styleMap(tileReceiptActionStyles(false))}>Go \u2192</span>\n </button>`;\n }\n return html`<button\n type=\"button\"\n data-trail-tile-receipt\n data-instance-id=${tr.instanceId}\n @click=${() => this._onTileReceiptClick(tr.instanceId)}\n style=${styleMap(tileReceiptChipStyles())}\n >\n <span style=${styleMap(tileReceiptGlyphStyles())} aria-hidden=\"true\"\n ><i style=${styleMap(tileReceiptGlyphLayerStyles(0))}></i\n ><i style=${styleMap(tileReceiptGlyphLayerStyles(1))}></i\n ></span>\n <span style=${styleMap(receiptChipTitleStyles('tile'))}>${tr.title}</span>\n <span style=${styleMap(tileReceiptActionStyles(tr.dismissed))}\n >${tr.dismissed ? 'Bring back \u21BA' : 'View \u25B8'}</span\n >\n </button>`;\n }\n\n private _onIntroSuggestionClick = (): void => {\n const s = this.introSuggestion;\n if (!s) return;\n this.dispatchEvent(\n new CustomEvent<{ prompt: string }>('trail-intro-suggestion', {\n detail: { prompt: s.prompt },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n /**\n * Visitor tapped a `suggest_replies` inline chip. Emit\n * `trail-suggested-reply` carrying the chip text \u2014 the parent\n * (AdaptiveChatBar) re-dispatches it as `chat-message-sent`, the\n * SAME channel the input row uses, so the reply rides the existing\n * send path (mountable \u2192 chatSession.send \u2192 transport). No fabricated\n * AG-UI events; this is exactly what typing the text and hitting\n * Enter would do. The chips clear on their own once the reply lands\n * and a newer assistant message becomes the latest.\n */\n private _onSuggestedReplyClick = (text: string): void => {\n const trimmed = text.trim();\n if (!trimmed) return;\n this.dispatchEvent(\n new CustomEvent<{ text: string }>('trail-suggested-reply', {\n detail: { text: trimmed },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n override render() {\n if (\n this.messages.length === 0 &&\n !this.greeting &&\n !this.introSuggestion &&\n this.tileReceipts.length === 0 &&\n this.inlineWidgets.length === 0\n )\n return nothing;\n if (this.messages.length === 0 && (this.greeting || this.introSuggestion)) {\n // Empty-state hero. Mirrors the platform chats' empty-state\n // pattern (icon disc + title + pill button) instead of pretending\n // the greeting is an assistant message \u2014 that reads as a chat\n // bubble the visitor must reply to. A centered hero reads as\n // configured page chrome: \"this is how the surface starts.\"\n //\n // Receipt strip is appended AFTER the hero so tile chips render\n // even when the message list is still empty (e.g. canvas replay\n // delivers TILE_MOUNTED before the first chat turn).\n return html`<div data-syntro-chat-trail data-state=\"empty\" style=${styleMap({\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n textAlign: 'center',\n gap: '12px',\n flex: '1 1 auto',\n width: '100%',\n padding: '24px 16px',\n pointerEvents: 'auto',\n })}>\n <div data-trail-empty-icon style=${styleMap(emptyIconStyles())} aria-hidden=\"true\">\u2726</div>\n ${\n this.greeting\n ? html`<h2\n data-trail-empty-title\n style=${styleMap(emptyTitleStyles())}\n >${unsafeHTML(renderMarkdown(stripTrailingWhitespace(this.greeting)))}</h2>`\n : nothing\n }\n ${\n this.introSuggestion\n ? html`<button\n type=\"button\"\n data-trail-intro-suggestion\n @click=${this._onIntroSuggestionClick}\n style=${styleMap(introSuggestionStyles())}\n >${this.introSuggestion.label}</button>`\n : nothing\n }\n ${this._renderReceiptStrip(this.tileReceipts)}\n ${this._renderInlineWidgetStrip(this.inlineWidgets)}\n </div>`;\n }\n if (\n this.messages.length === 0 &&\n (this.tileReceipts.length > 0 || this.inlineWidgets.length > 0)\n ) {\n // No greeting, no intro suggestion, but receipts exist (e.g. canvas\n // replay before the visitor sends a first message). Render just the\n // receipt strip so chips are always visible when tiles are mounted.\n return html`<div data-syntro-chat-trail data-state=\"empty\" style=${styleMap({\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-start',\n gap: '6px',\n width: '100%',\n padding: '8px 0',\n pointerEvents: 'auto',\n })}>\n ${this._renderReceiptStrip(this.tileReceipts)}\n ${this._renderInlineWidgetStrip(this.inlineWidgets)}\n </div>`;\n }\n\n // Identity of the assistant message that hosts inline reply chips\n // (suggest_replies). Chips belong to the CURRENT agent turn: scanning back\n // from the newest message, the host is the first assistant message that\n // actually carries suggested replies. A trailing assistant turn (the agent\n // kept talking or mounted a card AFTER offering chips) does NOT steal the\n // chips \u2014 but a visitor reply does: hitting a `user` message first means the\n // visitor already answered, so the stale chips clear. Computed from the raw\n // list (before filtering) so it's stable and usable by both the\n // empty-message filter below and the render.\n //\n // BUG-1782968219: this was gated on the absolute-latest assistant message,\n // so any trailing assistant turn (e.g. a final \"tap whichever fits best\"\n // line) orphaned the chips onto a non-latest message and they never rendered.\n let suggestionHostId: TrailMessage['id'] | null = null;\n for (let i = this.messages.length - 1; i >= 0; i--) {\n const m = this.messages[i]!;\n if (m.role === 'user') break;\n if (m.role === 'assistant' && extractSuggestedReplies(m.toolCalls).length > 0) {\n suggestionHostId = m.id;\n break;\n }\n }\n\n // NEVER render an empty assistant bubble. An assistant message paints a\n // chip ONLY if it produces something the visitor can see \u2014 actual text,\n // a pending tool call (needs a tap), an activity receipt (a mount that\n // landed), or inline reply chips. A name-based allowlist was wrong: it\n // kept `primary_response_action`/`suggest_replies` turns whose receipt/\n // chips hadn't derived yet (mid-stream, or args without a title),\n // painting a blank bubble (sometimes with a lone \u2713). The guard now\n // mirrors EXACTLY what the render below would draw, computed by the\n // single source of truth `assistantChipRendersContent`. User and system\n // messages always render. See AdaptiveChatTrail.test.ts \"never renders\n // an empty assistant bubble\".\n const renderable = this.messages.filter(\n (m) => m.role !== 'assistant' || assistantChipRendersContent(m, m.id === suggestionHostId)\n );\n // Choose the slice we actually paint. Newest are at the END of the\n // array (closest to the chat bar). When not expanded, take the last\n // `visibleCount`; when expanded, take all.\n const visible =\n this.expanded || this.forceExpanded ? renderable : renderable.slice(-this.visibleCount);\n const hidden = renderable.length - visible.length;\n\n // Partition receipts by their anchor message so each renders INLINE right\n // after the message it mounted on (see `_receiptAnchors`). Receipts whose\n // anchor is null (mounted pre-chat) or whose anchor message isn't in the\n // painted slice (scrolled out of the collapsed ambient view, or an\n // empty/filtered assistant turn) fall to a tail strip at the bottom \u2014 the\n // old always-pinned position \u2014 so a receipt is never dropped.\n const visibleIds = new Set<TrailMessage['id']>(visible.map((m) => m.id));\n const receiptsByAnchor = new Map<TrailMessage['id'], TileReceipt[]>();\n const tailReceipts: TileReceipt[] = [];\n for (const r of this.tileReceipts) {\n const anchor = this._receiptAnchors.get(r.instanceId) ?? null;\n if (anchor !== null && visibleIds.has(anchor)) {\n const list = receiptsByAnchor.get(anchor);\n if (list) list.push(r);\n else receiptsByAnchor.set(anchor, [r]);\n } else {\n tailReceipts.push(r);\n }\n }\n\n // Same partition for inline widgets \u2014 anchored right after their host\n // message; those with no in-slice anchor fall to the tail strip.\n const inlineByAnchor = new Map<TrailMessage['id'], InlineTrailWidget[]>();\n const tailInlineWidgets: InlineTrailWidget[] = [];\n for (const w of this.inlineWidgets) {\n const anchor = this._inlineAnchors.get(w.instanceId) ?? null;\n if (anchor !== null && visibleIds.has(anchor)) {\n const list = inlineByAnchor.get(anchor);\n if (list) list.push(w);\n else inlineByAnchor.set(anchor, [w]);\n } else {\n tailInlineWidgets.push(w);\n }\n }\n\n const baseStyles: Record<string, string> = {\n display: 'flex',\n flexDirection: 'column',\n gap: '6px',\n // NO `justifyContent: flex-end` here \u2014 combined with `overflow: auto`\n // it's a known cross-browser bug: oversized flex children get\n // pushed ABOVE the container without contributing to scrollHeight,\n // so the scrollbar never appears. We rely on `:first-child {\n // margin-top: auto }` (injected as global CSS) to push short\n // content to the bottom of the box while leaving overflow handling\n // to the native scroll container.\n width: '100%',\n // The trail itself has no chrome \u2014 chips sit on the host page bg.\n padding: '0',\n pointerEvents: 'auto',\n };\n\n // Expanded mode: cap height, scroll, and add a visible top border so\n // the panel reads as a bounded region. NO background tint or shadow\n // \u2014 the ambient (collapsed) treatment is fine and we don't want to\n // suddenly introduce panel chrome that wasn't there before. The\n // border alone marks the panel's top edge.\n // Falloff is turned off per-chip below \u2014 readability wins once the\n // user has explicitly asked for history. See PRD \u00A74.3.\n // Collapsed mode also gets a (looser) cap + scroll so a single long\n // markdown chip doesn't blow the chat-bar off-screen with no\n // scroll affordance. Tighter than expanded so the bubble-up trail\n // doesn't dominate the surface visually.\n const modeStyles: Record<string, string> = this.forceExpanded\n ? {\n // Full-screen host: fill all available vertical space and\n // scroll the overflow. ``flex: 1 1 auto`` (basis AUTO, not 0) \u2014\n // in a DEFINITE-height parent (full-screen panel) grow:1 still\n // fills all free space and margin-top:auto bottom-anchors, so\n // fill behavior is unchanged; but basis auto also lets the trail\n // report its CONTENT height as its natural size, so in an\n // INDEFINITE-height parent (velvet's shrink-wrap bottom sheet)\n // the trail contributes real content height instead of collapsing\n // to 0 \u2014 which is what lets the sheet hug its content with no void.\n // shrink:1 + min-height:0 still lets the trail shrink first when\n // the parent runs out of room; the input row is absolute-pinned\n // (never pushed off) and the header shrinks after the trail.\n flex: '1 1 auto',\n minHeight: '0',\n overflowY: 'auto',\n // ``contain`` prevents scroll from bubbling out to the host\n // page when the trail hits top or bottom. Required for the\n // panel-scroll-leak regression test in\n // SyntroBottomSheet.test.ts.\n overscrollBehavior: 'contain',\n paddingTop: '8px',\n borderTop: 'var(--sc-content-bubble-border, 1px solid rgba(255, 255, 255, 0.18))',\n scrollBehavior: 'smooth',\n scrollbarWidth: 'thin',\n }\n : this.expanded\n ? {\n maxHeight: 'min(320px, 40vh)',\n overflowY: 'auto',\n paddingTop: '8px',\n borderTop: 'var(--sc-content-bubble-border, 1px solid rgba(255, 255, 255, 0.18))',\n scrollBehavior: 'smooth',\n scrollbarWidth: 'thin',\n }\n : {\n // Collapsed mode = ambient peek surface. Never a scrollbar:\n // long messages slide up behind the blur veil instead of\n // exposing a scrollbar. The \"\u2191 N more \u00B7 expand\" affordance\n // is the only entry into history; clicking it switches to\n // expanded mode where scroll IS allowed.\n // Height kept short so the trail reads as a peek strip above\n // the chat bar, not a panel \u2014 long single replies fade into\n // the blur veil at the top, user expands to read the rest.\n maxHeight: 'min(140px, 22vh)',\n overflow: 'hidden',\n };\n\n const containerStyles = { ...baseStyles, ...modeStyles };\n\n // (suggestionHostId computed above, before the empty-message filter.)\n\n // Wrap the scroll container in a positioning frame so the absolute\n // blur veil (rendered at the top) anchors to the scroll viewport's\n // top edge \u2014 NOT to a chip that scrolls under it. Pixel-anchored\n // blur means: the top TRAIL_BLUR_VEIL_PX of the visible area is\n // veiled regardless of how many messages occupy those pixels.\n // The frame wraps the scroll container so the absolute blur veil\n // anchors to the scroll viewport's top edge. In ``forceExpanded``\n // mode it ALSO has to participate in the flex column laid out by\n // the trail host \u2014 otherwise the scroll container's ``flex: 1 1\n // 0`` has no flex context, falls back to content height, and the\n // trail's overflow:hidden clips at the TOP of the scroll\n // (showing oldest messages, hiding the newest at the bottom).\n const frameStyles: Record<string, string> = this.forceExpanded\n ? {\n position: 'relative',\n width: '100%',\n display: 'flex',\n flexDirection: 'column',\n // basis AUTO (see the scroller's modeStyles note): fills a definite\n // parent, contributes content height in an indefinite one (velvet\n // shrink-wrap). Every fill layer in the chain must be basis-auto or\n // the min-content of a basis-0 layer collapses the whole chain to 0.\n flex: '1 1 auto',\n minHeight: '0',\n }\n : {\n position: 'relative',\n width: '100%',\n };\n\n return html`\n ${\n // Single toggle button above the frame. Same DOM node morphs:\n // collapsed \u2192 \"\u2191 N more \u00B7 expand\" / \"\u2191 expand\" (calls _onExpand)\n // expanded \u2192 \"\u2304 minimize\" (calls _onCollapse)\n // Lives OUTSIDE the frame so the absolute blur veil (top:0,\n // z-index:2 inside the frame) doesn't cover it. Shown whenever\n // there's anything in the trail \u2014 the user expects this affordance\n // available regardless of how many chips are on screen.\n // When ``forceExpanded`` is set by the host (full-screen panel,\n // etc.), there's nowhere to collapse INTO and the affordance\n // would just confuse the user \u2014 suppress it entirely.\n this.messages.length === 0 || this.forceExpanded\n ? nothing\n : this.expanded\n ? html`<button\n type=\"button\"\n data-trail-toggle\n data-trail-collapse\n @click=${this._onCollapse}\n style=${styleMap(moreStyles())}\n >\u2304 minimize</button>`\n : html`<button\n type=\"button\"\n data-trail-toggle\n data-trail-more\n @click=${this._onExpand}\n style=${styleMap(moreStyles())}\n >${hidden > 0 ? html`\u2191 ${hidden} more \u00B7 expand` : html`\u2191 expand`}</button>`\n }\n <div data-syntro-chat-trail-frame style=${styleMap(frameStyles)}>\n <div data-syntro-chat-trail style=${styleMap(containerStyles)}>\n ${visible.map((m, i) => {\n // Stack position from the bar: 0 = closest, N-1 = oldest.\n // visible[last] is closest, so reverse the index from the\n // tail of the visible slice. When expanded, the ambient\n // falloff is suppressed (pos = 0) so every chip reads at\n // full opacity \u2014 explicit history view, not ambient trail.\n const pos = this.expanded || this.forceExpanded ? 0 : visible.length - 1 - i;\n const state = chipVisualState(m);\n const isStreaming = state.kind === 'streaming';\n // The chip body's artifacts \u2014 pending tool calls (need a visitor\n // tap; running/done/error are internal mechanics, never painted),\n // activity receipts (\"Added <type> \u00B7 <label>\" for mounts that\n // landed), and inline reply chips (latest turn only). Computed by\n // the SAME `computeAssistantChipParts` the empty-message filter\n // uses, so what we paint here and what the filter considers\n // \"non-empty\" can never drift. (`toolCalls` keeps its name below.)\n const {\n pendingToolCalls: toolCalls,\n receipts,\n replyChips,\n } = computeAssistantChipParts(m, m.id === suggestionHostId);\n // Assistant text is markdown-formatted by the agent (lists,\n // code, bold, links). renderMarkdown sanitizes via DOMPurify,\n // then unsafeHTML injects the safe HTML. User + system chips\n // stay plain text \u2014 no markdown risk + no expansion attack\n // surface on user-typed input.\n const renderedText =\n m.role === 'assistant'\n ? // Never paint a degenerate serialized-response dump, even if the\n // turn also carries a legit part (receipt/chip) that keeps it in\n // the renderable set. Mirrors the filter's drop signal.\n looksLikeSerializedModelResponse(m.text ?? '')\n ? nothing\n : html`${unsafeHTML(renderMarkdown(stripTrailingWhitespace(m.text)))}`\n : html`${m.text}`;\n // Entrance animation on streaming chips only. Lit mounts the\n // chip element once per message id, so the animation fires\n // when the streaming chip first appears (replacing the\n // thinking chip in the same visual slot) and does NOT fire\n // again on subsequent token deltas \u2014 those just update the\n // text inside the already-mounted element. User messages\n // and settled history don't get an entrance: the user just\n // tapped Send so they expect immediate feedback, and old\n // history doesn't need re-attention every refresh.\n const chipStyle = isStreaming\n ? {\n ...chipStyles(state, pos),\n animation: 'syntro-trail-chip-enter 220ms cubic-bezier(0.22, 1, 0.36, 1) both',\n }\n : chipStyles(state, pos);\n return html`<div\n data-trail-chip\n data-role=${m.role}\n data-status=${m.status ?? 'complete'}\n style=${styleMap(chipStyle)}\n >${renderedText}${\n isStreaming\n ? html`<span\n data-trail-caret\n aria-hidden=\"true\"\n style=${styleMap(caretStyles())}\n ></span>`\n : nothing\n }${\n toolCalls.length > 0\n ? html`<div data-trail-toolcalls style=${styleMap(toolCallStripStyles())}>\n ${toolCalls.map(\n (tc) => html`<button\n type=\"button\"\n data-trail-toolcall\n data-tool-id=${tc.id}\n data-tool-status=${tc.status}\n @click=${() => this._onToolCallClick(tc)}\n ?disabled=${tc.status !== 'pending'}\n style=${styleMap(toolCallChipStyles(tc.status))}\n title=\"${tc.name} \u00B7 ${tc.status}\"\n >${toolCallIcon(tc.status)} ${tc.name}</button>`\n )}\n </div>`\n : nothing\n }${\n receipts.length > 0\n ? html`<div data-trail-receipts style=${styleMap(receiptStripStyles())}>\n ${receipts.map(\n (r) => html`<div\n data-trail-receipt\n data-receipt-type=${r.type}\n style=${styleMap(receiptStyles())}\n ><span aria-hidden=\"true\" style=${styleMap(receiptIconStyles())}>\u2713</span\n ><span>${receiptText(r)}</span></div>`\n )}\n </div>`\n : nothing\n }${\n replyChips.length > 0\n ? html`<div data-trail-reply-chips style=${styleMap(replyChipStripStyles())}>\n ${replyChips.map(\n (reply) => html`<button\n type=\"button\"\n data-trail-reply-chip\n @click=${() => this._onSuggestedReplyClick(reply)}\n style=${styleMap(replyChipStyles())}\n >${reply}</button>`\n )}\n </div>`\n : nothing\n }</div>${\n // Receipt chips that mounted while THIS message was newest render\n // inline right here, so they read as part of the flow and drift up\n // as later messages append below them.\n this._renderReceiptStrip(receiptsByAnchor.get(m.id) ?? [])\n }${\n // Inline widgets (reco carousel) anchored to this message render\n // right here in the conversation flow \u2014 the whole point of the\n // chat-inline slot: visible in the trail, not behind the panel.\n this._renderInlineWidgetStrip(inlineByAnchor.get(m.id) ?? [])\n }`;\n })}\n ${\n // Thinking indicator \u2014 fills the gap between the user's\n // most recent message and the assistant's first token.\n // Shows when chatSession.inFlight is true AND the last\n // message is NOT a streaming assistant message (the\n // assistant's own caret takes over once tokens arrive).\n // Styled as an assistant chip with three bouncing dots\n // instead of text, so the thread reads naturally \u2014 the\n // visitor sees an \"assistant\" bubble that's clearly busy.\n this._shouldShowThinking()\n ? html`<div\n data-trail-thinking\n data-role=\"assistant\"\n data-status=\"thinking\"\n aria-label=${\n this.thinkingText\n ? `Assistant is thinking: ${this.thinkingText}`\n : 'Assistant is thinking'\n }\n style=${styleMap(thinkingSlotStyles())}\n >\n ${\n // When the backend has streamed reasoning narration into\n // `thinkingText`, render the tail of it as a small italic\n // line \u2014 the model's own intent (\"Let me check what we have\n // for student athletes\u2026\") narrates the gap better than\n // silent dots. Falls back to the bouncing-dot pulse when\n // no narration has arrived yet.\n this.thinkingText\n ? html`<span\n data-trail-thinking-text\n style=${styleMap(thinkingTextStyles())}\n >${truncateThinkingTail(this.thinkingText)}</span\n >`\n : html`<span data-trail-thinking-dots style=${styleMap(thinkingDotsStyles())}>\n <span style=${styleMap(thinkingDotStyles(0))}></span>\n <span style=${styleMap(thinkingDotStyles(1))}></span>\n <span style=${styleMap(thinkingDotStyles(2))}></span>\n </span>`\n }\n </div>`\n : nothing\n }\n ${\n // Tail strip: receipts with no in-slice anchor (mounted pre-chat, or\n // their anchor message scrolled out of the ambient view). Keeps them\n // reachable at the bottom \u2014 the old always-pinned position \u2014 rather\n // than dropping them. In expanded/maximized mode every message is\n // painted, so this is usually empty and receipts sit inline instead.\n this._renderReceiptStrip(tailReceipts)\n }\n ${\n // Inline widgets with no in-slice anchor (mounted pre-chat, or their\n // anchor scrolled out of the ambient view) render at the tail.\n this._renderInlineWidgetStrip(tailInlineWidgets)\n }\n </div>\n ${\n // The blur veil only fires in collapsed (ambient) mode.\n // Expanded = the user explicitly asked for history; blurring\n // the top of the panel would hide content (including the\n // minimize button just above the trail's top edge) the user\n // came here to see.\n this.expanded || this.forceExpanded\n ? nothing\n : html`<div\n data-trail-blur-veil\n aria-hidden=\"true\"\n style=${styleMap(blurVeilStyles())}\n ></div>`\n }\n </div>\n `;\n }\n}\n\n/**\n * Absolute blur veil at the top of the scroll viewport. Uses\n * `backdrop-filter: blur(...)` so whatever pixels sit beneath the veil\n * (top of the scroll content) become blurred, regardless of which chip\n * those pixels belong to. A linear mask fades the blur effect from full\n * at the top to zero at the bottom of the veil \u2014 newest content stays\n * crisp because it lives below the veil's height.\n *\n * Note: `mask-image` controls where the BACKDROP-FILTER applies (via\n * masking the veil element), so the bottom edge of the veil naturally\n * dissolves into the unblurred scroll area below.\n */\nfunction blurVeilStyles(): Record<string, string> {\n const mask = 'linear-gradient(to bottom, black 0%, black 40%, transparent 100%)';\n return {\n position: 'absolute',\n top: '0',\n left: '0',\n right: '0',\n height: `${TRAIL_BLUR_VEIL_PX}px`,\n pointerEvents: 'none',\n backdropFilter: `blur(${TRAIL_BLUR_MAX_PX}px)`,\n WebkitBackdropFilter: `blur(${TRAIL_BLUR_MAX_PX}px)`,\n maskImage: mask,\n WebkitMaskImage: mask,\n zIndex: '2',\n };\n}\n\n/**\n * Discriminated visual state for a chip. Replaces the older\n * `(role, { isStreaming, isError })` triple whose interaction order\n * could produce nonsense combinations (e.g. an assistant chip\n * accidentally reading as a user bubble because `isStreaming` was\n * checked before role). Each kind below is a real conversational\n * state with a single visual identity:\n *\n * - `settled` \u2014 a complete message; the user-vs-assistant\n * identity comes from `role`\n * - `streaming` \u2014 the assistant chip currently receiving tokens;\n * keeps assistant identity (the blinking caret\n * inside the chip carries \"in progress\")\n * - `pending` \u2014 the thinking chip shown between the user's\n * just-sent message and the assistant's first\n * token; assistant identity (the bouncing dots\n * inside carry \"in progress\")\n * - `error` \u2014 a chip whose stream failed mid-flight, OR any\n * system-role message (system messages render\n * with the error identity by convention)\n *\n * Bug history: an earlier branch-ladder design checked `isStreaming`\n * before `role`, so the `pending`/thinking chip inherited the user\n * bubble border. On hosts whose chat panel sits over a light surface\n * that read as a \"white div\" pasted into the assistant slot. The\n * discriminated state prevents that combination from being expressible.\n */\nexport type ChipVisualState =\n | { kind: 'settled'; role: 'user' | 'assistant' | 'system' }\n | { kind: 'streaming' }\n | { kind: 'pending' }\n | { kind: 'error'; role: 'user' | 'assistant' | 'system' };\n\n/**\n * Map a trail message + the trail's `inFlight` flag onto its visual\n * state. The thinking chip is rendered separately at the render-tree\n * level \u2014 this helper covers settled / streaming / error messages and\n * leaves the `pending` state to the dedicated thinking-chip render\n * path.\n */\nfunction chipVisualState(m: TrailMessage): ChipVisualState {\n // System messages and explicit error status both render as error\n // chips regardless of role (the original `isError` definition).\n if (m.status === 'error' || m.role === 'system') {\n return { kind: 'error', role: m.role };\n }\n if (m.role === 'assistant' && m.status === 'streaming') {\n return { kind: 'streaming' };\n }\n return { kind: 'settled', role: m.role };\n}\n\nfunction chipStyles(state: ChipVisualState, pos: number): Record<string, string> {\n const opacity = Math.max(OPACITY_FLOOR, 1 - pos * OPACITY_STEP);\n const yPx = pos * Y_DRIFT_PX;\n\n // Per-state visual tokens. Fallbacks are conservative neutrals so\n // the chip still renders sensibly on a host page that hasn't set\n // its design-system tokens yet. The contract: changing one state's\n // border MUST NOT silently affect another state's border.\n let border: string;\n let background: string;\n let color: string;\n let alignSelf: 'flex-start' | 'flex-end';\n\n switch (state.kind) {\n case 'settled':\n if (state.role === 'user') {\n border = 'var(--sc-content-bubble-border-user, 1px solid rgba(255, 255, 255, 0.28))';\n background = 'var(--sc-content-bubble-background-user, rgba(255, 255, 255, 0.10))';\n alignSelf = 'flex-end';\n } else {\n border = 'var(--sc-content-bubble-border, 1px solid rgba(255, 255, 255, 0.18))';\n background = 'var(--sc-content-bubble-background, rgba(20, 22, 24, 0.35))';\n alignSelf = 'flex-start';\n }\n color = 'var(--sc-tile-title-color, inherit)';\n break;\n case 'streaming':\n case 'pending':\n // Assistant identity. The caret (streaming) or bouncing dots\n // (pending) inside the chip carry the in-progress signal \u2014 the\n // chip's outer identity stays consistent with the assistant's\n // settled reply, so the visitor sees the SAME entity speaking\n // throughout the response lifecycle. This is the bug fix: prior\n // versions borrowed the user border for these states and broke\n // identity continuity.\n border = 'var(--sc-content-bubble-border, 1px solid rgba(255, 255, 255, 0.18))';\n background = 'var(--sc-content-bubble-background, rgba(20, 22, 24, 0.35))';\n color = 'var(--sc-tile-title-color, inherit)';\n alignSelf = 'flex-start';\n break;\n case 'error':\n border = 'var(--sc-content-bubble-border-error, 1px solid rgba(220, 80, 80, 0.55))';\n background = 'var(--sc-content-bubble-background-error, rgba(140, 40, 40, 0.42))';\n color = 'var(--sc-content-bubble-text-error, rgba(255, 220, 220, 0.95))';\n // Errors keep their originating role's alignment so a failed\n // user-side send still sits on the right where the user expects\n // their message to land.\n alignSelf = state.role === 'user' ? 'flex-end' : 'flex-start';\n break;\n }\n\n return {\n alignSelf,\n // Single shared width policy for EVERY bubble (user / assistant /\n // streaming / pending / error). Short and long replies now read as a\n // consistent column: `fit-content` sizes each bubble to its text, and\n // `TRAIL_MAX_WIDTH` caps the wide ones at the same ceiling \u2014 no more\n // per-role or per-path width drift (user feedback: chat tiles had\n // differing widths).\n maxWidth: TRAIL_MAX_WIDTH,\n width: 'fit-content',\n // Bumped from 11px \u2192 13px after the chat lid in production read as\n // cramped at the smaller size \u2014 body chat copy needs to be visitor-\n // legible on a phone without zoom, and 11px reads as a footnote\n // rather than the primary conversation surface. Code blocks inside\n // chip body scale proportionally (10px \u2192 11px) below.\n fontSize: '13px',\n lineHeight: '1.45',\n padding: '5px 11px',\n borderRadius: '10px',\n border,\n background,\n backdropFilter: 'blur(8px)',\n WebkitBackdropFilter: 'blur(8px)',\n color,\n transition:\n 'opacity 240ms cubic-bezier(0.22, 1, 0.36, 1), transform 240ms cubic-bezier(0.22, 1, 0.36, 1)',\n // Per-position opacity + y-drift falloff is still per-chip \u2014 those\n // operate naturally per element. Blur is NOT per-chip anymore: it's\n // applied via an absolute-positioned veil at the top of the scroll\n // viewport (TRAIL_BLUR_VEIL_PX above), so a single long message\n // doesn't get uniformly blurred across its full body.\n opacity: String(toFixedTrim(opacity)),\n transform: `translateY(${yPx}px)`,\n // User messages render as raw text (`html` template); pre-wrap preserves\n // newlines the visitor typed. Assistant messages render as markdown HTML\n // (`<p>` tags from marked); pre-wrap there would make marked's inter-tag\n // text nodes (the `\\n` between/after `<p>` tags) visible, producing the\n // trailing/inter-paragraph blank lines visitors reported. Markdown's own\n // structure carries the paragraph breaks, so assistant chips use the\n // default `normal` whitespace handling.\n whiteSpace:\n (state.kind === 'settled' || state.kind === 'error') && state.role === 'user'\n ? 'pre-wrap'\n : 'normal',\n wordBreak: 'break-word',\n };\n}\n\nfunction toolCallStripStyles(): Record<string, string> {\n return {\n display: 'flex',\n flexWrap: 'wrap',\n gap: '4px',\n marginTop: '4px',\n paddingTop: '4px',\n borderTop: '1px dashed var(--sc-content-divider-color, rgba(255, 255, 255, 0.12))',\n };\n}\n\nfunction toolCallChipStyles(status: TrailToolCall['status']): Record<string, string> {\n const isPending = status === 'pending';\n const isError = status === 'error';\n const isDone = status === 'done';\n return {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '4px',\n padding: '2px 7px',\n border: isError\n ? 'var(--sc-content-bubble-border-error, 1px solid rgba(220, 80, 80, 0.45))'\n : isPending\n ? 'var(--sc-content-bubble-border-user, 1px solid rgba(255, 255, 255, 0.28))'\n : 'var(--sc-content-bubble-border, 1px solid rgba(255, 255, 255, 0.18))',\n background: isError\n ? 'var(--sc-content-bubble-background-error, rgba(140, 40, 40, 0.35))'\n : isPending\n ? 'var(--sc-content-bubble-background-user, rgba(255, 255, 255, 0.10))'\n : isDone\n ? 'var(--sc-content-bubble-background-idle, rgba(40, 44, 50, 0.4))'\n : 'var(--sc-content-bubble-background, rgba(20, 22, 24, 0.35))',\n color: 'var(--sc-tile-text-color, inherit)',\n borderRadius: '999px',\n fontSize: '10px',\n fontWeight: '500',\n fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',\n cursor: isPending ? 'pointer' : 'default',\n opacity: isDone ? '0.7' : '1',\n };\n}\n\nfunction toolCallIcon(status: TrailToolCall['status']): string {\n switch (status) {\n case 'args-streaming':\n case 'running':\n return '\u22EF';\n case 'pending':\n return '?';\n case 'done':\n return '\u2713';\n case 'error':\n return '\u2717';\n default:\n return '\u00B7';\n }\n}\n\n/**\n * A parsed activity receipt \u2014 what the agent just put on the page.\n * Derived from a `primary_response_action` tool call's args.\n */\ninterface ActivityReceipt {\n /** Friendly element category for the receipt copy (\"card\", \"FAQ\", \u2026). */\n type: string;\n /** Human label \u2014 the mounted thing's title, or the template id. */\n label: string;\n}\n\n/**\n * Map a tool call onto an activity receipt, or null when it isn't a\n * mount we surface. Only `primary_response_action` (the mount tool)\n * produces a receipt: it's THE channel for putting something on the\n * page, so its appearance is what the visitor needs acknowledged.\n *\n * Type is derived from `template_id` with cheap substring heuristics \u2014\n * template ids are admin-authored and workspace-specific, so we match\n * on stable kind-words (\"card\", \"faq\", \"chart\", \"alert\"/\"navigation\")\n * rather than an enum that would drift. Label prefers\n * `content.title`, falling back to the template id so the receipt is\n * never blank.\n */\nfunction deriveActivityReceipt(tc: TrailToolCall): ActivityReceipt | null {\n if (tc.name !== 'primary_response_action') return null;\n const args = tc.args;\n if (!args || typeof args !== 'object') return null;\n const templateId = typeof args.template_id === 'string' ? args.template_id : '';\n const content = (args.content ?? null) as Record<string, unknown> | null;\n const title =\n content && typeof content.title === 'string' && content.title.trim()\n ? content.title.trim()\n : '';\n const id = templateId.toLowerCase();\n let type: string;\n if (id.includes('faq')) type = 'FAQ';\n else if (id.includes('chart') || id.includes('graph')) type = 'chart';\n else if (id.includes('card') || id.includes('product')) type = 'card';\n else if (id.includes('alert') || id.includes('navigation') || id.includes('nav')) type = 'alert';\n else type = 'added to your view';\n const label = title || templateId || 'something';\n return { type, label };\n}\n\n/**\n * User-facing receipt copy. Frames what the assistant did FOR the visitor\n * (\"Pulled up the FAQ for you\") rather than the mechanical system action\n * (\"Added alert \u00B7 Read the FAQ\"). Phrased to read naturally with the\n * admin-authored labels (which are often imperative CTAs like \"Read the FAQ\").\n */\nfunction receiptText(r: ActivityReceipt): string {\n switch (r.type) {\n case 'FAQ':\n return 'Opened the FAQ for you';\n case 'chart':\n return `Put together ${r.label} for you`;\n case 'card':\n // Product cards: the only label available is the mount's `title`, which\n // is a marketing eyebrow (\"Sharper thinking, backed by Lion's Mane\"), not\n // the product NAME (that's pinned in the template's default_widget_props,\n // which the receipt can't see). Echoing the eyebrow reads wrong, so use a\n // clean generic instead of `Pulled up <eyebrow> for you`.\n return 'Pulled up the product for you';\n case 'alert':\n // Navigation shortcuts only \u2014 the label is the CTA destination.\n return `Here's a shortcut: ${r.label}`;\n default:\n // Unknown template kinds ('added to your view'): a safe generic \u2014 never\n // mislabel a content mount as a navigation shortcut.\n return `Pulled up ${r.label} for you`;\n }\n}\n\n/**\n * Pull the candidate reply strings out of a message's `suggest_replies`\n * tool call. Returns [] when there's no such call or its `replies` arg\n * is missing / malformed. Caps at four (mirrors the backend tool) and\n * drops blanks so a sloppy args payload can't render empty chips.\n */\nfunction extractSuggestedReplies(toolCalls: TrailToolCall[] | undefined): string[] {\n if (!toolCalls) return [];\n for (const tc of toolCalls) {\n if (tc.name !== 'suggest_replies') continue;\n const replies = tc.args?.replies;\n if (!Array.isArray(replies)) return [];\n return replies\n .filter((r): r is string => typeof r === 'string' && r.trim().length > 0)\n .map((r) => r.trim())\n .slice(0, 4);\n }\n return [];\n}\n\n/**\n * The artifacts an assistant chip's body can paint, beyond its text. This is\n * THE single computation of \"what shows\" \u2014 BOTH the empty-message filter and\n * the per-message render read it, so \"is this bubble empty?\" and \"what do we\n * draw?\" can never disagree. That drift (two places each guessing what renders)\n * is what let blank bubbles regress repeatedly. To add a new visible artifact,\n * add it here once; the filter and render both honor it automatically.\n */\ninterface AssistantChipParts {\n /** Tool calls that need a visitor tap. running/done/error are internal\n * mechanics and are deliberately never painted. */\n pendingToolCalls: TrailToolCall[];\n /** \"Added <type> \u00B7 <label>\" lines for mounts that landed this turn. */\n receipts: ActivityReceipt[];\n /** Tappable suggested answers \u2014 only on the suggestion-host turn (the\n * current turn's suggest_replies message, until the visitor replies). */\n replyChips: string[];\n}\n\nfunction computeAssistantChipParts(m: TrailMessage, isSuggestionHost: boolean): AssistantChipParts {\n const toolCalls = m.toolCalls ?? [];\n return {\n pendingToolCalls: toolCalls.filter((tc) => tc.status === 'pending'),\n receipts: toolCalls.map(deriveActivityReceipt).filter((r): r is ActivityReceipt => r !== null),\n replyChips: isSuggestionHost ? extractSuggestedReplies(toolCalls) : [],\n };\n}\n\n/**\n * A misbehaving model can emit a raw SERIALIZED response payload as plain TEXT\n * on a spurious trailing turn \u2014 e.g.\n * `(Empty response: {'content': [{'type': 'thinking', \u2026}], 'stop_reason': \u2026})`.\n * Backstop for model degeneration (Kimi); the prompt (S-14) also asks for one\n * brief closing, but copy can't be trusted on the very turn that degenerates.\n *\n * Detection avoids false positives (which are WORSE than the dump \u2014 the visitor\n * would see nothing): a turn is dropped only if it OPENS with the literal\n * \"(Empty response\" marker, OR it carries \u22652 serialization tokens at once. A\n * single token (a product about a \"signature blend\", the agent quoting one JSON\n * key) never trips it; a real response dump carries all of them.\n */\nexport function looksLikeSerializedModelResponse(text: string): boolean {\n const t = text.trimStart();\n if (t.startsWith('(Empty response')) return true;\n let hits = 0;\n if (/['\"]stop_reason['\"]\\s*:/.test(t)) hits++;\n if (/['\"]signature['\"]\\s*:/.test(t)) hits++;\n if (/['\"]type['\"]\\s*:\\s*['\"]thinking['\"]/.test(t)) hits++;\n if (/['\"]content['\"]\\s*:\\s*\\[/.test(t)) hits++;\n return hits >= 2;\n}\n\n/**\n * Does this assistant chip paint anything the visitor can see? Derived from the\n * SAME parts the render draws (computeAssistantChipParts) plus the text, so the\n * empty-message filter and the render are guaranteed to agree and a bubble is\n * NEVER rendered blank. See AdaptiveChatTrail.test.ts \"never renders an empty\n * assistant bubble\".\n */\nfunction assistantChipRendersContent(m: TrailMessage, isSuggestionHost: boolean): boolean {\n const text = (m.text ?? '').trim();\n // A degenerate serialized-response dump has text but must never be shown \u2014\n // treat it as no content so the chip is filtered out, like an empty turn.\n if (text.length > 0 && !looksLikeSerializedModelResponse(text)) return true;\n const { pendingToolCalls, receipts, replyChips } = computeAssistantChipParts(m, isSuggestionHost);\n return pendingToolCalls.length > 0 || receipts.length > 0 || replyChips.length > 0;\n}\n\n/**\n * Wrapper for an inline widget block (reco carousel). Full trail width so\n * the horizontally-scrollable carousel fits the conversation column; the\n * widget inherits the chat theme tokens through the shadow boundary (CSS\n * custom properties cascade in). `minWidth: 0` lets the carousel's own\n * `overflow-x` scroll instead of forcing the trail wider. `contain` keeps\n * the carousel's internal scroll from leaking into the trail scroll.\n */\nfunction inlineWidgetBlockStyles(): Record<string, string> {\n return {\n alignSelf: 'stretch',\n width: '100%',\n minWidth: '0',\n marginTop: '6px',\n contain: 'layout',\n };\n}\n\nfunction receiptStripStyles(): Record<string, string> {\n return {\n display: 'flex',\n flexDirection: 'column',\n gap: '2px',\n marginTop: '4px',\n };\n}\n\nfunction receiptStyles(): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '5px',\n alignSelf: 'flex-start',\n fontSize: '11px',\n lineHeight: '1.3',\n fontWeight: '500',\n letterSpacing: '0.01em',\n // Inherit the chip's OWN resolved text color (muted via opacity), so the\n // receipt is legible on every theme by construction. The old\n // `--sc-content-muted-color` fallback was rgba(255,255,255,\u2026) \u2014 white \u2014\n // invisible on light canvases; a `--sc-tile-text-color` token can likewise\n // be unset/mismatched on dark canvases. `currentColor` always matches the\n // chip text the visitor is already reading.\n color: 'currentColor',\n opacity: '0.7',\n };\n}\n\nfunction receiptIconStyles(): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '14px',\n height: '14px',\n borderRadius: '50%',\n fontSize: '9px',\n fontWeight: '700',\n color: '#fff',\n background: 'hsl(var(--sc-accent-color, 145 40% 45%) / 0.7)',\n };\n}\n\nfunction replyChipStripStyles(): Record<string, string> {\n return {\n display: 'flex',\n flexWrap: 'wrap',\n gap: '6px',\n marginTop: '6px',\n alignSelf: 'flex-start',\n };\n}\n\nfunction replyChipStyles(): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n padding: '5px 12px',\n border: '1px solid hsl(var(--sc-accent-color, 145 40% 45%) / 0.40)',\n borderRadius: '9999px',\n background: 'hsl(var(--sc-accent-color, 145 40% 45%) / 0.12)',\n color: 'var(--sc-tile-text-color, currentColor)',\n font: 'inherit',\n fontSize: '12px',\n fontWeight: '500',\n lineHeight: '1.2',\n cursor: 'pointer',\n backdropFilter: 'blur(8px)',\n WebkitBackdropFilter: 'blur(8px)',\n transition: 'background 150ms ease, transform 120ms ease',\n };\n}\n\nfunction alertReceiptIconStyles(): Record<string, string> {\n return {\n flex: '0 0 auto',\n width: '26px',\n height: '26px',\n borderRadius: '8px',\n display: 'grid',\n placeItems: 'center',\n background: 'hsl(var(--sc-accent-color))',\n color: 'var(--sc-accent-foreground, #fff)',\n fontSize: '14px',\n };\n}\nfunction tileReceiptChipStyles(): Record<string, string> {\n return {\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n width: '100%',\n textAlign: 'left',\n cursor: 'pointer',\n padding: '9px 10px 9px 11px',\n borderRadius: '12px',\n border: '1px solid hsl(var(--sc-accent-color) / 0.28)',\n background: 'hsl(var(--sc-accent-color) / 0.06)',\n };\n}\nfunction tileReceiptGlyphStyles(): Record<string, string> {\n return { position: 'relative', flex: '0 0 auto', width: '28px', height: '28px' };\n}\nfunction tileReceiptGlyphLayerStyles(i: 0 | 1): Record<string, string> {\n return {\n position: 'absolute',\n inset: '0',\n borderRadius: '7px',\n background: 'hsl(var(--sc-accent-color) / 0.22)',\n boxShadow: 'inset 0 0 0 1px hsl(var(--sc-accent-color) / 0.4)',\n ...(i === 0 ? { transform: 'translate(3px,-3px) rotate(6deg)', opacity: '0.5' } : {}),\n };\n}\nfunction receiptChipTitleStyles(_kind: 'alert' | 'tile'): Record<string, string> {\n return {\n // Grows to fill the space between the icon and the action pill, truncating\n // long product names on one line (the chip is now single-line).\n flex: '1',\n minWidth: '0',\n fontSize: '13px',\n fontWeight: '650',\n lineHeight: '1.2',\n color: 'var(--sc-content-text-color, #0f172a)',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n };\n}\nfunction tileReceiptActionStyles(dismissed: boolean): Record<string, string> {\n return {\n flex: '0 0 auto',\n fontSize: '11px',\n fontWeight: '700',\n borderRadius: '999px',\n padding: '4px 10px',\n ...(dismissed\n ? { background: 'hsl(var(--sc-accent-color) / 0.14)', color: 'hsl(var(--sc-accent-color))' }\n : {\n background: 'hsl(var(--sc-accent-color) / 0.9)',\n color: 'var(--sc-accent-foreground, #fff)',\n }),\n };\n}\n\nfunction caretStyles(): Record<string, string> {\n return {\n display: 'inline-block',\n width: '6px',\n height: '12px',\n marginLeft: '3px',\n verticalAlign: '-1px',\n background: 'hsl(var(--sc-accent-color) / 0.85)',\n borderRadius: '1px',\n animation: 'syntro-trail-caret 1s steps(2, end) infinite',\n };\n}\n\n/**\n * Layout slot for the naked thinking indicator. No bubble \u2014 no\n * background, no border, no padding, no backdrop blur. The chip\n * decoration around an \"empty assistant message\" was reading as a\n * placeholder card on host themes that drew the chip background as a\n * solid color; stripping it lets the dots carry the entire signal.\n * What this style does keep:\n * - left alignment in the trail's flex column (assistant slot)\n * - the inherited chip text color, which the dots' `currentColor`\n * fill picks up so they tint with the assistant identity\n * - a fade-up entrance so the indicator arrives, not pops, into\n * view next to the user's just-sent message\n * - a small inset so the dots sit at the same baseline a text chip\n * would, preventing a vertical jump when the first token arrives\n * and the slot is replaced by the streaming chip\n */\nfunction thinkingSlotStyles(): Record<string, string> {\n return {\n alignSelf: 'flex-start',\n color: 'var(--sc-tile-title-color, inherit)',\n padding: '4px 4px',\n animation: 'syntro-trail-chip-enter 220ms cubic-bezier(0.22, 1, 0.36, 1) both',\n };\n}\n\nfunction thinkingDotsStyles(): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '6px',\n // Line height matches what a single-line text chip would compute\n // to, so swapping out the slot for the streaming chip doesn't\n // shift the next chip up or down by a couple of pixels.\n lineHeight: '14px',\n };\n}\n\nfunction thinkingDotStyles(index: number): Record<string, string> {\n return {\n display: 'inline-block',\n width: '7px',\n height: '7px',\n borderRadius: '50%',\n background: 'currentColor',\n // The dots are now the entire visual \u2014 no bubble framing them \u2014\n // so the pulse has to do all the work the chip used to do. Scale\n // 0.4 \u2192 1.0 with opacity 0.25 \u2192 1.0 gives an unmistakable\n // breathing motion: at the trough each dot reads like a faint\n // ghost, at the peak like a solid dot. 940ms cycle is a touch\n // faster than the original 1.05s; without the chip frame the\n // shorter cycle feels purposeful instead of agitated. Stagger\n // 130ms = clear rolling cadence across all three.\n transformOrigin: 'center',\n animation: `syntro-trail-thinking-pulse 940ms cubic-bezier(0.4, 0, 0.6, 1) ${index * 0.13}s infinite both`,\n };\n}\n\nfunction moreStyles(): Record<string, string> {\n return {\n // Center horizontally regardless of the parent's display model.\n // ``alignSelf: center`` only works when the parent is a flex/grid\n // container with cross-axis alignment; the chat-bar's flex column\n // stretches us full-width instead. ``display: block`` + auto inline\n // margins centers the auto-sized button without needing the parent\n // to opt in.\n display: 'block',\n marginLeft: 'auto',\n marginRight: 'auto',\n marginBottom: '6px',\n fontSize: '10px',\n fontWeight: '500',\n letterSpacing: '0.06em',\n padding: '4px 10px',\n border: '1px solid hsl(var(--sc-accent-color) / 0.32)',\n borderRadius: '999px',\n background: 'hsl(var(--sc-accent-color) / 0.10)',\n color: 'var(--sc-tile-text-color, currentColor)',\n cursor: 'pointer',\n opacity: '0.85',\n backdropFilter: 'blur(8px)',\n WebkitBackdropFilter: 'blur(8px)',\n transition: 'opacity 150ms ease, background 150ms ease',\n };\n}\n\n// The trail used to inject these rules into `document.head` via a\n// helper. With the move to shadow DOM (see `static styles` on\n// AdaptiveChatTrail above), the rules are owned by Lit and scoped to\n// the trail's own tree. document.head injection is the wrong choice\n// from inside a shadow-rooted hierarchy \u2014 see the static-styles\n// comment for the failure mode.\n\n/**\n * Pre-process LLM markdown before rendering. Three common artifacts:\n *\n * 1. Trailing \" \" (two spaces = markdown hard-break) sprinkled at\n * end-of-line, even inside list items where it just leaks\n * invisible whitespace into the DOM.\n * 2. Runs of 3+ blank lines used as visual separators. Markdown\n * treats any number of blank lines as a single paragraph break,\n * so the extras add nothing semantically \u2014 but combined with\n * paragraph margins they create huge gaps in the tiny chip layout.\n * 3. Leading / trailing newlines on the whole message. Trailing\n * `\\n\\n` is the common one \u2014 marked turns it into a final empty\n * <p> that still occupies a full line-height of vertical space,\n * leaving a visible gap between the last text and the chat bar.\n *\n * Collapsing all three keeps the rendered HTML tight without changing\n * the agent's semantic intent.\n */\nfunction stripTrailingWhitespace(text: string): string {\n return text\n .replace(/[ \\t]+$/gm, '') // trailing whitespace per line\n .replace(/\\n{3,}/g, '\\n\\n') // collapse runs of blank lines\n .trim(); // drop leading/trailing whitespace+newlines on the whole message\n}\n\n/** Two-decimal trim that avoids trailing zeros (\".50\" \u2192 \".5\"). */\nfunction toFixedTrim(n: number): string {\n const s = n.toFixed(2);\n return s.replace(/\\.?0+$/, '') || '0';\n}\n\nconst THINKING_TAIL_MAX = 120;\n\n/**\n * Render the tail end of a streaming thinking buffer \u2014 the model's\n * narration grows monotonically as it reasons, but we only ever want\n * to display the last sentence (or so) to keep the chip compact while\n * still feeling alive as new content lands. Returns the input verbatim\n * if it's already short; otherwise prepends an ellipsis to signal the\n * head was trimmed.\n */\nfunction truncateThinkingTail(text: string): string {\n const flat = text.replace(/\\s+/g, ' ').trim();\n if (flat.length <= THINKING_TAIL_MAX) return flat;\n return `\u2026${flat.slice(-THINKING_TAIL_MAX)}`;\n}\n\nfunction thinkingTextStyles(): Record<string, string> {\n return {\n fontStyle: 'italic',\n opacity: '0.75',\n fontSize: '13px',\n lineHeight: '18px',\n maxWidth: '32ch',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n };\n}\n\nfunction introSuggestionStyles(): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '6px',\n marginTop: '4px',\n padding: '10px 18px',\n borderRadius: '9999px',\n border: '0',\n background:\n 'linear-gradient(135deg, var(--sc-color-primary, #5faf7d) 0%, var(--sc-color-primary-hover, #3d8a5e) 100%)',\n color: '#fff',\n cursor: 'pointer',\n font: 'inherit',\n fontSize: '14px',\n fontWeight: '600',\n transition: 'transform 120ms ease, filter 160ms ease',\n };\n}\n\nfunction emptyIconStyles(): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '48px',\n height: '48px',\n borderRadius: '9999px',\n background:\n 'var(--sc-tile-icon-background, linear-gradient(135deg, var(--sc-color-primary, #5faf7d) 0%, var(--sc-color-primary-hover, #3d8a5e) 100%))',\n color: '#fff',\n fontSize: '22px',\n };\n}\n\nfunction emptyTitleStyles(): Record<string, string> {\n return {\n margin: '0',\n fontSize: '15px',\n fontWeight: '600',\n lineHeight: '1.35',\n color: 'var(--sc-content-text-color, inherit)',\n maxWidth: '32ch',\n };\n}\n\nif (!customElements.get('adaptive-chat-trail')) {\n customElements.define('adaptive-chat-trail', AdaptiveChatTrail);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'adaptive-chat-trail': AdaptiveChatTrail;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
package/dist/runtime.js CHANGED
@@ -10,12 +10,12 @@ import {
10
10
  fetchMountedElements,
11
11
  renderFallbackHtml
12
12
  } from "./chunk-6ONIYMVA.js";
13
- import "./chunk-G2DSOWTP.js";
13
+ import "./chunk-L3LR2J3L.js";
14
14
  import {
15
15
  getElementInstanceStore,
16
16
  setElementInstanceStore
17
17
  } from "./chunk-EWPPVPJ4.js";
18
- import "./chunk-ZPN3HRYX.js";
18
+ import "./chunk-NWSIOIQ3.js";
19
19
  import "./chunk-5PW6T3QF.js";
20
20
  import "./chunk-FVNSOP7B.js";
21
21
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syntrologie/adapt-chatbot",
3
- "version": "2.8.0-canary.406",
3
+ "version": "2.8.0-canary.408",
4
4
  "description": "Adaptive Chatbot - AI chat assistant widget with action execution",
5
5
  "license": "Proprietary",
6
6
  "private": false,
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/AdaptiveChatTrail.ts"],
4
- "sourcesContent": ["/**\n * AdaptiveChatTrail \u2014 the \"bubble-up\" message column that sits above the\n * chat bar in the canvas lid.\n *\n * Messages appear immediately above the chat bar and drift upward as\n * newer ones arrive. Each stack position carries an opacity + blur\n * falloff so older messages read as fading from the page. Beyond a\n * `visibleCount` cap (default 3) the trail collapses into an \"N more \u00B7\n * expand\" affordance \u2014 clicking emits `trail-expand`.\n *\n * Shadow DOM (default Lit open root) so chip styles, markdown reset\n * rules, and animation @keyframes are scoped to this element's tree.\n * Theme CSS variables (--sc-tile-text-color, --sc-content-bubble-*,\n * etc.) inherit through the shadow boundary, so canvas-level theming\n * still reaches the chips. The earlier light-DOM render-root override\n * silently broke @keyframes lookup once the trail was hosted inside\n * any shadow root (sc-mount, velvet-mobile, etc.) \u2014 keyframes injected\n * into `document.head` aren't visible from another tree scope.\n *\n * See PRD \u00A74.3 (chat trail) for the canonical motion + falloff spec.\n */\n\nimport { renderMarkdown } from '@syntrologie/chat';\nimport { css, html, LitElement, nothing } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\n\nexport interface TrailToolCall {\n id: string;\n name: string;\n status: 'args-streaming' | 'pending' | 'running' | 'done' | 'error';\n /**\n * Parsed tool-call arguments, when available. Threaded through from\n * the AG-UI `ToolCall.args` so the trail can render argument-derived\n * affordances WITHOUT a new transport: an activity receipt for a\n * `primary_response_action` mount (derives type + label from\n * `template_id` / `content.title`) and inline reply chips for a\n * `suggest_replies` call (reads the `replies` array). Undefined while\n * args are still streaming or for tools whose args we don't surface.\n */\n args?: Record<string, unknown>;\n}\n\nexport interface TrailMessage {\n /** Stable identity for keyed rendering (must be unique within the trail). */\n id: number | string;\n role: 'user' | 'assistant' | 'system';\n text: string;\n /** Streaming \u2192 assistant text still arriving from backend. Complete \u2192 final. Error \u2192 fatal during stream. */\n status?: 'streaming' | 'complete' | 'error';\n /** Tool calls attached to an assistant message (rendered as compact chips). */\n toolCalls?: TrailToolCall[];\n}\n\nexport type TileReceipt =\n | { kind: 'tile'; instanceId: string; title: string; dismissed: boolean }\n | { kind: 'alert'; instanceId: string; title: string };\n\n/**\n * A widget the backend wants rendered INLINE IN THE CHAT TRAIL (in the\n * conversation flow, like a rich message) \u2014 currently the reco carousel.\n * Sourced from `ElementInstanceStore.listInlineWidgets()` (backend\n * `chat-inline` slot mounts) and forwarded by AdaptiveChatBar.\n *\n * The trail mounts `tag` by name via `document.createElement` and assigns\n * `props` onto the element \u2014 it never imports the widget package (the\n * element self-defines when its own bundle loads; on demos both bundles\n * are present). If `tag` is not a defined custom element, the trail\n * renders NOTHING for it (no broken box).\n */\nexport interface InlineTrailWidget {\n instanceId: string;\n /** Custom-element tag (e.g. `syntro-product-reco-carousel`). */\n tag: string;\n props: Record<string, unknown>;\n}\n\n/** PRD \u00A74.3 constants. */\nconst DEFAULT_VISIBLE = 3;\n/**\n * Shared max-width for EVERY message bubble in the trail (user,\n * assistant, streaming, pending, error). Single source of truth so\n * bubbles never drift to different widths across rendering paths \u2014 the\n * user reported chat tiles at inconsistent widths. Paired with\n * `width: fit-content` in `chipStyles`, short replies stay tight while\n * long ones cap here.\n */\nconst TRAIL_MAX_WIDTH = '88%';\nconst OPACITY_STEP = 0.22;\nconst OPACITY_FLOOR = 0.18;\nconst Y_DRIFT_PX = -2;\n/**\n * Height of the absolute blur veil at the top of the trail's scroll\n * area. Pixel-based, NOT message-count-based: with the old per-chip\n * `filter: blur(pos * step)` model, a single long markdown response\n * at pos=1 would have its entire body uniformly blurred \u2014 including\n * the chunk visually adjacent to the crisp newest message \u2014 because\n * blur is a property of the chip element, not of pixels. Switching\n * to a fixed-height backdrop-blur veil keeps the bottom of the\n * visible area (newest content) crisp regardless of message length.\n */\nconst TRAIL_BLUR_VEIL_PX = 72;\n/** Max blur applied at the very top of the veil; tapers to 0 at the bottom edge. */\nconst TRAIL_BLUR_MAX_PX = 5;\n\nexport class AdaptiveChatTrail extends LitElement {\n // Trail-local styles. The chat-trail used to render into light DOM\n // (`createRenderRoot() { return this }`) and inject these rules into\n // `document.head` so chip + markdown styles could find their selectors.\n // That broke the moment the trail was hosted inside any shadow root\n // (sc-mount \u2192 custom-canvas \u2192 velvet-mobile \u2192 sc-mount \u2192 chat-bar \u2192\n // chat-trail is the production chain): CSS animations require the\n // @keyframes rule to be in the SAME TreeScope as the element using\n // it, and document-level keyframes don't cross a shadow boundary.\n // Result was silent \u2014 `animation-name` parsed fine, the property got\n // the right resolved value, but the browser never instantiated an\n // Animation object because no matching keyframe was visible from\n // inside the shadow tree. `getAnimations()` returned `[]`, dots sat\n // frozen at base scale, the typing indicator looked dead.\n //\n // Shadow DOM with `static styles` is the right architecture here.\n // CSS custom properties (--sc-tile-text-color, --sc-content-bubble-*,\n // etc.) inherit through shadow boundaries by default, so the canvas\n // theme cascade still reaches the chips without the light-DOM\n // workaround. As a bonus the markdown reset rules can't leak out\n // onto the host page, and the keyframes are owned by the trail's\n // own tree scope where the chip + dot elements live.\n static override styles = css`\n [data-syntro-chat-trail] > :first-child {\n margin-top: auto;\n }\n [data-trail-chip] > p:first-child {\n margin-top: 0;\n }\n [data-trail-chip] > p:last-child {\n margin-bottom: 0;\n }\n [data-trail-chip] p {\n margin: 4px 0;\n }\n [data-trail-chip] br + br {\n display: none;\n }\n [data-trail-chip] ul,\n [data-trail-chip] ol {\n margin: 4px 0;\n padding-left: 1.1em;\n }\n [data-trail-chip] li {\n margin: 0;\n }\n [data-trail-chip] li + li {\n margin-top: 1px;\n }\n [data-trail-chip] pre {\n margin: 6px 0;\n padding: 6px 8px;\n background: var(--sc-content-code-background-block, rgba(0, 0, 0, 0.35));\n border-radius: 6px;\n overflow-x: auto;\n font-size: 11px;\n }\n [data-trail-chip] code {\n font-family: ui-monospace, SF Mono, Menlo, monospace;\n font-size: 11px;\n background: var(--sc-content-code-background, rgba(0, 0, 0, 0.25));\n padding: 1px 4px;\n border-radius: 3px;\n }\n [data-trail-chip] pre code {\n background: transparent;\n padding: 0;\n }\n [data-trail-chip] a {\n color: var(--sc-content-link-color, var(--sc-color-primary, #b72e2a));\n text-decoration: underline;\n }\n [data-trail-chip] strong {\n font-weight: 600;\n }\n /* Streaming-caret blink for in-progress assistant chips. */\n @keyframes syntro-trail-caret {\n 0% {\n opacity: 1;\n }\n 50% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n }\n /* Thinking-dot scale + opacity pulse. The naked-dots redesign\n relies entirely on this motion to signal \"alive\" \u2014 there's no\n chip frame around the dots, so a subtle animation reads as\n broken. 0.4 \u2192 1.0 scale with 0.25 \u2192 1.0 opacity gives an\n unmistakable breathing cue. */\n @keyframes syntro-trail-thinking-pulse {\n 0%,\n 100% {\n transform: scale(0.4);\n opacity: 0.25;\n }\n 45% {\n transform: scale(1);\n opacity: 1;\n }\n }\n /* Chip entrance \u2014 fades a freshly-mounted chip up from below\n so the thinking \u2192 first-streaming-chip handoff feels like one\n continuous motion instead of an element swap. */\n @keyframes syntro-trail-chip-enter {\n from {\n opacity: 0;\n transform: translateY(6px) scale(0.97);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n `;\n\n static override properties = {\n messages: { attribute: false },\n visibleCount: { type: Number },\n expanded: { type: Boolean },\n greeting: { type: String },\n /** When true: trail renders fully expanded AND the\n * expand/collapse affordance is hidden. Used by hosts that mount\n * the chat in a full-screen surface (the mobile panel) where\n * collapse makes no sense \u2014 there's nothing to collapse INTO. */\n forceExpanded: { type: Boolean },\n /**\n * Mirrors `chatSession.inFlight` \u2014 true between `send()` and the\n * assistant's first `receiveStart`/`receiveDelta`, OR while a\n * stream is in progress. Drives the \"thinking\" indicator that\n * fills the gap between the user's just-sent message and the\n * first assistant token. Wired through AdaptiveChatBar (it owns\n * the chatSession subscription and forwards inFlight as a prop).\n */\n inFlight: { type: Boolean },\n /**\n * Live reasoning narration streamed from the model via AG-UI\n * `THINKING_TEXT_MESSAGE_CONTENT`. When non-empty, the thinking\n * chip renders this in place of the bouncing dots so the visitor\n * sees what the model is actually doing instead of staring at\n * silent loading state during a tool-call gap.\n */\n thinkingText: { attribute: false },\n /**\n * Pre-conversation suggestion chip. When the visitor opens the\n * chat and `messages` is empty, the trail renders this as a\n * button beneath the greeting. Clicking it dispatches a\n * `trail-intro-suggestion` event with the configured prompt \u2014\n * the parent (chat-bar) forwards that to chatSession.send().\n * Disappears the moment the first message lands.\n */\n introSuggestion: { attribute: false },\n /**\n * Tappable tile-receipt chips rendered once at the end of the\n * trail. Produced from the store by Task 3 (AdaptiveChatBar).\n * Each chip emits `tile-receipt-activate` with its instanceId.\n */\n tileReceipts: { attribute: false },\n /**\n * Widgets rendered INLINE in the trail (reco carousel etc.),\n * anchored to a message position like receipts. Sourced from the\n * store's `chat-inline` slot mounts via AdaptiveChatBar.\n */\n inlineWidgets: { attribute: false },\n };\n\n messages: TrailMessage[] = [];\n tileReceipts: TileReceipt[] = [];\n inlineWidgets: InlineTrailWidget[] = [];\n visibleCount = DEFAULT_VISIBLE;\n expanded = false;\n forceExpanded = false;\n inFlight = false;\n thinkingText = '';\n introSuggestion: { label: string; prompt: string } | undefined = undefined;\n /**\n * Pre-conversation phantom assistant message. Rendered only when\n * `messages` is empty. NOT injected into chatSession state \u2014 the\n * greeting is configuration, not conversation, so it disappears\n * automatically when the first real message arrives.\n */\n greeting: string | undefined = undefined;\n\n // No `createRenderRoot()` override \u2192 default open shadow root. CSS\n // custom properties (--sc-tile-text-color, --sc-content-bubble-*,\n // etc.) inherit through the shadow boundary, so canvas-level theming\n // continues to cascade into the chips without the light-DOM hack.\n // See the `static styles` block above for the in-shadow stylesheet.\n\n private _onExpand = (): void => {\n // Self-manage: clicking the inline link expands the trail in place.\n // We still dispatch the event so any parent that wants to react\n // (telemetry, mirror state to a side panel, etc.) can listen.\n this.expanded = true;\n this.dispatchEvent(new CustomEvent('trail-expand', { bubbles: true, composed: true }));\n };\n\n /**\n * Approve a pending client tool call. The trail emits a generic\n * event so the host can decide whether to forward to chatSession\n * (the common path) or override. Keeps the trail itself free of\n * direct chatSession coupling \u2014 it's a pure view component.\n */\n private _onToolCallClick = (tc: TrailToolCall): void => {\n if (tc.status !== 'pending') return;\n this.dispatchEvent(\n new CustomEvent<{ toolCallId: string; approved: boolean }>('trail-toolcall-approved', {\n detail: { toolCallId: tc.id, approved: true },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n private _onCollapse = (): void => {\n // Mirror of _onExpand for the minimize affordance shown while\n // expanded. Self-manages + dispatches `trail-collapse` for parent\n // observers (telemetry, side-panel mirrors).\n this.expanded = false;\n this.dispatchEvent(new CustomEvent('trail-collapse', { bubbles: true, composed: true }));\n };\n\n /**\n * Whether to render the thinking-dots chip after the last message.\n * True iff a request is in flight AND the assistant hasn't started\n * streaming a reply yet \u2014 once the first delta lands, the streaming\n * chip's caret takes over and the thinking indicator hides so the\n * visitor isn't shown both at once. Also hidden when the last\n * message is an error/system message, because the request that\n * \"errored\" is already over from the user's perspective.\n */\n private _shouldShowThinking(): boolean {\n if (!this.inFlight) return false;\n const last = this.messages[this.messages.length - 1];\n if (!last) return true;\n // A streaming assistant message with no text yet is a PLACEHOLDER\n // (time-to-first-token window, or a tool phase before the first token).\n // It is not rendered as a bubble (see the `renderable` filter below) \u2014\n // keep the in-place thinking indicator showing until the first real\n // token lands, then hand off to the streaming chip. Without this the\n // indicator vanished at message-start and the visitor saw a blank bubble.\n if (last.role === 'assistant' && last.status === 'streaming') {\n return (last.text ?? '').trim().length === 0;\n }\n if (last.role === 'system' || last.status === 'error') return false;\n return true;\n }\n\n /**\n * instanceId \u2192 id of the message that was newest when the receipt first\n * appeared. This is what makes a receipt read like a chat bubble: it renders\n * inline right after its anchor message, so newer messages push it up into\n * history instead of it staying pinned below everything. Assigned once per\n * instanceId (in willUpdate, the only place that sees both `messages` and\n * `tileReceipts` at the moment a tile mounts) and never re-homed \u2014 a\n * dismiss/bring-back keeps the chip where it was created. `null` = the tile\n * mounted before the first chat message (canvas replay); those fall to the\n * tail strip (see render).\n */\n private readonly _receiptAnchors = new Map<string, TrailMessage['id'] | null>();\n\n /**\n * instanceId \u2192 anchor message id for inline widgets \u2014 same mechanism as\n * `_receiptAnchors`. The inline carousel renders right after the message\n * that was newest when it mounted, so it reads like a rich reply and\n * drifts up into history as later messages append.\n */\n private readonly _inlineAnchors = new Map<string, TrailMessage['id'] | null>();\n\n /**\n * instanceId \u2192 the live custom element mounted for an inline widget.\n * Cached so a prop patch (same instanceId, new props) updates the\n * EXISTING element instead of tearing it down and re-creating it \u2014\n * which would reset the carousel's scroll position + internal state.\n * The element is created lazily via `document.createElement(tag)` the\n * first time we see a defined tag; an undefined tag caches `null` so\n * the fail-safe renders nothing without re-checking the registry.\n */\n private readonly _inlineElements = new Map<string, HTMLElement | null>();\n\n override willUpdate(changed: Map<string, unknown>): void {\n // Only (re)compute anchors when the receipt set itself changes. A plain\n // message update must NOT re-home existing receipts \u2014 that's exactly how\n // they scroll up: their anchor stays put while new messages append below.\n if (changed.has('tileReceipts')) {\n const lastId = this.messages.length > 0 ? this.messages[this.messages.length - 1].id : null;\n const live = new Set<string>();\n for (const r of this.tileReceipts) {\n live.add(r.instanceId);\n if (!this._receiptAnchors.has(r.instanceId)) {\n this._receiptAnchors.set(r.instanceId, lastId);\n }\n }\n // Drop anchors for receipts that are gone (unmounted/expired) so the map\n // stays bounded over a long session.\n for (const key of this._receiptAnchors.keys()) {\n if (!live.has(key)) this._receiptAnchors.delete(key);\n }\n }\n // Same anchoring pass for inline widgets. Also reconcile the element\n // cache: create/refresh the element for each live widget, drop cached\n // elements + anchors for widgets that are gone.\n if (changed.has('inlineWidgets')) {\n const lastId = this.messages.length > 0 ? this.messages[this.messages.length - 1].id : null;\n const live = new Set<string>();\n for (const w of this.inlineWidgets) {\n live.add(w.instanceId);\n if (!this._inlineAnchors.has(w.instanceId)) {\n this._inlineAnchors.set(w.instanceId, lastId);\n }\n this._ensureInlineElement(w);\n }\n for (const key of this._inlineAnchors.keys()) {\n if (!live.has(key)) this._inlineAnchors.delete(key);\n }\n for (const key of this._inlineElements.keys()) {\n if (!live.has(key)) this._inlineElements.delete(key);\n }\n }\n }\n\n /**\n * Create (once) or refresh the cached custom element for an inline\n * widget. Mounts by tag name so the chat bundle never imports the\n * widget package. Fail-safe: if the tag is not a defined custom\n * element, cache `null` and render nothing (no broken box).\n */\n private _ensureInlineElement(w: InlineTrailWidget): void {\n let el = this._inlineElements.get(w.instanceId);\n if (el === undefined) {\n if (!customElements.get(w.tag)) {\n this._inlineElements.set(w.instanceId, null);\n return;\n }\n el = document.createElement(w.tag);\n el.setAttribute('data-inline-widget-el', '');\n this._inlineElements.set(w.instanceId, el);\n }\n if (!el) return; // previously-cached undefined tag \u2192 nothing to update\n // Assign props onto the element (not attributes) so complex values\n // (arrays/objects) reach the widget intact.\n for (const [k, v] of Object.entries(w.props)) {\n (el as unknown as Record<string, unknown>)[k] = v;\n }\n }\n\n override updated(changed: Map<string, unknown>): void {\n // Anchor the scroll to the bottom whenever:\n // - the trail flips into expanded mode (UX continuity), OR\n // - new messages or text deltas arrive (so a long streaming chip\n // stays pinned to the latest line, not the start of the chip).\n // Skip when the user has manually scrolled UP into history \u2014 we'd\n // rather lose pinning than yank them out of what they're reading.\n if (changed.has('expanded') || changed.has('messages')) {\n requestAnimationFrame(() => {\n const container = this.renderRoot.querySelector<HTMLElement>('[data-syntro-chat-trail]');\n if (!container) return;\n const distanceFromBottom =\n container.scrollHeight - container.scrollTop - container.clientHeight;\n // 200px tolerance \u2014 streaming deltas can append a paragraph in\n // one update, easily 80-150px. A tighter window would strand\n // the viewer at the top of the chip mid-stream because the\n // first delta blew past the threshold. User-driven scroll-up\n // of >200px disables auto-pin until they scroll back down.\n if (distanceFromBottom < 200 || changed.has('expanded')) {\n container.scrollTop = container.scrollHeight;\n }\n });\n }\n }\n\n private _onTileReceiptClick = (instanceId: string): void => {\n this.dispatchEvent(\n new CustomEvent('tile-receipt-activate', {\n detail: { instanceId },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n private _onAlertReceiptClick = (instanceId: string): void => {\n this.dispatchEvent(\n new CustomEvent('alert-receipt-activate', {\n detail: { instanceId },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n /** Render a set of inline widgets (reco carousel etc.) as\n * `[data-trail-widget]` blocks, anchored to a message position like\n * receipts. Each block hosts the cached custom element for that\n * instanceId \u2014 a defined tag mounts inline; an undefined tag renders\n * nothing (fail-safe). Rendered at every trail site (inline per anchor,\n * tail, empty-state) so placement can't diverge. */\n private _renderInlineWidgetStrip(list: InlineTrailWidget[]) {\n if (list.length === 0) return nothing;\n const blocks = list\n .map((w) => {\n const el = this._inlineElements.get(w.instanceId);\n if (!el) return nothing; // undefined tag / not yet created \u2192 nothing\n // Key the block by instanceId so Lit re-uses the same wrapper (and\n // therefore the same cached element child) across patches.\n return html`<div\n data-trail-widget\n data-instance-id=${w.instanceId}\n style=${styleMap(inlineWidgetBlockStyles())}\n >${el}</div>`;\n })\n .filter((b) => b !== nothing);\n if (blocks.length === 0) return nothing;\n return html`${blocks}`;\n }\n\n /** A row of receipt chips, used at every trail render site (inline per\n * anchor message, the tail fallback, and the empty-state branches) so the\n * markup + styling can never diverge. Returns `nothing` for an empty list. */\n private _renderReceiptStrip(list: TileReceipt[]) {\n if (list.length === 0) return nothing;\n return html`<div data-trail-tile-receipts style=${styleMap(replyChipStripStyles())}>\n ${list.map((tr) => this._renderReceiptChip(tr))}\n </div>`;\n }\n\n /** One receipt chip \u2014 a single, unified, single-line design for both kinds\n * (nav \"alert\" + mounted \"tile\"). Same container/title/action style so they\n * read as one chip family; the icon + action label carry the kind. No\n * subtitle: the old \"Brought up earlier\" line was hardcoded (wrong for\n * same-turn mounts) and made the chip taller \u2014 dropping it is the \"shorter\"\n * chip. Rendered at every trail site so the kinds can't diverge. */\n private _renderReceiptChip(tr: TileReceipt) {\n if (tr.kind === 'alert') {\n return html`<button\n type=\"button\"\n data-trail-alert-receipt\n data-instance-id=${tr.instanceId}\n @click=${() => this._onAlertReceiptClick(tr.instanceId)}\n style=${styleMap(tileReceiptChipStyles())}\n >\n <span style=${styleMap(alertReceiptIconStyles())} aria-hidden=\"true\">\u26A1</span>\n <span style=${styleMap(receiptChipTitleStyles('alert'))}>${tr.title}</span>\n <span style=${styleMap(tileReceiptActionStyles(false))}>Go \u2192</span>\n </button>`;\n }\n return html`<button\n type=\"button\"\n data-trail-tile-receipt\n data-instance-id=${tr.instanceId}\n @click=${() => this._onTileReceiptClick(tr.instanceId)}\n style=${styleMap(tileReceiptChipStyles())}\n >\n <span style=${styleMap(tileReceiptGlyphStyles())} aria-hidden=\"true\"\n ><i style=${styleMap(tileReceiptGlyphLayerStyles(0))}></i\n ><i style=${styleMap(tileReceiptGlyphLayerStyles(1))}></i\n ></span>\n <span style=${styleMap(receiptChipTitleStyles('tile'))}>${tr.title}</span>\n <span style=${styleMap(tileReceiptActionStyles(tr.dismissed))}\n >${tr.dismissed ? 'Bring back \u21BA' : 'View \u25B8'}</span\n >\n </button>`;\n }\n\n private _onIntroSuggestionClick = (): void => {\n const s = this.introSuggestion;\n if (!s) return;\n this.dispatchEvent(\n new CustomEvent<{ prompt: string }>('trail-intro-suggestion', {\n detail: { prompt: s.prompt },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n /**\n * Visitor tapped a `suggest_replies` inline chip. Emit\n * `trail-suggested-reply` carrying the chip text \u2014 the parent\n * (AdaptiveChatBar) re-dispatches it as `chat-message-sent`, the\n * SAME channel the input row uses, so the reply rides the existing\n * send path (mountable \u2192 chatSession.send \u2192 transport). No fabricated\n * AG-UI events; this is exactly what typing the text and hitting\n * Enter would do. The chips clear on their own once the reply lands\n * and a newer assistant message becomes the latest.\n */\n private _onSuggestedReplyClick = (text: string): void => {\n const trimmed = text.trim();\n if (!trimmed) return;\n this.dispatchEvent(\n new CustomEvent<{ text: string }>('trail-suggested-reply', {\n detail: { text: trimmed },\n bubbles: true,\n composed: true,\n })\n );\n };\n\n override render() {\n if (\n this.messages.length === 0 &&\n !this.greeting &&\n !this.introSuggestion &&\n this.tileReceipts.length === 0 &&\n this.inlineWidgets.length === 0\n )\n return nothing;\n if (this.messages.length === 0 && (this.greeting || this.introSuggestion)) {\n // Empty-state hero. Mirrors the platform chats' empty-state\n // pattern (icon disc + title + pill button) instead of pretending\n // the greeting is an assistant message \u2014 that reads as a chat\n // bubble the visitor must reply to. A centered hero reads as\n // configured page chrome: \"this is how the surface starts.\"\n //\n // Receipt strip is appended AFTER the hero so tile chips render\n // even when the message list is still empty (e.g. canvas replay\n // delivers TILE_MOUNTED before the first chat turn).\n return html`<div data-syntro-chat-trail data-state=\"empty\" style=${styleMap({\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n textAlign: 'center',\n gap: '12px',\n flex: '1 1 auto',\n width: '100%',\n padding: '24px 16px',\n pointerEvents: 'auto',\n })}>\n <div data-trail-empty-icon style=${styleMap(emptyIconStyles())} aria-hidden=\"true\">\u2726</div>\n ${\n this.greeting\n ? html`<h2\n data-trail-empty-title\n style=${styleMap(emptyTitleStyles())}\n >${unsafeHTML(renderMarkdown(stripTrailingWhitespace(this.greeting)))}</h2>`\n : nothing\n }\n ${\n this.introSuggestion\n ? html`<button\n type=\"button\"\n data-trail-intro-suggestion\n @click=${this._onIntroSuggestionClick}\n style=${styleMap(introSuggestionStyles())}\n >${this.introSuggestion.label}</button>`\n : nothing\n }\n ${this._renderReceiptStrip(this.tileReceipts)}\n ${this._renderInlineWidgetStrip(this.inlineWidgets)}\n </div>`;\n }\n if (\n this.messages.length === 0 &&\n (this.tileReceipts.length > 0 || this.inlineWidgets.length > 0)\n ) {\n // No greeting, no intro suggestion, but receipts exist (e.g. canvas\n // replay before the visitor sends a first message). Render just the\n // receipt strip so chips are always visible when tiles are mounted.\n return html`<div data-syntro-chat-trail data-state=\"empty\" style=${styleMap({\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'flex-start',\n gap: '6px',\n width: '100%',\n padding: '8px 0',\n pointerEvents: 'auto',\n })}>\n ${this._renderReceiptStrip(this.tileReceipts)}\n ${this._renderInlineWidgetStrip(this.inlineWidgets)}\n </div>`;\n }\n\n // Identity of the assistant message that hosts inline reply chips\n // (suggest_replies). Chips belong to the CURRENT agent turn: scanning back\n // from the newest message, the host is the first assistant message that\n // actually carries suggested replies. A trailing assistant turn (the agent\n // kept talking or mounted a card AFTER offering chips) does NOT steal the\n // chips \u2014 but a visitor reply does: hitting a `user` message first means the\n // visitor already answered, so the stale chips clear. Computed from the raw\n // list (before filtering) so it's stable and usable by both the\n // empty-message filter below and the render.\n //\n // BUG-1782968219: this was gated on the absolute-latest assistant message,\n // so any trailing assistant turn (e.g. a final \"tap whichever fits best\"\n // line) orphaned the chips onto a non-latest message and they never rendered.\n let suggestionHostId: TrailMessage['id'] | null = null;\n for (let i = this.messages.length - 1; i >= 0; i--) {\n const m = this.messages[i]!;\n if (m.role === 'user') break;\n if (m.role === 'assistant' && extractSuggestedReplies(m.toolCalls).length > 0) {\n suggestionHostId = m.id;\n break;\n }\n }\n\n // NEVER render an empty assistant bubble. An assistant message paints a\n // chip ONLY if it produces something the visitor can see \u2014 actual text,\n // a pending tool call (needs a tap), an activity receipt (a mount that\n // landed), or inline reply chips. A name-based allowlist was wrong: it\n // kept `primary_response_action`/`suggest_replies` turns whose receipt/\n // chips hadn't derived yet (mid-stream, or args without a title),\n // painting a blank bubble (sometimes with a lone \u2713). The guard now\n // mirrors EXACTLY what the render below would draw, computed by the\n // single source of truth `assistantChipRendersContent`. User and system\n // messages always render. See AdaptiveChatTrail.test.ts \"never renders\n // an empty assistant bubble\".\n const renderable = this.messages.filter(\n (m) => m.role !== 'assistant' || assistantChipRendersContent(m, m.id === suggestionHostId)\n );\n // Choose the slice we actually paint. Newest are at the END of the\n // array (closest to the chat bar). When not expanded, take the last\n // `visibleCount`; when expanded, take all.\n const visible =\n this.expanded || this.forceExpanded ? renderable : renderable.slice(-this.visibleCount);\n const hidden = renderable.length - visible.length;\n\n // Partition receipts by their anchor message so each renders INLINE right\n // after the message it mounted on (see `_receiptAnchors`). Receipts whose\n // anchor is null (mounted pre-chat) or whose anchor message isn't in the\n // painted slice (scrolled out of the collapsed ambient view, or an\n // empty/filtered assistant turn) fall to a tail strip at the bottom \u2014 the\n // old always-pinned position \u2014 so a receipt is never dropped.\n const visibleIds = new Set<TrailMessage['id']>(visible.map((m) => m.id));\n const receiptsByAnchor = new Map<TrailMessage['id'], TileReceipt[]>();\n const tailReceipts: TileReceipt[] = [];\n for (const r of this.tileReceipts) {\n const anchor = this._receiptAnchors.get(r.instanceId) ?? null;\n if (anchor !== null && visibleIds.has(anchor)) {\n const list = receiptsByAnchor.get(anchor);\n if (list) list.push(r);\n else receiptsByAnchor.set(anchor, [r]);\n } else {\n tailReceipts.push(r);\n }\n }\n\n // Same partition for inline widgets \u2014 anchored right after their host\n // message; those with no in-slice anchor fall to the tail strip.\n const inlineByAnchor = new Map<TrailMessage['id'], InlineTrailWidget[]>();\n const tailInlineWidgets: InlineTrailWidget[] = [];\n for (const w of this.inlineWidgets) {\n const anchor = this._inlineAnchors.get(w.instanceId) ?? null;\n if (anchor !== null && visibleIds.has(anchor)) {\n const list = inlineByAnchor.get(anchor);\n if (list) list.push(w);\n else inlineByAnchor.set(anchor, [w]);\n } else {\n tailInlineWidgets.push(w);\n }\n }\n\n const baseStyles: Record<string, string> = {\n display: 'flex',\n flexDirection: 'column',\n gap: '6px',\n // NO `justifyContent: flex-end` here \u2014 combined with `overflow: auto`\n // it's a known cross-browser bug: oversized flex children get\n // pushed ABOVE the container without contributing to scrollHeight,\n // so the scrollbar never appears. We rely on `:first-child {\n // margin-top: auto }` (injected as global CSS) to push short\n // content to the bottom of the box while leaving overflow handling\n // to the native scroll container.\n width: '100%',\n // The trail itself has no chrome \u2014 chips sit on the host page bg.\n padding: '0',\n pointerEvents: 'auto',\n };\n\n // Expanded mode: cap height, scroll, and add a visible top border so\n // the panel reads as a bounded region. NO background tint or shadow\n // \u2014 the ambient (collapsed) treatment is fine and we don't want to\n // suddenly introduce panel chrome that wasn't there before. The\n // border alone marks the panel's top edge.\n // Falloff is turned off per-chip below \u2014 readability wins once the\n // user has explicitly asked for history. See PRD \u00A74.3.\n // Collapsed mode also gets a (looser) cap + scroll so a single long\n // markdown chip doesn't blow the chat-bar off-screen with no\n // scroll affordance. Tighter than expanded so the bubble-up trail\n // doesn't dominate the surface visually.\n const modeStyles: Record<string, string> = this.forceExpanded\n ? {\n // Full-screen host: fill all available vertical space and\n // scroll the overflow. ``flex: 1 1 0`` (basis 0, not auto)\n // makes the trail shrink to 0 first when the parent runs\n // out of space \u2014 so the header above and the input row\n // below stay pinned at their natural sizes instead of one\n // of them being pushed off-screen.\n flex: '1 1 0',\n minHeight: '0',\n overflowY: 'auto',\n // ``contain`` prevents scroll from bubbling out to the host\n // page when the trail hits top or bottom. Required for the\n // panel-scroll-leak regression test in\n // SyntroBottomSheet.test.ts.\n overscrollBehavior: 'contain',\n paddingTop: '8px',\n borderTop: 'var(--sc-content-bubble-border, 1px solid rgba(255, 255, 255, 0.18))',\n scrollBehavior: 'smooth',\n scrollbarWidth: 'thin',\n }\n : this.expanded\n ? {\n maxHeight: 'min(320px, 40vh)',\n overflowY: 'auto',\n paddingTop: '8px',\n borderTop: 'var(--sc-content-bubble-border, 1px solid rgba(255, 255, 255, 0.18))',\n scrollBehavior: 'smooth',\n scrollbarWidth: 'thin',\n }\n : {\n // Collapsed mode = ambient peek surface. Never a scrollbar:\n // long messages slide up behind the blur veil instead of\n // exposing a scrollbar. The \"\u2191 N more \u00B7 expand\" affordance\n // is the only entry into history; clicking it switches to\n // expanded mode where scroll IS allowed.\n // Height kept short so the trail reads as a peek strip above\n // the chat bar, not a panel \u2014 long single replies fade into\n // the blur veil at the top, user expands to read the rest.\n maxHeight: 'min(140px, 22vh)',\n overflow: 'hidden',\n };\n\n const containerStyles = { ...baseStyles, ...modeStyles };\n\n // (suggestionHostId computed above, before the empty-message filter.)\n\n // Wrap the scroll container in a positioning frame so the absolute\n // blur veil (rendered at the top) anchors to the scroll viewport's\n // top edge \u2014 NOT to a chip that scrolls under it. Pixel-anchored\n // blur means: the top TRAIL_BLUR_VEIL_PX of the visible area is\n // veiled regardless of how many messages occupy those pixels.\n // The frame wraps the scroll container so the absolute blur veil\n // anchors to the scroll viewport's top edge. In ``forceExpanded``\n // mode it ALSO has to participate in the flex column laid out by\n // the trail host \u2014 otherwise the scroll container's ``flex: 1 1\n // 0`` has no flex context, falls back to content height, and the\n // trail's overflow:hidden clips at the TOP of the scroll\n // (showing oldest messages, hiding the newest at the bottom).\n const frameStyles: Record<string, string> = this.forceExpanded\n ? {\n position: 'relative',\n width: '100%',\n display: 'flex',\n flexDirection: 'column',\n flex: '1 1 0',\n minHeight: '0',\n }\n : {\n position: 'relative',\n width: '100%',\n };\n\n return html`\n ${\n // Single toggle button above the frame. Same DOM node morphs:\n // collapsed \u2192 \"\u2191 N more \u00B7 expand\" / \"\u2191 expand\" (calls _onExpand)\n // expanded \u2192 \"\u2304 minimize\" (calls _onCollapse)\n // Lives OUTSIDE the frame so the absolute blur veil (top:0,\n // z-index:2 inside the frame) doesn't cover it. Shown whenever\n // there's anything in the trail \u2014 the user expects this affordance\n // available regardless of how many chips are on screen.\n // When ``forceExpanded`` is set by the host (full-screen panel,\n // etc.), there's nowhere to collapse INTO and the affordance\n // would just confuse the user \u2014 suppress it entirely.\n this.messages.length === 0 || this.forceExpanded\n ? nothing\n : this.expanded\n ? html`<button\n type=\"button\"\n data-trail-toggle\n data-trail-collapse\n @click=${this._onCollapse}\n style=${styleMap(moreStyles())}\n >\u2304 minimize</button>`\n : html`<button\n type=\"button\"\n data-trail-toggle\n data-trail-more\n @click=${this._onExpand}\n style=${styleMap(moreStyles())}\n >${hidden > 0 ? html`\u2191 ${hidden} more \u00B7 expand` : html`\u2191 expand`}</button>`\n }\n <div data-syntro-chat-trail-frame style=${styleMap(frameStyles)}>\n <div data-syntro-chat-trail style=${styleMap(containerStyles)}>\n ${visible.map((m, i) => {\n // Stack position from the bar: 0 = closest, N-1 = oldest.\n // visible[last] is closest, so reverse the index from the\n // tail of the visible slice. When expanded, the ambient\n // falloff is suppressed (pos = 0) so every chip reads at\n // full opacity \u2014 explicit history view, not ambient trail.\n const pos = this.expanded || this.forceExpanded ? 0 : visible.length - 1 - i;\n const state = chipVisualState(m);\n const isStreaming = state.kind === 'streaming';\n // The chip body's artifacts \u2014 pending tool calls (need a visitor\n // tap; running/done/error are internal mechanics, never painted),\n // activity receipts (\"Added <type> \u00B7 <label>\" for mounts that\n // landed), and inline reply chips (latest turn only). Computed by\n // the SAME `computeAssistantChipParts` the empty-message filter\n // uses, so what we paint here and what the filter considers\n // \"non-empty\" can never drift. (`toolCalls` keeps its name below.)\n const {\n pendingToolCalls: toolCalls,\n receipts,\n replyChips,\n } = computeAssistantChipParts(m, m.id === suggestionHostId);\n // Assistant text is markdown-formatted by the agent (lists,\n // code, bold, links). renderMarkdown sanitizes via DOMPurify,\n // then unsafeHTML injects the safe HTML. User + system chips\n // stay plain text \u2014 no markdown risk + no expansion attack\n // surface on user-typed input.\n const renderedText =\n m.role === 'assistant'\n ? // Never paint a degenerate serialized-response dump, even if the\n // turn also carries a legit part (receipt/chip) that keeps it in\n // the renderable set. Mirrors the filter's drop signal.\n looksLikeSerializedModelResponse(m.text ?? '')\n ? nothing\n : html`${unsafeHTML(renderMarkdown(stripTrailingWhitespace(m.text)))}`\n : html`${m.text}`;\n // Entrance animation on streaming chips only. Lit mounts the\n // chip element once per message id, so the animation fires\n // when the streaming chip first appears (replacing the\n // thinking chip in the same visual slot) and does NOT fire\n // again on subsequent token deltas \u2014 those just update the\n // text inside the already-mounted element. User messages\n // and settled history don't get an entrance: the user just\n // tapped Send so they expect immediate feedback, and old\n // history doesn't need re-attention every refresh.\n const chipStyle = isStreaming\n ? {\n ...chipStyles(state, pos),\n animation: 'syntro-trail-chip-enter 220ms cubic-bezier(0.22, 1, 0.36, 1) both',\n }\n : chipStyles(state, pos);\n return html`<div\n data-trail-chip\n data-role=${m.role}\n data-status=${m.status ?? 'complete'}\n style=${styleMap(chipStyle)}\n >${renderedText}${\n isStreaming\n ? html`<span\n data-trail-caret\n aria-hidden=\"true\"\n style=${styleMap(caretStyles())}\n ></span>`\n : nothing\n }${\n toolCalls.length > 0\n ? html`<div data-trail-toolcalls style=${styleMap(toolCallStripStyles())}>\n ${toolCalls.map(\n (tc) => html`<button\n type=\"button\"\n data-trail-toolcall\n data-tool-id=${tc.id}\n data-tool-status=${tc.status}\n @click=${() => this._onToolCallClick(tc)}\n ?disabled=${tc.status !== 'pending'}\n style=${styleMap(toolCallChipStyles(tc.status))}\n title=\"${tc.name} \u00B7 ${tc.status}\"\n >${toolCallIcon(tc.status)} ${tc.name}</button>`\n )}\n </div>`\n : nothing\n }${\n receipts.length > 0\n ? html`<div data-trail-receipts style=${styleMap(receiptStripStyles())}>\n ${receipts.map(\n (r) => html`<div\n data-trail-receipt\n data-receipt-type=${r.type}\n style=${styleMap(receiptStyles())}\n ><span aria-hidden=\"true\" style=${styleMap(receiptIconStyles())}>\u2713</span\n ><span>${receiptText(r)}</span></div>`\n )}\n </div>`\n : nothing\n }${\n replyChips.length > 0\n ? html`<div data-trail-reply-chips style=${styleMap(replyChipStripStyles())}>\n ${replyChips.map(\n (reply) => html`<button\n type=\"button\"\n data-trail-reply-chip\n @click=${() => this._onSuggestedReplyClick(reply)}\n style=${styleMap(replyChipStyles())}\n >${reply}</button>`\n )}\n </div>`\n : nothing\n }</div>${\n // Receipt chips that mounted while THIS message was newest render\n // inline right here, so they read as part of the flow and drift up\n // as later messages append below them.\n this._renderReceiptStrip(receiptsByAnchor.get(m.id) ?? [])\n }${\n // Inline widgets (reco carousel) anchored to this message render\n // right here in the conversation flow \u2014 the whole point of the\n // chat-inline slot: visible in the trail, not behind the panel.\n this._renderInlineWidgetStrip(inlineByAnchor.get(m.id) ?? [])\n }`;\n })}\n ${\n // Thinking indicator \u2014 fills the gap between the user's\n // most recent message and the assistant's first token.\n // Shows when chatSession.inFlight is true AND the last\n // message is NOT a streaming assistant message (the\n // assistant's own caret takes over once tokens arrive).\n // Styled as an assistant chip with three bouncing dots\n // instead of text, so the thread reads naturally \u2014 the\n // visitor sees an \"assistant\" bubble that's clearly busy.\n this._shouldShowThinking()\n ? html`<div\n data-trail-thinking\n data-role=\"assistant\"\n data-status=\"thinking\"\n aria-label=${\n this.thinkingText\n ? `Assistant is thinking: ${this.thinkingText}`\n : 'Assistant is thinking'\n }\n style=${styleMap(thinkingSlotStyles())}\n >\n ${\n // When the backend has streamed reasoning narration into\n // `thinkingText`, render the tail of it as a small italic\n // line \u2014 the model's own intent (\"Let me check what we have\n // for student athletes\u2026\") narrates the gap better than\n // silent dots. Falls back to the bouncing-dot pulse when\n // no narration has arrived yet.\n this.thinkingText\n ? html`<span\n data-trail-thinking-text\n style=${styleMap(thinkingTextStyles())}\n >${truncateThinkingTail(this.thinkingText)}</span\n >`\n : html`<span data-trail-thinking-dots style=${styleMap(thinkingDotsStyles())}>\n <span style=${styleMap(thinkingDotStyles(0))}></span>\n <span style=${styleMap(thinkingDotStyles(1))}></span>\n <span style=${styleMap(thinkingDotStyles(2))}></span>\n </span>`\n }\n </div>`\n : nothing\n }\n ${\n // Tail strip: receipts with no in-slice anchor (mounted pre-chat, or\n // their anchor message scrolled out of the ambient view). Keeps them\n // reachable at the bottom \u2014 the old always-pinned position \u2014 rather\n // than dropping them. In expanded/maximized mode every message is\n // painted, so this is usually empty and receipts sit inline instead.\n this._renderReceiptStrip(tailReceipts)\n }\n ${\n // Inline widgets with no in-slice anchor (mounted pre-chat, or their\n // anchor scrolled out of the ambient view) render at the tail.\n this._renderInlineWidgetStrip(tailInlineWidgets)\n }\n </div>\n ${\n // The blur veil only fires in collapsed (ambient) mode.\n // Expanded = the user explicitly asked for history; blurring\n // the top of the panel would hide content (including the\n // minimize button just above the trail's top edge) the user\n // came here to see.\n this.expanded || this.forceExpanded\n ? nothing\n : html`<div\n data-trail-blur-veil\n aria-hidden=\"true\"\n style=${styleMap(blurVeilStyles())}\n ></div>`\n }\n </div>\n `;\n }\n}\n\n/**\n * Absolute blur veil at the top of the scroll viewport. Uses\n * `backdrop-filter: blur(...)` so whatever pixels sit beneath the veil\n * (top of the scroll content) become blurred, regardless of which chip\n * those pixels belong to. A linear mask fades the blur effect from full\n * at the top to zero at the bottom of the veil \u2014 newest content stays\n * crisp because it lives below the veil's height.\n *\n * Note: `mask-image` controls where the BACKDROP-FILTER applies (via\n * masking the veil element), so the bottom edge of the veil naturally\n * dissolves into the unblurred scroll area below.\n */\nfunction blurVeilStyles(): Record<string, string> {\n const mask = 'linear-gradient(to bottom, black 0%, black 40%, transparent 100%)';\n return {\n position: 'absolute',\n top: '0',\n left: '0',\n right: '0',\n height: `${TRAIL_BLUR_VEIL_PX}px`,\n pointerEvents: 'none',\n backdropFilter: `blur(${TRAIL_BLUR_MAX_PX}px)`,\n WebkitBackdropFilter: `blur(${TRAIL_BLUR_MAX_PX}px)`,\n maskImage: mask,\n WebkitMaskImage: mask,\n zIndex: '2',\n };\n}\n\n/**\n * Discriminated visual state for a chip. Replaces the older\n * `(role, { isStreaming, isError })` triple whose interaction order\n * could produce nonsense combinations (e.g. an assistant chip\n * accidentally reading as a user bubble because `isStreaming` was\n * checked before role). Each kind below is a real conversational\n * state with a single visual identity:\n *\n * - `settled` \u2014 a complete message; the user-vs-assistant\n * identity comes from `role`\n * - `streaming` \u2014 the assistant chip currently receiving tokens;\n * keeps assistant identity (the blinking caret\n * inside the chip carries \"in progress\")\n * - `pending` \u2014 the thinking chip shown between the user's\n * just-sent message and the assistant's first\n * token; assistant identity (the bouncing dots\n * inside carry \"in progress\")\n * - `error` \u2014 a chip whose stream failed mid-flight, OR any\n * system-role message (system messages render\n * with the error identity by convention)\n *\n * Bug history: an earlier branch-ladder design checked `isStreaming`\n * before `role`, so the `pending`/thinking chip inherited the user\n * bubble border. On hosts whose chat panel sits over a light surface\n * that read as a \"white div\" pasted into the assistant slot. The\n * discriminated state prevents that combination from being expressible.\n */\nexport type ChipVisualState =\n | { kind: 'settled'; role: 'user' | 'assistant' | 'system' }\n | { kind: 'streaming' }\n | { kind: 'pending' }\n | { kind: 'error'; role: 'user' | 'assistant' | 'system' };\n\n/**\n * Map a trail message + the trail's `inFlight` flag onto its visual\n * state. The thinking chip is rendered separately at the render-tree\n * level \u2014 this helper covers settled / streaming / error messages and\n * leaves the `pending` state to the dedicated thinking-chip render\n * path.\n */\nfunction chipVisualState(m: TrailMessage): ChipVisualState {\n // System messages and explicit error status both render as error\n // chips regardless of role (the original `isError` definition).\n if (m.status === 'error' || m.role === 'system') {\n return { kind: 'error', role: m.role };\n }\n if (m.role === 'assistant' && m.status === 'streaming') {\n return { kind: 'streaming' };\n }\n return { kind: 'settled', role: m.role };\n}\n\nfunction chipStyles(state: ChipVisualState, pos: number): Record<string, string> {\n const opacity = Math.max(OPACITY_FLOOR, 1 - pos * OPACITY_STEP);\n const yPx = pos * Y_DRIFT_PX;\n\n // Per-state visual tokens. Fallbacks are conservative neutrals so\n // the chip still renders sensibly on a host page that hasn't set\n // its design-system tokens yet. The contract: changing one state's\n // border MUST NOT silently affect another state's border.\n let border: string;\n let background: string;\n let color: string;\n let alignSelf: 'flex-start' | 'flex-end';\n\n switch (state.kind) {\n case 'settled':\n if (state.role === 'user') {\n border = 'var(--sc-content-bubble-border-user, 1px solid rgba(255, 255, 255, 0.28))';\n background = 'var(--sc-content-bubble-background-user, rgba(255, 255, 255, 0.10))';\n alignSelf = 'flex-end';\n } else {\n border = 'var(--sc-content-bubble-border, 1px solid rgba(255, 255, 255, 0.18))';\n background = 'var(--sc-content-bubble-background, rgba(20, 22, 24, 0.35))';\n alignSelf = 'flex-start';\n }\n color = 'var(--sc-tile-title-color, inherit)';\n break;\n case 'streaming':\n case 'pending':\n // Assistant identity. The caret (streaming) or bouncing dots\n // (pending) inside the chip carry the in-progress signal \u2014 the\n // chip's outer identity stays consistent with the assistant's\n // settled reply, so the visitor sees the SAME entity speaking\n // throughout the response lifecycle. This is the bug fix: prior\n // versions borrowed the user border for these states and broke\n // identity continuity.\n border = 'var(--sc-content-bubble-border, 1px solid rgba(255, 255, 255, 0.18))';\n background = 'var(--sc-content-bubble-background, rgba(20, 22, 24, 0.35))';\n color = 'var(--sc-tile-title-color, inherit)';\n alignSelf = 'flex-start';\n break;\n case 'error':\n border = 'var(--sc-content-bubble-border-error, 1px solid rgba(220, 80, 80, 0.55))';\n background = 'var(--sc-content-bubble-background-error, rgba(140, 40, 40, 0.42))';\n color = 'var(--sc-content-bubble-text-error, rgba(255, 220, 220, 0.95))';\n // Errors keep their originating role's alignment so a failed\n // user-side send still sits on the right where the user expects\n // their message to land.\n alignSelf = state.role === 'user' ? 'flex-end' : 'flex-start';\n break;\n }\n\n return {\n alignSelf,\n // Single shared width policy for EVERY bubble (user / assistant /\n // streaming / pending / error). Short and long replies now read as a\n // consistent column: `fit-content` sizes each bubble to its text, and\n // `TRAIL_MAX_WIDTH` caps the wide ones at the same ceiling \u2014 no more\n // per-role or per-path width drift (user feedback: chat tiles had\n // differing widths).\n maxWidth: TRAIL_MAX_WIDTH,\n width: 'fit-content',\n // Bumped from 11px \u2192 13px after the chat lid in production read as\n // cramped at the smaller size \u2014 body chat copy needs to be visitor-\n // legible on a phone without zoom, and 11px reads as a footnote\n // rather than the primary conversation surface. Code blocks inside\n // chip body scale proportionally (10px \u2192 11px) below.\n fontSize: '13px',\n lineHeight: '1.45',\n padding: '5px 11px',\n borderRadius: '10px',\n border,\n background,\n backdropFilter: 'blur(8px)',\n WebkitBackdropFilter: 'blur(8px)',\n color,\n transition:\n 'opacity 240ms cubic-bezier(0.22, 1, 0.36, 1), transform 240ms cubic-bezier(0.22, 1, 0.36, 1)',\n // Per-position opacity + y-drift falloff is still per-chip \u2014 those\n // operate naturally per element. Blur is NOT per-chip anymore: it's\n // applied via an absolute-positioned veil at the top of the scroll\n // viewport (TRAIL_BLUR_VEIL_PX above), so a single long message\n // doesn't get uniformly blurred across its full body.\n opacity: String(toFixedTrim(opacity)),\n transform: `translateY(${yPx}px)`,\n // User messages render as raw text (`html` template); pre-wrap preserves\n // newlines the visitor typed. Assistant messages render as markdown HTML\n // (`<p>` tags from marked); pre-wrap there would make marked's inter-tag\n // text nodes (the `\\n` between/after `<p>` tags) visible, producing the\n // trailing/inter-paragraph blank lines visitors reported. Markdown's own\n // structure carries the paragraph breaks, so assistant chips use the\n // default `normal` whitespace handling.\n whiteSpace:\n (state.kind === 'settled' || state.kind === 'error') && state.role === 'user'\n ? 'pre-wrap'\n : 'normal',\n wordBreak: 'break-word',\n };\n}\n\nfunction toolCallStripStyles(): Record<string, string> {\n return {\n display: 'flex',\n flexWrap: 'wrap',\n gap: '4px',\n marginTop: '4px',\n paddingTop: '4px',\n borderTop: '1px dashed var(--sc-content-divider-color, rgba(255, 255, 255, 0.12))',\n };\n}\n\nfunction toolCallChipStyles(status: TrailToolCall['status']): Record<string, string> {\n const isPending = status === 'pending';\n const isError = status === 'error';\n const isDone = status === 'done';\n return {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '4px',\n padding: '2px 7px',\n border: isError\n ? 'var(--sc-content-bubble-border-error, 1px solid rgba(220, 80, 80, 0.45))'\n : isPending\n ? 'var(--sc-content-bubble-border-user, 1px solid rgba(255, 255, 255, 0.28))'\n : 'var(--sc-content-bubble-border, 1px solid rgba(255, 255, 255, 0.18))',\n background: isError\n ? 'var(--sc-content-bubble-background-error, rgba(140, 40, 40, 0.35))'\n : isPending\n ? 'var(--sc-content-bubble-background-user, rgba(255, 255, 255, 0.10))'\n : isDone\n ? 'var(--sc-content-bubble-background-idle, rgba(40, 44, 50, 0.4))'\n : 'var(--sc-content-bubble-background, rgba(20, 22, 24, 0.35))',\n color: 'var(--sc-tile-text-color, inherit)',\n borderRadius: '999px',\n fontSize: '10px',\n fontWeight: '500',\n fontFamily: 'ui-monospace, SF Mono, Menlo, monospace',\n cursor: isPending ? 'pointer' : 'default',\n opacity: isDone ? '0.7' : '1',\n };\n}\n\nfunction toolCallIcon(status: TrailToolCall['status']): string {\n switch (status) {\n case 'args-streaming':\n case 'running':\n return '\u22EF';\n case 'pending':\n return '?';\n case 'done':\n return '\u2713';\n case 'error':\n return '\u2717';\n default:\n return '\u00B7';\n }\n}\n\n/**\n * A parsed activity receipt \u2014 what the agent just put on the page.\n * Derived from a `primary_response_action` tool call's args.\n */\ninterface ActivityReceipt {\n /** Friendly element category for the receipt copy (\"card\", \"FAQ\", \u2026). */\n type: string;\n /** Human label \u2014 the mounted thing's title, or the template id. */\n label: string;\n}\n\n/**\n * Map a tool call onto an activity receipt, or null when it isn't a\n * mount we surface. Only `primary_response_action` (the mount tool)\n * produces a receipt: it's THE channel for putting something on the\n * page, so its appearance is what the visitor needs acknowledged.\n *\n * Type is derived from `template_id` with cheap substring heuristics \u2014\n * template ids are admin-authored and workspace-specific, so we match\n * on stable kind-words (\"card\", \"faq\", \"chart\", \"alert\"/\"navigation\")\n * rather than an enum that would drift. Label prefers\n * `content.title`, falling back to the template id so the receipt is\n * never blank.\n */\nfunction deriveActivityReceipt(tc: TrailToolCall): ActivityReceipt | null {\n if (tc.name !== 'primary_response_action') return null;\n const args = tc.args;\n if (!args || typeof args !== 'object') return null;\n const templateId = typeof args.template_id === 'string' ? args.template_id : '';\n const content = (args.content ?? null) as Record<string, unknown> | null;\n const title =\n content && typeof content.title === 'string' && content.title.trim()\n ? content.title.trim()\n : '';\n const id = templateId.toLowerCase();\n let type: string;\n if (id.includes('faq')) type = 'FAQ';\n else if (id.includes('chart') || id.includes('graph')) type = 'chart';\n else if (id.includes('card') || id.includes('product')) type = 'card';\n else if (id.includes('alert') || id.includes('navigation') || id.includes('nav')) type = 'alert';\n else type = 'added to your view';\n const label = title || templateId || 'something';\n return { type, label };\n}\n\n/**\n * User-facing receipt copy. Frames what the assistant did FOR the visitor\n * (\"Pulled up the FAQ for you\") rather than the mechanical system action\n * (\"Added alert \u00B7 Read the FAQ\"). Phrased to read naturally with the\n * admin-authored labels (which are often imperative CTAs like \"Read the FAQ\").\n */\nfunction receiptText(r: ActivityReceipt): string {\n switch (r.type) {\n case 'FAQ':\n return 'Opened the FAQ for you';\n case 'chart':\n return `Put together ${r.label} for you`;\n case 'card':\n // Product cards: the only label available is the mount's `title`, which\n // is a marketing eyebrow (\"Sharper thinking, backed by Lion's Mane\"), not\n // the product NAME (that's pinned in the template's default_widget_props,\n // which the receipt can't see). Echoing the eyebrow reads wrong, so use a\n // clean generic instead of `Pulled up <eyebrow> for you`.\n return 'Pulled up the product for you';\n case 'alert':\n // Navigation shortcuts only \u2014 the label is the CTA destination.\n return `Here's a shortcut: ${r.label}`;\n default:\n // Unknown template kinds ('added to your view'): a safe generic \u2014 never\n // mislabel a content mount as a navigation shortcut.\n return `Pulled up ${r.label} for you`;\n }\n}\n\n/**\n * Pull the candidate reply strings out of a message's `suggest_replies`\n * tool call. Returns [] when there's no such call or its `replies` arg\n * is missing / malformed. Caps at four (mirrors the backend tool) and\n * drops blanks so a sloppy args payload can't render empty chips.\n */\nfunction extractSuggestedReplies(toolCalls: TrailToolCall[] | undefined): string[] {\n if (!toolCalls) return [];\n for (const tc of toolCalls) {\n if (tc.name !== 'suggest_replies') continue;\n const replies = tc.args?.replies;\n if (!Array.isArray(replies)) return [];\n return replies\n .filter((r): r is string => typeof r === 'string' && r.trim().length > 0)\n .map((r) => r.trim())\n .slice(0, 4);\n }\n return [];\n}\n\n/**\n * The artifacts an assistant chip's body can paint, beyond its text. This is\n * THE single computation of \"what shows\" \u2014 BOTH the empty-message filter and\n * the per-message render read it, so \"is this bubble empty?\" and \"what do we\n * draw?\" can never disagree. That drift (two places each guessing what renders)\n * is what let blank bubbles regress repeatedly. To add a new visible artifact,\n * add it here once; the filter and render both honor it automatically.\n */\ninterface AssistantChipParts {\n /** Tool calls that need a visitor tap. running/done/error are internal\n * mechanics and are deliberately never painted. */\n pendingToolCalls: TrailToolCall[];\n /** \"Added <type> \u00B7 <label>\" lines for mounts that landed this turn. */\n receipts: ActivityReceipt[];\n /** Tappable suggested answers \u2014 only on the suggestion-host turn (the\n * current turn's suggest_replies message, until the visitor replies). */\n replyChips: string[];\n}\n\nfunction computeAssistantChipParts(m: TrailMessage, isSuggestionHost: boolean): AssistantChipParts {\n const toolCalls = m.toolCalls ?? [];\n return {\n pendingToolCalls: toolCalls.filter((tc) => tc.status === 'pending'),\n receipts: toolCalls.map(deriveActivityReceipt).filter((r): r is ActivityReceipt => r !== null),\n replyChips: isSuggestionHost ? extractSuggestedReplies(toolCalls) : [],\n };\n}\n\n/**\n * A misbehaving model can emit a raw SERIALIZED response payload as plain TEXT\n * on a spurious trailing turn \u2014 e.g.\n * `(Empty response: {'content': [{'type': 'thinking', \u2026}], 'stop_reason': \u2026})`.\n * Backstop for model degeneration (Kimi); the prompt (S-14) also asks for one\n * brief closing, but copy can't be trusted on the very turn that degenerates.\n *\n * Detection avoids false positives (which are WORSE than the dump \u2014 the visitor\n * would see nothing): a turn is dropped only if it OPENS with the literal\n * \"(Empty response\" marker, OR it carries \u22652 serialization tokens at once. A\n * single token (a product about a \"signature blend\", the agent quoting one JSON\n * key) never trips it; a real response dump carries all of them.\n */\nexport function looksLikeSerializedModelResponse(text: string): boolean {\n const t = text.trimStart();\n if (t.startsWith('(Empty response')) return true;\n let hits = 0;\n if (/['\"]stop_reason['\"]\\s*:/.test(t)) hits++;\n if (/['\"]signature['\"]\\s*:/.test(t)) hits++;\n if (/['\"]type['\"]\\s*:\\s*['\"]thinking['\"]/.test(t)) hits++;\n if (/['\"]content['\"]\\s*:\\s*\\[/.test(t)) hits++;\n return hits >= 2;\n}\n\n/**\n * Does this assistant chip paint anything the visitor can see? Derived from the\n * SAME parts the render draws (computeAssistantChipParts) plus the text, so the\n * empty-message filter and the render are guaranteed to agree and a bubble is\n * NEVER rendered blank. See AdaptiveChatTrail.test.ts \"never renders an empty\n * assistant bubble\".\n */\nfunction assistantChipRendersContent(m: TrailMessage, isSuggestionHost: boolean): boolean {\n const text = (m.text ?? '').trim();\n // A degenerate serialized-response dump has text but must never be shown \u2014\n // treat it as no content so the chip is filtered out, like an empty turn.\n if (text.length > 0 && !looksLikeSerializedModelResponse(text)) return true;\n const { pendingToolCalls, receipts, replyChips } = computeAssistantChipParts(m, isSuggestionHost);\n return pendingToolCalls.length > 0 || receipts.length > 0 || replyChips.length > 0;\n}\n\n/**\n * Wrapper for an inline widget block (reco carousel). Full trail width so\n * the horizontally-scrollable carousel fits the conversation column; the\n * widget inherits the chat theme tokens through the shadow boundary (CSS\n * custom properties cascade in). `minWidth: 0` lets the carousel's own\n * `overflow-x` scroll instead of forcing the trail wider. `contain` keeps\n * the carousel's internal scroll from leaking into the trail scroll.\n */\nfunction inlineWidgetBlockStyles(): Record<string, string> {\n return {\n alignSelf: 'stretch',\n width: '100%',\n minWidth: '0',\n marginTop: '6px',\n contain: 'layout',\n };\n}\n\nfunction receiptStripStyles(): Record<string, string> {\n return {\n display: 'flex',\n flexDirection: 'column',\n gap: '2px',\n marginTop: '4px',\n };\n}\n\nfunction receiptStyles(): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '5px',\n alignSelf: 'flex-start',\n fontSize: '11px',\n lineHeight: '1.3',\n fontWeight: '500',\n letterSpacing: '0.01em',\n // Inherit the chip's OWN resolved text color (muted via opacity), so the\n // receipt is legible on every theme by construction. The old\n // `--sc-content-muted-color` fallback was rgba(255,255,255,\u2026) \u2014 white \u2014\n // invisible on light canvases; a `--sc-tile-text-color` token can likewise\n // be unset/mismatched on dark canvases. `currentColor` always matches the\n // chip text the visitor is already reading.\n color: 'currentColor',\n opacity: '0.7',\n };\n}\n\nfunction receiptIconStyles(): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '14px',\n height: '14px',\n borderRadius: '50%',\n fontSize: '9px',\n fontWeight: '700',\n color: '#fff',\n background: 'hsl(var(--sc-accent-color, 145 40% 45%) / 0.7)',\n };\n}\n\nfunction replyChipStripStyles(): Record<string, string> {\n return {\n display: 'flex',\n flexWrap: 'wrap',\n gap: '6px',\n marginTop: '6px',\n alignSelf: 'flex-start',\n };\n}\n\nfunction replyChipStyles(): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n padding: '5px 12px',\n border: '1px solid hsl(var(--sc-accent-color, 145 40% 45%) / 0.40)',\n borderRadius: '9999px',\n background: 'hsl(var(--sc-accent-color, 145 40% 45%) / 0.12)',\n color: 'var(--sc-tile-text-color, currentColor)',\n font: 'inherit',\n fontSize: '12px',\n fontWeight: '500',\n lineHeight: '1.2',\n cursor: 'pointer',\n backdropFilter: 'blur(8px)',\n WebkitBackdropFilter: 'blur(8px)',\n transition: 'background 150ms ease, transform 120ms ease',\n };\n}\n\nfunction alertReceiptIconStyles(): Record<string, string> {\n return {\n flex: '0 0 auto',\n width: '26px',\n height: '26px',\n borderRadius: '8px',\n display: 'grid',\n placeItems: 'center',\n background: 'hsl(var(--sc-accent-color))',\n color: 'var(--sc-accent-foreground, #fff)',\n fontSize: '14px',\n };\n}\nfunction tileReceiptChipStyles(): Record<string, string> {\n return {\n display: 'flex',\n alignItems: 'center',\n gap: '10px',\n width: '100%',\n textAlign: 'left',\n cursor: 'pointer',\n padding: '9px 10px 9px 11px',\n borderRadius: '12px',\n border: '1px solid hsl(var(--sc-accent-color) / 0.28)',\n background: 'hsl(var(--sc-accent-color) / 0.06)',\n };\n}\nfunction tileReceiptGlyphStyles(): Record<string, string> {\n return { position: 'relative', flex: '0 0 auto', width: '28px', height: '28px' };\n}\nfunction tileReceiptGlyphLayerStyles(i: 0 | 1): Record<string, string> {\n return {\n position: 'absolute',\n inset: '0',\n borderRadius: '7px',\n background: 'hsl(var(--sc-accent-color) / 0.22)',\n boxShadow: 'inset 0 0 0 1px hsl(var(--sc-accent-color) / 0.4)',\n ...(i === 0 ? { transform: 'translate(3px,-3px) rotate(6deg)', opacity: '0.5' } : {}),\n };\n}\nfunction receiptChipTitleStyles(_kind: 'alert' | 'tile'): Record<string, string> {\n return {\n // Grows to fill the space between the icon and the action pill, truncating\n // long product names on one line (the chip is now single-line).\n flex: '1',\n minWidth: '0',\n fontSize: '13px',\n fontWeight: '650',\n lineHeight: '1.2',\n color: 'var(--sc-content-text-color, #0f172a)',\n whiteSpace: 'nowrap',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n };\n}\nfunction tileReceiptActionStyles(dismissed: boolean): Record<string, string> {\n return {\n flex: '0 0 auto',\n fontSize: '11px',\n fontWeight: '700',\n borderRadius: '999px',\n padding: '4px 10px',\n ...(dismissed\n ? { background: 'hsl(var(--sc-accent-color) / 0.14)', color: 'hsl(var(--sc-accent-color))' }\n : {\n background: 'hsl(var(--sc-accent-color) / 0.9)',\n color: 'var(--sc-accent-foreground, #fff)',\n }),\n };\n}\n\nfunction caretStyles(): Record<string, string> {\n return {\n display: 'inline-block',\n width: '6px',\n height: '12px',\n marginLeft: '3px',\n verticalAlign: '-1px',\n background: 'hsl(var(--sc-accent-color) / 0.85)',\n borderRadius: '1px',\n animation: 'syntro-trail-caret 1s steps(2, end) infinite',\n };\n}\n\n/**\n * Layout slot for the naked thinking indicator. No bubble \u2014 no\n * background, no border, no padding, no backdrop blur. The chip\n * decoration around an \"empty assistant message\" was reading as a\n * placeholder card on host themes that drew the chip background as a\n * solid color; stripping it lets the dots carry the entire signal.\n * What this style does keep:\n * - left alignment in the trail's flex column (assistant slot)\n * - the inherited chip text color, which the dots' `currentColor`\n * fill picks up so they tint with the assistant identity\n * - a fade-up entrance so the indicator arrives, not pops, into\n * view next to the user's just-sent message\n * - a small inset so the dots sit at the same baseline a text chip\n * would, preventing a vertical jump when the first token arrives\n * and the slot is replaced by the streaming chip\n */\nfunction thinkingSlotStyles(): Record<string, string> {\n return {\n alignSelf: 'flex-start',\n color: 'var(--sc-tile-title-color, inherit)',\n padding: '4px 4px',\n animation: 'syntro-trail-chip-enter 220ms cubic-bezier(0.22, 1, 0.36, 1) both',\n };\n}\n\nfunction thinkingDotsStyles(): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '6px',\n // Line height matches what a single-line text chip would compute\n // to, so swapping out the slot for the streaming chip doesn't\n // shift the next chip up or down by a couple of pixels.\n lineHeight: '14px',\n };\n}\n\nfunction thinkingDotStyles(index: number): Record<string, string> {\n return {\n display: 'inline-block',\n width: '7px',\n height: '7px',\n borderRadius: '50%',\n background: 'currentColor',\n // The dots are now the entire visual \u2014 no bubble framing them \u2014\n // so the pulse has to do all the work the chip used to do. Scale\n // 0.4 \u2192 1.0 with opacity 0.25 \u2192 1.0 gives an unmistakable\n // breathing motion: at the trough each dot reads like a faint\n // ghost, at the peak like a solid dot. 940ms cycle is a touch\n // faster than the original 1.05s; without the chip frame the\n // shorter cycle feels purposeful instead of agitated. Stagger\n // 130ms = clear rolling cadence across all three.\n transformOrigin: 'center',\n animation: `syntro-trail-thinking-pulse 940ms cubic-bezier(0.4, 0, 0.6, 1) ${index * 0.13}s infinite both`,\n };\n}\n\nfunction moreStyles(): Record<string, string> {\n return {\n // Center horizontally regardless of the parent's display model.\n // ``alignSelf: center`` only works when the parent is a flex/grid\n // container with cross-axis alignment; the chat-bar's flex column\n // stretches us full-width instead. ``display: block`` + auto inline\n // margins centers the auto-sized button without needing the parent\n // to opt in.\n display: 'block',\n marginLeft: 'auto',\n marginRight: 'auto',\n marginBottom: '6px',\n fontSize: '10px',\n fontWeight: '500',\n letterSpacing: '0.06em',\n padding: '4px 10px',\n border: '1px solid hsl(var(--sc-accent-color) / 0.32)',\n borderRadius: '999px',\n background: 'hsl(var(--sc-accent-color) / 0.10)',\n color: 'var(--sc-tile-text-color, currentColor)',\n cursor: 'pointer',\n opacity: '0.85',\n backdropFilter: 'blur(8px)',\n WebkitBackdropFilter: 'blur(8px)',\n transition: 'opacity 150ms ease, background 150ms ease',\n };\n}\n\n// The trail used to inject these rules into `document.head` via a\n// helper. With the move to shadow DOM (see `static styles` on\n// AdaptiveChatTrail above), the rules are owned by Lit and scoped to\n// the trail's own tree. document.head injection is the wrong choice\n// from inside a shadow-rooted hierarchy \u2014 see the static-styles\n// comment for the failure mode.\n\n/**\n * Pre-process LLM markdown before rendering. Three common artifacts:\n *\n * 1. Trailing \" \" (two spaces = markdown hard-break) sprinkled at\n * end-of-line, even inside list items where it just leaks\n * invisible whitespace into the DOM.\n * 2. Runs of 3+ blank lines used as visual separators. Markdown\n * treats any number of blank lines as a single paragraph break,\n * so the extras add nothing semantically \u2014 but combined with\n * paragraph margins they create huge gaps in the tiny chip layout.\n * 3. Leading / trailing newlines on the whole message. Trailing\n * `\\n\\n` is the common one \u2014 marked turns it into a final empty\n * <p> that still occupies a full line-height of vertical space,\n * leaving a visible gap between the last text and the chat bar.\n *\n * Collapsing all three keeps the rendered HTML tight without changing\n * the agent's semantic intent.\n */\nfunction stripTrailingWhitespace(text: string): string {\n return text\n .replace(/[ \\t]+$/gm, '') // trailing whitespace per line\n .replace(/\\n{3,}/g, '\\n\\n') // collapse runs of blank lines\n .trim(); // drop leading/trailing whitespace+newlines on the whole message\n}\n\n/** Two-decimal trim that avoids trailing zeros (\".50\" \u2192 \".5\"). */\nfunction toFixedTrim(n: number): string {\n const s = n.toFixed(2);\n return s.replace(/\\.?0+$/, '') || '0';\n}\n\nconst THINKING_TAIL_MAX = 120;\n\n/**\n * Render the tail end of a streaming thinking buffer \u2014 the model's\n * narration grows monotonically as it reasons, but we only ever want\n * to display the last sentence (or so) to keep the chip compact while\n * still feeling alive as new content lands. Returns the input verbatim\n * if it's already short; otherwise prepends an ellipsis to signal the\n * head was trimmed.\n */\nfunction truncateThinkingTail(text: string): string {\n const flat = text.replace(/\\s+/g, ' ').trim();\n if (flat.length <= THINKING_TAIL_MAX) return flat;\n return `\u2026${flat.slice(-THINKING_TAIL_MAX)}`;\n}\n\nfunction thinkingTextStyles(): Record<string, string> {\n return {\n fontStyle: 'italic',\n opacity: '0.75',\n fontSize: '13px',\n lineHeight: '18px',\n maxWidth: '32ch',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n };\n}\n\nfunction introSuggestionStyles(): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n gap: '6px',\n marginTop: '4px',\n padding: '10px 18px',\n borderRadius: '9999px',\n border: '0',\n background:\n 'linear-gradient(135deg, var(--sc-color-primary, #5faf7d) 0%, var(--sc-color-primary-hover, #3d8a5e) 100%)',\n color: '#fff',\n cursor: 'pointer',\n font: 'inherit',\n fontSize: '14px',\n fontWeight: '600',\n transition: 'transform 120ms ease, filter 160ms ease',\n };\n}\n\nfunction emptyIconStyles(): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '48px',\n height: '48px',\n borderRadius: '9999px',\n background:\n 'var(--sc-tile-icon-background, linear-gradient(135deg, var(--sc-color-primary, #5faf7d) 0%, var(--sc-color-primary-hover, #3d8a5e) 100%))',\n color: '#fff',\n fontSize: '22px',\n };\n}\n\nfunction emptyTitleStyles(): Record<string, string> {\n return {\n margin: '0',\n fontSize: '15px',\n fontWeight: '600',\n lineHeight: '1.35',\n color: 'var(--sc-content-text-color, inherit)',\n maxWidth: '32ch',\n };\n}\n\nif (!customElements.get('adaptive-chat-trail')) {\n customElements.define('adaptive-chat-trail', AdaptiveChatTrail);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'adaptive-chat-trail': AdaptiveChatTrail;\n }\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }