@adia-ai/web-modules 0.8.32 → 0.8.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # Changelog — @adia-ai/web-modules
2
2
 
3
+ ## [0.8.34] — 2026-08-11
4
+
5
+ ### Fixed
6
+
7
+ - **`agent-admin-ui` — the composite demo rendered as garbled overlap (gh#956); three root causes fixed.** Column tokens were spacing tokens (`--a-space-12` = 48px roster, 77px settings — both panels clipped since WCH-5); now 13rem/17rem. The 900px stack breakpoint was a viewport `@media` query that never fired for a narrow CONTAINER on a wide screen; a ResizeObserver now reflects `[data-narrow]` below an 800px container width (SSR-guarded per the gh#285 pattern) and CSS keys the single-column stack on it. And `chat-thread`'s `empty` property defaulted true with reflection firing only on change, so a fresh thread never stamped `[empty]` and the CSS gate hid the authored empty state — `#syncEmptyFromChildren` now stamps the attribute directly (base-class fix in web-components gh#961 covers the whole latent class).
8
+ - **`chat-shell` — `--chat-code-bg` aligned to the container-low chip tier** (one inline-code language with `--richtext-code-bg`, gh#972).
9
+ - **`admin-shell` — `padded` standalone template variant (gh#964):** an isolated-doc iframe route can opt into the `doc` template's `<admin-page-body><section>` wrapper (`route.padded`), inheriting normal page padding/max-width instead of rendering full-bleed — the Pattern Library catalog pages are the first consumers.
10
+ - **`chat-empty` / `editor-canvas-empty` and 11 more doc pages — `.examples.html` source repairs (gh#959):** unescaped inline component-tag references in doc-header prose parsed as real elements and swallowed their sentences (8 files escaped to `<code>&lt;tag&gt;</code>`); admin-roster, admin-settings, and agent-admin gained the standard doc scaffold; responsive-shell-sidebar's examples file was a DOCTYPE-bearing duplicate of the standalone page and its route rendered empty — ported to fragment shape and registered in the sitemap.
11
+
12
+ ### Maintenance
13
+ - **`dist/` bundles rebuilt** in this cut's window (7 file(s)) — regenerated from the source changes described above, not independent edits.
14
+
15
+ ## [0.8.33] — 2026-08-11
16
+
17
+ ### Fixed
18
+
19
+ - **`confirm-dialog-ui`'s demo no longer models a destructive "Discard" as ConfirmDialog's cancel action (gh#860, part of; item 2 of the #853 split-off — item 1, combobox/command option semantics, stays open).** CodeRabbit's original PR #851 finding: the "Basic — save changes" example set `cancel-text="Discard"` on `<confirm-dialog-ui>`, directly contradicting the page's own copy ("Do NOT model the cancel option as a 'Discard' action... belongs in AlertDialog") and yaml `a2ui.rules`. Operator ruling (issue #860) picked switching the example's construct over softening its cancel action — a non-destructive cancel-text on the same scenario would have hidden the boundary the demo exists to teach. The section now demonstrates the discard-unsaved-changes flow with `<modal-ui role="alertdialog">` (Cancel / danger-toned Discard / primary Save & close), the same composition `alert-dialog.examples.html`'s "warning-unsaved" section already canonicalizes. Also fixed the page's adjacent "Related" link, which pointed at the nonexistent `/site/components/alertdialog` — the real route is `/site/patterns/alert-dialog` (AlertDialog is a pattern, not a registered primitive tag; there is no `<alert-dialog-ui>` custom element). Regenerated via `node scripts/build/site-a2ui.mjs --page /site/components/confirm-dialog`; `npm run verify:site-a2ui` clean (score 100, no new findings).
20
+ - **8 site-a2ui example previews rendered their empty/default state instead of the documented non-empty ones (gh#853).** Root causes split three ways, all in the SOURCE `.examples.html` fixtures / their yaml contracts — never the generated `.a2ui.json`:
21
+ - **Array/string-prop data was set via a post-upgrade `<script>` JS property assignment** (`el.integrations = …`, `el.invoices = …`, etc.) instead of an inline HTML attribute — invisible to the static HTML→A2UI transpile, which only reads attributes. `integrations-page`, `invoice-history`, `payment-method-list`, `plan-picker`, and `notification-preferences`' `preferences`/`channels` now carry the same demo data as an inline JSON attribute (`integrations='[{...}]'`, mirroring `chart-ui`'s existing `data='[{...}]'` convention) alongside the unchanged `<script>` block (still exercises the real live-DOM property-set path).
22
+ - **`date-range-selector.yaml` never declared `disabled`/`name` in `props:`** even though both are real, reflected `UIFormElement` properties the component already implements (and the demo markup already set) — the catalog-driven extractor only carries attributes a yaml declares. Added, mirroring the sibling `payment-method-form.yaml` pattern.
23
+ - **`invoice-detail.invoice` and `notification-preferences.channelEnabled` are `type: object` props** — the transpiler's catalog-driven extractor had no object branch (only string/boolean/number/array), so these were unreachable via any attribute shape. Fixed at the transpiler (`@adia-ai/a2ui-compose` CHANGELOG); fixtures now set them as JSON-object attributes.
24
+ - **`channelEnabled`'s catalog key is camelCase but HTML attributes lowercase on parse** — also fixed at the transpiler (kebab-case fallback); the fixture uses `channel-enabled='{...}'`.
25
+ - **`payment-method-form`'s `tokenizing` state had no `props:` entry at all** — it's set internally by `tokenize()` via raw `setAttribute`/`removeAttribute`, mirroring the existing "declared despite being externally read-only" precedent already set by `value`/`error` on this same component. Added to `props:` (yaml) AND to `payment-method-form.class.js`'s `static properties` (the latter closes an `audit:static-properties-vs-yaml` critical the yaml-only edit would have introduced — `reflect: true` needs a matching class.js entry or `el.tokenizing = x` silently no-ops).
26
+ - Regenerated via `node scripts/build/site-a2ui.mjs --page <route>` for all 8 routes; never hand-edited the generated `.a2ui.json`.
27
+ - **`form-popover-ui`'s trigger gains select-ui's hover/focus recipe and an aria-expanded/aria-haspopup contract (gh#857, part 1+2 of 3; panel-border token mismatch stays open — see the issue's Findings).** `form-popover.css` re-pointed only the trigger's rest-state `button-ui` tokens (bg/fg/border); hover/focus fell through to `button-ui`'s own uncoordinated default (a heavier neutral fill), unlike `select.css:103-125`'s explicit `--select-bg-hover`/`--select-border-hover`/`--select-focus-ring` recipe. Added the matching `--form-popover-trigger-bg-hover`/`-border-hover`/`-focus-ring` tokens, an explicit hover override, and a `--button-focus-ring` re-point (same consumer-override path the file's rest-state block already uses). Separately, neither `popover.class.js` nor `form-popover.js` ever set `aria-expanded`/`aria-haspopup` on the trigger — `form-popover.js` now stamps `aria-haspopup="dialog"` + `aria-expanded="false"` at construction and keeps `aria-expanded` synced to the internal `popover-ui`'s own `[open]` reflection via a `MutationObserver` (same DOM-is-the-source-of-truth pattern the existing summary observer uses). Scoped to `form-popover-ui` only — `popover-ui` itself stays the documented generic anchored surface with no role/expanded semantics of its own (`popover.yaml`'s decision rule); arrow-key listbox navigation was deliberately NOT added, since the panel holds an arbitrary form fragment (checks/radios/inputs), never an option list — documented in `form-popover.yaml`'s new "Accessibility contract" note.
28
+ - **`payment-method-form.examples.html` used a nonexistent `<option-ui>` tag (gh#848).** `<select-ui>` reads declarative native `<option>` children (FB-79 — `extractSelectOptions` folds them into the `options` prop); `option-ui` is defined nowhere in `packages/`, so the country picker's two options were invisible to the transpiler and the whole form converted to a hollow container. Replaced with native `<option>`; the converted page now renders the real form with "United States" selected (browser-probed).
29
+
30
+ ### Changed
31
+
32
+ - **BREAKING + VISIBLE BEHAVIOR CHANGE — `billing-overview`/`invoice-history`/`plan-picker`/`simple-hero`/`simple-shell` follow `badge-ui`/`tag-ui`/`button-ui`'s `accent` retirement (variant/color/tone convention cut, gh#873, gh#874, gh#875, gh#876).** `plan-picker.class.js`'s "Recommended" pill (`tag-ui`) moves `variant="accent"`→`variant="primary"`; its "Current plan" pill's `setAttribute('variant', 'muted')` is dropped entirely — `muted` was never a valid `tag-ui` `variant` value (a pre-existing invalid-value no-op; the invalid value matched no rule and fell through to the family-less solid base pair every bare tag renders unconditionally, gh#794, so dropping the call is a zero-visual-change edit — not, as first stated, `tone` defaulting to muted). `simple-hero`/`simple-shell`'s CTA examples move `variant="solid" color="accent"` → `variant="primary"` (`button-ui`'s `color="accent"` never had CSS — gh#875's re-confirmed finding — so this is a stated remap of the authored *intent*, not a mechanical rename; the button finally renders the fill it was asking for). Two pre-existing latent bugs surfaced and fixed while sweeping the adjacent vocabulary, both independent of the accent retirement itself: `invoice-history.class.js`'s `STATUS_TO_VARIANT` map used `variant="neutral"` (draft) and a `'neutral'` fallback default on its status `badge-ui` — never a valid badge variant post-cut, now `tone="muted"`; `billing-overview.class.js`'s `STATUS_TO_VARIANT` map used `variant="muted"` (canceled) on its status `tag-ui` — `muted` was never a valid `tag-ui` variant value even before this cut (tag's `variant` enum is the family axis; `muted` only ever existed on `tone`), now `tone="muted"`. Both status badges are DOM elements read across re-renders, so the fix explicitly clears the attribute not taken (`variant`/`tone`) on each branch, not just sets the one taken — a stale attribute from a prior render otherwise survives.
33
+
34
+ ### Added
35
+
36
+ - **18 web-module composites are now reachable from the A2UI wire (gh#848).** Every module listed in `packages/a2ui/runtime/CHANGELOG.md`'s Unreleased entry ships a full contract but had no runtime-registry mapping, so any A2UI document naming them (including the converted docs pages for their own `/site/components/*` routes) rendered a blank shell. No module source changed — this is purely the registry side of the gap.
37
+
38
+ ### Maintenance
39
+ - **`dashboard/` touched in this release window** (2 file(s), e.g. `date-range-selector/date-range-selector.a2ui.json`) — carried by the entries above.
40
+ - **`dist/` bundles rebuilt** in this cut's window (3 file(s)) — regenerated from the source changes described above, not independent edits.
41
+ - **`feedback/` touched in this release window** (2 file(s), e.g. `confirm-dialog/confirm-dialog.examples.html`) — carried by the entries above.
42
+ - **`settings/` touched in this release window** (2 file(s), e.g. `integrations-page/integrations-page.examples.html`) — carried by the entries above.
43
+
3
44
  ## [0.8.32] — 2026-08-09
4
45
 
5
46
  ### Maintenance
@@ -10,14 +10,19 @@
10
10
  @scope (agent-admin-ui) {
11
11
 
12
12
  :where(:scope) {
13
- --agent-admin-roster-w: var(--a-space-12);
14
- --agent-admin-settings-w: calc(var(--a-space-12) * 1.6);
13
+ /* Real panel widths (gh#956): the module shipped with --a-space-12
14
+ a 48px SPACING token — as the roster column, rendering the roster
15
+ at 48px and settings at 77px (48 × 1.6): both panels clipped to
16
+ garble. 13rem/17rem fit the roster's persona entries and the
17
+ settings pane's prompt-section list. */
18
+ --agent-admin-roster-w: 13rem;
19
+ --agent-admin-settings-w: 17rem;
15
20
  --agent-admin-border: var(--a-border-subtle);
16
21
  }
17
22
 
18
23
  :scope {
19
24
  display: grid;
20
- grid-template-columns: var(--agent-admin-roster-w) var(--agent-admin-settings-w) 1fr;
25
+ grid-template-columns: var(--agent-admin-roster-w) var(--agent-admin-settings-w) minmax(0, 1fr);
21
26
  min-height: 0;
22
27
  }
23
28
 
@@ -35,15 +40,20 @@
35
40
  min-width: 0;
36
41
  }
37
42
 
38
- @media (max-width: 900px) {
39
- :scope {
40
- grid-template-columns: 1fr;
41
- grid-auto-rows: auto;
42
- }
43
- :scope > admin-roster-ui,
44
- :scope > admin-settings-ui {
45
- border-right: none;
46
- border-bottom: 1px solid var(--agent-admin-border);
47
- }
43
+ /* Single-column stack when the HOST is narrow — keyed on [data-narrow],
44
+ reflected by agent-admin.js's ResizeObserver (gh#956). The previous
45
+ `@media (max-width: 900px)` measured the VIEWPORT, so a narrow
46
+ container on a wide screen (the docs demo at 568px in a 1148px
47
+ window) never stacked — the 3-column grid crushed into the
48
+ container instead. Chat takes the leftover height (min 0, scrolls
49
+ inside) under a consumer-set fixed height. */
50
+ :scope[data-narrow] {
51
+ grid-template-columns: 1fr;
52
+ grid-template-rows: auto auto minmax(0, 1fr);
53
+ }
54
+ :scope[data-narrow] > admin-roster-ui,
55
+ :scope[data-narrow] > admin-settings-ui {
56
+ border-right: none;
57
+ border-bottom: 1px solid var(--agent-admin-border);
48
58
  }
49
59
  }
@@ -82,6 +82,16 @@ class UIAgentAdmin extends UIElement {
82
82
  #activeStore = null;
83
83
  #session = null;
84
84
  #surfaceRegistry = NOOP_REGISTRY;
85
+ #resizeObserver = null;
86
+
87
+ /* Container width below which the 3-column grid stacks to one column
88
+ (CSS keys on the reflected [data-narrow] — agent-admin.css). Chosen
89
+ so the fixed rails (13rem + 17rem = 480px at 16px root) always
90
+ leave the chat pane ≥ ~320px before stacking kicks in. A container
91
+ measurement, not a viewport @media query — the docs demo renders
92
+ this module 568px wide inside a 1148px window, where a 900px
93
+ viewport query never fires (gh#956). */
94
+ static NARROW_BREAKPOINT = 800;
85
95
 
86
96
  get personas() { return this.#personas; }
87
97
  set personas(value) {
@@ -131,6 +141,18 @@ class UIAgentAdmin extends UIElement {
131
141
 
132
142
  this.#syncRosterSummaries();
133
143
  this.#activateInitialIfNeeded();
144
+
145
+ // gh#285 pattern — SSR DOM shims have no ResizeObserver global; the
146
+ // stacked layout is then reachable only via a consumer setting
147
+ // [data-narrow] themselves, which is fine server-side (no live resize).
148
+ if (typeof ResizeObserver !== 'undefined') {
149
+ this.#resizeObserver = new ResizeObserver((entries) => {
150
+ const w = entries[0]?.contentBoxSize?.[0]?.inlineSize
151
+ ?? entries[0]?.contentRect?.width ?? 0;
152
+ this.toggleAttribute('data-narrow', w > 0 && w < UIAgentAdmin.NARROW_BREAKPOINT);
153
+ });
154
+ this.#resizeObserver.observe(this);
155
+ }
134
156
  }
135
157
 
136
158
  #activateInitialIfNeeded() {
@@ -143,6 +165,8 @@ class UIAgentAdmin extends UIElement {
143
165
  this.#roster?.removeEventListener('persona-change', this.#onPersonaChange);
144
166
  this.#roster?.removeEventListener('persona-import', this.#onPersonaImport);
145
167
  this.#chat?.removeEventListener('submit', this.#onChatSubmit);
168
+ this.#resizeObserver?.disconnect();
169
+ this.#resizeObserver = null;
146
170
  }
147
171
 
148
172
  // ── the store-swap law ──────────────────────────────────────────
@@ -56,7 +56,7 @@
56
56
  --chat-actions-gap: var(--a-space-1);
57
57
 
58
58
  /* Code blocks inside messages */
59
- --chat-code-bg: var(--a-canvas-2);
59
+ --chat-code-bg: var(--md-sys-color-neutral-container-low); /* one chip language with --richtext-code-bg (gh#972) */
60
60
  --chat-code-radius: var(--a-radius-md);
61
61
 
62
62
  /* Typography */
@@ -78,7 +78,14 @@ class ChatThread extends UIElement {
78
78
  const messageChildren = Array.from(this.children).filter(
79
79
  (c) => c.tagName.toLowerCase() !== 'chat-empty'
80
80
  );
81
- this.empty = messageChildren.length === 0;
81
+ const isEmpty = messageChildren.length === 0;
82
+ this.empty = isEmpty;
83
+ // Stamp the attribute directly as well (gh#956): `empty` DEFAULTS to
84
+ // true and the property system only reflects on CHANGE, so a fresh
85
+ // empty thread sets true-over-true, the attribute never lands, and
86
+ // the CSS gate `chat-thread:not([empty]) > chat-empty` hides the
87
+ // authored empty state forever — the docs demo's blank chat pane.
88
+ this.toggleAttribute('empty', isEmpty);
82
89
  }
83
90
 
84
91
  #setupChildObserver() {
@@ -1 +1 @@
1
- :where(chat-shell){--chat-bg:var(--a-canvas-0);--chat-border:unset;--chat-radius:unset;--chat-header-height:var(--a-chrome-app-header-height);--chat-header-px:var(--a-space-4);--chat-header-gap:var(--a-space-2);--chat-header-border:1px solid var(--md-sys-color-neutral-outline-variant);--chat-messages-px:var(--a-space-4);--chat-messages-py:var(--a-space-4);--chat-messages-gap:var(--a-space-3);--chat-message-max-width:85%;--chat-user-bg:var(--md-sys-color-primary);--chat-user-fg:var(--md-sys-color-primary-on-primary);--chat-user-radius:var(--a-radius-md);--chat-user-tail-radius:var(--a-radius-sm);--chat-user-px:var(--a-space-3);--chat-user-py:var(--a-space-1);--chat-assistant-bg:var(--a-canvas-2);--chat-assistant-fg:var(--md-sys-color-neutral-on-surface);--chat-assistant-radius:var(--a-radius-lg);--chat-assistant-tail-radius:var(--a-radius-sm);--chat-assistant-px:var(--a-space-3);--chat-assistant-py:var(--a-space-1);--chat-avatar-size:1.75rem;--chat-avatar-bg:var(--chat-assistant-bg);--chat-avatar-fg:var(--chat-assistant-fg);--chat-avatar-font:var(--a-ui-sm);--chat-avatar-weight:var(--a-weight-semibold);--chat-cursor-width:2px;--chat-cursor-color:currentColor;--chat-cursor-speed:.8s;--chat-footer-px:var(--a-space-3);--chat-footer-py:var(--a-space-3);--chat-actions-gap:var(--a-space-1);--chat-code-bg:var(--a-canvas-2);--chat-code-radius:var(--a-radius-md);--chat-font-size:var(--a-ui-size);--chat-line-height:var(--a-leading-normal);--chat-weight-semibold:var(--a-weight-semibold);--chat-header-name-font:var(--a-ui-lg);--chat-header-status-font:var(--a-ui-md);--chat-header-status-fg:var(--a-fg-muted);--chat-error-gap:var(--a-space-2);--chat-error-fg:var(--a-danger-strong);--chat-error-font:var(--a-ui-sm);--chat-actions-duration:var(--a-duration-fast);--chat-actions-easing:var(--a-easing);--chat-avatar-radius:var(--a-radius-full);--chat-thinking-fg:var(--a-fg-muted);--chat-code-inline-radius:var(--a-radius-sm);--chat-code-inline-family:var(--a-font-family-code);--chat-code-block-px:var(--a-space-3);--chat-code-block-my:var(--a-space-2);--chat-code-block-font:var(--a-ui-sm)}chat-shell{box-sizing:border-box;border:var(--chat-border);border-radius:var(--chat-radius);background:var(--chat-bg);flex-direction:column;height:100%;display:flex;overflow:hidden}chat-shell>header{align-items:center;gap:var(--chat-header-gap);min-height:var(--chat-header-height);padding:0 var(--chat-header-px);border-bottom:var(--chat-header-border);flex-shrink:0;display:flex}chat-shell>header [data-chat-name]{font-weight:var(--chat-weight-semibold);font-size:var(--chat-header-name-font)}chat-shell>header chat-status{font-size:var(--chat-header-status-font);color:var(--chat-header-status-fg);margin-inline-start:auto}chat-shell>chat-thread,chat-shell>section{padding:var(--chat-messages-py) var(--chat-messages-px);gap:var(--chat-messages-gap);flex-direction:column;flex:1;min-height:0;display:flex;overflow-y:auto}chat-shell>footer{padding:var(--chat-footer-py) var(--chat-footer-px);flex-shrink:0;align-items:center;display:flex}chat-shell>footer chat-input-ui{flex:1}chat-shell [data-role]{gap:var(--chat-header-gap);max-width:var(--chat-message-max-width);align-items:flex-end;display:flex}chat-shell [data-role=user]{flex-direction:row-reverse;align-self:flex-end}chat-shell [data-role=assistant]{align-self:flex-start}chat-shell [data-role] [data-avatar]{width:var(--chat-avatar-size);height:var(--chat-avatar-size);border-radius:var(--chat-avatar-radius);background:var(--chat-avatar-bg);color:var(--chat-avatar-fg);font-size:var(--chat-avatar-font);font-weight:var(--chat-avatar-weight);flex-shrink:0;justify-content:center;align-items:center;display:flex}chat-shell [data-role] [data-bubble]{padding:var(--chat-assistant-py) var(--chat-assistant-px);border-radius:var(--chat-assistant-radius);font-size:var(--chat-font-size);line-height:var(--chat-line-height);white-space:pre-wrap;word-break:break-word}chat-shell [data-role] [data-bubble]>:first-child{margin-block-start:0}chat-shell [data-role] [data-bubble]>:last-child{margin-block-end:0}chat-shell [data-role=user] [data-bubble]{background:var(--chat-user-bg);color:var(--chat-user-fg);padding:var(--chat-user-py) var(--chat-user-px);border-radius:var(--chat-user-radius);border-bottom-right-radius:var(--chat-user-tail-radius)}chat-shell [data-role=assistant] [data-bubble]{background:var(--chat-assistant-bg);color:var(--chat-assistant-fg);border-bottom-left-radius:var(--chat-assistant-tail-radius)}chat-shell [data-role]:has([data-bubble][data-surface]),chat-shell [data-role]:has([data-bubble]>[data-surface-root]){max-width:none}chat-shell [data-role=error]{align-self:center;align-items:center;gap:var(--chat-error-gap);max-width:none;color:var(--chat-error-fg);font-size:var(--chat-error-font);display:flex}chat-shell [data-role] [data-actions]{gap:var(--chat-actions-gap);opacity:0;transition:opacity var(--chat-actions-duration) var(--chat-actions-easing);display:flex}chat-shell [data-role]:hover [data-actions]{opacity:1}chat-shell [data-cursor]{width:var(--chat-cursor-width);background:var(--chat-cursor-color);vertical-align:text-bottom;height:1em;animation:chat-shell-blink var(--chat-cursor-speed) step-end infinite;margin-inline-start:1px;display:inline-block}@keyframes chat-shell-blink{50%{opacity:0}}@media (prefers-reduced-motion:reduce){chat-shell [data-cursor]{opacity:.7;animation:none}}chat-shell [data-role=assistant][data-thinking] [data-bubble]{color:var(--chat-thinking-fg)}chat-shell [data-bubble] [data-content]{white-space:normal}chat-shell [data-bubble] [data-content] p{margin:0 0 .5em}chat-shell [data-bubble] [data-content] p:last-child{margin-bottom:0}chat-shell [data-bubble] [data-content] strong{font-weight:var(--chat-weight-semibold)}chat-shell [data-bubble] [data-content] code{background:var(--chat-code-bg);border-radius:var(--chat-code-inline-radius);font-family:var(--chat-code-inline-family);padding:.1em .15em;font-size:.875em}chat-shell [data-bubble] [data-content] pre{background:var(--chat-code-bg);border-radius:var(--chat-code-radius);padding:var(--chat-code-block-px);margin:var(--chat-code-block-my) 0;font-size:var(--chat-code-block-font);line-height:1.5;overflow-x:auto}chat-shell [data-bubble] [data-content] pre code{font-size:inherit;background:0 0;border-radius:0;padding:0}chat-shell [data-bubble] [data-content] ul,chat-shell [data-bubble] [data-content] ol{margin:.25em 0;padding-inline-start:1.25em}chat-shell [data-bubble] [data-content] li{margin-bottom:.15em}chat-shell [data-bubble] [data-content] a{color:inherit;text-underline-offset:2px;text-decoration:underline}chat-shell [data-bubble] [data-content] h1,chat-shell [data-bubble] [data-content] h2,chat-shell [data-bubble] [data-content] h3,chat-shell [data-bubble] [data-content] h4{font-weight:var(--chat-weight-semibold);margin:.75em 0 .25em}chat-shell [data-bubble] [data-content] h1:first-child,chat-shell [data-bubble] [data-content] h2:first-child,chat-shell [data-bubble] [data-content] h3:first-child{margin-top:0}chat-shell chat-empty{margin:auto}chat-shell[streaming] chat-empty,chat-shell:has([data-role]) chat-empty{display:none}chat-shell>chat-header,chat-sidebar>chat-header[slot=header],chat-sidebar>chat-header:first-child{align-items:center;gap:var(--chat-header-gap,var(--a-space-2));padding:0 var(--chat-header-px,var(--a-space-3));height:var(--chat-header-height,var(--a-size-lg));font-size:var(--chat-header-font,var(--a-ui-size));border-bottom:var(--chat-border,1px solid var(--md-sys-color-neutral-outline-variant));background:var(--chat-bg,var(--md-sys-color-neutral-background));flex-shrink:0;display:flex}chat-header>[slot=name]{font-weight:var(--a-weight-medium,500);color:var(--md-sys-color-neutral-on-surface)}chat-header>[slot=status]{margin-inline-start:var(--a-space-2)}chat-header>[slot=action]:first-of-type{margin-inline-start:auto}chat-header>[slot=action-leading]{margin-inline-end:var(--a-space-2)}chat-status{align-items:center;gap:var(--a-space-1);font-size:var(--a-ui-sm);color:var(--a-fg-muted);display:inline-flex}chat-shell>chat-thread{overscroll-behavior:contain;gap:var(--chat-message-gap,var(--a-space-3));min-height:0;padding:var(--chat-thread-py,var(--a-space-4)) var(--chat-thread-px,var(--a-space-4));background:var(--chat-thread-bg,var(--md-sys-color-neutral-background));flex-direction:column;flex:1;display:flex;overflow-y:auto}chat-thread:not([empty])>chat-empty{display:none}chat-thread[empty]>chat-empty{padding:var(--a-space-6);flex:1;justify-content:center;align-items:center;display:flex}chat-shell>chat-composer{align-items:stretch;gap:var(--a-space-2);padding:var(--chat-composer-py,var(--a-space-3)) var(--chat-composer-px,var(--a-space-3));border-top:var(--chat-border,1px solid var(--md-sys-color-neutral-outline-variant));background:var(--chat-bg,var(--md-sys-color-neutral-background));flex-shrink:0;display:flex}chat-composer>[slot=leading],chat-composer>[slot=attach],chat-composer>[slot=trailing]{align-items:center;gap:var(--a-space-1);flex-shrink:0;display:inline-flex}chat-composer>:is(chat-input-ui,input-ui,textarea-ui){flex:1;min-width:0}chat-composer[disabled]{opacity:.6;pointer-events:none}:is(chat-sidebar[slot=leading],chat-sidebar[slot=trailing]){min-width:var(--chat-sidebar-min-width,48px);max-width:var(--chat-sidebar-max-width,480px);min-height:0;font-size:var(--chat-sidebar-font,var(--a-ui-size));transition:width var(--chat-duration,var(--a-duration,.2s)) var(--chat-easing,var(--a-easing,ease));background:var(--chat-bg,var(--md-sys-color-neutral-background));flex-direction:column;flex-shrink:0;display:flex;position:relative;container:sidebar/inline-size}chat-sidebar[slot=leading]{width:var(--chat-sidebar-width-leading,240px);border-right:var(--chat-border,1px solid var(--md-sys-color-neutral-outline-variant))}chat-sidebar[slot=trailing]{width:var(--chat-sidebar-width-trailing,320px);border-left:var(--chat-border,1px solid var(--md-sys-color-neutral-outline-variant))}:is(chat-sidebar[slot=leading],chat-sidebar[slot=trailing])>[data-resize]{cursor:col-resize;z-index:1;-webkit-user-select:none;user-select:none;width:6px;position:absolute;top:0;bottom:0}chat-sidebar[slot=leading]>[data-resize]{right:-3px}chat-sidebar[slot=trailing]>[data-resize]{left:-3px}:is(chat-sidebar[slot=leading],chat-sidebar[slot=trailing])>[data-resize]:hover{background:var(--md-sys-color-primary);opacity:.5}chat-sidebar[resizing]{transition:none}chat-sidebar[resizing]>[data-resize]{background:var(--md-sys-color-primary);opacity:.8}chat-shell:has(>chat-sidebar){flex-direction:row;display:flex}chat-shell:has(>chat-sidebar)>:not(chat-sidebar){display:contents}
1
+ :where(chat-shell){--chat-bg:var(--a-canvas-0);--chat-border:unset;--chat-radius:unset;--chat-header-height:var(--a-chrome-app-header-height);--chat-header-px:var(--a-space-4);--chat-header-gap:var(--a-space-2);--chat-header-border:1px solid var(--md-sys-color-neutral-outline-variant);--chat-messages-px:var(--a-space-4);--chat-messages-py:var(--a-space-4);--chat-messages-gap:var(--a-space-3);--chat-message-max-width:85%;--chat-user-bg:var(--md-sys-color-primary);--chat-user-fg:var(--md-sys-color-primary-on-primary);--chat-user-radius:var(--a-radius-md);--chat-user-tail-radius:var(--a-radius-sm);--chat-user-px:var(--a-space-3);--chat-user-py:var(--a-space-1);--chat-assistant-bg:var(--a-canvas-2);--chat-assistant-fg:var(--md-sys-color-neutral-on-surface);--chat-assistant-radius:var(--a-radius-lg);--chat-assistant-tail-radius:var(--a-radius-sm);--chat-assistant-px:var(--a-space-3);--chat-assistant-py:var(--a-space-1);--chat-avatar-size:1.75rem;--chat-avatar-bg:var(--chat-assistant-bg);--chat-avatar-fg:var(--chat-assistant-fg);--chat-avatar-font:var(--a-ui-sm);--chat-avatar-weight:var(--a-weight-semibold);--chat-cursor-width:2px;--chat-cursor-color:currentColor;--chat-cursor-speed:.8s;--chat-footer-px:var(--a-space-3);--chat-footer-py:var(--a-space-3);--chat-actions-gap:var(--a-space-1);--chat-code-bg:var(--md-sys-color-neutral-container-low);--chat-code-radius:var(--a-radius-md);--chat-font-size:var(--a-ui-size);--chat-line-height:var(--a-leading-normal);--chat-weight-semibold:var(--a-weight-semibold);--chat-header-name-font:var(--a-ui-lg);--chat-header-status-font:var(--a-ui-md);--chat-header-status-fg:var(--a-fg-muted);--chat-error-gap:var(--a-space-2);--chat-error-fg:var(--a-danger-strong);--chat-error-font:var(--a-ui-sm);--chat-actions-duration:var(--a-duration-fast);--chat-actions-easing:var(--a-easing);--chat-avatar-radius:var(--a-radius-full);--chat-thinking-fg:var(--a-fg-muted);--chat-code-inline-radius:var(--a-radius-sm);--chat-code-inline-family:var(--a-font-family-code);--chat-code-block-px:var(--a-space-3);--chat-code-block-my:var(--a-space-2);--chat-code-block-font:var(--a-ui-sm)}chat-shell{box-sizing:border-box;border:var(--chat-border);border-radius:var(--chat-radius);background:var(--chat-bg);flex-direction:column;height:100%;display:flex;overflow:hidden}chat-shell>header{align-items:center;gap:var(--chat-header-gap);min-height:var(--chat-header-height);padding:0 var(--chat-header-px);border-bottom:var(--chat-header-border);flex-shrink:0;display:flex}chat-shell>header [data-chat-name]{font-weight:var(--chat-weight-semibold);font-size:var(--chat-header-name-font)}chat-shell>header chat-status{font-size:var(--chat-header-status-font);color:var(--chat-header-status-fg);margin-inline-start:auto}chat-shell>chat-thread,chat-shell>section{padding:var(--chat-messages-py) var(--chat-messages-px);gap:var(--chat-messages-gap);flex-direction:column;flex:1;min-height:0;display:flex;overflow-y:auto}chat-shell>footer{padding:var(--chat-footer-py) var(--chat-footer-px);flex-shrink:0;align-items:center;display:flex}chat-shell>footer chat-input-ui{flex:1}chat-shell [data-role]{gap:var(--chat-header-gap);max-width:var(--chat-message-max-width);align-items:flex-end;display:flex}chat-shell [data-role=user]{flex-direction:row-reverse;align-self:flex-end}chat-shell [data-role=assistant]{align-self:flex-start}chat-shell [data-role] [data-avatar]{width:var(--chat-avatar-size);height:var(--chat-avatar-size);border-radius:var(--chat-avatar-radius);background:var(--chat-avatar-bg);color:var(--chat-avatar-fg);font-size:var(--chat-avatar-font);font-weight:var(--chat-avatar-weight);flex-shrink:0;justify-content:center;align-items:center;display:flex}chat-shell [data-role] [data-bubble]{padding:var(--chat-assistant-py) var(--chat-assistant-px);border-radius:var(--chat-assistant-radius);font-size:var(--chat-font-size);line-height:var(--chat-line-height);white-space:pre-wrap;word-break:break-word}chat-shell [data-role] [data-bubble]>:first-child{margin-block-start:0}chat-shell [data-role] [data-bubble]>:last-child{margin-block-end:0}chat-shell [data-role=user] [data-bubble]{background:var(--chat-user-bg);color:var(--chat-user-fg);padding:var(--chat-user-py) var(--chat-user-px);border-radius:var(--chat-user-radius);border-bottom-right-radius:var(--chat-user-tail-radius)}chat-shell [data-role=assistant] [data-bubble]{background:var(--chat-assistant-bg);color:var(--chat-assistant-fg);border-bottom-left-radius:var(--chat-assistant-tail-radius)}chat-shell [data-role]:has([data-bubble][data-surface]),chat-shell [data-role]:has([data-bubble]>[data-surface-root]){max-width:none}chat-shell [data-role=error]{align-self:center;align-items:center;gap:var(--chat-error-gap);max-width:none;color:var(--chat-error-fg);font-size:var(--chat-error-font);display:flex}chat-shell [data-role] [data-actions]{gap:var(--chat-actions-gap);opacity:0;transition:opacity var(--chat-actions-duration) var(--chat-actions-easing);display:flex}chat-shell [data-role]:hover [data-actions]{opacity:1}chat-shell [data-cursor]{width:var(--chat-cursor-width);background:var(--chat-cursor-color);vertical-align:text-bottom;height:1em;animation:chat-shell-blink var(--chat-cursor-speed) step-end infinite;margin-inline-start:1px;display:inline-block}@keyframes chat-shell-blink{50%{opacity:0}}@media (prefers-reduced-motion:reduce){chat-shell [data-cursor]{opacity:.7;animation:none}}chat-shell [data-role=assistant][data-thinking] [data-bubble]{color:var(--chat-thinking-fg)}chat-shell [data-bubble] [data-content]{white-space:normal}chat-shell [data-bubble] [data-content] p{margin:0 0 .5em}chat-shell [data-bubble] [data-content] p:last-child{margin-bottom:0}chat-shell [data-bubble] [data-content] strong{font-weight:var(--chat-weight-semibold)}chat-shell [data-bubble] [data-content] code{background:var(--chat-code-bg);border-radius:var(--chat-code-inline-radius);font-family:var(--chat-code-inline-family);padding:.1em .15em;font-size:.875em}chat-shell [data-bubble] [data-content] pre{background:var(--chat-code-bg);border-radius:var(--chat-code-radius);padding:var(--chat-code-block-px);margin:var(--chat-code-block-my) 0;font-size:var(--chat-code-block-font);line-height:1.5;overflow-x:auto}chat-shell [data-bubble] [data-content] pre code{font-size:inherit;background:0 0;border-radius:0;padding:0}chat-shell [data-bubble] [data-content] ul,chat-shell [data-bubble] [data-content] ol{margin:.25em 0;padding-inline-start:1.25em}chat-shell [data-bubble] [data-content] li{margin-bottom:.15em}chat-shell [data-bubble] [data-content] a{color:inherit;text-underline-offset:2px;text-decoration:underline}chat-shell [data-bubble] [data-content] h1,chat-shell [data-bubble] [data-content] h2,chat-shell [data-bubble] [data-content] h3,chat-shell [data-bubble] [data-content] h4{font-weight:var(--chat-weight-semibold);margin:.75em 0 .25em}chat-shell [data-bubble] [data-content] h1:first-child,chat-shell [data-bubble] [data-content] h2:first-child,chat-shell [data-bubble] [data-content] h3:first-child{margin-top:0}chat-shell chat-empty{margin:auto}chat-shell[streaming] chat-empty,chat-shell:has([data-role]) chat-empty{display:none}chat-shell>chat-header,chat-sidebar>chat-header[slot=header],chat-sidebar>chat-header:first-child{align-items:center;gap:var(--chat-header-gap,var(--a-space-2));padding:0 var(--chat-header-px,var(--a-space-3));height:var(--chat-header-height,var(--a-size-lg));font-size:var(--chat-header-font,var(--a-ui-size));border-bottom:var(--chat-border,1px solid var(--md-sys-color-neutral-outline-variant));background:var(--chat-bg,var(--md-sys-color-neutral-background));flex-shrink:0;display:flex}chat-header>[slot=name]{font-weight:var(--a-weight-medium,500);color:var(--md-sys-color-neutral-on-surface)}chat-header>[slot=status]{margin-inline-start:var(--a-space-2)}chat-header>[slot=action]:first-of-type{margin-inline-start:auto}chat-header>[slot=action-leading]{margin-inline-end:var(--a-space-2)}chat-status{align-items:center;gap:var(--a-space-1);font-size:var(--a-ui-sm);color:var(--a-fg-muted);display:inline-flex}chat-shell>chat-thread{overscroll-behavior:contain;gap:var(--chat-message-gap,var(--a-space-3));min-height:0;padding:var(--chat-thread-py,var(--a-space-4)) var(--chat-thread-px,var(--a-space-4));background:var(--chat-thread-bg,var(--md-sys-color-neutral-background));flex-direction:column;flex:1;display:flex;overflow-y:auto}chat-thread:not([empty])>chat-empty{display:none}chat-thread[empty]>chat-empty{padding:var(--a-space-6);flex:1;justify-content:center;align-items:center;display:flex}chat-shell>chat-composer{align-items:stretch;gap:var(--a-space-2);padding:var(--chat-composer-py,var(--a-space-3)) var(--chat-composer-px,var(--a-space-3));border-top:var(--chat-border,1px solid var(--md-sys-color-neutral-outline-variant));background:var(--chat-bg,var(--md-sys-color-neutral-background));flex-shrink:0;display:flex}chat-composer>[slot=leading],chat-composer>[slot=attach],chat-composer>[slot=trailing]{align-items:center;gap:var(--a-space-1);flex-shrink:0;display:inline-flex}chat-composer>:is(chat-input-ui,input-ui,textarea-ui){flex:1;min-width:0}chat-composer[disabled]{opacity:.6;pointer-events:none}:is(chat-sidebar[slot=leading],chat-sidebar[slot=trailing]){min-width:var(--chat-sidebar-min-width,48px);max-width:var(--chat-sidebar-max-width,480px);min-height:0;font-size:var(--chat-sidebar-font,var(--a-ui-size));transition:width var(--chat-duration,var(--a-duration,.2s)) var(--chat-easing,var(--a-easing,ease));background:var(--chat-bg,var(--md-sys-color-neutral-background));flex-direction:column;flex-shrink:0;display:flex;position:relative;container:sidebar/inline-size}chat-sidebar[slot=leading]{width:var(--chat-sidebar-width-leading,240px);border-right:var(--chat-border,1px solid var(--md-sys-color-neutral-outline-variant))}chat-sidebar[slot=trailing]{width:var(--chat-sidebar-width-trailing,320px);border-left:var(--chat-border,1px solid var(--md-sys-color-neutral-outline-variant))}:is(chat-sidebar[slot=leading],chat-sidebar[slot=trailing])>[data-resize]{cursor:col-resize;z-index:1;-webkit-user-select:none;user-select:none;width:6px;position:absolute;top:0;bottom:0}chat-sidebar[slot=leading]>[data-resize]{right:-3px}chat-sidebar[slot=trailing]>[data-resize]{left:-3px}:is(chat-sidebar[slot=leading],chat-sidebar[slot=trailing])>[data-resize]:hover{background:var(--md-sys-color-primary);opacity:.5}chat-sidebar[resizing]{transition:none}chat-sidebar[resizing]>[data-resize]{background:var(--md-sys-color-primary);opacity:.8}chat-shell:has(>chat-sidebar){flex-direction:row;display:flex}chat-shell:has(>chat-sidebar)>:not(chat-sidebar){display:contents}