@gemboss/ui 0.30.2 → 0.33.1

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.
@@ -32,7 +32,7 @@ import React, {
32
32
  import { BridgeNotice, copyText } from "./engine";
33
33
  import { EngineMark } from "./engine-mark";
34
34
  import { isEngineMarkId } from "./engine-mark-art";
35
- import { CODE_FOLD_LINES, parseBlocks, parseInline, type Block, type ImageHost } from "./chat-markdown";
35
+ import { CODE_FOLD_LINES, linkTarget, parseBlocks, parseInline, type Block, type ImageHost } from "./chat-markdown";
36
36
 
37
37
  const cx = (...p: Array<string | false | null | undefined>) => p.filter(Boolean).join(" ");
38
38
  const useBeforePaint = typeof window === "undefined" ? useEffect : useLayoutEffect;
@@ -171,14 +171,31 @@ export interface ChatMarkdownProps {
171
171
  onNavigate?: (href: string) => void;
172
172
  /** More hosts whose pictures may be drawn (added to the fleet's). */
173
173
  imageHosts?: readonly ImageHost[];
174
- /** A link scheme of the surface's own (`customer:12`): `ownLink` says which, `renderLink` draws it. */
174
+ /** A link scheme of the surface's own (`customer:12`): `ownLink` says which, `renderLink` draws it. Kept for the surfaces
175
+ * that use it; `linkPolicy` says the same in one prop and wins when both are given. */
175
176
  ownLink?: (href: string) => boolean;
176
177
  renderLink?: (href: string, label: string) => ReactNode;
178
+ /**
179
+ * What EVERY link in an answer becomes (0.32.0), asked with the href as the model wrote it (before any normalising),
180
+ * its words, and `target`: what the kit would link (`linkTarget`: an in-app path or http(s), normalised) or null when the
181
+ * kit refuses it (`javascript:`, `//host`, a tab inside the scheme). Return `true` (or undefined) = the kit's link (in-app
182
+ * through `onNavigate`, https in a new tab; still words when `target` is null); `false` (or null) = its words, no link;
183
+ * anything else is drawn as given (a router link, a button for `customer:12`). A policy that draws its OWN link for an
184
+ * ordinary URL builds it from `target.href`, never from `href`: the raw one is unchecked (review #3952). Bare URLs and
185
+ * pictures from other hosts (drawn as links) ask it too. Three surfaces had to say "this link is text" through the pair
186
+ * above: `ownLink` claiming it, `renderLink` giving back the label (partner-radar, search-radar), or claiming EVERY link
187
+ * and re-implementing the kit's link (GemFeedback, whose bare URLs then skipped its rule).
188
+ * `linkPolicy={(href) => !keepAsText(href)}`.
189
+ */
190
+ linkPolicy?: (href: string, label: string, target: { href: string; internal: boolean } | null) => ReactNode;
177
191
  }
178
192
 
193
+ /** Claims every written link raw for `linkPolicy` (the decision is made at render, with the label). */
194
+ const CLAIM_ALL = () => true;
195
+
179
196
  function Inline({ text, p }: { text: string; p: ChatMarkdownProps }) {
180
197
  const L = useLabels();
181
- const toks = parseInline(text, { imageHosts: p.imageHosts, ownLink: p.ownLink });
198
+ const toks = parseInline(text, { imageHosts: p.imageHosts, ownLink: p.linkPolicy ? CLAIM_ALL : p.ownLink });
182
199
  return (
183
200
  <>
184
201
  {toks.map((tok, key) => {
@@ -188,8 +205,17 @@ function Inline({ text, p }: { text: string; p: ChatMarkdownProps }) {
188
205
  case "bold": return <strong key={key}>{tok.text}</strong>;
189
206
  case "italic": return <em key={key}>{tok.text}</em>;
190
207
  case "link": {
191
- if (p.ownLink?.(tok.href) && p.renderLink) return <Fragment key={key}>{p.renderLink(tok.href, tok.label)}</Fragment>;
192
- const { href, internal, label } = tok;
208
+ let target: { href: string; internal: boolean } | null = tok;
209
+ if (p.linkPolicy) {
210
+ // A claimed (raw) href passes the kit's own rule; a bare URL or a picture's link already did.
211
+ target = tok.own ? linkTarget(tok.href) : { href: tok.href, internal: tok.internal };
212
+ const d = p.linkPolicy(tok.href, tok.label, target);
213
+ if (d === false || d === null) return <Fragment key={key}>{tok.label}</Fragment>;
214
+ if (d !== true && d !== undefined) return <Fragment key={key}>{d}</Fragment>;
215
+ if (!target) return <Fragment key={key}>{tok.label}</Fragment>;
216
+ } else if (p.ownLink?.(tok.href) && p.renderLink) return <Fragment key={key}>{p.renderLink(tok.href, tok.label)}</Fragment>;
217
+ const { href, internal } = target;
218
+ const { label } = tok;
193
219
  return (
194
220
  <a key={key} className="gemboss-ec-md-link" href={href}
195
221
  target={internal ? undefined : "_blank"} rel={internal ? undefined : "noopener noreferrer"}
@@ -755,10 +781,22 @@ export function AssistantChat(p: AssistantChatProps) {
755
781
  const setDraft = (v: string) => { if (!controlled) setOwnDraft(v); p.onDraftChange?.(v); };
756
782
  const ownInput = useRef<HTMLTextAreaElement | null>(null);
757
783
  const inputRef = p.inputRef ?? ownInput;
758
- const md: ChatMarkdownProps = { text: "", onNavigate: p.onNavigate, imageHosts: p.imageHosts, ownLink: p.ownLink, renderLink: p.renderLink };
784
+ const md: ChatMarkdownProps = { text: "", onNavigate: p.onNavigate, imageHosts: p.imageHosts, ownLink: p.ownLink, renderLink: p.renderLink, linkPolicy: p.linkPolicy };
759
785
  // Back to the end on a send, and when another conversation is shown (its first message is another one, or it is empty).
786
+ // 0.32.0: and when a NEW user message appears, wherever it was sent from. A question sent by a button outside the chat (a
787
+ // page's "Ask about this partner", the 📎 upload, a starter of the surface's own) never went through the composer, so the
788
+ // log stayed where the reader had scrolled and the answer streamed out of sight (partner-radar #968 scrolled by hand).
789
+ // Only a message ADDED counts (more user messages than before): an edit that drops one, or a temporary id swapped for the
790
+ // server's, does not pull a reader who scrolled up (review #3952). Counted once per list, not per streamed token.
760
791
  const [sent, setSent] = useState(0);
761
- const pinKey = `${sent}:${p.messages[0]?.id ?? ""}:${p.messages.length === 0}`;
792
+ const users = useMemo(() => p.messages.reduce((n, m) => n + (m.role === "user" ? 1 : 0), 0), [p.messages]);
793
+ const usersBefore = useRef(users);
794
+ const [asked, setAsked] = useState(0);
795
+ useEffect(() => {
796
+ if (users > usersBefore.current) setAsked((n) => n + 1);
797
+ usersBefore.current = users;
798
+ }, [users]);
799
+ const pinKey = `${sent}:${p.messages[0]?.id ?? ""}:${p.messages.length === 0}:${asked}`;
762
800
  const send = (text: string) => { p.onSend(text); setSent((n) => n + 1); if (!controlled) setOwnDraft(""); };
763
801
  const rootRef = useRef<HTMLDivElement>(null);
764
802
  useFullChromeRoom(rootRef);
@@ -171,19 +171,30 @@ export interface EnginePickerProps {
171
171
  locked?: boolean;
172
172
  /** Align the panel's right edge with the chip's (a chip near the right edge of a narrow frame). */
173
173
  end?: boolean;
174
+ /** The chip button, for the surface (`useEnginePicker` passes its own: `close()` puts focus back on it). 0.32.0. */
175
+ chipRef?: React.Ref<HTMLButtonElement>;
174
176
  labels?: Partial<EnginePickerLabels>;
175
177
  className?: string;
176
178
  }
177
179
 
178
180
  /** The open state and tab of one picker, for a surface that also renders a `BridgeNotice`:
179
- * `const p = useEnginePicker(); <EnginePicker {...p.props} …/> <BridgeNotice onOpenSetup={() => p.openTab("setup")} …/>` */
181
+ * `const p = useEnginePicker(); <EnginePicker {...p.props} …/> <BridgeNotice onOpenSetup={() => p.openTab("setup")} …/>`
182
+ *
183
+ * `close()` (0.32.0) is the surface's close: a button inside the panel that acts and then shuts it (Stop bridge, Remove
184
+ * from this machine, before a confirm opens). The button that had focus goes away with the panel, so focus would fall to
185
+ * <body> and the confirm would record <body> as where to return; `close()` puts it on the chip first. Every surface
186
+ * wrote that by hand (`querySelector(".gb-engine-chip").focus()`: partner-radar, search-radar, gemwatcher #922). An
187
+ * outside click still closes without moving focus (`props.onOpenChange(false)`). */
180
188
  export function useEnginePicker(initial: EnginePickerTab = "engine") {
181
189
  const [open, setOpen] = useState(false);
182
190
  const [tab, setTab] = useState<EnginePickerTab>(initial);
191
+ const chipRef = useRef<HTMLButtonElement | null>(null);
183
192
  const openTab = useCallback((t: EnginePickerTab) => { setTab(t); setOpen(true); }, []);
184
193
  // Closing goes back to Engine: after "Open setup" the next click on the chip is about the engine again (review #3885).
185
194
  const onOpenChange = useCallback((v: boolean) => { setOpen(v); if (!v) setTab(initial); }, [initial]);
186
- return { open, tab, setOpen, setTab, openTab, props: { open, onOpenChange, tab, onTabChange: setTab } };
195
+ const focusChip = useCallback(() => { chipRef.current?.focus(); }, []);
196
+ const close = useCallback(() => { onOpenChange(false); focusChip(); }, [onOpenChange, focusChip]);
197
+ return { open, tab, setOpen, setTab, openTab, close, focusChip, chipRef, props: { open, onOpenChange, tab, onTabChange: setTab, chipRef } };
187
198
  }
188
199
 
189
200
  function availableTabs(p: Pick<EnginePickerProps, "bridge" | "setup">): EnginePickerTab[] {
@@ -224,7 +235,13 @@ export function EnginePicker(props: EnginePickerProps) {
224
235
  // Decided after mount, so the server and the first client render agree.
225
236
  const [portal, setPortal] = useState(false);
226
237
  useEffect(() => { setPortal(!canFloatMenus()); }, []);
227
- const chipRef = useRef<HTMLButtonElement>(null);
238
+ const chipRef = useRef<HTMLButtonElement | null>(null);
239
+ const outerChipRef = props.chipRef;
240
+ const setChip = useCallback((el: HTMLButtonElement | null) => {
241
+ chipRef.current = el;
242
+ if (typeof outerChipRef === "function") outerChipRef(el);
243
+ else if (outerChipRef) (outerChipRef as { current: HTMLButtonElement | null }).current = el;
244
+ }, [outerChipRef]);
228
245
  const panelRef = useRef<HTMLDivElement>(null);
229
246
  const panelId = useId();
230
247
 
@@ -340,7 +357,7 @@ export function EnginePicker(props: EnginePickerProps) {
340
357
  return (
341
358
  <span className={cx("gb-engine", className)}>
342
359
  <button
343
- ref={chipRef}
360
+ ref={setChip}
344
361
  type="button"
345
362
  className={mark ? "gb-engine-chip has-mark" : "gb-engine-chip"}
346
363
  disabled={props.disabled || undefined}
@@ -39,6 +39,7 @@ export interface AssistantHostLabels {
39
39
  close: string; closeBusy: string; closeBusyTitle: string;
40
40
  shrinkToPopup: string; tablist: string; primaryTab: string;
41
41
  pinSide: string; floatPopup: string; sideGrip: string; backToSide: string;
42
+ more: string; clearHistory: string;
42
43
  }
43
44
  const EN: AssistantHostLabels = {
44
45
  ready: "Ready", working: "Working", done: "Done — tap to see it",
@@ -52,8 +53,88 @@ const EN: AssistantHostLabels = {
52
53
  shrinkToPopup: "Shrink to popup", tablist: "Assistant or a person", primaryTab: "Assistant",
53
54
  pinSide: "Pin to the side", floatPopup: "Float as a popup", sideGrip: "Drag to resize the assistant; left and right arrows work too",
54
55
  backToSide: "Back to the side panel",
56
+ more: "More", clearHistory: "Clear history",
55
57
  };
56
58
 
59
+ /**
60
+ * One row of the header's ⋯ menu (0.31.0). The fleet's menu row (`ui-menu__item`, shell.css, which every surface with
61
+ * the shell loads, the admin too). A surface's own rows go in `menuItems`.
62
+ * It closes the menu and puts focus on ⋯ BEFORE its handler (review #3941): closing after it hid the focused row, so focus
63
+ * fell to <body>, and a confirm the handler opened (content-radar's Clear history) saved that hidden row as the place to
64
+ * return to. No `role="menuitem"`: like the kit's Menu, a disclosure of buttons; the menu role promises arrow keys.
65
+ */
66
+ export function AssistantMenuItem({ danger, disabled, onClick, className, children }: {
67
+ danger?: boolean;
68
+ disabled?: boolean;
69
+ onClick?: React.MouseEventHandler<HTMLButtonElement>;
70
+ className?: string;
71
+ children?: ReactNode;
72
+ }) {
73
+ return (
74
+ <button
75
+ type="button"
76
+ className={["ui-menu__item", danger ? "ui-menu__item--danger" : "", className ?? ""].filter(Boolean).join(" ")}
77
+ disabled={disabled}
78
+ onClick={(e) => {
79
+ const menu = e.currentTarget.closest("details");
80
+ menu?.removeAttribute("open");
81
+ menu?.querySelector("summary")?.focus();
82
+ onClick?.(e);
83
+ }}
84
+ >
85
+ {children}
86
+ </button>
87
+ );
88
+ }
89
+
90
+ /**
91
+ * The header's ⋯ (0.31.0, Chris 08/10/2026: "clear history lên topbar … nhiều icon rồi nên cần gom nhóm"). A `<details>`
92
+ * like the kit's Menu, but its position and trigger are the host's (assistant.css): the kit's `.ui-menu` rules live in
93
+ * kit-plain.css, which the admin does not load, while the row (`ui-menu__item`) and the surface
94
+ * (`gemboss-popover-surface`) are shell.css, which it does. Escape and an outside press close it, the way the engine
95
+ * picker's popup closes (engine.tsx): Escape with focus inside goes back to ⋯ and is stopped, so the surface's own
96
+ * "Escape hides the assistant" does not fire on the same key; an Escape meant for a modal elsewhere is left to it. It also
97
+ * closes when the window loses focus (a click into an iframe), like the kit's plain menus (kit-plain.js initMenus).
98
+ */
99
+ function HostMenu({ label, trigger = "gb-dock-icon", children }: { label: string; trigger?: string; children: ReactNode }) {
100
+ const ref = useRef<HTMLDetailsElement>(null);
101
+ // Listening all the time and asking `el.open`, like the kit's Menu: gating the listeners on an `open` state left the
102
+ // render between the toggle and the effect unguarded, and a press outside in that window kept the menu open (measured
103
+ // in the browser test under load).
104
+ useEffect(() => {
105
+ const el = ref.current;
106
+ if (!el) return undefined;
107
+ const onKey = (e: KeyboardEvent) => {
108
+ if (!el.open || e.key !== "Escape" || e.defaultPrevented || e.isComposing || e.keyCode === 229) return;
109
+ const modal = (document.activeElement as Element | null)?.closest?.('dialog[open], [aria-modal="true"]');
110
+ if (modal && !el.contains(modal)) return;
111
+ e.preventDefault();
112
+ if (el.contains(document.activeElement)) { e.stopPropagation(); el.open = false; el.querySelector("summary")?.focus(); }
113
+ else el.open = false;
114
+ };
115
+ const onDown = (e: PointerEvent) => { if (el.open && !el.contains(e.target as Node)) el.open = false; };
116
+ const onBlur = () => { if (el.open) el.open = false; };
117
+ window.addEventListener("keydown", onKey, true);
118
+ document.addEventListener("pointerdown", onDown, true);
119
+ window.addEventListener("blur", onBlur);
120
+ return () => {
121
+ window.removeEventListener("keydown", onKey, true);
122
+ document.removeEventListener("pointerdown", onDown, true);
123
+ window.removeEventListener("blur", onBlur);
124
+ };
125
+ }, []);
126
+ return (
127
+ <details ref={ref} className="gb-dock-menu">
128
+ <summary className={trigger} title={label} aria-label={label}>
129
+ <svg viewBox="0 0 20 20" aria-hidden><circle cx="5" cy="10" r="1.5" fill="currentColor"/><circle cx="10" cy="10" r="1.5" fill="currentColor"/><circle cx="15" cy="10" r="1.5" fill="currentColor"/></svg>
130
+ </summary>
131
+ {/* title="": the popup's header carries "Drag this bar…" as its title, and a browser shows an ancestor's title on
132
+ any child without one of its own, so every row said it (review #3941). */}
133
+ <div className="gemboss-popover-surface gb-dock-menu-list" title="">{children}</div>
134
+ </details>
135
+ );
136
+ }
137
+
57
138
  /** An optional second tab in the popup (the admin: a person on the Gem team, through gemcare). */
58
139
  export interface AssistantSecondTab {
59
140
  label: ReactNode;
@@ -88,14 +169,23 @@ function useSideFits(): boolean {
88
169
  }
89
170
 
90
171
  export function AssistantHost({
91
- title, labels, onNewChat, onExpand, onShrink, fullActions, secondTab, view = "primary", onViewChange,
92
- miniHint, allowSide = true, children,
172
+ title, labels, onNewChat, onClearHistory, canClearHistory = true, menuItems, onExpand, onShrink, fullActions, secondTab,
173
+ view = "primary", onViewChange, miniHint, allowSide = true, children,
93
174
  }: {
94
175
  /** "Gem assistant" in the admin. Names the region, the popup header and the status bar. */
95
176
  title: string;
96
177
  labels?: Partial<AssistantHostLabels>;
97
178
  /** The popup header's +. Omit it and the button is not drawn. */
98
179
  onNewChat?: () => void;
180
+ /**
181
+ * "Clear history" in the ⋯ menu (0.31.0), in the panel's header and in full screen's chrome. The surface confirms (it
182
+ * knows what is cleared: this browser's chats, an engine's session). Omit it and the row is not drawn.
183
+ */
184
+ onClearHistory?: () => void;
185
+ /** False greys "Clear history" out (nothing to clear). */
186
+ canClearHistory?: boolean;
187
+ /** The surface's own rows at the top of the ⋯ menu, as `AssistantMenuItem`s. */
188
+ menuItems?: ReactNode;
99
189
  /** Popup → full screen. The surface decides what that means (the admin navigates to its page). */
100
190
  onExpand: () => void;
101
191
  /** Full screen → popup, e.g. open the dock and go back to the screen they came from. */
@@ -196,8 +286,8 @@ export function AssistantHost({
196
286
  return { min: 8, max: Math.max(8, Math.floor(track - width - 8)) };
197
287
  }, []);
198
288
  const onHeaderDown = useCallback((e: React.PointerEvent<HTMLElement>) => {
199
- // Buttons in the header keep their clicks; only the bare strip drags.
200
- if ((e.target as HTMLElement).closest("button")) return;
289
+ // Buttons in the header keep their clicks — the ⋯ menu's <summary> and its rows too; only the bare strip drags.
290
+ if ((e.target as HTMLElement).closest("button, summary, .gb-dock-menu")) return;
201
291
  (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);
202
292
  setDragging(true);
203
293
  slideRef.current = { startX: e.clientX, startOffset: dock.dockOffsetRight, moved: false };
@@ -291,6 +381,11 @@ export function AssistantHost({
291
381
  // real ceiling for this window, which changes when the window does.
292
382
  const maxDockHeight = clampDockHeight(Number.MAX_SAFE_INTEGER, typeof window === "undefined" ? 900 : window.innerHeight);
293
383
  const statusText = dock.busy ? L.working : dock.unread ? L.done : L.ready;
384
+ // The surface's rows of the ⋯ menu, in the panel's header and in full screen's chrome alike.
385
+ const clearRow = onClearHistory ? (
386
+ <AssistantMenuItem danger disabled={!canClearHistory} onClick={onClearHistory}>{L.clearHistory}</AssistantMenuItem>
387
+ ) : null;
388
+ const surfaceRows = menuItems || clearRow ? <>{menuItems}{clearRow}</> : null;
294
389
  // Full screen is the assistant's own page and has no tab strip; the second tab lives in the popup.
295
390
  const secondVisible = isPanel && !!secondTab && view === "secondary";
296
391
  const secondBadge = secondTab?.badge || 0;
@@ -308,6 +403,7 @@ export function AssistantHost({
308
403
  // data-gb-dock-chrome: what AssistantChat measures to keep its first line clear of these buttons (0.29.0).
309
404
  <div className="gb-dock-fullchrome" data-gb-dock-chrome="">
310
405
  {fullActions}
406
+ {surfaceRows ? <HostMenu label={L.more} trigger="gb-dock-shrink gb-dock-menu-pill">{surfaceRows}</HostMenu> : null}
311
407
  <button type="button" className="gb-dock-shrink" onClick={onShrink}>
312
408
  {/* Two arrows pulled INTO the centre. The first attempt drew two corner brackets, which at 16px
313
409
  reads as a plus sign — the opposite of "make this smaller". */}
@@ -406,29 +502,6 @@ export function AssistantHost({
406
502
  <span className="gb-dock-sr">{L.newChat}</span>
407
503
  </button>
408
504
  ) : null}
409
- {/* On `dock.sideAllowed`, not the prop: it already folds in the window width (SIDE_FITS_QUERY), so the pin
410
- never shows where pressing it would only drop the working shape to "dock" (review #3744). */}
411
- {isDock && dock.sideAllowed ? (
412
- <button type="button" className="gb-dock-icon gb-dock-action gb-dock-pinside" title={L.pinSide} onClick={dock.openSide}>
413
- {/* A window with its right third filled: the panel it will become. */}
414
- <svg viewBox="0 0 20 20" aria-hidden>
415
- <rect x="3.5" y="4.5" width="13" height="11" rx="1.5" stroke="currentColor" strokeWidth="1.5" fill="none"/>
416
- <path d="M12 4.5v11" stroke="currentColor" strokeWidth="1.5"/>
417
- <path d="M12.75 5.25h3v9.5h-3z" fill="currentColor"/>
418
- </svg>
419
- <span className="gb-dock-sr">{L.pinSide}</span>
420
- </button>
421
- ) : null}
422
- {isSide ? (
423
- <button type="button" className="gb-dock-icon gb-dock-action" title={L.floatPopup} onClick={dock.openDock}>
424
- {/* The same window with a small box floating in its bottom-right corner: the popup. */}
425
- <svg viewBox="0 0 20 20" aria-hidden>
426
- <rect x="3.5" y="4.5" width="13" height="11" rx="1.5" stroke="currentColor" strokeWidth="1.5" fill="none"/>
427
- <rect x="10" y="10" width="5" height="4" rx="0.75" fill="currentColor"/>
428
- </svg>
429
- <span className="gb-dock-sr">{L.floatPopup}</span>
430
- </button>
431
- ) : null}
432
505
  <button
433
506
  type="button"
434
507
  className="gb-dock-icon"
@@ -442,10 +515,19 @@ export function AssistantHost({
442
515
  </svg>
443
516
  <span className="gb-dock-sr">{L.openFull}</span>
444
517
  </button>
445
- <button type="button" className="gb-dock-icon" title={L.minimizeTitle} onClick={dock.minimize}>
446
- <svg viewBox="0 0 20 20" aria-hidden><path d="M5 13h10" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round"/></svg>
447
- <span className="gb-dock-sr">{L.minimize}</span>
448
- </button>
518
+ {/* ⋯ (0.31.0): what is used once in a while — the surface's rows, Clear history, and the two window controls
519
+ that were icons (pin / float, minimise). Four controls stay in sight: +, full screen, ⋯, ×. On
520
+ `dock.sideAllowed`, not the prop, for the pin: it already folds in the window width (SIDE_FITS_QUERY),
521
+ so it is never offered where pressing it would only drop the working shape to "dock" (review #3744). */}
522
+ <HostMenu label={L.more}>
523
+ {surfaceRows}
524
+ {surfaceRows ? <hr className="gb-dock-menu-sep" /> : null}
525
+ {isDock && dock.sideAllowed ? (
526
+ <AssistantMenuItem className="gb-dock-pinside" onClick={dock.openSide}>{L.pinSide}</AssistantMenuItem>
527
+ ) : null}
528
+ {isSide ? <AssistantMenuItem onClick={dock.openDock}>{L.floatPopup}</AssistantMenuItem> : null}
529
+ <AssistantMenuItem onClick={dock.minimize}>{L.minimizeTitle}</AssistantMenuItem>
530
+ </HostMenu>
449
531
  <button
450
532
  type="button"
451
533
  className="gb-dock-icon"
@@ -1,6 +1,6 @@
1
1
  // The assistant's frame: popup, status bar, full screen — and the rules for when each shows.
2
2
  // A separate entry from the shell/auth barrel so a surface that never opens an assistant pays nothing for it.
3
- export { AssistantHost, type AssistantHostLabels, type AssistantSecondTab } from "./host";
3
+ export { AssistantHost, AssistantMenuItem, type AssistantHostLabels, type AssistantSecondTab } from "./host";
4
4
  export { AssistantProvider, SIDE_WIDTH_VAR, useAssistant, useAssistantPageFacts, type AssistantDockApi, type AssistantOptions } from "./provider";
5
5
  export * from "./dock";
6
6
  export { AssistantWorkspaceLayout, OpenChatTabs, SessionRail, SESSION_RAIL_EN, groupSessions, normalizeForSearch, relativeTime, type AssistantSession, type SessionGroup, type SessionRailIcons, type SessionRailLabels } from "./sessions";
@@ -10,3 +10,5 @@ export { AssistantChat, ChatAttach, ChatBubble, ChatComposer, ChatError, ChatLab
10
10
  export { bareUrl, CODE_FOLD_LINES, FLEET_IMAGE_HOSTS, imageSource, linkTarget, parseBlocks, parseInline, type Block, type ImageHost, type Inline, type InlineOptions } from "./chat-markdown";
11
11
  export { ENGINE_MARK_ART, ENGINE_MARK_FILL_RULE, EngineMark, isEngineMarkId, type EngineMarkArt, type EngineMarkId } from "./engine-mark";
12
12
  export { atBridge, BRIDGE_GONE, bridgeTurnError, PAIRING_REJECTED, useChatTurns, type ChatTurns, type TurnError } from "./chat-turns";
13
+ // 0.32.0: the bridge on the user's machine, seen from the browser (the radars' copies, once): client, state, picker props.
14
+ export { BRIDGE_CLOSED_EARLY, BRIDGE_SETUP_EN, BridgePairForm, SERVER_CLOSED_EARLY, bridgeControlNote, bridgePickerProps, createBridgeClient, isLocalPage, localNetworkPermission, mergeBridgeEngines, pickerBridgeState, postTurn, readTurnEvents, useBridge, type BridgeApi, type BridgeClient, type BridgeClientOptions, type BridgeEngineStatus, type BridgeEngines, type BridgePickerOptions, type BridgeProbe, type BridgeProbeState, type BridgeSetupLabels, type TurnEvent, type UseBridgeOptions } from "./bridge";
package/src/assistant.css CHANGED
@@ -1 +1 @@
1
- .gb-dock{position:fixed;z-index:320;right:24px;bottom:0;width:min(460px,calc(100vw - 288px));display:flex;flex-direction:column;min-height:0;background:var(--gemboss-surface);background:color-mix(in srgb,var(--gemboss-surface) 93%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.4);backdrop-filter:blur(14px) saturate(1.4);border:1px solid var(--gemboss-divider);border-bottom:0;border-radius:12px 12px 0 0;box-shadow:0 -2px 6px #0f172a0d,0 24px 64px #0f172a2e;overflow:hidden;transition:transform .14s cubic-bezier(.2,.8,.3,1),opacity .14s ease-out}@starting-style{.gb-dock-dock,.gb-dock-mini{transform:translateY(10px);opacity:0}.gb-dock-side{transform:translate(12px);opacity:0}}.gb-dock-dragging,.gb-dock-dragging *{transition:none!important}@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))){.gb-dock{background:var(--gemboss-surface)}}@media (prefers-reduced-motion: reduce){.gb-dock{transition:none}}.gb-dock-hidden{display:none}.gb-dock-full{z-index:4;inset:56px 0 0 240px;width:auto;border:0;border-radius:0;box-shadow:none;background:var(--gemboss-app-bg)}.gb-dock-side{z-index:290;top:56px;right:0;bottom:0;width:var(--gb-dock-side-w, 400px);background:var(--gemboss-surface);-webkit-backdrop-filter:none;backdrop-filter:none;border:0;border-left:1px solid var(--gemboss-divider);border-radius:0;box-shadow:none;overflow:visible}.gb-dock-side .gb-dock-body,.gb-dock-side .gb-dock-pane{overflow:hidden}.gb-dock-side .gb-dock-header{cursor:default;touch-action:auto}.gb-dock-side .gb-dock-status{flex:0 0 auto;position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.gb-dock-side .gb-dock-header:active{cursor:default}.gb-dock-side>.gb-dock-sidegrip{position:absolute;top:0;bottom:0;left:-3px;width:5px;z-index:3}@media (min-width: 1100px){body.gemboss-assistant-side .gemboss-platform-main{margin-right:var(--gb-assistant-side-w, 400px)}}.gb-dock-fullchrome{position:absolute;top:10px;right:16px;z-index:1;display:flex;gap:8px}.gb-dock-shrink{display:inline-flex;align-items:center;gap:6px;min-height:44px;padding:0 12px;border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-full);background:var(--gemboss-surface);color:var(--gemboss-text-muted);font:inherit;font-size:var(--gemboss-fs-caption);cursor:pointer;white-space:nowrap}.gb-dock-shrink:hover{background:var(--gemboss-hover);color:var(--gemboss-text)}.gb-dock-shrink:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:2px}.gb-dock-shrink svg{width:16px;height:16px;flex:0 0 auto}@media (max-width: 560px){.gb-dock-shrink span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.gb-dock-shrink{padding:0;width:44px;justify-content:center}.gb-dock-shrink-keep span{position:static;width:auto;height:auto;overflow:visible;clip:auto}.gb-dock-shrink-keep{padding:0 12px;width:auto}.gb-dock-fullchrome{position:static;justify-content:flex-end;padding:8px 12px 0}}.gb-dock-mini{height:auto;width:min(320px,calc(100vw - 288px));-webkit-backdrop-filter:blur(14px) saturate(1.4);backdrop-filter:blur(14px) saturate(1.4);border-radius:12px 12px 0 0}.gb-dock-mini .gb-dock-body{display:none}.gb-dock-minirow{display:flex;align-items:center;padding-right:4px}.gb-dock-minirow .gb-dock-minibar{flex:1 1 auto;min-width:0}.gb-dock-minirow .gb-dock-icon{flex:0 0 auto}.gb-dock-minibar{display:flex;align-items:center;gap:8px;width:100%;min-height:48px;padding:0 12px;border:0;background:transparent;font:inherit;color:var(--gemboss-text-strong);cursor:pointer;text-align:left}.gb-dock-minibar:hover{background:var(--gemboss-hover)}.gb-dock-minibar strong{font-size:13px;font-weight:600;flex:0 0 auto}.gb-dock-ministatus{flex:1 1 auto;min-width:0;font-size:12px;color:var(--gemboss-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gb-dock-minichevron{font-size:10px;color:var(--gemboss-text-muted)}.gb-dock-grip{position:absolute;top:0;left:0;right:0;height:14px;z-index:2;display:grid;place-items:center;cursor:ns-resize;touch-action:none;background:transparent}.gb-dock-grip>span{display:block;width:44px;height:4px;border-radius:2px;background:var(--gemboss-divider)}.gb-dock-grip:hover>span,.gb-dock-grip:focus-visible>span{background:var(--gemboss-text-muted)}.gb-dock-grip:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:-2px}.gb-dock-header{flex:0 0 auto;cursor:grab;touch-action:none;user-select:none;display:flex;align-items:center;gap:8px;padding:0 4px 0 16px;min-height:48px;border-bottom:1px solid var(--gemboss-divider);background:transparent}.gb-dock-title{font-size:13px;font-weight:600;color:var(--gemboss-text-strong);white-space:nowrap;flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis}.gb-dock-status{flex:1 1 auto;min-width:0;font-size:12px;color:var(--gemboss-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gb-dock-header:active{cursor:grabbing}.gb-dock-actions{display:flex;align-items:center;gap:2px;cursor:default;margin-left:auto}.gb-dock-action{margin-right:8px}.gb-dock-icon{width:44px;height:44px;display:grid;place-items:center;border:0;border-radius:8px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;padding:0}.gb-dock-icon:hover{background:var(--gemboss-hover);color:var(--gemboss-text-strong)}.gb-dock-icon:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:-2px}.gb-dock-icon svg{width:18px;height:18px}.gb-dock-icon-on{color:var(--gemboss-active-fg);background:var(--gemboss-active-bg)}.gb-dock-dot{flex:0 0 auto;width:8px;height:8px;border-radius:50%;background:var(--gemboss-divider)}.gb-dock-dot-busy{background:var(--gemboss-primary);animation:gb-dock-pulse 1.4s ease-in-out infinite}.gb-dock-dot-unread{background:var(--gemboss-success-strong)}@keyframes gb-dock-pulse{0%,to{opacity:1}50%{opacity:.35}}@media (prefers-reduced-motion: reduce){.gb-dock-dot-busy{animation:none}}.gb-dock-tabs{flex:0 0 auto;display:flex;gap:4px;padding:0 8px;border-bottom:1px solid var(--gemboss-divider)}.gb-dock-tab{position:relative;display:inline-flex;align-items:center;gap:6px;min-height:44px;padding:0 12px;border:0;border-bottom:2px solid transparent;background:transparent;color:var(--gemboss-text-muted);font:inherit;font-size:13px;cursor:pointer;white-space:nowrap}.gb-dock-tab:hover{color:var(--gemboss-text-strong)}.gb-dock-tab[aria-selected=true]{color:var(--gemboss-text-strong);font-weight:600;border-bottom-color:var(--gemboss-primary)}.gb-dock-tab:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:-2px}.gb-dock-badge{min-width:18px;padding:0 6px;border-radius:var(--gemboss-radius-full);background:var(--gemboss-primary);color:var(--gemboss-on-primary, #fff);font-size:11px;font-weight:700;line-height:18px;text-align:center}.gb-dock-body{flex:1 1 auto;min-height:0;display:flex;min-width:0}.gb-dock-body>*{flex:1 1 auto;min-width:0;min-height:0}.gb-dock-pane{display:flex;min-width:0;min-height:0}.gb-dock-pane>*{flex:1 1 auto;min-width:0;min-height:0}.gb-dock-body .gemboss-assistant-layout,.gb-dock-body .gemboss-assistant-page{height:auto;min-height:0}.gb-dock-pane[hidden]{display:none}.gb-dock-booting{flex:1 1 auto;display:grid;place-items:center;padding:24px;color:var(--gemboss-text-muted);font-size:14px}.gb-dock-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}@media (max-width: 420px){.gb-dock-status{display:none}}@media (max-width: 760px){.gb-dock{right:8px;left:8px;width:auto;padding-bottom:env(safe-area-inset-bottom);border-radius:12px 12px 0 0}.gb-dock-mini{width:auto}.gb-dock-full{inset:56px 0 0;border-radius:0}.gb-dock-side{left:0;right:0;width:auto;border-left:0;border-radius:0}.gb-dock-sidegrip,.gb-dock-pinside{display:none}}@media (min-width: 761px) and (max-width: 1099.98px){.gb-dock-side{left:240px;width:auto}.gb-dock-side .gb-dock-sidegrip,.gb-dock-pinside{display:none}}.gb-assistant-launcher{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;font-family:var(--gemboss-font-sans, system-ui, sans-serif)}.gb-assistant-launcher svg{flex:0 0 auto}.gb-assistant-launcher:focus-visible{outline:2px solid var(--gemboss-accent, #5661f5);outline-offset:2px}.gb-assistant-launcher--rail{width:100%;min-height:44px;margin:8px 0 4px;padding:0 12px;border-radius:var(--gemboss-radius-md, 8px);background:var(--gemboss-accent-soft);color:var(--gemboss-accent-strong);font-size:13px;font-weight:600;line-height:1;text-align:left}.gb-assistant-launcher--rail:hover{background:color-mix(in srgb,var(--gemboss-accent) 16%,var(--gemboss-surface))}.gb-assistant-launcher--rail .gb-assistant-launcher-label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gb-assistant-launcher-kbd{font:inherit;font-size:11px;opacity:.7;border:1px solid currentColor;border-radius:5px;padding:1px 5px}.gb-assistant-launcher--topbar{display:none;position:relative;justify-content:center;flex:0 0 auto;width:44px;height:44px;padding:0;border-radius:var(--gemboss-radius-md, 8px);background:transparent;color:var(--gemboss-text, #1b1c1e)}.gb-assistant-launcher--topbar:hover,.gb-assistant-launcher--topbar:active{background:var(--gemboss-hover, #eceef2)}.gb-assistant-launcher--topbar .gb-assistant-launcher-label,.gb-assistant-launcher--topbar .gb-assistant-launcher-kbd{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}@media (max-width: 760px){.gb-assistant-launcher--rail{display:none}.gb-assistant-launcher--topbar{display:inline-flex}}
1
+ .gb-dock{position:fixed;z-index:320;right:24px;bottom:0;width:min(460px,calc(100vw - 288px));display:flex;flex-direction:column;min-height:0;background:var(--gemboss-surface);background:color-mix(in srgb,var(--gemboss-surface) 93%,transparent);-webkit-backdrop-filter:blur(14px) saturate(1.4);backdrop-filter:blur(14px) saturate(1.4);border:1px solid var(--gemboss-divider);border-bottom:0;border-radius:12px 12px 0 0;box-shadow:0 -2px 6px #0f172a0d,0 24px 64px #0f172a2e;overflow:hidden;transition:transform .14s cubic-bezier(.2,.8,.3,1),opacity .14s ease-out}@starting-style{.gb-dock-dock,.gb-dock-mini{transform:translateY(10px);opacity:0}.gb-dock-side{transform:translate(12px);opacity:0}}.gb-dock-dragging,.gb-dock-dragging *{transition:none!important}@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))){.gb-dock{background:var(--gemboss-surface)}}@media (prefers-reduced-motion: reduce){.gb-dock{transition:none}}.gb-dock-hidden{display:none}.gb-dock-full{z-index:4;inset:56px 0 0 240px;width:auto;border:0;border-radius:0;box-shadow:none;background:var(--gemboss-app-bg)}.gb-dock-side{z-index:290;top:56px;right:0;bottom:0;width:var(--gb-dock-side-w, 400px);background:var(--gemboss-surface);-webkit-backdrop-filter:none;backdrop-filter:none;border:0;border-left:1px solid var(--gemboss-divider);border-radius:0;box-shadow:none;overflow:visible}.gb-dock-side .gb-dock-body,.gb-dock-side .gb-dock-pane{overflow:hidden}.gb-dock-side .gb-dock-header{cursor:default;touch-action:auto}.gb-dock-side .gb-dock-status{flex:0 0 auto;position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.gb-dock-side .gb-dock-header:active{cursor:default}.gb-dock-side>.gb-dock-sidegrip{position:absolute;top:0;bottom:0;left:-3px;width:5px;z-index:3}@media (min-width: 1100px){body.gemboss-assistant-side .gemboss-platform-main{margin-right:var(--gb-assistant-side-w, 400px)}}.gb-dock-fullchrome{position:absolute;top:10px;right:16px;z-index:1;display:flex;gap:8px}.gb-dock-shrink{display:inline-flex;align-items:center;gap:6px;min-height:44px;padding:0 12px;border:1px solid var(--gemboss-divider);border-radius:var(--gemboss-radius-full);background:var(--gemboss-surface);color:var(--gemboss-text-muted);font:inherit;font-size:var(--gemboss-fs-caption);cursor:pointer;white-space:nowrap}.gb-dock-shrink:hover{background:var(--gemboss-hover);color:var(--gemboss-text)}.gb-dock-shrink:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:2px}.gb-dock-shrink svg{width:16px;height:16px;flex:0 0 auto}@media (max-width: 560px){.gb-dock-shrink span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}.gb-dock-shrink{padding:0;width:44px;justify-content:center}.gb-dock-shrink-keep span{position:static;width:auto;height:auto;overflow:visible;clip:auto}.gb-dock-shrink-keep{padding:0 12px;width:auto}.gb-dock-fullchrome{position:static;justify-content:flex-end;padding:8px 12px 0}}.gb-dock-mini{height:auto;width:min(320px,calc(100vw - 288px));-webkit-backdrop-filter:blur(14px) saturate(1.4);backdrop-filter:blur(14px) saturate(1.4);border-radius:12px 12px 0 0}.gb-dock-mini .gb-dock-body{display:none}.gb-dock-minirow{display:flex;align-items:center;padding-right:4px}.gb-dock-minirow .gb-dock-minibar{flex:1 1 auto;min-width:0}.gb-dock-minirow .gb-dock-icon{flex:0 0 auto}.gb-dock-minibar{display:flex;align-items:center;gap:8px;width:100%;min-height:48px;padding:0 12px;border:0;background:transparent;font:inherit;color:var(--gemboss-text-strong);cursor:pointer;text-align:left}.gb-dock-minibar:hover{background:var(--gemboss-hover)}.gb-dock-minibar strong{font-size:13px;font-weight:600;flex:0 0 auto}.gb-dock-ministatus{flex:1 1 auto;min-width:0;font-size:12px;color:var(--gemboss-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gb-dock-minichevron{font-size:10px;color:var(--gemboss-text-muted)}.gb-dock-grip{position:absolute;top:0;left:0;right:0;height:14px;z-index:2;display:grid;place-items:center;cursor:ns-resize;touch-action:none;background:transparent}.gb-dock-grip>span{display:block;width:44px;height:4px;border-radius:2px;background:var(--gemboss-divider)}.gb-dock-grip:hover>span,.gb-dock-grip:focus-visible>span{background:var(--gemboss-text-muted)}.gb-dock-grip:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:-2px}.gb-dock-header{flex:0 0 auto;cursor:grab;touch-action:none;user-select:none;display:flex;align-items:center;gap:8px;padding:0 4px 0 16px;min-height:48px;border-bottom:1px solid var(--gemboss-divider);background:transparent}.gb-dock-title{font-size:13px;font-weight:600;color:var(--gemboss-text-strong);white-space:nowrap;flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis}.gb-dock-status{flex:1 1 auto;min-width:0;font-size:12px;color:var(--gemboss-text-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gb-dock-header:active{cursor:grabbing}.gb-dock-actions{display:flex;align-items:center;gap:2px;cursor:default;margin-left:auto}.gb-dock-action{margin-right:8px}.gb-dock-menu{position:relative}.gb-dock-menu>summary{list-style:none}.gb-dock-menu>summary::-webkit-details-marker{display:none}.gb-dock-menu[open]>summary{color:var(--gemboss-text-strong);background:var(--gemboss-hover)}.gb-dock-menu-list{position:absolute;top:calc(100% + 4px);right:0;z-index:5;display:grid;min-width:220px;padding:4px;box-sizing:border-box;cursor:default}.gb-dock-menu-list>.ui-menu__item{border-radius:8px}.gb-dock-menu-list>.ui-menu__item:disabled{opacity:.5;cursor:not-allowed;background:transparent}.gb-dock-menu-sep{height:1px;margin:4px 0;border:0;background:var(--gemboss-divider)}.gb-dock-menu-pill{width:44px;padding:0;justify-content:center}.gb-dock-menu-pill svg{width:18px;height:18px}.gb-dock-icon{width:44px;height:44px;display:grid;place-items:center;border:0;border-radius:8px;background:transparent;color:var(--gemboss-text-muted);cursor:pointer;padding:0}.gb-dock-icon:hover{background:var(--gemboss-hover);color:var(--gemboss-text-strong)}.gb-dock-icon:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:-2px}.gb-dock-icon svg{width:18px;height:18px}.gb-dock-icon-on{color:var(--gemboss-active-fg);background:var(--gemboss-active-bg)}.gb-dock-dot{flex:0 0 auto;width:8px;height:8px;border-radius:50%;background:var(--gemboss-divider)}.gb-dock-dot-busy{background:var(--gemboss-primary);animation:gb-dock-pulse 1.4s ease-in-out infinite}.gb-dock-dot-unread{background:var(--gemboss-success-strong)}@keyframes gb-dock-pulse{0%,to{opacity:1}50%{opacity:.35}}@media (prefers-reduced-motion: reduce){.gb-dock-dot-busy{animation:none}}.gb-dock-tabs{flex:0 0 auto;display:flex;gap:4px;padding:0 8px;border-bottom:1px solid var(--gemboss-divider)}.gb-dock-tab{position:relative;display:inline-flex;align-items:center;gap:6px;min-height:44px;padding:0 12px;border:0;border-bottom:2px solid transparent;background:transparent;color:var(--gemboss-text-muted);font:inherit;font-size:13px;cursor:pointer;white-space:nowrap}.gb-dock-tab:hover{color:var(--gemboss-text-strong)}.gb-dock-tab[aria-selected=true]{color:var(--gemboss-text-strong);font-weight:600;border-bottom-color:var(--gemboss-primary)}.gb-dock-tab:focus-visible{outline:2px solid var(--gemboss-primary);outline-offset:-2px}.gb-dock-badge{min-width:18px;padding:0 6px;border-radius:var(--gemboss-radius-full);background:var(--gemboss-primary);color:var(--gemboss-on-primary, #fff);font-size:11px;font-weight:700;line-height:18px;text-align:center}.gb-dock-body{flex:1 1 auto;min-height:0;display:flex;min-width:0}.gb-dock-body>*{flex:1 1 auto;min-width:0;min-height:0}.gb-dock-pane{display:flex;min-width:0;min-height:0}.gb-dock-pane>*{flex:1 1 auto;min-width:0;min-height:0}.gb-dock-body .gemboss-assistant-layout,.gb-dock-body .gemboss-assistant-page{height:auto;min-height:0}.gb-dock-pane[hidden]{display:none}.gb-dock-booting{flex:1 1 auto;display:grid;place-items:center;padding:24px;color:var(--gemboss-text-muted);font-size:14px}.gb-dock-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}@media (max-width: 420px){.gb-dock-status{display:none}}@media (max-width: 760px){.gb-dock{right:8px;left:8px;width:auto;padding-bottom:env(safe-area-inset-bottom);border-radius:12px 12px 0 0}.gb-dock-mini{width:auto}.gb-dock-full{inset:56px 0 0;border-radius:0}.gb-dock-side{left:0;right:0;width:auto;border-left:0;border-radius:0}.gb-dock-sidegrip,.gb-dock-pinside{display:none}.gb-dock-menu-list>.gb-dock-pinside{display:none}}@media (min-width: 761px) and (max-width: 1099.98px){.gb-dock-side{left:240px;width:auto}.gb-dock-side .gb-dock-sidegrip,.gb-dock-pinside{display:none}.gb-dock-menu-list>.gb-dock-pinside{display:none}}.gb-assistant-launcher{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;font-family:var(--gemboss-font-sans, system-ui, sans-serif)}.gb-assistant-launcher svg{flex:0 0 auto}.gb-assistant-launcher:focus-visible{outline:2px solid var(--gemboss-accent, #5661f5);outline-offset:2px}.gb-assistant-launcher--rail{width:100%;min-height:44px;margin:8px 0 4px;padding:0 12px;border-radius:var(--gemboss-radius-md, 8px);background:var(--gemboss-accent-soft);color:var(--gemboss-accent-strong);font-size:13px;font-weight:600;line-height:1;text-align:left}.gb-assistant-launcher--rail:hover{background:color-mix(in srgb,var(--gemboss-accent) 16%,var(--gemboss-surface))}.gb-assistant-launcher--rail .gb-assistant-launcher-label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.gb-assistant-launcher-kbd{font:inherit;font-size:11px;opacity:.7;border:1px solid currentColor;border-radius:5px;padding:1px 5px}.gb-assistant-launcher--topbar{display:none;position:relative;justify-content:center;flex:0 0 auto;width:44px;height:44px;padding:0;border-radius:var(--gemboss-radius-md, 8px);background:transparent;color:var(--gemboss-text, #1b1c1e)}.gb-assistant-launcher--topbar:hover,.gb-assistant-launcher--topbar:active{background:var(--gemboss-hover, #eceef2)}.gb-assistant-launcher--topbar .gb-assistant-launcher-label,.gb-assistant-launcher--topbar .gb-assistant-launcher-kbd{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}@media (max-width: 760px){.gb-assistant-launcher--rail{display:none}.gb-assistant-launcher--topbar{display:inline-flex}}
package/src/chat-plain.js CHANGED
@@ -1,4 +1,4 @@
1
- (function(O){"use strict";var N=O.gembossUI;if(!N){O.console&&O.console.error("@gemboss/ui chat-plain.js: load kit-plain.js first (it defines gembossUI)");return}if(N.chat)return;var b={thread:"Conversation",message:"Message",send:"Send",stop:"Stop",attach:"Attach a file",copy:"Copy",copied:"Copied",copyCommand:"Copy command",originalError:"Original error",stopped:"Stopped",steps:"What it is doing",thought:"Thought",thinking:"Thinking",working:"Working",showLess:"Show less",showAll:"Show all {n} lines",openImage:"Open image"},S="http://www.w3.org/2000/svg",A=function(e){return typeof Node<"u"&&e instanceof Node};function l(e,n,r){var t=document.createElement(e);if(n)for(var a in n){var i=n[a];i==null||i===!1||(a==="text"?t.textContent=String(i):a==="className"?t.className=i:t.setAttribute(a,i===!0?"":String(i)))}return R(t,r),t}function R(e,n){return n==null||n===!1?e:Array.isArray(n)?(n.forEach(function(r){R(e,r)}),e):(e.appendChild(A(n)?n:document.createTextNode(String(n))),e)}function M(e,n,r){var t=document.createElementNS(S,"svg");if(t.setAttribute("viewBox",e),t.setAttribute("aria-hidden","true"),t.setAttribute("focusable","false"),n.forEach(function(i){var s=document.createElementNS(S,i.tag||"path");for(var o in i)o!=="tag"&&s.setAttribute(o,i[o]);t.appendChild(s)}),r)for(var a in r)t.setAttribute(a,r[a]);return t}var ae=[{host:"gemwatcher-api-production.up.railway.app",path:"/watch/artifacts/"},{host:"gemmedia-api-production.up.railway.app",path:"/"},{host:"media.gemboss.ai",path:"/v1/theme-media/assets/"},{host:"gemmedia.ops.gemboss.ai",path:"/v1/theme-media/assets/"},{host:"gemmedia.gemboss.ai",path:"/v1/theme-media/assets/"},{host:"cdn.shopify.com",path:"/"}],q=/[\u0000-\u001f\u007f]/g;function C(e){var n=String(e).replace(q,"").trim();return n?n.charAt(0)==="/"?n.charAt(1)==="/"||n.charAt(1)==="\\"?null:{href:n,internal:!0}:/^(https?:\/\/|mailto:)/i.test(n)?{href:n,internal:!1}:null:null}var D="https://same-origin.invalid",ie=/^\/[^/]+(\/[^/]+)*\/$/;function H(e,n){var r=String(e).replace(q,"").trim(),t;if(r.charAt(0)==="/"){var a=(n||[]).filter(function(s){return!s.host&&ie.test(s.path)});if(!a.length||r.charAt(1)==="/"||r.indexOf("\\")>=0||/%(2f|5c|25)|;/i.test(r))return null;try{t=new URL(r,D)}catch{return null}return t.origin!==D||/\.\.|%2e/i.test(t.pathname)?null:a.some(function(s){return t.pathname.indexOf(s.path)===0})?t.href.slice(D.length):null}try{t=new URL(r)}catch{return null}if(t.protocol!=="https:"||t.username||t.password||t.port)return null;var i=t.hostname.toLowerCase();return ae.concat(n||[]).some(function(s){return s.host===i&&t.pathname.indexOf(s.path)===0})?t.href:null}var T=function(e,n){return e.split(n).length-1};function P(e,n){var r=e.length,t,a,i,s,o=T(e,"("),d=T(e,")"),f=T(e,"["),c=T(e,"]");for(n=n!==!1;n&&r>0;)t=e.charAt(r-1),/[.,:;!?_~'"]/.test(t)?r-=1:t===")"&&o<d?(r-=1,d-=1):t==="]"&&f<c?(r-=1,c-=1):n=!1;if(s=e.slice(0,r),a=C(s),!a||a.internal)return null;try{i=new URL(a.href)}catch{return null}return!/^https?:$/.test(i.protocol)||!i.hostname?null:{href:a.href,rest:e.slice(r)}}var le=/(`([^`]+)`)|(\*\*([^*]+)\*\*)|(\*([^*\n]+)\*)|(!\[([^\]]*)\]\(([^)\s]+)\))|(\[([^\]]+)\]\(([^)\s]+)\))|(<(https?:\/\/[^\s<>]+)>)|(https?:\/\/[^\s<>`"*\u2000-\u206f\u3000-\u9fff\uff00-\uffef]+)/gi;function F(e,n){n=n||{};for(var r=[],t=function(m){if(m){var v=r[r.length-1];v&&v.t==="text"?v.text+=m:r.push({t:"text",text:m})}},a=new RegExp(le.source,"gi"),i=0,s;(s=a.exec(e))!==null;){if(t(e.slice(i,s.index)),s[2]!=null)r.push({t:"code",text:s[2]});else if(s[4]!=null)r.push({t:"bold",text:s[4]});else if(s[6]!=null)r.push({t:"italic",text:s[6]});else if(s[7]!=null){var o=H(s[9],n.imageHosts),d=s[8].trim();if(o)r.push({t:"image",alt:d,src:o});else{var f=C(s[9]);f&&!f.internal?r.push({t:"link",label:d||"image",href:f.href,internal:!1}):t(d)}}else if(s[10]!=null){var c=s[12],p=n.ownLink&&n.ownLink(c)?{href:c,internal:!0}:C(c);p?r.push({t:"link",label:s[11],href:p.href,internal:p.internal}):t(s[11])}else{var h=s[15]!=null&&s.index>0&&/[a-z\d]/i.test(e.charAt(s.index-1)),g=h?null:s[14]!=null?P(s[14],!1):P(s[15]);g?(r.push({t:"link",label:g.href,href:g.href,internal:!1}),t(g.rest)):t(s[0])}i=s.index+s[0].length}return t(e.slice(i)),r}var $=function(e){return/^\s*\|.*\|\s*$/.test(e)},se=function(e){return/^\s*\|?[\s:-]*-[-\s:|]*\|?\s*$/.test(e)&&e.indexOf("-")>=0},U=function(e){return e.trim().replace(/^\||\|$/g,"").split("|").map(function(n){return n.trim()})};function K(e){for(var n=String(e??"").split(`
1
+ (function(O){"use strict";var N=O.gembossUI;if(!N){O.console&&O.console.error("@gemboss/ui chat-plain.js: load kit-plain.js first (it defines gembossUI)");return}if(N.chat)return;var b={thread:"Conversation",message:"Message",send:"Send",stop:"Stop",attach:"Attach a file",copy:"Copy",copied:"Copied",copyCommand:"Copy command",originalError:"Original error",stopped:"Stopped",steps:"What it is doing",thought:"Thought",thinking:"Thinking",working:"Working",showLess:"Show less",showAll:"Show all {n} lines",openImage:"Open image"},S="http://www.w3.org/2000/svg",A=function(e){return typeof Node<"u"&&e instanceof Node};function l(e,n,r){var t=document.createElement(e);if(n)for(var a in n){var i=n[a];i==null||i===!1||(a==="text"?t.textContent=String(i):a==="className"?t.className=i:t.setAttribute(a,i===!0?"":String(i)))}return R(t,r),t}function R(e,n){return n==null||n===!1?e:Array.isArray(n)?(n.forEach(function(r){R(e,r)}),e):(e.appendChild(A(n)?n:document.createTextNode(String(n))),e)}function M(e,n,r){var t=document.createElementNS(S,"svg");if(t.setAttribute("viewBox",e),t.setAttribute("aria-hidden","true"),t.setAttribute("focusable","false"),n.forEach(function(i){var s=document.createElementNS(S,i.tag||"path");for(var o in i)o!=="tag"&&s.setAttribute(o,i[o]);t.appendChild(s)}),r)for(var a in r)t.setAttribute(a,r[a]);return t}var ae=[{host:"gemwatcher-api-production.up.railway.app",path:"/watch/artifacts/"},{host:"gemmedia-api-production.up.railway.app",path:"/"},{host:"media.gemboss.ai",path:"/v1/theme-media/assets/"},{host:"gemmedia.ops.gemboss.ai",path:"/v1/theme-media/assets/"},{host:"gemmedia.gemboss.ai",path:"/v1/theme-media/assets/"},{host:"cdn.shopify.com",path:"/"}],q=/[\u0000-\u001f\u007f]/g;function C(e){var n=String(e).replace(q,"").trim();return n?n.charAt(0)==="/"?n.charAt(1)==="/"||n.charAt(1)==="\\"?null:{href:n,internal:!0}:/^(https?:\/\/|mailto:)/i.test(n)?{href:n,internal:!1}:null:null}var D="https://same-origin.invalid",ie=/^\/[^/]+(\/[^/]+)*\/$/;function H(e,n){var r=String(e).replace(q,"").trim(),t;if(r.charAt(0)==="/"){var a=(n||[]).filter(function(s){return!s.host&&ie.test(s.path)});if(!a.length||r.charAt(1)==="/"||r.indexOf("\\")>=0||/%(2f|5c|25)|;/i.test(r))return null;try{t=new URL(r,D)}catch{return null}return t.origin!==D||/\.\.|%2e/i.test(t.pathname)?null:a.some(function(s){return t.pathname.indexOf(s.path)===0})?t.href.slice(D.length):null}try{t=new URL(r)}catch{return null}if(t.protocol!=="https:"||t.username||t.password||t.port)return null;var i=t.hostname.toLowerCase();return ae.concat(n||[]).some(function(s){return s.host===i&&t.pathname.indexOf(s.path)===0})?t.href:null}var T=function(e,n){return e.split(n).length-1};function P(e,n){var r=e.length,t,a,i,s,o=T(e,"("),d=T(e,")"),f=T(e,"["),c=T(e,"]");for(n=n!==!1;n&&r>0;)t=e.charAt(r-1),/[.,:;!?_~'"]/.test(t)?r-=1:t===")"&&o<d?(r-=1,d-=1):t==="]"&&f<c?(r-=1,c-=1):n=!1;if(s=e.slice(0,r),a=C(s),!a||a.internal)return null;try{i=new URL(a.href)}catch{return null}return!/^https?:$/.test(i.protocol)||!i.hostname?null:{href:a.href,rest:e.slice(r)}}var le=/(`([^`]+)`)|(\*\*([^*]+)\*\*)|(\*([^*\n]+)\*)|(!\[([^\]]*)\]\(([^)\s]+)\))|(\[([^\]]+)\]\(([^)\s]+)\))|(<(https?:\/\/[^\s<>]+)>)|(https?:\/\/[^\s<>`"*\u2000-\u206f\u3000-\u9fff\uff00-\uffef]+)/gi;function F(e,n){n=n||{};for(var r=[],t=function(m){if(m){var v=r[r.length-1];v&&v.t==="text"?v.text+=m:r.push({t:"text",text:m})}},a=new RegExp(le.source,"gi"),i=0,s;(s=a.exec(e))!==null;){if(t(e.slice(i,s.index)),s[2]!=null)r.push({t:"code",text:s[2]});else if(s[4]!=null)r.push({t:"bold",text:s[4]});else if(s[6]!=null)r.push({t:"italic",text:s[6]});else if(s[7]!=null){var o=H(s[9],n.imageHosts),d=s[8].trim();if(o)r.push({t:"image",alt:d,src:o});else{var f=C(s[9]);f&&!f.internal?r.push({t:"link",label:d||"image",href:f.href,internal:!1}):t(d)}}else if(s[10]!=null){var c=s[12],p=n.ownLink&&n.ownLink(c)?{href:c,internal:!0,own:!0}:C(c);p?r.push({t:"link",label:s[11],href:p.href,internal:p.internal}):t(s[11])}else{var h=s[15]!=null&&s.index>0&&/[a-z\d]/i.test(e.charAt(s.index-1)),g=h?null:s[14]!=null?P(s[14],!1):P(s[15]);g?(r.push({t:"link",label:g.href,href:g.href,internal:!1}),t(g.rest)):t(s[0])}i=s.index+s[0].length}return t(e.slice(i)),r}var $=function(e){return/^\s*\|.*\|\s*$/.test(e)},se=function(e){return/^\s*\|?[\s:-]*-[-\s:|]*\|?\s*$/.test(e)&&e.indexOf("-")>=0},U=function(e){return e.trim().replace(/^\||\|$/g,"").split("|").map(function(n){return n.trim()})};function K(e){for(var n=String(e??"").split(`
2
2
  `),r=[],t=0,a=[],i=function(){a.length&&r.push({t:"para",lines:a.slice()}),a.length=0};t<n.length;){var s=n[t],o;if(o=/^\s*```([\w#+.-]*)\s*$/.exec(s)){i();var d=[];for(t+=1;t<n.length&&!/^\s*```\s*$/.test(n[t]);)d.push(n[t]),t+=1;t+=1,r.push({t:"code",lang:o[1]||"",body:d.join(`
3
3
  `)});continue}if(o=/^(#{1,6})\s+(.*)$/.exec(s)){i(),o[2].trim()&&r.push({t:"heading",level:Math.min(o[1].length,3),text:o[2].trim()}),t+=1;continue}if(/^\s*(---|\*\*\*|___)\s*$/.test(s)){i(),r.push({t:"rule"}),t+=1;continue}if($(s)&&t+1<n.length&&se(n[t+1])){i();var f=U(s),c=[];for(t+=2;t<n.length&&$(n[t]);)c.push(U(n[t])),t+=1;r.push({t:"table",head:f,rows:c});continue}if(o=/^\s*([-*+]|\d+[.)])\s+(.*)$/.exec(s)){i();for(var p=/\d/.test(o[1]),h=p?parseInt(o[1],10):void 0,g=[];t<n.length;){var m=/^\s*([-*+]|\d+[.)])\s+(.*)$/.exec(n[t]);if(!m||/\d/.test(m[1])!==p)break;g.push(m[2]),t+=1}var v={t:"list",ordered:p,items:g};h!==void 0&&h!==1&&(v.start=h),r.push(v);continue}if(/^\s*>\s?/.test(s)){i();for(var y=[];t<n.length&&/^\s*>\s?/.test(n[t]);)y.push(n[t].replace(/^\s*>\s?/,"")),t+=1;r.push({t:"quote",lines:y});continue}if(s.trim()===""){i(),t+=1;continue}a.push(s),t+=1}return i(),r}var j=12;function L(e,n,r){return F(e,n).map(function(t){if(t.t==="text")return document.createTextNode(t.text);if(t.t==="code")return l("code",{className:"gemboss-md-code",text:t.text});if(t.t==="bold")return l("strong",{text:t.text});if(t.t==="italic")return l("em",{text:t.text});if(t.t==="link"){if(n.ownLink&&n.ownLink(t.href)&&n.renderLink)return n.renderLink(t.href,t.label)||document.createTextNode(t.label);var a=l("a",{className:"gemboss-ec-md-link",href:t.href,target:t.internal?null:"_blank",rel:t.internal?null:"noopener noreferrer",text:t.label});return t.internal&&n.onNavigate&&a.addEventListener("click",function(i){i.metaKey||i.ctrlKey||i.shiftKey||(i.preventDefault(),n.onNavigate(t.href))}),a}return l("a",{className:"gemboss-md-imglink",href:t.src,target:"_blank",rel:"noopener noreferrer","aria-label":t.alt?null:r.openImage},l("img",{className:"gemboss-md-img",src:t.src,alt:t.alt,loading:"lazy",referrerpolicy:"no-referrer"}))})}function z(e,n,r){var t=[];return e.forEach(function(a,i){t=t.concat(L(a,n,r)),i<e.length-1&&t.push(l("br"))}),t}function oe(e,n){var r=e.body.split(`
4
4
  `),t=r.length>j,a=!1,i=l("code",{text:t?r.slice(0,j).join(`
@@ -1 +1 @@
1
- :root{--ui-coll-head-bg: color-mix(in srgb, var(--ui-text, #1b1c1e) 3.5%, var(--ui-surface, #fff));--ui-coll-hover: color-mix(in srgb, var(--ui-text, #1b1c1e) 3.5%, var(--ui-surface, #fff));--ui-coll-selected: color-mix(in srgb, var(--ui-text, #1b1c1e) 6%, var(--ui-surface, #fff));--ui-coll-check-w: 40px}.ui-table--sticky-first tr{background:var(--ui-surface)}.ui-table--sticky-first tbody tr:hover{background:var(--ui-surface-2)}.ui-table--sticky-first :is(th,td):first-child{position:sticky;left:0;z-index:1;background:inherit}@supports (animation-timeline: scroll()){.ui-table-wrap:has(>.ui-table--sticky-first){scroll-timeline:--ui-coll-x inline}.ui-table--sticky-first :is(th,td):first-child{animation:ui-coll-edge linear both;animation-timeline:--ui-coll-x;animation-range:0 24px}}@keyframes ui-coll-edge{0%{box-shadow:none}to{box-shadow:1px 0 0 var(--ui-border),6px 0 8px -6px #0000002e}}.ui-table--compact :is(td,tbody th){padding-block:6px}.ui-table--compact thead th{padding-block:6px}.ui-table__totals>tr{background:var(--ui-coll-head-bg)}.ui-table__totals>tr>:is(td,th){background:var(--ui-coll-head-bg);font-weight:650;color:var(--ui-text);border-top:1px solid var(--ui-border);border-bottom:0}.ui-table__footer{padding:8px 12px;background:var(--ui-coll-head-bg);border-top:1px solid var(--ui-border);color:var(--ui-text-muted);font-size:var(--ui-fs-body);text-align:center}.ui-table th.ui-table__rowhead{font-weight:450;color:var(--ui-text);text-align:left}.ui-table th.ui-table__rowhead:not(.is-num){white-space:normal;min-width:9.0625rem}.ui-table th.ui-table__rowhead>a,.ui-table:where(:not(.ui-table--index)) tbody :is(td,th) li>a{display:inline-flex;align-items:center;min-height:24px}.ui-table:where(:not(.ui-table--index)) tbody :is(td,th){vertical-align:top}.ui-table:where(:not(.ui-table--index)) tbody :is(td>a,th.ui-table__rowhead>a,:is(td,th) li>a){margin-block:calc((1lh - 24px)/2)}.ui-table__sort{display:flex;width:max-content;max-width:100%;align-items:center;gap:4px;min-height:24px;margin-block:-2px;padding:0;border:0;background:none;color:inherit;font:inherit;text-align:inherit;text-decoration:none;cursor:pointer;white-space:nowrap}.ui-table__sort:hover{color:var(--ui-text)}.ui-table__sort:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px;border-radius:4px}.ui-table__sort:after{content:"";flex:none;width:16px;height:16px;background:currentColor;opacity:0;-webkit-mask:var(--ui-coll-arrow) center / 16px no-repeat;mask:var(--ui-coll-arrow) center / 16px no-repeat;--ui-coll-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 3.5v9M4.5 9 8 12.5 11.5 9' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}.ui-table__sort:is(:hover,:focus-visible):after{opacity:.45}th[aria-sort=ascending]>.ui-table__sort:after,th[aria-sort=descending]>.ui-table__sort:after{opacity:1}th[aria-sort=ascending]>.ui-table__sort:after{transform:rotate(180deg)}th[aria-sort=ascending]>.ui-table__sort,th[aria-sort=descending]>.ui-table__sort{color:var(--ui-text)}.ui-table .is-num>.ui-table__sort{flex-direction:row-reverse;margin-left:auto}.ui-trunc{display:block;max-width:var(--ui-trunc, 32ch);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-clamp-2{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;white-space:normal;overflow-wrap:anywhere}.ui-index{position:relative;container:ui-index / inline-size;min-width:0}.ui-table--index{font-size:var(--ui-fs-body)}.ui-table--index tr{background:var(--ui-surface)}.ui-table.ui-table--index thead th{padding:8px 6px;background:var(--ui-coll-head-bg);color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:20px;font-weight:550;text-transform:none;letter-spacing:0}.ui-table.ui-table--index :is(td,tbody th){padding:6px;line-height:20px;white-space:nowrap;vertical-align:middle;border-bottom:0;border-top:1px solid var(--ui-border)}.ui-table.ui-table--index :is(th,td):where(:first-child){padding-left:var(--ui-space-3)}.ui-table.ui-table--index :is(th,td):where(:last-child){padding-right:var(--ui-space-3)}.ui-table--index tbody tr:hover{background:var(--ui-coll-hover)}.ui-table--index tbody tr:is(.is-selected,[aria-selected=true]){background:var(--ui-coll-selected)}.ui-table--index tbody tr:is([data-href],.is-linked){cursor:pointer}.ui-table--index tbody tr:has(.ui-table__title:focus-visible){outline:2px solid var(--ui-focus);outline-offset:-2px}.ui-table__title:focus-visible{outline:none}.ui-table__primary{min-width:0}.ui-table__primary-inner{display:flex;align-items:center;gap:var(--ui-space-3);min-width:0}.ui-table__primary-text{min-width:0}.ui-table__title{display:block;max-width:var(--ui-trunc, 40ch);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-text);font-weight:650;text-decoration:none}a.ui-table__title:hover{text-decoration:underline}.ui-table--index .ui-table__title+.ui-sub,.ui-table--index .ui-sub{display:block;max-width:var(--ui-trunc, 40ch);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:0;line-height:16px}.ui-table--index td>a.ui-table__title{display:block;min-height:0}.ui-table--index td>.ui-table__primary-inner>a.ui-table__title,.ui-table--index .ui-table__primary-text>a.ui-table__title{line-height:20px}.ui-table.ui-table--index .ui-table__check{width:var(--ui-coll-check-w);padding:6px 8px 6px 12px}.ui-table.ui-table--index thead .ui-table__check{padding:8px 8px 8px 12px}.ui-table__checkbox{display:flex;width:max-content;align-items:center;justify-content:center;min-width:24px;min-height:24px;margin:-2px 0;cursor:pointer}.ui-table__checkbox>input,.ui-list__check>input{width:16px;height:16px;margin:0;accent-color:var(--ui-accent);cursor:pointer}.ui-table__checkbox>input:focus-visible,.ui-list__check>input:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px}.ui-table--index :is(.ui-table__check,.ui-table__primary){position:sticky;z-index:1;background:inherit}.ui-table--index .ui-table__check,.ui-table--index .ui-table__primary{left:0}.ui-table--index:has(.ui-table__check) .ui-table__primary{left:var(--ui-coll-check-w)}.ui-table__actions{width:1%;text-align:right}.ui-table__actions>*{vertical-align:middle}.ui-row-actions{display:inline-flex;align-items:center;gap:var(--ui-space-2)}.ui-bulkbar{position:relative;z-index:3;display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-space-2);box-sizing:border-box;min-height:38px;margin-bottom:-38px;padding:4px 8px 4px 12px;background:var(--ui-surface);border:1px solid var(--ui-border);border-bottom-color:transparent;border-radius:var(--ui-radius-lg) var(--ui-radius-lg) 0 0;font-size:var(--ui-fs-body)}.ui-bulkbar[hidden]{display:none}.ui-bulkbar__count{font-weight:550;font-variant-numeric:tabular-nums}.ui-bulkbar__actions{display:inline-flex;flex-wrap:wrap;gap:var(--ui-space-2);margin-left:auto}.ui-bulkbar .ui-table__checkbox{margin-right:4px}.ui-index__sortbar{display:none}@container ui-index (max-width: 768px){.ui-table--index,.ui-table--index tbody{display:block;width:100%}.ui-table--index thead{display:none}.ui-table--index tbody tr{position:relative;display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 12px;min-height:44px;box-sizing:border-box;padding:10px 12px;border-top:1px solid var(--ui-border)}.ui-table--index tbody tr:first-child{border-top:0}.ui-table--index tbody tr:has(>.ui-table__check){padding-left:48px}.ui-table.ui-table--index tbody :is(td,th){display:block;padding:0;border:0;position:static;background:none;white-space:nowrap}.ui-table--index tbody .ui-table__primary{flex:1 0 100%;white-space:normal}.ui-table--index tbody td:not(.ui-table__primary,.ui-table__check,.ui-table__actions){flex:none;max-width:100%;overflow:hidden;text-overflow:ellipsis;color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:18px}.ui-table--index tbody td[data-label]:not(.ui-table__primary):before{content:attr(data-label) " ";color:var(--ui-text-muted)}.ui-table--index tbody td:not(.ui-table__primary,.ui-table__check,.ui-table__actions) .ui-trunc{display:inline-block;vertical-align:bottom}.ui-table--index tbody td:not(.ui-table__primary,.ui-table__check,.ui-table__actions) .ui-sub{display:inline;margin-left:6px}.ui-table--index tbody td.is-num{text-align:left}.ui-table--index tbody td[data-condensed=hide]{display:none}.ui-table.ui-table--index tbody .ui-table__check{position:absolute;left:4px;top:4px;width:auto;padding:0}.ui-table.ui-table--index tbody .ui-table__actions{order:99;margin-left:auto;width:auto;padding:0;align-self:center}.ui-table--index .ui-table__checkbox{min-width:44px;min-height:44px;margin:0}.ui-table--index .ui-table__title,.ui-table--index .ui-sub{max-width:none}.ui-index__sortbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-space-2);margin:0 0 var(--ui-space-3);font-size:var(--ui-fs-caption);color:var(--ui-text-muted)}.ui-index .ui-bulkbar{margin-bottom:var(--ui-space-2);border-bottom-color:var(--ui-border);border-radius:var(--ui-radius-lg)}.ui-index .ui-table-wrap{overflow-x:visible}}.ui-list{container:ui-list / inline-size;margin:0;padding:0;list-style:none;background:var(--ui-surface);border:1px solid var(--ui-border);border-radius:var(--ui-radius-lg);box-shadow:var(--ui-card-shadow)}.ui-list--flush{border:0;border-radius:0;box-shadow:none;background:transparent}.ui-list__item{position:relative;display:flex;align-items:flex-start;gap:var(--ui-space-3);box-sizing:border-box;padding:var(--ui-space-3);min-height:44px;border-top:1px solid var(--ui-border)}.ui-list>.ui-list__item:first-child{border-top:0}.ui-list>.ui-list__item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.ui-list>.ui-list__item:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.ui-list__item:has(.ui-list__title[href]):hover{background:var(--ui-coll-hover)}.ui-list__item:is(.is-selected,[aria-selected=true]){background:var(--ui-coll-selected)}.ui-list__item:has(.ui-list__title:focus-visible){outline:2px solid var(--ui-focus);outline-offset:-2px}.ui-list__media{flex:none;display:flex;align-items:center;min-height:40px}.ui-list__body{flex:1 1 auto;min-width:0}.ui-list__title{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-text);font-size:var(--ui-fs-body);line-height:20px;font-weight:650;text-decoration:none}.ui-list__title[href]:after{content:"";position:absolute;inset:0;z-index:0}.ui-list__title:focus-visible{outline:none}.ui-list__sub{margin:0;color:var(--ui-text-muted);font-size:var(--ui-fs-body);line-height:20px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;overflow-wrap:anywhere}.ui-list__meta{margin:2px 0 0;color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:16px}.ui-list__badges{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.ui-list__aside{flex:none;align-self:center;color:var(--ui-text);font-variant-numeric:tabular-nums;text-align:right}.ui-list__actions{flex:none;align-self:center;display:inline-flex;align-items:center;gap:var(--ui-space-2)}.ui-list__item :is(.ui-list__actions,.ui-list__aside a,.ui-list__body a:not(.ui-list__title),button,input,select,textarea,label,summary,details){position:relative;z-index:1}@container ui-list (max-width: 400px){.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item{display:grid;grid-template-columns:auto minmax(0,1fr) auto;grid-template-areas:"media body body" "media aside actions";gap:0;align-items:start}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__media{grid-area:media;margin-inline-end:var(--ui-space-3)}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__body{grid-area:body}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__aside{grid-area:aside;justify-self:start;align-self:center;margin-top:4px;text-align:left}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__actions{grid-area:actions;justify-self:end;align-self:center;margin:4px 0 0 var(--ui-space-3)}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item:has(>.ui-list__body>.ui-list__title:only-child){grid-template-columns:auto minmax(0,1fr) auto auto;grid-template-areas:"media body aside actions";align-items:center}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item:has(>.ui-list__body>.ui-list__title:only-child)>:is(.ui-list__aside,.ui-list__actions){margin-top:0}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item:has(>.ui-list__body>.ui-list__title:only-child)>.ui-list__aside{margin-inline-start:var(--ui-space-3);text-align:right}}.ui-resource>.ui-bulkbar{margin-bottom:0;border-bottom-color:var(--ui-border)}.ui-resource>.ui-bulkbar:has(+.ui-list--flush){border-width:0 0 1px;border-radius:0}.ui-resource>.ui-list,.ui-resource>[aria-busy]>.ui-list{border-top:0;border-top-left-radius:0;border-top-right-radius:0}.ui-list__check{display:flex;flex:none;align-items:center;justify-content:center;min-width:24px;min-height:24px;cursor:pointer}.ui-list__check:not(:last-child){margin-inline-end:8px}@media (pointer: coarse),(max-width: 47.9975em){.ui-list__check{min-width:44px;min-height:44px;margin-block:-2px;margin-inline-start:-12px}.ui-list__check:not(:last-child){margin-inline-end:-2px}.ui-resource>.ui-bulkbar>.ui-table__checkbox{min-width:44px;min-height:44px;margin:-8px -8px -8px -12px}}.ui-thumb{display:block;flex:none;width:40px;height:40px;box-sizing:border-box;border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);background:var(--ui-surface-2);overflow:hidden;object-fit:cover}.ui-thumb--xs{width:24px;height:24px;border-radius:var(--ui-radius-sm)}.ui-thumb--md{width:60px;height:60px}.ui-thumb--lg{width:80px;height:80px}.ui-thumb>img{display:block;width:100%;height:100%;object-fit:cover}.ui-list--compact>.ui-list__item{display:block;padding:0;min-height:0}.ui-list__row{display:flex;align-items:center;gap:var(--ui-space-2);box-sizing:border-box;width:100%;min-height:36px;padding:8px 12px;border:0;background:none;color:var(--ui-text);font:inherit;font-size:var(--ui-fs-body);line-height:20px;text-align:left;text-decoration:none;border-radius:inherit}:is(a,button).ui-list__row{cursor:pointer}:is(a,button).ui-list__row:hover{background:var(--ui-coll-hover)}:is(a,button).ui-list__row:focus-visible{outline:2px solid var(--ui-focus);outline-offset:-2px}.ui-list__row[aria-current=page],.ui-list__row.is-selected{background:var(--ui-coll-selected)}.ui-list__icon{flex:none;display:inline-flex;width:20px;height:20px;align-items:center;justify-content:center;color:var(--ui-text-muted)}.ui-list__icon>svg{width:16px;height:16px}.ui-list__label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-list__row>.ui-list__meta{flex:none;margin:0;font-variant-numeric:tabular-nums}@media (pointer: coarse),(max-width: 47.9975em){.ui-list__row{min-height:44px}}.ui-list--activity>.ui-list__item{display:grid;grid-template-columns:20px minmax(0,1fr) auto;column-gap:var(--ui-space-2);align-items:start;padding:8px 12px;min-height:36px;border-top:0}.ui-list--activity>.ui-list__item:before{content:"";position:absolute;left:21.5px;top:0;bottom:0;width:1px;background:var(--ui-border)}.ui-list--activity>.ui-list__item:first-child:before{top:14px}.ui-list--activity>.ui-list__item:last-child:before{bottom:calc(100% - 14px)}.ui-list--activity>.ui-list__item:only-child:before{display:none}.ui-list__dot{position:relative;z-index:1;width:8px;height:8px;margin:6px 0 0 6px;border-radius:50%;background:var(--ui-text-muted);box-shadow:0 0 0 3px var(--ui-surface)}.ui-list__dot--success{background:var(--gemboss-success, #0a8f6a)}.ui-list__dot--warning{background:var(--gemboss-warning, #b25e09)}.ui-list__dot--critical{background:var(--gemboss-danger-strong, #c70a24)}.ui-list__dot--info{background:var(--gemboss-accent, #5661f5)}.ui-list--activity .ui-list__label{display:block;white-space:nowrap}.ui-list--activity .ui-list__detail{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:16px}.ui-list--activity time,.ui-list--activity .ui-list__time{color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:20px;white-space:nowrap;font-variant-numeric:tabular-nums}.ui-list__content{margin-top:4px;color:var(--ui-text);font-size:var(--ui-fs-body);line-height:20px;overflow-wrap:anywhere}.ui-list__content>p{margin:0}.ui-list__content>p+p{margin-top:4px}.ui-list--wrap .ui-list__label,.ui-list--wrap .ui-list__detail{white-space:normal;overflow:visible;text-overflow:clip;overflow-wrap:anywhere}.ui-list--wrap .ui-list__row{align-items:flex-start}@media (pointer: coarse),(max-width: 47.9975em){.ui-list--wrap .ui-list__row{padding-block:12px}}.ui-list--wrap .ui-list__row>.ui-list__meta{line-height:20px}.ui-cardgrid{--ui-cardgrid-min: 240px;display:grid;grid-template-columns:repeat(auto-fill,minmax(min(var(--ui-cardgrid-min),100%),1fr));gap:var(--ui-space-4);margin:0;padding:0;list-style:none}.ui-cardgrid[data-min="200"]{--ui-cardgrid-min: 200px}.ui-cardgrid[data-min="320"]{--ui-cardgrid-min: 320px}.ui-cardgrid>*{min-width:0}.ui-board{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(240px,1fr);gap:var(--ui-space-4);align-items:start;overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;padding-bottom:4px}@media (max-width: 47.9975em){.ui-board{grid-auto-columns:78%}}.ui-board__col{display:flex;flex-direction:column;gap:var(--ui-space-2);min-width:0;padding:var(--ui-space-2);scroll-snap-align:start;background:var(--ui-coll-head-bg);border-radius:var(--ui-radius-lg)}.ui-board__head{display:flex;align-items:center;gap:var(--ui-space-2);min-height:28px;padding:0 4px;font-size:var(--ui-fs-body);font-weight:650}.ui-board__name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-board__count{margin-left:auto;color:var(--ui-text-muted);font-weight:450;font-variant-numeric:tabular-nums}.ui-board__dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--ui-text-muted)}.ui-board__dot--success{background:var(--gemboss-success, #0a8f6a)}.ui-board__dot--warning{background:var(--gemboss-warning, #b25e09)}.ui-board__dot--critical{background:var(--gemboss-danger-strong, #c70a24)}.ui-board__dot--info{background:var(--gemboss-accent, #5661f5)}.ui-board__list{display:grid;gap:var(--ui-space-2);margin:0;padding:0;list-style:none}.ui-board__list>li{min-width:0}.ui-board__empty{margin:0;padding:var(--ui-space-4) var(--ui-space-2);color:var(--ui-text-muted);font-size:var(--ui-fs-body);text-align:center;border:1px dashed var(--ui-border);border-radius:var(--ui-radius-md)}.ui-board__more>summary{list-style:none;justify-self:center;margin:4px auto 0;width:fit-content}.ui-board__more>summary::-webkit-details-marker{display:none}.ui-board__more[open]>summary{display:none}.ui-board__more{display:grid;gap:var(--ui-space-2)}.ui-board__next.ui-more{padding:4px 0 0}.ui-board__next .ui-more__error{color:var(--gemboss-danger-strong, #c70a24)}.ui-board[data-gb-move] .ui-board__list>li[data-id]{position:relative;border-radius:var(--ui-radius-lg);cursor:grab}.ui-board[data-gb-move] .ui-board__list>li[data-id]:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px}.ui-board__list>li[data-gb-lifted]{outline:2px solid var(--ui-focus);outline-offset:2px;box-shadow:var(--gemboss-shadow-md, 0 4px 12px rgba(0,0,0,.12));border-radius:var(--ui-radius-lg)}.ui-board[data-gb-dragging] .ui-board__list>li[data-gb-lifted]{outline:0;opacity:.4}.ui-board__col[data-gb-over]{background:color-mix(in srgb,var(--ui-focus) 10%,var(--ui-coll-head-bg))}.ui-board__list>li[data-gb-drop]:before{content:"";position:absolute;left:0;right:0;height:2px;border-radius:1px;background:var(--ui-focus);pointer-events:none}.ui-board__list>li[data-gb-drop=before]:before{top:-5px}.ui-board__list>li[data-gb-drop=after]:before{bottom:-5px}.ui-empty--no-match{padding-block:32px}.ui-coll-error{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-space-2) var(--ui-space-3);margin:var(--ui-space-3)}.ui-coll-error>:first-child{flex:1 1 240px;min-width:0}.ui-coll-count{margin-left:auto;color:var(--ui-text-muted);font-size:var(--ui-fs-body);font-variant-numeric:tabular-nums;white-space:nowrap}.ui-chip__x{margin-right:-4px;font-size:14px;line-height:1;opacity:.7}:is(.ui-table-wrap,.ui-index,.ui-list,.ui-cardgrid,.ui-board)[aria-busy=true]{position:relative}:is(.ui-table-wrap,.ui-index,.ui-list,.ui-cardgrid,.ui-board)[aria-busy=true]>:not(.ui-bulkbar,.ui-coll-busy){opacity:.55;pointer-events:none;transition:opacity .15s}.ui-coll-busy{position:absolute;top:8px;right:8px;z-index:4}:is(.ui-skeleton--table,.ui-skeleton--list,.ui-skeleton--compact,.ui-skeleton--grid,.ui-skeleton--board) .ui-skeleton__line{height:8px;border-radius:4px}.ui-skeleton--table td .ui-skeleton__line{width:70%;margin-block:6px}.ui-skeleton--table td:first-child .ui-skeleton__line{width:85%}.ui-skeleton--table tbody tr:hover{background:none}.ui-skeleton__block{display:block;flex:none;width:40px;height:40px;border-radius:var(--ui-radius-md);background:var(--ui-surface-2)}.ui-skeleton__block--round{border-radius:50%;width:32px;height:32px}.ui-skeleton--list>.ui-list__item{align-items:center}.ui-skeleton--list .ui-list__body{display:grid;gap:12px}.ui-skeleton--list .ui-list__body>.ui-skeleton__line:last-child{width:60%}.ui-skeleton--compact .ui-list__row{gap:12px}.ui-skeleton--compact .ui-list__row>.ui-skeleton__line{flex:1 1 auto;max-width:60%}.ui-skeleton--grid .ui-card__body{display:grid;gap:12px;justify-items:stretch}.ui-skeleton--grid .ui-card__body>.ui-skeleton__line:last-child{width:50%}.ui-skeleton--board .ui-board__list>li{height:72px;border-radius:var(--ui-radius-md);background:var(--ui-surface)}@media (pointer: coarse){.ui-table__sort{min-height:44px;margin-block:-12px}.ui-table__checkbox{min-width:44px;min-height:44px;margin:-12px 0}}@media (pointer: coarse),(max-width: 47.9975em){.ui-table__sort{min-width:44px}}@media (prefers-reduced-motion: reduce){.ui-table--sticky-first :is(th,td):first-child{animation:none}:is(.ui-table-wrap,.ui-index,.ui-list,.ui-cardgrid,.ui-board)[aria-busy=true]>*{transition:none}.ui-board{scroll-behavior:auto}}
1
+ :root{--ui-coll-head-bg: color-mix(in srgb, var(--ui-text, #1b1c1e) 3.5%, var(--ui-surface, #fff));--ui-coll-hover: color-mix(in srgb, var(--ui-text, #1b1c1e) 3.5%, var(--ui-surface, #fff));--ui-coll-selected: color-mix(in srgb, var(--ui-text, #1b1c1e) 6%, var(--ui-surface, #fff));--ui-coll-check-w: 40px}.ui-table--sticky-first tr{background:var(--ui-surface)}.ui-table--sticky-first tbody tr:hover{background:var(--ui-surface-2)}.ui-table--sticky-first :is(th,td):first-child{position:sticky;left:0;z-index:1;background:inherit}@supports (animation-timeline: scroll()){.ui-table-wrap:has(>.ui-table--sticky-first){scroll-timeline:--ui-coll-x inline}.ui-table--sticky-first :is(th,td):first-child{animation:ui-coll-edge linear both;animation-timeline:--ui-coll-x;animation-range:0 24px}}@keyframes ui-coll-edge{0%{box-shadow:none}to{box-shadow:1px 0 0 var(--ui-border),6px 0 8px -6px #0000002e}}.ui-table--compact :is(td,tbody th){padding-block:6px}.ui-table--compact thead th{padding-block:6px}.ui-table__totals>tr{background:var(--ui-coll-head-bg)}.ui-table__totals>tr>:is(td,th){background:var(--ui-coll-head-bg);font-weight:650;color:var(--ui-text);border-top:1px solid var(--ui-border);border-bottom:0}.ui-table__footer{padding:8px 12px;background:var(--ui-coll-head-bg);border-top:1px solid var(--ui-border);color:var(--ui-text-muted);font-size:var(--ui-fs-body);text-align:center}.ui-table th.ui-table__rowhead{font-weight:450;color:var(--ui-text);text-align:left}.ui-table th.ui-table__rowhead:not(.is-num){white-space:normal;min-width:9.0625rem}.ui-table th.ui-table__rowhead>a,.ui-table:where(:not(.ui-table--index)) tbody :is(td,th) li>a{display:inline-flex;align-items:center;min-height:24px}.ui-table:where(:not(.ui-table--index)) tbody :is(td,th){vertical-align:top}.ui-table:where(:not(.ui-table--index)) tbody :is(td>a,th.ui-table__rowhead>a,:is(td,th) li>a){margin-block:calc((1lh - 24px)/2)}.ui-table__sort{display:flex;width:max-content;max-width:100%;align-items:center;gap:4px;min-height:24px;margin-block:-2px;padding:0;border:0;background:none;color:inherit;font:inherit;text-align:inherit;text-decoration:none;cursor:pointer;white-space:nowrap}.ui-table__sort:hover{color:var(--ui-text)}.ui-table__sort:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px;border-radius:4px}.ui-table__sort:after{content:"";flex:none;width:16px;height:16px;background:currentColor;opacity:0;-webkit-mask:var(--ui-coll-arrow) center / 16px no-repeat;mask:var(--ui-coll-arrow) center / 16px no-repeat;--ui-coll-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 3.5v9M4.5 9 8 12.5 11.5 9' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}.ui-table__sort:is(:hover,:focus-visible):after{opacity:.45}th[aria-sort=ascending]>.ui-table__sort:after,th[aria-sort=descending]>.ui-table__sort:after{opacity:1}th[aria-sort=ascending]>.ui-table__sort:after{transform:rotate(180deg)}th[aria-sort=ascending]>.ui-table__sort,th[aria-sort=descending]>.ui-table__sort{color:var(--ui-text)}.ui-table .is-num>.ui-table__sort{flex-direction:row-reverse;margin-left:auto}.ui-trunc{display:block;max-width:var(--ui-trunc, 32ch);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-clamp-2{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;white-space:normal;overflow-wrap:anywhere}.ui-index{position:relative;container:ui-index / inline-size;min-width:0}.ui-table--index{font-size:var(--ui-fs-body)}.ui-table--index tr{background:var(--ui-surface)}.ui-table.ui-table--index thead th{padding:8px 6px;background:var(--ui-coll-head-bg);color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:20px;font-weight:550;text-transform:none;letter-spacing:0}.ui-table.ui-table--index :is(td,tbody th){padding:6px;line-height:20px;white-space:nowrap;vertical-align:middle;border-bottom:0;border-top:1px solid var(--ui-border)}.ui-table.ui-table--index :is(th,td):where(:first-child){padding-left:var(--ui-space-3)}.ui-table.ui-table--index :is(th,td):where(:last-child){padding-right:var(--ui-space-3)}.ui-table--index tbody tr:hover{background:var(--ui-coll-hover)}.ui-table--index tbody tr:is(.is-selected,[aria-selected=true]){background:var(--ui-coll-selected)}.ui-table--index tbody tr:is([data-href],.is-linked){cursor:pointer}.ui-table--index tbody tr:has(.ui-table__title:focus-visible){outline:2px solid var(--ui-focus);outline-offset:-2px}.ui-table__title:focus-visible{outline:none}.ui-table__primary{min-width:0}.ui-table__primary-inner{display:flex;align-items:center;gap:var(--ui-space-3);min-width:0}.ui-table__primary-text{min-width:0}.ui-table__title{display:block;max-width:var(--ui-trunc, 40ch);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-text);font-weight:650;text-decoration:none}a.ui-table__title:hover{text-decoration:underline}.ui-table--index .ui-table__title+.ui-sub,.ui-table--index .ui-sub{display:block;max-width:var(--ui-trunc, 40ch);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-top:0;line-height:16px}.ui-table--index td>a.ui-table__title{display:block;min-height:0}.ui-table--index td>.ui-table__primary-inner>a.ui-table__title,.ui-table--index .ui-table__primary-text>a.ui-table__title{line-height:20px}.ui-table.ui-table--index .ui-table__check{width:var(--ui-coll-check-w);padding:6px 8px 6px 12px}.ui-table.ui-table--index thead .ui-table__check{padding:8px 8px 8px 12px}.ui-table__checkbox{display:flex;width:max-content;align-items:center;justify-content:center;min-width:24px;min-height:24px;margin:-2px 0;cursor:pointer}.ui-table__checkbox>input,.ui-list__check>input{width:16px;height:16px;margin:0;accent-color:var(--ui-accent);cursor:pointer}.ui-table__checkbox>input:focus-visible,.ui-list__check>input:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px}.ui-table--index :is(.ui-table__check,.ui-table__primary){position:sticky;z-index:1;background:inherit}.ui-table--index .ui-table__check,.ui-table--index .ui-table__primary{left:0}.ui-table--index:has(.ui-table__check) .ui-table__primary{left:var(--ui-coll-check-w)}.ui-table__actions{width:1%;text-align:right}.ui-table__actions>*{vertical-align:middle}.ui-row-actions{display:inline-flex;align-items:center;gap:var(--ui-space-2)}.ui-bulkbar{position:relative;z-index:3;display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-space-2);box-sizing:border-box;min-height:38px;margin-bottom:-38px;padding:4px 8px 4px 12px;background:var(--ui-surface);border:1px solid var(--ui-border);border-bottom-color:transparent;border-radius:var(--ui-radius-lg) var(--ui-radius-lg) 0 0;font-size:var(--ui-fs-body)}.ui-bulkbar[hidden]{display:none}.ui-bulkbar__count{flex:none;font-weight:550;font-variant-numeric:tabular-nums;white-space:nowrap}.ui-bulkbar__actions{display:inline-flex;flex-wrap:wrap;gap:var(--ui-space-2);margin-left:auto}.ui-bulkbar .ui-table__checkbox{margin-right:4px}.ui-bulkbar[data-fit=pending]{flex-wrap:nowrap}.ui-bulkbar[data-fit=pending]>.ui-bulkbar__actions{flex:0 1 auto;flex-wrap:nowrap;min-width:0;overflow:hidden}.ui-bulkbar__actions>.ui-bulkbar__more{flex:none}.ui-bulkbar__measure{position:absolute;top:0;left:0;display:inline-flex;gap:var(--ui-space-2);height:0;overflow:hidden;visibility:hidden;pointer-events:none;white-space:nowrap}.ui-bulkbar__measure>*{flex:none}.ui-index__sortbar{display:none}@container ui-index (max-width: 768px){.ui-table--index,.ui-table--index tbody{display:block;width:100%}.ui-table--index thead{display:none}.ui-table--index tbody tr{position:relative;display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 12px;min-height:44px;box-sizing:border-box;padding:10px 12px;border-top:1px solid var(--ui-border)}.ui-table--index tbody tr:first-child{border-top:0}.ui-table--index tbody tr:has(>.ui-table__check){padding-left:48px}.ui-table.ui-table--index tbody :is(td,th){display:block;padding:0;border:0;position:static;background:none;white-space:nowrap}.ui-table--index tbody .ui-table__primary{flex:1 0 100%;white-space:normal}.ui-table--index tbody td:not(.ui-table__primary,.ui-table__check,.ui-table__actions){flex:none;max-width:100%;overflow:hidden;text-overflow:ellipsis;color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:18px}.ui-table--index tbody td[data-label]:not(.ui-table__primary):before{content:attr(data-label) " ";color:var(--ui-text-muted)}.ui-table--index tbody td:not(.ui-table__primary,.ui-table__check,.ui-table__actions) .ui-trunc{display:inline-block;vertical-align:bottom}.ui-table--index tbody td:not(.ui-table__primary,.ui-table__check,.ui-table__actions) .ui-sub{display:inline;margin-left:6px}.ui-table--index tbody td.is-num{text-align:left}.ui-table--index tbody td[data-condensed=hide]{display:none}.ui-table.ui-table--index tbody .ui-table__check{position:absolute;left:4px;top:4px;width:auto;padding:0}.ui-table.ui-table--index tbody .ui-table__actions{order:99;margin-left:auto;width:auto;padding:0;align-self:center}.ui-table--index .ui-table__checkbox{min-width:44px;min-height:44px;margin:0}.ui-table--index .ui-table__title,.ui-table--index .ui-sub{max-width:none}.ui-index__sortbar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-space-2);margin:0 0 var(--ui-space-3);font-size:var(--ui-fs-caption);color:var(--ui-text-muted)}.ui-index .ui-bulkbar{margin-bottom:var(--ui-space-2);border-bottom-color:var(--ui-border);border-radius:var(--ui-radius-lg)}.ui-index .ui-table-wrap{overflow-x:visible}}.ui-list{container:ui-list / inline-size;margin:0;padding:0;list-style:none;background:var(--ui-surface);border:1px solid var(--ui-border);border-radius:var(--ui-radius-lg);box-shadow:var(--ui-card-shadow)}.ui-list--flush{border:0;border-radius:0;box-shadow:none;background:transparent}.ui-list__item{position:relative;display:flex;align-items:flex-start;gap:var(--ui-space-3);box-sizing:border-box;padding:var(--ui-space-3);min-height:44px;border-top:1px solid var(--ui-border)}.ui-list>.ui-list__item:first-child{border-top:0}.ui-list>.ui-list__item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.ui-list>.ui-list__item:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.ui-list__item:has(.ui-list__title[href]):hover{background:var(--ui-coll-hover)}.ui-list__item:is(.is-selected,[aria-selected=true]){background:var(--ui-coll-selected)}.ui-list__item:has(.ui-list__title:focus-visible){outline:2px solid var(--ui-focus);outline-offset:-2px}.ui-list__media{flex:none;display:flex;align-items:center;min-height:40px}.ui-list__body{flex:1 1 auto;min-width:0}.ui-list__title{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-text);font-size:var(--ui-fs-body);line-height:20px;font-weight:650;text-decoration:none}.ui-list__title[href]:after{content:"";position:absolute;inset:0;z-index:0}.ui-list__title:focus-visible{outline:none}.ui-list__sub{margin:0;color:var(--ui-text-muted);font-size:var(--ui-fs-body);line-height:20px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;overflow-wrap:anywhere}.ui-list__meta{margin:2px 0 0;color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:16px}.ui-list__badges{display:flex;flex-wrap:wrap;gap:4px;margin-top:4px}.ui-list__aside{flex:none;align-self:center;color:var(--ui-text);font-variant-numeric:tabular-nums;text-align:right}.ui-list__actions{flex:none;align-self:center;display:inline-flex;align-items:center;gap:var(--ui-space-2)}.ui-list__item :is(.ui-list__actions,.ui-list__aside a,.ui-list__body a:not(.ui-list__title),button,input,select,textarea,label,summary,details){position:relative;z-index:1}@container ui-list (max-width: 400px){.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item{display:grid;grid-template-columns:auto minmax(0,1fr) auto;grid-template-areas:"media body body" "media aside actions";gap:0;align-items:start}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__media{grid-area:media;margin-inline-end:var(--ui-space-3)}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__body{grid-area:body}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__aside{grid-area:aside;justify-self:start;align-self:center;margin-top:4px;text-align:left}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item>.ui-list__actions{grid-area:actions;justify-self:end;align-self:center;margin:4px 0 0 var(--ui-space-3)}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item:has(>.ui-list__body>.ui-list__title:only-child){grid-template-columns:auto minmax(0,1fr) auto auto;grid-template-areas:"media body aside actions";align-items:center}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item:has(>.ui-list__body>.ui-list__title:only-child)>:is(.ui-list__aside,.ui-list__actions){margin-top:0}.ui-list:not(.ui-list--compact,.ui-skeleton--list)>.ui-list__item:has(>.ui-list__body>.ui-list__title:only-child)>.ui-list__aside{margin-inline-start:var(--ui-space-3);text-align:right}}.ui-resource>.ui-bulkbar{margin-bottom:0;border-bottom-color:var(--ui-border)}.ui-resource>.ui-bulkbar:has(+.ui-list--flush){border-width:0 0 1px;border-radius:0}.ui-resource>.ui-list,.ui-resource>[aria-busy]>.ui-list{border-top:0;border-top-left-radius:0;border-top-right-radius:0}.ui-list__check{display:flex;flex:none;align-items:center;justify-content:center;min-width:24px;min-height:24px;cursor:pointer}.ui-list__check:not(:last-child){margin-inline-end:8px}@media (pointer: coarse),(max-width: 47.9975em){.ui-list__check{min-width:44px;min-height:44px;margin-block:-2px;margin-inline-start:-12px}.ui-list__check:not(:last-child){margin-inline-end:-2px}.ui-resource>.ui-bulkbar>.ui-table__checkbox{min-width:44px;min-height:44px;margin:-8px -8px -8px -12px}}.ui-thumb{display:block;flex:none;width:40px;height:40px;box-sizing:border-box;border:1px solid var(--ui-border);border-radius:var(--ui-radius-md);background:var(--ui-surface-2);overflow:hidden;object-fit:cover}.ui-thumb--xs{width:24px;height:24px;border-radius:var(--ui-radius-sm)}.ui-thumb--md{width:60px;height:60px}.ui-thumb--lg{width:80px;height:80px}.ui-thumb>img{display:block;width:100%;height:100%;object-fit:cover}.ui-list--compact>.ui-list__item{display:block;padding:0;min-height:0}.ui-list__row{display:flex;align-items:center;gap:var(--ui-space-2);box-sizing:border-box;width:100%;min-height:36px;padding:8px 12px;border:0;background:none;color:var(--ui-text);font:inherit;font-size:var(--ui-fs-body);line-height:20px;text-align:left;text-decoration:none;border-radius:inherit}:is(a,button).ui-list__row{cursor:pointer}:is(a,button).ui-list__row:hover{background:var(--ui-coll-hover)}:is(a,button).ui-list__row:focus-visible{outline:2px solid var(--ui-focus);outline-offset:-2px}.ui-list__row[aria-current=page],.ui-list__row.is-selected{background:var(--ui-coll-selected)}.ui-list__icon{flex:none;display:inline-flex;width:20px;height:20px;align-items:center;justify-content:center;color:var(--ui-text-muted)}.ui-list__icon>svg{width:16px;height:16px}.ui-list__label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-list__row>.ui-list__meta{flex:none;margin:0;font-variant-numeric:tabular-nums}@media (pointer: coarse),(max-width: 47.9975em){.ui-list__row{min-height:44px}}.ui-list--activity>.ui-list__item{display:grid;grid-template-columns:20px minmax(0,1fr) auto;column-gap:var(--ui-space-2);align-items:start;padding:8px 12px;min-height:36px;border-top:0}.ui-list--activity>.ui-list__item:before{content:"";position:absolute;left:21.5px;top:0;bottom:0;width:1px;background:var(--ui-border)}.ui-list--activity>.ui-list__item:first-child:before{top:14px}.ui-list--activity>.ui-list__item:last-child:before{bottom:calc(100% - 14px)}.ui-list--activity>.ui-list__item:only-child:before{display:none}.ui-list__dot{position:relative;z-index:1;width:8px;height:8px;margin:6px 0 0 6px;border-radius:50%;background:var(--ui-text-muted);box-shadow:0 0 0 3px var(--ui-surface)}.ui-list__dot--success{background:var(--gemboss-success, #0a8f6a)}.ui-list__dot--warning{background:var(--gemboss-warning, #b25e09)}.ui-list__dot--critical{background:var(--gemboss-danger-strong, #c70a24)}.ui-list__dot--info{background:var(--gemboss-accent, #5661f5)}.ui-list--activity .ui-list__label{display:block;white-space:nowrap}.ui-list--activity a.ui-list__label{position:relative;color:var(--ui-text);text-decoration:none;padding-block:2px;margin-block:-2px}.ui-list--activity a.ui-list__label:hover{text-decoration:underline}.ui-list--activity a.ui-list__label:focus-visible{outline:2px solid var(--ui-focus);outline-offset:0;border-radius:4px}.ui-list--activity .ui-list__detail{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:16px}.ui-list--activity time,.ui-list--activity .ui-list__time{color:var(--ui-text-muted);font-size:var(--ui-fs-caption);line-height:20px;white-space:nowrap;font-variant-numeric:tabular-nums}.ui-list__content{margin-top:4px;color:var(--ui-text);font-size:var(--ui-fs-body);line-height:20px;overflow-wrap:anywhere}.ui-list__content>p{margin:0}.ui-list__content>p+p{margin-top:4px}.ui-list--wrap .ui-list__label,.ui-list--wrap .ui-list__detail{white-space:normal;overflow:visible;text-overflow:clip;overflow-wrap:anywhere}.ui-list--wrap .ui-list__row{align-items:flex-start}@media (pointer: coarse),(max-width: 47.9975em){.ui-list--wrap .ui-list__row{padding-block:12px}}.ui-list--wrap .ui-list__row>.ui-list__meta{line-height:20px}.ui-cardgrid{--ui-cardgrid-min: 240px;display:grid;grid-template-columns:repeat(auto-fill,minmax(min(var(--ui-cardgrid-min),100%),1fr));gap:var(--ui-space-4);margin:0;padding:0;list-style:none}.ui-cardgrid[data-min="200"]{--ui-cardgrid-min: 200px}.ui-cardgrid[data-min="320"]{--ui-cardgrid-min: 320px}.ui-cardgrid>*{min-width:0}.ui-board{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(240px,1fr);gap:var(--ui-space-4);align-items:start;overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;padding-bottom:4px}@media (max-width: 47.9975em){.ui-board{grid-auto-columns:78%}}.ui-board__col{display:flex;flex-direction:column;gap:var(--ui-space-2);min-width:0;padding:var(--ui-space-2);scroll-snap-align:start;background:var(--ui-coll-head-bg);border-radius:var(--ui-radius-lg)}.ui-board__head{display:flex;align-items:center;gap:var(--ui-space-2);min-height:28px;padding:0 4px;font-size:var(--ui-fs-body);font-weight:650}.ui-board__name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-board__count{margin-left:auto;color:var(--ui-text-muted);font-weight:450;font-variant-numeric:tabular-nums}.ui-board__dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--ui-text-muted)}.ui-board__dot--success{background:var(--gemboss-success, #0a8f6a)}.ui-board__dot--warning{background:var(--gemboss-warning, #b25e09)}.ui-board__dot--critical{background:var(--gemboss-danger-strong, #c70a24)}.ui-board__dot--info{background:var(--gemboss-accent, #5661f5)}.ui-board__list{display:grid;gap:var(--ui-space-2);margin:0;padding:0;list-style:none}.ui-board__list>li{min-width:0}.ui-board__empty{margin:0;padding:var(--ui-space-4) var(--ui-space-2);color:var(--ui-text-muted);font-size:var(--ui-fs-body);text-align:center;border:1px dashed var(--ui-border);border-radius:var(--ui-radius-md)}.ui-board__more>summary{list-style:none;justify-self:center;margin:4px auto 0;width:fit-content}.ui-board__more>summary::-webkit-details-marker{display:none}.ui-board__more[open]>summary{display:none}.ui-board__more{display:grid;gap:var(--ui-space-2)}.ui-board__next.ui-more{padding:4px 0 0}.ui-board__next .ui-more__error{color:var(--gemboss-danger-strong, #c70a24)}.ui-board[data-gb-move] .ui-board__list>li[data-id]{position:relative;border-radius:var(--ui-radius-lg);cursor:grab}.ui-board[data-gb-move] .ui-board__list>li[data-id]:focus-visible{outline:2px solid var(--ui-focus);outline-offset:2px}.ui-board__list>li[data-gb-lifted]{outline:2px solid var(--ui-focus);outline-offset:2px;box-shadow:var(--gemboss-shadow-md, 0 4px 12px rgba(0,0,0,.12));border-radius:var(--ui-radius-lg)}.ui-board[data-gb-dragging] .ui-board__list>li[data-gb-lifted]{outline:0;opacity:.4}.ui-board__col[data-gb-over]{background:color-mix(in srgb,var(--ui-focus) 10%,var(--ui-coll-head-bg))}.ui-board__list>li[data-gb-drop]:before{content:"";position:absolute;left:0;right:0;height:2px;border-radius:1px;background:var(--ui-focus);pointer-events:none}.ui-board__list>li[data-gb-drop=before]:before{top:-5px}.ui-board__list>li[data-gb-drop=after]:before{bottom:-5px}.ui-empty--no-match{padding-block:32px}.ui-coll-error{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ui-space-2) var(--ui-space-3);margin:var(--ui-space-3)}.ui-coll-error>:first-child{flex:1 1 240px;min-width:0}.ui-coll-count{margin-left:auto;color:var(--ui-text-muted);font-size:var(--ui-fs-body);font-variant-numeric:tabular-nums;white-space:nowrap}.ui-chip__x{margin-right:-4px;font-size:14px;line-height:1;opacity:.7}:is(.ui-table-wrap,.ui-index,.ui-list,.ui-cardgrid,.ui-board)[aria-busy=true]{position:relative}:is(.ui-table-wrap,.ui-index,.ui-list,.ui-cardgrid,.ui-board)[aria-busy=true]>:not(.ui-bulkbar,.ui-coll-busy){opacity:.55;pointer-events:none;transition:opacity .15s}.ui-coll-busy{position:absolute;top:8px;right:8px;z-index:4}:is(.ui-skeleton--table,.ui-skeleton--list,.ui-skeleton--compact,.ui-skeleton--grid,.ui-skeleton--board) .ui-skeleton__line{height:8px;border-radius:4px}.ui-skeleton--table td .ui-skeleton__line{width:70%;margin-block:6px}.ui-skeleton--table td:first-child .ui-skeleton__line{width:85%}.ui-skeleton--table tbody tr:hover{background:none}.ui-skeleton__block{display:block;flex:none;width:40px;height:40px;border-radius:var(--ui-radius-md);background:var(--ui-surface-2)}.ui-skeleton__block--round{border-radius:50%;width:32px;height:32px}.ui-skeleton--list>.ui-list__item{align-items:center}.ui-skeleton--list .ui-list__body{display:grid;gap:12px}.ui-skeleton--list .ui-list__body>.ui-skeleton__line:last-child{width:60%}.ui-skeleton--compact .ui-list__row{gap:12px}.ui-skeleton--compact .ui-list__row>.ui-skeleton__line{flex:1 1 auto;max-width:60%}.ui-skeleton--grid .ui-card__body{display:grid;gap:12px;justify-items:stretch}.ui-skeleton--grid .ui-card__body>.ui-skeleton__line:last-child{width:50%}.ui-skeleton--board .ui-board__list>li{height:72px;border-radius:var(--ui-radius-md);background:var(--ui-surface)}@media (pointer: coarse){.ui-table__sort{min-height:44px;margin-block:-12px}.ui-table__checkbox{min-width:44px;min-height:44px;margin:-12px 0}}@media (pointer: coarse),(max-width: 47.9975em){.ui-table__sort{min-width:44px}}@media (prefers-reduced-motion: reduce){.ui-table--sticky-first :is(th,td):first-child{animation:none}:is(.ui-table-wrap,.ui-index,.ui-list,.ui-cardgrid,.ui-board)[aria-busy=true]>*{transition:none}.ui-board{scroll-behavior:auto}}