@khorsheed/dsh-mobile 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/LICENSE +21 -0
  2. package/README.i18n.yaml +6 -0
  3. package/README.md +132 -0
  4. package/README.zh.md +132 -0
  5. package/cordis.patch.yml +3 -0
  6. package/examples/https-ingress.mjs +84 -0
  7. package/examples/safari-stream-compat.mjs +98 -0
  8. package/lib/client.js +6138 -0
  9. package/lib/index.js +172 -0
  10. package/lib/invariant.js +20 -0
  11. package/lib/types/client/ConnectPhone.d.ts +9 -0
  12. package/lib/types/client/ConnectPhone.js +83 -0
  13. package/lib/types/client/DirectoryFlow.d.ts +14 -0
  14. package/lib/types/client/DirectoryFlow.js +75 -0
  15. package/lib/types/client/MobileChrome.d.ts +15 -0
  16. package/lib/types/client/MobileChrome.js +124 -0
  17. package/lib/types/client/MobileIcon.d.ts +6 -0
  18. package/lib/types/client/MobileIcon.js +16 -0
  19. package/lib/types/client/MobileLibrary.d.ts +13 -0
  20. package/lib/types/client/MobileLibrary.js +73 -0
  21. package/lib/types/client/MobileQueue.d.ts +9 -0
  22. package/lib/types/client/MobileQueue.js +90 -0
  23. package/lib/types/client/MobileRooms.d.ts +13 -0
  24. package/lib/types/client/MobileRooms.js +80 -0
  25. package/lib/types/client/MobileSeats.d.ts +4 -0
  26. package/lib/types/client/MobileSeats.js +5 -0
  27. package/lib/types/client/MobileTools.d.ts +7 -0
  28. package/lib/types/client/MobileTools.js +34 -0
  29. package/lib/types/client/SessionRename.d.ts +10 -0
  30. package/lib/types/client/SessionRename.js +43 -0
  31. package/lib/types/client/SubmissionFocus.d.ts +26 -0
  32. package/lib/types/client/SubmissionFocus.js +74 -0
  33. package/lib/types/client/composerActions.d.ts +24 -0
  34. package/lib/types/client/composerActions.js +66 -0
  35. package/lib/types/client/composerFocus.d.ts +15 -0
  36. package/lib/types/client/composerFocus.js +41 -0
  37. package/lib/types/client/directory.d.ts +17 -0
  38. package/lib/types/client/directory.js +54 -0
  39. package/lib/types/client/foreground.d.ts +4 -0
  40. package/lib/types/client/foreground.js +47 -0
  41. package/lib/types/client/gestures.d.ts +4 -0
  42. package/lib/types/client/gestures.js +118 -0
  43. package/lib/types/client/index.d.ts +20 -0
  44. package/lib/types/client/index.js +144 -0
  45. package/lib/types/client/locales.d.ts +145 -0
  46. package/lib/types/client/locales.js +80 -0
  47. package/lib/types/client/messageMenu.d.ts +19 -0
  48. package/lib/types/client/messageMenu.js +99 -0
  49. package/lib/types/client/native.d.ts +6 -0
  50. package/lib/types/client/native.js +15 -0
  51. package/lib/types/client/navigation.d.ts +41 -0
  52. package/lib/types/client/navigation.js +61 -0
  53. package/lib/types/client/pickers.d.ts +17 -0
  54. package/lib/types/client/pickers.js +109 -0
  55. package/lib/types/client/presentation.d.ts +38 -0
  56. package/lib/types/client/presentation.js +146 -0
  57. package/lib/types/client/queue.d.ts +47 -0
  58. package/lib/types/client/queue.js +26 -0
  59. package/lib/types/client/roomActions.d.ts +6 -0
  60. package/lib/types/client/roomActions.js +41 -0
  61. package/lib/types/client/rooms.d.ts +44 -0
  62. package/lib/types/client/rooms.js +75 -0
  63. package/lib/types/client/styles.d.ts +4 -0
  64. package/lib/types/client/styles.js +434 -0
  65. package/lib/types/client/surface.d.ts +17 -0
  66. package/lib/types/client/surface.js +112 -0
  67. package/lib/types/client/viewport.d.ts +13 -0
  68. package/lib/types/client/viewport.js +42 -0
  69. package/lib/types/connect.d.ts +7 -0
  70. package/lib/types/connect.js +61 -0
  71. package/lib/types/directories.d.ts +5 -0
  72. package/lib/types/directories.js +39 -0
  73. package/lib/types/index.d.ts +9 -0
  74. package/lib/types/index.js +21 -0
  75. package/lib/types/invariant.d.ts +16 -0
  76. package/lib/types/invariant.js +17 -0
  77. package/lib/types/protocol.d.ts +30 -0
  78. package/lib/types/protocol.js +17 -0
  79. package/locale/en.json +1 -0
  80. package/locale/zh.json +1 -0
  81. package/package.json +102 -0
@@ -0,0 +1,47 @@
1
+ /** Text-carrying block face mobile reads; attachment blocks are passed through opaquely. */
2
+ export interface QueueContentBlock {
3
+ readonly type: string;
4
+ readonly text?: string;
5
+ }
6
+ /**
7
+ * dsh-agent's inbox projection value, duck-typed to what mobile reads: the
8
+ * typed `UserMessage` face (`InboxState`) lives outside this package's compile
9
+ * closure — the projection's declared wire value is `JsonValue` rows. Rows
10
+ * carry `id`/`content`/`source`; a browser-submitted row echoes its prompt RPC
11
+ * identity as `rpcId` on a `kind: 'user'` source.
12
+ */
13
+ export interface MobileInboxState {
14
+ readonly 'next-turn'?: readonly {
15
+ readonly id: string;
16
+ readonly content: readonly QueueContentBlock[];
17
+ readonly source: {
18
+ readonly kind: string;
19
+ };
20
+ }[];
21
+ }
22
+ /** One queued prompt, normalized across host lines. */
23
+ export interface QueueRow {
24
+ readonly id: string;
25
+ /** Prompt-RPC correlation of a browser-submitted row; opaque wire identity. */
26
+ readonly rpcId?: unknown;
27
+ /** Full text of an all-text row, null when attachments make it uneditable. */
28
+ readonly text: string | null;
29
+ readonly content: readonly QueueContentBlock[];
30
+ }
31
+ /** The 0.1.5 session-snapshot queue row (alpha.2 deleted the snapshot queue for the inbox projection). */
32
+ export interface LegacyQueuedMessage {
33
+ readonly id: string;
34
+ readonly placement?: string;
35
+ readonly rpcId?: unknown;
36
+ readonly text?: string | null;
37
+ readonly content: readonly QueueContentBlock[];
38
+ }
39
+ /** All-text join, or null when any block is not text (the official QueueDock's edit rule). */
40
+ export declare function queueText(content: readonly QueueContentBlock[]): string | null;
41
+ /**
42
+ * Queued prompts on either host line: alpha.2 serves the `inbox` projection's
43
+ * `next-turn` rows (already the queued placement); 0.1.5 has no inbox key, so
44
+ * the undefined read falls back to the snapshot queue's `queued` rows.
45
+ */
46
+ export declare function queuedRows(legacyQueue: readonly LegacyQueuedMessage[] | undefined, inbox: MobileInboxState | undefined): readonly QueueRow[];
47
+ //# sourceMappingURL=queue.d.ts.map
@@ -0,0 +1,26 @@
1
+ /** All-text join, or null when any block is not text (the official QueueDock's edit rule). */
2
+ export function queueText(content) {
3
+ return content.every(block => block.type === 'text') ? content.map(block => block.text ?? '').join('') : null;
4
+ }
5
+ /**
6
+ * Queued prompts on either host line: alpha.2 serves the `inbox` projection's
7
+ * `next-turn` rows (already the queued placement); 0.1.5 has no inbox key, so
8
+ * the undefined read falls back to the snapshot queue's `queued` rows.
9
+ */
10
+ export function queuedRows(legacyQueue, inbox) {
11
+ const nextTurn = inbox?.['next-turn'];
12
+ if (nextTurn !== undefined) {
13
+ return nextTurn.map(row => ({
14
+ id: row.id,
15
+ ...(row.source.kind === 'user' && 'rpcId' in row.source ? { rpcId: row.source.rpcId } : {}),
16
+ text: queueText(row.content),
17
+ content: row.content,
18
+ }));
19
+ }
20
+ return (legacyQueue ?? []).filter(row => row.placement === 'queued').map(row => ({
21
+ id: row.id,
22
+ ...(row.rpcId === undefined ? {} : { rpcId: row.rpcId }),
23
+ text: row.text === undefined ? queueText(row.content) : row.text,
24
+ content: row.content,
25
+ }));
26
+ }
@@ -0,0 +1,6 @@
1
+ /** Relay to the installed Room UI so validation, first-task dispatch, directory
2
+ * picking and structured errors have one owner. Unknown layouts keep their UI. */
3
+ export declare function roomInviteButton(doc: Document): HTMLButtonElement | undefined;
4
+ export declare function openRoomInvite(doc: Document): boolean;
5
+ export declare function openRoomMemberSettings(doc: Document, name: string, stillCurrent: () => boolean): Promise<boolean>;
6
+ //# sourceMappingURL=roomActions.d.ts.map
@@ -0,0 +1,41 @@
1
+ /** Relay to the installed Room UI so validation, first-task dispatch, directory
2
+ * picking and structured errors have one owner. Unknown layouts keep their UI. */
3
+ export function roomInviteButton(doc) {
4
+ return [...doc.querySelectorAll('[data-slot="main.conversation"] [data-slot="conversation.session.header.actions"] button[aria-label]')]
5
+ .find(button => /^(+|\+)?\s*(邀请 agent|Invite agent)$/i.test(button.getAttribute('aria-label') ?? ''));
6
+ }
7
+ export function openRoomInvite(doc) {
8
+ const button = roomInviteButton(doc);
9
+ if (!button || button.disabled || !doc.documentElement.hasAttribute('data-dsh-mobile'))
10
+ return false;
11
+ button.click();
12
+ return true;
13
+ }
14
+ export async function openRoomMemberSettings(doc, name, stillCurrent) {
15
+ const root = doc.querySelector('[data-slot="main.conversation"]');
16
+ const tab = [...root?.querySelectorAll('[role="tab"]') ?? []].find(b => /^(成员|Members)$/i.test(b.textContent?.trim() ?? ''));
17
+ if (!root || !tab || tab.disabled || !stillCurrent())
18
+ return false;
19
+ tab.click();
20
+ return new Promise(resolve => {
21
+ let finished = false;
22
+ const finish = (ok) => { if (finished)
23
+ return; finished = true; observer.disconnect(); clearTimeout(timer); resolve(ok); };
24
+ const attempt = () => {
25
+ if (!root.isConnected || !stillCurrent() || !doc.documentElement.hasAttribute('data-dsh-mobile')) {
26
+ finish(false);
27
+ return;
28
+ }
29
+ const card = [...root.querySelectorAll('[data-member]')].find(el => el.dataset.member === name && !el.closest('[role="dialog"]'));
30
+ const button = [...card?.querySelectorAll('button') ?? []].find(b => /^(编辑|Edit)$/i.test(b.textContent?.trim() ?? ''));
31
+ if (button && !button.disabled) {
32
+ finish(true);
33
+ button.click();
34
+ }
35
+ };
36
+ const observer = new MutationObserver(attempt);
37
+ const timer = setTimeout(() => finish(false), 3000);
38
+ observer.observe(root, { subtree: true, childList: true });
39
+ attempt();
40
+ });
41
+ }
@@ -0,0 +1,44 @@
1
+ /** Optional Room Remote vocabulary, audited against dsh-room's public wire face.
2
+ * No sibling runtime import, registration, roster persistence or agent execution. */
3
+ export interface MobileMember {
4
+ name: string;
5
+ kind: 'main-agent' | 'cli';
6
+ provider?: string;
7
+ instructions?: string;
8
+ cwd?: string;
9
+ childSessionId?: string;
10
+ }
11
+ export interface MobileRoom {
12
+ members: readonly MobileMember[];
13
+ runs: readonly {
14
+ member: string;
15
+ state: string;
16
+ }[];
17
+ }
18
+ export type RoomRemoteFace = Record<string, (request: Record<string, unknown>) => Promise<{
19
+ ok: boolean;
20
+ value?: unknown;
21
+ }>>;
22
+ export declare class RoomFailure extends Error {
23
+ readonly code: string;
24
+ constructor(code: string);
25
+ }
26
+ export declare class MobileRooms {
27
+ private remote;
28
+ private cache;
29
+ private pending;
30
+ private listeners;
31
+ private version;
32
+ private alive;
33
+ constructor(remote: () => RoomRemoteFace | undefined);
34
+ readonly subscribe: (fn: () => void) => () => void;
35
+ readonly getSnapshot: () => number;
36
+ available(): boolean;
37
+ get(id: string): MobileRoom | null | undefined;
38
+ refresh(id: string, force?: boolean): Promise<MobileRoom | null | undefined>;
39
+ private fetch;
40
+ private publish;
41
+ private readState;
42
+ dispose(): void;
43
+ }
44
+ //# sourceMappingURL=rooms.d.ts.map
@@ -0,0 +1,75 @@
1
+ export class RoomFailure extends Error {
2
+ code;
3
+ constructor(code) {
4
+ super(code);
5
+ this.code = code;
6
+ }
7
+ }
8
+ export class MobileRooms {
9
+ remote;
10
+ cache = new Map();
11
+ pending = new Map();
12
+ listeners = new Set();
13
+ version = 0;
14
+ alive = true;
15
+ constructor(remote) {
16
+ this.remote = remote;
17
+ }
18
+ subscribe = (fn) => { this.listeners.add(fn); return () => { this.listeners.delete(fn); }; };
19
+ getSnapshot = () => this.version;
20
+ available() { return typeof this.remote()?.getState === 'function'; }
21
+ get(id) { return this.cache.get(id)?.state; }
22
+ async refresh(id, force = false) {
23
+ if (!this.alive || !this.available())
24
+ return undefined;
25
+ const cached = this.cache.get(id);
26
+ if (!force && cached && Date.now() - cached.at < 15000)
27
+ return cached.state;
28
+ const running = this.pending.get(id);
29
+ if (running)
30
+ return running;
31
+ const work = this.fetch(id).finally(() => this.pending.delete(id));
32
+ this.pending.set(id, work);
33
+ return work;
34
+ }
35
+ async fetch(id) {
36
+ try {
37
+ const state = await this.readState(id);
38
+ if (!Array.isArray(state.members) || !Array.isArray(state.runs))
39
+ throw new RoomFailure('unsupported');
40
+ this.publish(id, state);
41
+ return state;
42
+ }
43
+ catch (error) {
44
+ if (error instanceof RoomFailure && error.code === 'not-a-room') {
45
+ this.publish(id, null);
46
+ return null;
47
+ }
48
+ return undefined; // Offline/removed plugin is unknown, never silently a one-member room.
49
+ }
50
+ }
51
+ publish(id, state) {
52
+ if (!this.alive)
53
+ return;
54
+ this.cache.delete(id);
55
+ this.cache.set(id, { state, at: Date.now() });
56
+ if (this.cache.size > 200)
57
+ this.cache.delete(this.cache.keys().next().value);
58
+ this.version++;
59
+ for (const fn of this.listeners)
60
+ fn();
61
+ }
62
+ async readState(sessionId) {
63
+ const remote = this.remote();
64
+ if (!remote?.getState)
65
+ throw new RoomFailure('unavailable');
66
+ const carried = await remote.getState({ sessionId });
67
+ if (!carried.ok)
68
+ throw new RoomFailure('connection');
69
+ const result = carried.value;
70
+ if (!result?.ok || !result.value)
71
+ throw new RoomFailure(result?.error?.code ?? 'unknown');
72
+ return result.value;
73
+ }
74
+ dispose() { this.alive = false; this.listeners.clear(); this.cache.clear(); }
75
+ }
@@ -0,0 +1,4 @@
1
+ export declare const ORDINARY_TITLE = "[data-slot=\"main.conversation\"] header:has([data-conversation-header-corner]) nav:has(> span:only-child > button:disabled + [data-slot=\"conversation.session.header.lineage\"]:empty)";
2
+ /** Local overrides target official slot anchors; frame attributes are verified before activation. */
3
+ export declare const MOBILE_CSS = "\nhtml[data-dsh-mobile] { --mobile-bar: 56px; --mobile-accent: #4d6bfe; }\nhtml[data-dsh-mobile] body { overscroll-behavior: none; }\nhtml[data-dsh-mobile] [data-mobile-frame] {\n background: var(--dsw-alias-bg-base, #fff);\n box-sizing: border-box; height: var(--mobile-height, 100dvh) !important;\n padding-top: var(--mobile-bar); padding-bottom: env(safe-area-inset-bottom, 0px);\n grid-template-columns: 0px minmax(0, 1fr) 0px !important;\n grid-template-rows: minmax(0, 1fr); transition: none !important;\n}\nhtml[data-dsh-mobile] [data-mobile-frame] > div:has(> [data-slot=\"sidebar\"]) {\n position: absolute; inset: var(--mobile-bar) auto 0 0; z-index: 22;\n width: min(88vw, 360px); border-radius: 0 24px 24px 0;\n box-shadow: 16px 0 60px #15244320;\n}\nhtml[data-dsh-mobile] [data-mobile-frame][data-sidebar-collapsed] > div:has(> [data-slot=\"sidebar\"]) { display: none; }\nhtml[data-dsh-mobile] [data-mobile-frame] > div:has(> [data-slot=\"main\"]) { grid-column: 2; grid-row: 1; min-width: 0; }\nhtml[data-dsh-mobile] [data-mobile-frame] > [data-rightbar-col] { grid-column: 3; grid-row: 1; }\nhtml[data-dsh-mobile] [data-mobile-frame]:not([data-rightbar-collapsed]) > [data-rightbar-col] {\n position: absolute; inset: var(--mobile-bar) 0 0; z-index: 24; width: 100%;\n background: var(--dsw-alias-bg-base, white); min-width: 0;\n}\nhtml[data-dsh-mobile] [data-mobile-frame] > [data-side] { display: none; }\nhtml[data-dsh-mobile] [data-mobile-frame] > [data-shell-overlay] { z-index: 23; pointer-events: none; }\nhtml[data-dsh-mobile] [data-slot=\"main.conversation\"] > div {\n --dsh-chat-content-width: calc(100vw - 48px);\n --dsh-composer-side-clearance: 12px;\n}\nhtml[data-dsh-mobile] [data-composer-card] { border-radius: 24px; }\nhtml[data-dsh-mobile] [data-composer-card] [contenteditable=\"true\"] { font-size: 16px; }\nhtml[data-dsh-mobile] [data-width-handle] { display: none; }\nhtml[data-dsh-mobile] [data-composer-seat] { padding-bottom: 8px; }\nhtml[data-dsh-mobile] [data-conversation-scroll] { overscroll-behavior-y: contain; }\nhtml[data-dsh-mobile] [data-slot=\"conversation.header.tabs\"] { overflow-x: auto; }\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.left\"],\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.right\"] { max-width: 100%; }\n[data-mobile-toolbar] {\n position: absolute; inset: 0 0 auto; height: var(--mobile-bar, 56px); display: flex;\n align-items: center; justify-content: space-between; gap: 8px; padding: 0 12px;\n box-sizing: border-box; background: var(--dsw-alias-bg-base, #fff);\n border-bottom: 1px solid var(--dsw-alias-border-l3, #edf0f5); pointer-events: auto;\n}\n[data-mobile-toolbar] button, [data-mobile-dialog] button {\n border: 0; border-radius: 16px; min-height: 44px; min-width: 44px;\n padding: 10px 14px; font: inherit; cursor: pointer;\n color: var(--dsw-alias-label-primary, #152443); background: transparent;\n -webkit-tap-highlight-color: transparent;\n}\n[data-mobile-toolbar] button:hover, [data-mobile-dialog] button:hover { background: #4d6bfe12; }\n[data-mobile-toolbar] strong { font-size: 18px; font-weight: 600; letter-spacing: -0.6px; color: var(--mobile-accent, #4d6bfe); }\n[data-mobile-toolbar] small { color: var(--dsw-alias-label-tertiary, #778195); font-size: 11px; display: block; text-align: center; }\n[data-mobile-toolbar] svg { display: block; }\n[data-mobile-shade] { position: absolute; inset: var(--mobile-bar) 0 0 min(88vw, 360px); border: 0; background: #15244330; pointer-events: auto; }\n[data-mobile-dialog] {\n color: var(--dsw-alias-label-primary, #152443); background: var(--dsw-alias-bg-base, white);\n border: 1px solid var(--dsw-alias-border-l3, #e6eaf2); border-radius: 28px;\n width: min(440px, calc(100vw - 32px)); box-sizing: border-box; padding: 24px;\n max-height: calc(100dvh - 48px); overflow-y: auto; box-shadow: 0 24px 90px #15244325;\n}\n[data-mobile-dialog] input { box-sizing: border-box; width: 100%; margin-top: 12px; padding: 14px; border: 1px solid #ccd3df; border-radius: 14px; font: inherit; font-size: 16px; }\n[data-mobile-dialog] button:disabled { opacity: .4; cursor: default; }\n[data-mobile-dialog]::backdrop { background: #15244355; backdrop-filter: blur(8px); }\n[data-mobile-dialog] h2 { margin: 0 0 24px; font-size: 24px; font-weight: 500; }\n[data-mobile-dialog] h3 { font-size: 13px; font-weight: 500; color: var(--dsw-alias-label-tertiary, #778195); margin: 24px 0 10px; }\n[data-mobile-dialog] p { font-size: 13px; line-height: 1.7; color: var(--dsw-alias-label-tertiary, #778195); overflow-wrap: anywhere; }\n[data-mobile-dialog] [role=\"group\"] { display: flex; flex-wrap: wrap; gap: 6px; }\n[data-mobile-dialog] button[aria-pressed=\"true\"] { color: #4d6bfe; background: #4d6bfe12; }\n[data-mobile-dialog] [data-mobile-done] { display: block; width: 100%; margin-top: 24px; background: #4d6bfe; color: white; border-radius: 100px; }\n\n/* Hide an empty ordinary breadcrumb; populated catalogs keep their Host trigger. */\nhtml[data-dsh-mobile]:has([data-mobile-session-title]) [data-slot=\"main.conversation\"] header:has([data-conversation-header-corner]) nav:has(> span:only-child > button:disabled + [data-slot=\"conversation.session.header.lineage\"]:empty) { display:none; }\nhtml[data-dsh-mobile] [data-mobile-lineage-count] { flex-shrink:0; white-space:nowrap; }\n[data-mobile-restore] { position:fixed; right:16px; bottom:max(16px,env(safe-area-inset-bottom)); z-index:1200; pointer-events:auto; min-height:44px; padding:10px 18px; border:1px solid #4d6bfe40; border-radius:24px; background:var(--dsw-alias-bg-base,white); color:#4d6bfe; font:inherit; box-shadow:0 3px 18px #15244318; }\n\n/* Mobile-owned library: scrolling content and a separate keyboard-aware search dock. */\n[data-mobile-library] { position:absolute; inset:var(--mobile-bar,56px) 0 0; display:flex; flex-direction:column; overflow:hidden; pointer-events:auto; background:var(--dsw-alias-bg-base,white); color:var(--dsw-alias-label-primary,#181a20); }\n[data-mobile-library] button { font:inherit; cursor:pointer; color:inherit; -webkit-tap-highlight-color:transparent; }\n[data-mobile-library-header] { display:flex; align-items:center; justify-content:space-between; flex-shrink:0; gap:12px; padding:12px 22px 14px; }\n[data-mobile-library] h1 { margin:0; font-size:30px; font-weight:600; letter-spacing:-1px; }\n[data-mobile-grouping] { display:flex; padding:3px; border-radius:13px; background:var(--dsw-alias-bg-module-platform,#f2f3f6); }\n[data-mobile-grouping] button { border:0; border-radius:10px; min-height:44px; padding:0 12px; font-size:12px; background:none; }\n[data-mobile-grouping] button[aria-pressed=true] { background:var(--dsw-alias-button-floating-fill,white); box-shadow:0 1px 4px #17203815; }\n[data-mobile-recents] { flex:1; min-height:0; overflow-y:auto; padding:0 22px 12px; overscroll-behavior:contain; }\n[data-mobile-session-group] h2 { color:var(--dsw-alias-label-tertiary,#727680); font-size:12px; font-weight:500; margin:16px 0 4px; }\n[data-mobile-session-group] ul { list-style:none; padding:0; margin:0; }\n[data-mobile-workspace-group] { display:grid; grid-template-columns:18px minmax(0,1fr) auto 18px; align-items:center; width:100%; gap:9px; padding:14px 0; min-height:48px; text-align:left; background:none; border:0; }\n[data-mobile-workspace-group] svg { display:block; }\n[data-mobile-workspace-group] strong, [data-mobile-workspace-group] small { line-height:20px; margin:0; }\n[data-mobile-workspace-group] strong { min-width:0; overflow-wrap:anywhere; font-size:14px; font-weight:500; }\n[data-mobile-workspace-group] small { color:var(--dsw-alias-label-tertiary,#727680); font-size:12px; }\n[data-mobile-session] { display:flex; align-items:center; gap:12px; width:100%; min-height:78px; padding:16px 0; text-align:left; border:0; border-bottom:1px solid var(--dsw-alias-border-l3,#e8e9ee); background:none; }\n[data-mobile-session-copy] { min-width:0; flex:1; }\n[data-mobile-session-copy] strong { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:16px; line-height:1.5; font-weight:500; }\n[data-mobile-session-copy] small { display:block; color:var(--dsw-alias-label-tertiary,#727680); font-size:12px; margin-top:6px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n[data-mobile-session] time { font-size:11px; color:var(--dsw-alias-label-tertiary,#727680); flex-shrink:0; }\n[data-mobile-session]:active { background:#4d6bfe0a; }\n[data-mobile-activity] { font-size:11px; color:var(--mobile-accent,#4d6bfe); white-space:nowrap; }\n[data-mobile-activity]::before { content:''; display:inline-block; width:5px; height:5px; margin-right:5px; vertical-align:middle; border-radius:50%; background:currentColor; }\n[data-mobile-empty] { color:var(--dsw-alias-label-tertiary,#727680); padding:32px 0; text-align:center; font-size:14px; }\n[data-mobile-search-dock] { display:flex; flex-shrink:0; align-items:center; gap:10px; padding:12px 16px max(10px,env(safe-area-inset-bottom)); background:var(--dsw-alias-bg-base,white); }\n[data-mobile-search] { display:flex; flex:1; min-width:0; align-items:center; gap:8px; min-height:50px; border:1px solid var(--dsw-alias-border-l3,#e8e9ee); border-radius:28px; padding:0 16px; background:var(--dsw-alias-bg-module-platform,#f2f3f6); color:var(--dsw-alias-label-tertiary,#727680); }\n[data-mobile-search] svg { flex-shrink:0; }\n[data-mobile-search] input { width:100%; min-width:0; border:0; background:none; color:var(--dsw-alias-label-primary,#181a20); font:inherit; font-size:16px; padding:12px 0; }\n[data-mobile-search]:focus-within { outline:2px solid #4d6bfe65; outline-offset:2px; }\n[data-mobile-scan] { display:grid; place-items:center; width:50px; height:50px; flex-shrink:0; border:1px solid var(--dsw-alias-border-l3,#e8e9ee); background:var(--dsw-alias-bg-module-platform,#f2f3f6); border-radius:50%; }\n[data-mobile-search-cancel] { min-height:50px; min-width:44px; color:var(--mobile-accent,#4d6bfe) !important; background:none; border:0; font-size:14px; }\n[data-mobile-nav-title] { flex:1; min-width:0; text-align:center; }\n[data-mobile-nav-title] strong { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:var(--dsw-alias-label-primary,#181a20); font-size:16px; }\nhtml[data-dsh-mobile] [data-mobile-toolbar] { border-bottom:0; padding:0 12px; }\n[data-mobile-toolbar] button { color:var(--mobile-accent,#4d6bfe); }\n[data-mobile-connection-status] { position:absolute; top:var(--mobile-bar); left:12px; right:12px; display:flex; align-items:center; justify-content:space-between; gap:12px; border-radius:12px; padding:0 12px; font-size:12px; background:var(--dsw-alias-bg-module-platform,#f2f3f6); pointer-events:auto; z-index:1; }\n[data-mobile-connection-status] button { border:0; background:none; color:var(--mobile-accent,#4d6bfe); min-height:40px; }\nhtml[data-dsh-mobile]:has([data-mobile-connection-status]) { --mobile-bar:96px; }\nhtml[data-dsh-mobile]:has([data-mobile-connection-status]) [data-mobile-toolbar] { height:56px; }\nhtml[data-dsh-mobile]:has([data-mobile-connection-status]) [data-mobile-connection-status] { top:56px; }\n[data-mobile-dialog] { margin:auto 0 0; width:100%; max-width:none; max-height:75dvh; border-radius:26px 26px 0 0; padding-bottom:max(24px,env(safe-area-inset-bottom)); }\n[data-mobile-dialog] [data-mobile-option] { width:100%; display:block; text-align:left; border-radius:0; border-bottom:1px solid var(--dsw-alias-border-l3,#e8e9ee); padding:14px 0; }\n/* Preserve the official composer, controls, confirmations and message actions. */\nhtml[data-dsh-mobile] [data-composer-card] { border-radius:20px; box-shadow:none; background:var(--dsw-alias-bg-module-platform,#f2f3f6); }\nhtml[data-dsh-mobile] [data-composer-card] [data-input-scroll] { max-height:min(28dvh,220px); }\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child { flex-wrap:wrap; gap:8px; }\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child > div { flex-wrap:wrap; min-width:0; gap:6px; }\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child > div:last-child { margin-left:auto; }\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child button { min-height:44px; }\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.model\"] { min-width:0; max-width:min(62vw,270px); }\n/* Dock the same blank-session composer; the checked hero mark anchors its optional headline. */\nhtml[data-dsh-mobile] [data-slot=\"main.conversation\"] [data-phase=\"hero\"] [data-conversation-scroll] { justify-content:flex-end; }\nhtml[data-dsh-mobile] [data-slot=\"main.conversation\"] [data-phase=\"hero\"] [data-composer-seat] { flex:1; min-height:0; }\nhtml[data-dsh-mobile] [data-phase=\"hero\"] [data-composer-seat] > div:has([data-slot=\"conversation.hero.brand.mark\"]) { flex:1; align-self:stretch; padding-bottom:8px; }\nhtml[data-dsh-mobile] [data-phase=\"hero\"] [data-composer-seat] > div > div:first-child:has([data-slot=\"conversation.hero.brand.mark\"]) { flex:1; min-height:100px; justify-content:center; }\n/* rc1 semantic menu anchors, only inside the official composer/hero seats. */\nhtml[data-dsh-mobile] :is([data-composer-card],[data-slot=\"conversation.hero.agentPreset\"],[data-slot=\"conversation.hero.workspace\"]) [role=\"menu\"]:not([role=\"menu\"] [role=\"menu\"]) {\n position:fixed !important; inset:auto 12px max(12px,env(safe-area-inset-bottom)) !important; width:auto !important; min-width:0; max-width:none; max-height:min(65dvh,520px); overflow-y:auto; border-radius:24px; padding:12px; z-index:1100;\n}\nhtml[data-dsh-mobile] :is([data-composer-card],[data-slot=\"conversation.hero.agentPreset\"],[data-slot=\"conversation.hero.workspace\"]) [role=\"menuitem\"] { min-height:48px; }\n/* Approved mobile visual system. Native SwiftUI owns its safe area; Safari owns its own. */\n/* Resolve aliases on body: the official theme presenter publishes its palette there.\n Root aliases resolve before body tokens exist and freeze their light fallbacks. */\nhtml[data-dsh-mobile] body { --mobile-face:var(--dsw-alias-button-floating-fill,#fff); --mobile-soft:var(--dsw-alias-bg-module-platform,#f3f4f6); --mobile-line:var(--dsw-alias-border-l3,#eceef1); --mobile-accent:var(--dsw-alias-state-business-primary,#4d6bfe); --mobile-shadow:0 6px 24px #1823380b; }\nhtml[data-mobile-native-insets] [data-mobile-frame] { padding-bottom:0; }\nhtml[data-mobile-native-insets] :is([data-mobile-search-dock],[data-mobile-dialog]) { padding-bottom:8px; }\nhtml[data-dsh-mobile] [data-mobile-toolbar] { height:64px; padding:8px 16px; }\nhtml[data-dsh-mobile] { --mobile-bar:64px; }\nhtml[data-dsh-mobile]:has([data-mobile-connection-status]) { --mobile-bar:104px; }\nhtml[data-dsh-mobile]:has([data-mobile-connection-status]) [data-mobile-toolbar] { height:64px; }\nhtml[data-dsh-mobile]:has([data-mobile-connection-status]) [data-mobile-connection-status] { top:64px; }\n[data-mobile-toolbar] button { display:grid; place-items:center; width:44px; height:44px; padding:0; border-radius:50%; corner-shape:round; background:var(--mobile-face); box-shadow:var(--mobile-shadow); color:var(--dsw-alias-label-primary,#202226); }\n[data-mobile-nav-title] strong { font-weight:500; letter-spacing:0; }\n[data-mobile-library] h1 { font-size:26px; font-weight:500; letter-spacing:-.7px; }\n[data-mobile-grouping] { border-radius:19px; }\n[data-mobile-grouping] button { border-radius:16px; min-height:38px; }\n[data-mobile-library-header] { padding:16px 20px; }\n[data-mobile-recents] { padding:0 12px 12px; }\n[data-mobile-workspace-group] { padding:12px 10px; color:var(--dsw-alias-label-tertiary,#74767c)!important; }\n[data-mobile-workspace-group] strong { font-size:13px; font-weight:400; }\n[data-mobile-session-group] h2 { padding:0 10px; }\n[data-mobile-session] { border:0; border-radius:16px; padding:14px 12px; min-height:68px; }\n[data-mobile-session][aria-current=page] { background:var(--mobile-soft); }\n[data-mobile-session-copy] strong { font-size:15px; font-weight:400; }\n[data-mobile-session-copy] small:empty { display:none; }\n[data-mobile-search-dock] { padding:12px 14px max(8px,env(safe-area-inset-bottom)); gap:8px; }\n[data-mobile-search] { min-height:50px; background:var(--mobile-face); border:1px solid var(--mobile-line); box-shadow:var(--mobile-shadow); }\n[data-mobile-search]:focus-within { outline:none; }\n[data-mobile-search] input:focus, html[data-dsh-mobile] [data-composer-card] [contenteditable]:focus { outline:none!important; box-shadow:none!important; }\n[data-mobile-search] input::placeholder { color:var(--dsw-alias-label-secondary,#61666b); opacity:1; }\nhtml[data-dsh-mobile] [data-composer-placeholder] { color:var(--dsw-alias-label-secondary,#61666b); }\n[data-mobile-search] input, html[data-dsh-mobile] [data-composer-card] [contenteditable] { caret-color:var(--mobile-accent); }\nhtml[data-mobile-input=keyboard] [data-mobile-search]:focus-within, html[data-mobile-input=keyboard] [data-composer-card]:has([contenteditable]:focus) { outline:2px solid var(--mobile-accent); outline-offset:3px; }\n[data-mobile-scan], [data-mobile-search-cancel] { display:grid; place-items:center; min-width:50px; width:50px; height:50px; border:1px solid var(--mobile-line); background:var(--mobile-face); box-shadow:var(--mobile-shadow); border-radius:50%; corner-shape:round; color:var(--dsw-alias-label-primary,#202226)!important; }\nhtml[data-dsh-mobile] [data-composer-card] { border-radius:25px; border:1px solid var(--mobile-line); background:var(--mobile-face); box-shadow:var(--mobile-shadow); }\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child { gap:4px; }\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child > div { gap:3px; }\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child button { min-height:40px; }\n/* rc1's two direct toolbar buttons precede the hidden attachment input.\n Scope narrowly so plugin buttons, permission menus and send retain their own states. */\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child > div:first-child > button:has(~ input[type=file][hidden]) { width:40px; height:40px; min-width:40px; padding:0; background:transparent; border-radius:50%; }\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child > div:first-child > button:has(~ input[type=file][hidden]):active:not(:disabled) { background:var(--dsw-alias-interactive-bg-active); }\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.model\"] { max-width:min(43vw,210px); }\nhtml[data-dsh-mobile] [data-composer-seat] { padding-bottom:2px; }\n/* The compact stats row on both host lines: 0.1.5 mounts it as\n [data-composer-stats]; alpha.2 deleted that attribute and wraps the dock\n (stats pills + context meter) in a real flex row directly after the card.\n On 0.1.5 the sibling selector lands on the display:contents slot wrapper \u2014\n inert for padding/gap, same font-size by inheritance \u2014 so both rules stay. */\nhtml[data-dsh-mobile] [data-composer-stats], html[data-dsh-mobile] [data-composer-card] + div { padding:4px 12px 0; gap:10px; font-size:11px; }\nhtml[data-dsh-mobile] [data-composer-stats] button, html[data-dsh-mobile] [data-composer-card] + div button { min-height:32px; }\n/* Follow the real chain fallback -> stack -> HeroShell path, not display:contents wrappers. */\nhtml[data-dsh-mobile] [data-phase=hero] [data-composer-seat] { flex:1 0 auto; }\nhtml[data-dsh-mobile] [data-phase=hero] [data-chain-overlay-fallback=\"conversation.composer\"] > div:has([data-mobile-welcome]) { flex:1; align-self:stretch; padding-bottom:0; width:100%; }\nhtml[data-dsh-mobile] [data-phase=hero] [data-chain-overlay-fallback=\"conversation.composer\"] > div > div:has([data-mobile-welcome]) { flex:1; height:auto; min-height:160px; padding:24px 16px 40px; }\nhtml[data-dsh-mobile] [data-phase=hero] span:has(> [data-slot=\"conversation.hero.brand.mark\"]):has([data-mobile-welcome]) + span { display:none; }\n[data-mobile-welcome] { text-align:center; }\n[data-mobile-welcome] small { color:var(--mobile-accent); letter-spacing:3px; font-size:13px; }\n[data-mobile-welcome] h2 { font-size:25px; font-weight:500; line-height:1.4; margin:16px 0 9px; letter-spacing:-.6px; }\n[data-mobile-welcome] p { font-size:13px; line-height:1.6; margin:0; color:var(--dsw-alias-label-tertiary,#74767c); }\nhtml[data-dsh-mobile]:has([data-phase=hero]) [data-mobile-toolbar][data-library=false] [data-mobile-new=true] { visibility:hidden; }\nhtml[data-dsh-mobile] [data-phase=hero] div:has(> [data-slot=\"conversation.hero.workspace\"]) { gap:6px; padding:6px 18px; flex-wrap:wrap; }\nhtml[data-dsh-mobile] [data-phase=hero] div:has(> [data-slot=\"conversation.hero.workspace\"]) > button, html[data-dsh-mobile] [data-slot=\"conversation.hero.agentPreset\"] button[aria-haspopup] { border-radius:18px; min-height:40px; font-size:13px; background:var(--mobile-soft); }\n/* Quiet, read-only metadata below the mobile title. */\n[data-mobile-subtitle] { display:flex; justify-content:center; align-items:center; gap:5px; margin-top:3px; font-size:11px; line-height:16px; color:var(--dsw-alias-label-secondary,#61666b); }\n[data-mobile-subtitle] > span:first-child { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n[data-mobile-subtitle] > span:last-child:not(:first-child) { flex-shrink:0; max-width:60%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\nhtml[data-dsh-mobile]:has([data-mobile-session-title]) [data-mobile-header-hidden], [data-mobile-hidden-tab] { display:none!important; }\n/* Fold only the identified official trigger buttons, not their menus or owners. */\n[data-mobile-folded-action] { display:none!important; }\n[data-mobile-tools-seat] { display:contents; }\nhtml[data-dsh-mobile] [data-mobile-tools-open] { display:grid; place-items:center; width:44px; height:44px; min-width:44px; padding:0; border:0; border-radius:50%; corner-shape:round; color:var(--dsw-alias-label-primary); background:var(--mobile-soft); }\n[data-mobile-tools-dialog] { box-sizing:border-box; margin:auto auto 0; width:min(100%,520px); max-width:100%; max-height:75dvh; overflow-y:auto; padding:16px 20px max(20px,env(safe-area-inset-bottom)); border:1px solid var(--mobile-line); border-bottom:0; border-radius:26px 26px 0 0; background:var(--mobile-face); color:var(--dsw-alias-label-primary); box-shadow:0 -8px 40px #0002; }\n[data-mobile-tools-dialog]::backdrop { background:#0005; }\n[data-mobile-tools-dialog] [data-mobile-tools-handle] { width:34px; height:4px; margin:0 auto 12px; border-radius:4px; background:var(--dsw-alias-label-tertiary); opacity:.5; }\n[data-mobile-tools-dialog] header { display:flex; align-items:center; justify-content:space-between; margin-bottom:12px; }\n[data-mobile-tools-dialog] strong { font-size:16px; font-weight:500; }\n[data-mobile-tools-dialog] button { font:inherit; color:inherit; cursor:pointer; border:0; background:transparent; -webkit-tap-highlight-color:transparent; }\n[data-mobile-tools-dialog] button:disabled { opacity:.45; cursor:default; }\n[data-mobile-tools-dialog] header button { width:44px; height:44px; display:grid; place-items:center; border-radius:50%; padding:0; }\n[data-mobile-tools-grid] { display:grid; grid-template-columns:1fr 1fr; gap:12px; }\n[data-mobile-tools-grid] button { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:10px; min-height:92px; padding:12px; border-radius:20px; background:var(--mobile-soft); font-size:14px; }\n[data-mobile-tools-permission] { display:flex; align-items:center; width:100%; gap:10px; margin-top:12px; min-height:64px; padding:12px 0; text-align:left; font-size:14px!important; }\n[data-mobile-tools-permission] > span { flex-shrink:0; }\n[data-mobile-tools-permission] > small { margin-left:auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:12px; color:var(--dsw-alias-label-secondary); }\n[data-mobile-tools-dialog] svg { flex:none; }\nhtml[data-mobile-input=pointer] [data-mobile-tools-dialog] button:focus { outline:none; }\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child > div:last-child > button:has(>svg):not([aria-haspopup]) { width:44px; height:44px; min-width:44px; padding:0; border-radius:50%; corner-shape:round; transform:none; }\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child > div:last-child > button:has(>svg):not([aria-haspopup]) > svg { width:20px; height:20px; flex:none; }\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.model\"] { max-width:min(56vw,260px); }\n/* Keep the send row on one line; 0.1.5 also seats the host context meter in it\n (alpha.2 moved the meter into the dock row below the card). */\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child, html[data-dsh-mobile] [data-composer-card] > div:last-child > div:last-child { flex-wrap:nowrap; }\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.model\"] { min-width:0; max-width:min(43vw,210px); flex:1 1 auto; }\n/* rc1's model slot uses display:contents. Size its root and restore the label\n after folding the other input controls; unknown renderers keep their markup. */\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.model\"] > div { min-width:0; max-width:min(43vw,210px); }\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.model\"] > div > button[aria-haspopup=\"menu\"]:has(> svg:first-child + span) { max-width:100%; height:44px; }\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.model\"] > div > button[aria-haspopup=\"menu\"] > svg:first-child:has(+ span) { display:none; }\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.model\"] > div > button[aria-haspopup=\"menu\"] > svg:first-child + span { display:block; }\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child > div:last-child > span:has(> button[aria-haspopup=\"dialog\"] > svg > circle) { position:static; flex:0 0 auto; }\n/* Translucency belongs to surfaces. Foreground colors remain fully opaque. */\nhtml[data-dsh-mobile] body { --mobile-shadow:0 6px 22px color-mix(in srgb,var(--dsw-alias-label-primary) 9%,transparent); --mobile-glass:color-mix(in srgb,var(--mobile-face) 86%,transparent); --mobile-edge:color-mix(in srgb,var(--dsw-alias-label-primary) 14%,transparent); }\nhtml[data-dsh-mobile] :is([data-mobile-toolbar] button,[data-mobile-scan],[data-mobile-search-cancel],[data-mobile-search],[data-mobile-tools-open],[data-composer-card]) {\n background:var(--mobile-glass); border:1px solid var(--mobile-edge); box-shadow:inset 0 1px 0 color-mix(in srgb,var(--dsw-alias-label-primary) 5%,transparent),var(--mobile-shadow);\n -webkit-backdrop-filter:blur(18px) saturate(1.25); backdrop-filter:blur(18px) saturate(1.25);\n}\nhtml[data-dsh-mobile] :is([data-mobile-toolbar] button,[data-mobile-scan],[data-mobile-tools-open]):active { background:var(--mobile-soft); transform:scale(.97); }\nhtml[data-dsh-mobile] [data-mobile-icon] { flex-shrink:0; aspect-ratio:1; }\n@media (prefers-reduced-transparency: reduce) { html[data-dsh-mobile] body { --mobile-glass:var(--mobile-face); } }\n@supports not (backdrop-filter:blur(1px)) { html[data-dsh-mobile] body { --mobile-glass:var(--mobile-face); } }\nhtml[data-dsh-mobile] [data-composer-card] > div:last-child > div:last-child { flex:1 1 0; justify-content:flex-end; }\nhtml[data-dsh-mobile] [data-composer-seat] div:has(> textarea):has(> div > button[aria-label]) { border-radius:25px; background:var(--mobile-glass); border:1px solid var(--mobile-edge); box-shadow:var(--mobile-shadow); -webkit-backdrop-filter:blur(18px); backdrop-filter:blur(18px); }\nhtml[data-dsh-mobile] [data-composer-seat] textarea { font-size:16px; max-height:26dvh; }\nhtml[data-dsh-mobile] [data-composer-seat] div:has(> textarea) > div > button[aria-label] { width:44px; height:44px; min-width:44px; padding:0; border-radius:50%; }\nhtml[data-dsh-mobile] [data-composer-seat]:has([data-mobile-room-queue]) [data-testid=\"room-queue-strip\"] { display:none; }\n[data-mobile-room-queue] { padding:4px 16px; }\n[data-mobile-queue-pill] { border:1px solid var(--mobile-edge); background:var(--mobile-glass); border-radius:20px; padding:8px 14px; min-height:36px; color:var(--dsw-alias-label-primary); }\n[data-mobile-queue-row] { padding:8px 0; border-bottom:1px solid var(--mobile-line); }\n[data-mobile-queue-row] p { overflow-wrap:anywhere; white-space:pre-wrap; font-size:14px; }\n[data-mobile-queue-row] button { min-height:44px; padding:8px 12px; }\n[data-mobile-queue-row] textarea { width:100%; background:var(--mobile-soft); color:var(--dsw-alias-label-primary); border:1px solid var(--mobile-line); border-radius:12px; padding:8px; }\n/* Mobile action surfaces retain each plugin's controls and callback semantics. */\n[data-mobile-message-menu] { position:fixed; margin:0; width:240px; max-width:calc(100vw - 24px); padding:8px; border-radius:22px; border:1px solid var(--mobile-edge); background:var(--mobile-glass); color:var(--dsw-alias-label-primary); box-shadow:var(--mobile-shadow); -webkit-backdrop-filter:blur(22px); backdrop-filter:blur(22px); }\n[data-mobile-message-menu]::backdrop { background:#0002; }\n[data-mobile-message-menu] button { display:flex; gap:14px; align-items:center; width:100%; min-height:48px; padding:8px 14px; border:0; border-radius:14px; background:none; color:inherit; font:inherit; text-align:left; }\n[data-mobile-message-menu] button:active { background:var(--mobile-soft); }\n[data-mobile-message-menu] svg { width:20px; height:20px; flex:none; }\n[data-mobile-message-menu] button:disabled { opacity:.45; }\n[data-mobile-toolbar]:has([data-mobile-members-open]) > [data-mobile-new] { display:none; }\n[data-mobile-members-open] { position:relative; }\n[data-mobile-members-open] small { position:absolute; bottom:-3px; right:-2px; min-width:16px; border-radius:10px; font-size:10px; background:var(--mobile-soft); color:var(--dsw-alias-label-primary); }\n[data-mobile-room-dialog] { text-align:left; line-height:1.5; }\n[data-mobile-room-dialog] header button { background:var(--mobile-soft); }\n[data-mobile-room-dialog] label { display:block; font-size:13px; margin:16px 0; }\n[data-mobile-room-dialog] :is(input,textarea,select) { display:block; width:100%; box-sizing:border-box; border:1px solid var(--mobile-line); border-radius:14px; padding:12px; margin-top:6px; font:inherit; font-size:16px; background:var(--mobile-soft); color:var(--dsw-alias-label-primary); }\n[data-mobile-room-dialog] [role=alert] { color:var(--dsw-alias-state-danger-primary,#b73535); font-size:13px; }\n[data-mobile-room-hint], [data-mobile-room-dialog] details { font-size:12px; color:var(--dsw-alias-label-secondary); }\n[data-mobile-room-dialog] details { overflow-wrap:anywhere; }\n[data-mobile-member-row] { display:flex; align-items:center; gap:8px; padding:6px 0; }\n[data-mobile-member-chat] { display:flex!important; align-items:center; flex:1; min-width:0; gap:12px; text-align:left; padding:8px 0; }\n[data-mobile-member-chat]:disabled { opacity:1!important; }\n[data-mobile-member-chat] > span:last-child { min-width:0; }\n[data-mobile-member-chat] strong, [data-mobile-member-chat] small { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }\n[data-mobile-member-chat] small { font-size:12px; color:var(--dsw-alias-label-secondary); }\n[data-mobile-avatar] { display:grid; place-items:center; width:42px; height:42px; flex:none; border-radius:15px; background:var(--mobile-soft); }\n[data-mobile-room-dialog] [data-mobile-room-primary] { display:flex; align-items:center; justify-content:center; gap:8px; width:100%; min-height:46px; margin:18px 0 8px; border-radius:16px; background:var(--mobile-accent); color:var(--dsw-alias-bg-base); }\n[data-mobile-room-dialog] :is([data-mobile-room-back],[data-mobile-room-secondary] button,[data-mobile-confirm] button) { min-height:44px; padding:8px 16px; }\n[data-mobile-room-secondary] { display:flex; justify-content:space-between; }\nhtml[data-dsh-mobile] [data-queue-dock] { max-width:100%; }\nhtml[data-dsh-mobile] [data-queue-dock] button { min-height:40px; }\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.dock\"] section:has(> button[aria-expanded]) > button { min-height:36px; border-radius:20px; }\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.dock\"] section > ul[aria-label] { position:fixed; inset:auto 12px max(12px,env(safe-area-inset-bottom)); min-width:0; max-width:none; max-height:62dvh; border-radius:24px; padding:12px; z-index:1200; box-shadow:var(--mobile-shadow); }\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.dock\"] section > ul[aria-label] button { min-height:44px; }\n@media (prefers-reduced-motion: reduce) { [data-mobile-frame] * { scroll-behavior:auto !important; } }\n\n/* One mobile reading scale; derived from host text size without writing its preference. */\nhtml[data-dsh-mobile] body { --mobile-text:max(17px,var(--dsh-content-font-size,14px)); --mobile-caption:max(14px,var(--dsh-content-font-size-secondary,13px)); }\nhtml[data-dsh-mobile] :is([data-mobile-library],[data-mobile-dialog],[data-mobile-tools-dialog],[data-mobile-message-menu]) { font-size:var(--mobile-text); line-height:1.55; }\nhtml[data-dsh-mobile] :is([data-mobile-nav-title] strong,[data-mobile-session-copy] strong,[data-mobile-search] input,[data-composer-card] [contenteditable],[data-composer-seat] textarea,[data-mobile-member-chat] strong) { font-size:var(--mobile-text); line-height:1.55; }\nhtml[data-dsh-mobile] :is([data-mobile-workspace-group] strong,[data-mobile-tools-grid] button,[data-mobile-tools-permission],[data-mobile-dialog] h3,[data-mobile-grouping] button) { font-size:16px!important; }\nhtml[data-dsh-mobile] :is([data-mobile-subtitle],[data-mobile-nav-title] small,[data-mobile-session-copy] small,[data-mobile-session] time,[data-mobile-workspace-group] small,[data-mobile-session-group] h2,[data-mobile-activity],[data-mobile-room-hint],[data-mobile-member-chat] small,[data-mobile-tools-permission] small,[data-mobile-dialog] p) { font-size:var(--mobile-caption); line-height:1.5; color:var(--dsw-alias-label-secondary); }\nhtml[data-dsh-mobile] [data-slot=\"conversation.input.model\"] button { font-size:15px; }\nhtml[data-dsh-mobile] [data-conversation-scroll] {\n --dsh-content-font-size:var(--mobile-text); --dsh-content-font-size-secondary:var(--mobile-caption);\n --dsw-font-markdown-base:var(--mobile-text)/1.65 var(--dsw-font-family);\n --dsw-font-markdown-base-font-size:var(--mobile-text); --dsw-font-markdown-base-line-height:1.65;\n --dsw-font-markdown-base-strong:600 var(--mobile-text)/1.65 var(--dsw-font-family);\n --dsw-font-markdown-base-strong-font-size:var(--mobile-text);\n --dsw-font-markdown-base-italic:italic var(--mobile-text)/1.65 var(--dsw-font-family);\n --dsw-font-markdown-base-italic-font-size:var(--mobile-text);\n}\n/* All Room invite/edit entry points retain the same React form and callbacks. */\nhtml[data-dsh-mobile] [data-mobile-header-hidden]:has([data-mobile-room-form]) { display:contents!important; }\nhtml[data-dsh-mobile] [data-mobile-room-overlay] { position:fixed; inset:0; height:var(--mobile-height,100dvh); z-index:1400; align-items:flex-end; justify-content:center; padding:8px; box-sizing:border-box; background:#0005; -webkit-backdrop-filter:blur(5px); backdrop-filter:blur(5px); }\nhtml[data-dsh-mobile] [data-mobile-room-form] { box-sizing:border-box; width:100%; max-width:560px; max-height:calc(var(--mobile-height,100dvh) - 24px); margin:0; gap:16px; padding:20px 20px max(16px,env(safe-area-inset-bottom)); border-radius:28px; border:1px solid var(--mobile-edge); background:var(--mobile-face); color:var(--dsw-alias-label-primary); box-shadow:var(--mobile-shadow); text-align:left; overflow-y:auto; font-size:var(--mobile-text); }\nhtml[data-dsh-mobile] [data-mobile-room-form]::before { content:''; display:block; flex:none; width:36px; height:4px; border-radius:4px; background:var(--dsw-alias-label-secondary); opacity:.35; align-self:center; margin:-10px 0 0; }\nhtml[data-dsh-mobile] [data-mobile-room-form] > div:first-child { font-size:21px; line-height:1.4; font-weight:600; }\nhtml[data-dsh-mobile] [data-mobile-room-form] > div:has(> div > label) { flex-direction:column; gap:16px; }\nhtml[data-dsh-mobile] [data-mobile-room-form] > div > div:has(>label) { gap:18px; }\nhtml[data-dsh-mobile] [data-mobile-room-form] > div > div:has(>[data-member]) { order:-1; width:auto; }\nhtml[data-dsh-mobile] [data-mobile-room-form] > div > div:has(>[data-member]) > span { display:none; }\nhtml[data-dsh-mobile] [data-mobile-room-form] [data-member] { border:0; background:var(--mobile-soft); border-radius:18px; padding:14px; }\nhtml[data-dsh-mobile] [data-mobile-room-form] [data-member] p { font-size:14px; margin:6px 0 0; }\nhtml[data-dsh-mobile] [data-mobile-room-form] label { gap:7px; }\nhtml[data-dsh-mobile] [data-mobile-room-form] label > span:first-child { font-size:15px; line-height:1.5; font-weight:500; color:var(--dsw-alias-label-primary); }\nhtml[data-dsh-mobile] [data-mobile-room-form] label > span:last-child:not(:first-child), html[data-dsh-mobile] [data-mobile-room-form] [role=status] { font-size:14px; line-height:1.5; color:var(--dsw-alias-label-secondary); }\nhtml[data-dsh-mobile] [data-mobile-room-form] :is(input,textarea,select) { box-sizing:border-box; min-width:0; min-height:48px; border-radius:14px; padding:11px 12px; font-size:17px; line-height:1.5; background:var(--mobile-soft); border:1px solid var(--mobile-edge); color:var(--dsw-alias-label-primary); }\nhtml[data-dsh-mobile] [data-mobile-room-form] textarea { min-height:94px; resize:vertical; }\nhtml[data-dsh-mobile] [data-mobile-room-form] button { min-height:44px; min-width:44px; font-size:16px; border-radius:14px; }\nhtml[data-dsh-mobile] [data-mobile-room-form] summary { min-height:44px; padding:10px 0; font-size:16px; color:var(--dsw-alias-label-primary); }\nhtml[data-dsh-mobile] [data-mobile-room-form] > div:last-child { position:sticky; bottom:-16px; background:var(--mobile-face); padding:12px 0 0; margin-top:0; display:grid; grid-template-columns:1fr 1fr; gap:12px; }\nhtml[data-dsh-mobile] [data-mobile-room-form] [role=alert] { font-size:15px; line-height:1.5; }\nhtml[data-dsh-mobile] [data-member] { font-size:16px; }\nhtml[data-dsh-mobile] [data-member] button { min-height:44px; font-size:15px; }\nhtml[data-dsh-mobile] [data-mobile-room-form] [data-member] > div:first-child > span:nth-child(2) > span:first-child { font-size:16px; }\nhtml[data-dsh-mobile] [data-mobile-room-form] [data-member] p { color:var(--dsw-alias-label-secondary); }\nhtml[data-dsh-mobile] [data-mobile-room-form] > div:last-child button:disabled { opacity:1; color:var(--dsw-alias-label-secondary); background:var(--mobile-soft); border:1px solid var(--mobile-edge); cursor:default; }\nhtml[data-dsh-mobile] [data-mobile-queue-row] p { font-size:var(--mobile-text); }\nhtml[data-dsh-mobile] [data-mobile-members-open] small { font-size:12px; min-width:18px; }\n\n/* One viewport: the transcript alone scrolls; the official seat keeps its identity. */\nhtml[data-dsh-mobile], html[data-dsh-mobile] body, html[data-dsh-mobile] #root { width:100%; height:100%; overflow:hidden; overscroll-behavior:none; }\nhtml[data-dsh-mobile] [data-mobile-frame] { position:fixed; inset:var(--mobile-top,0px) 0 auto; overflow:hidden; }\nhtml[data-dsh-mobile] [data-mobile-frame] > div:has(> [data-slot=\"main\"]) { position:relative; min-height:0; height:100%; overflow:hidden; }\nhtml[data-dsh-mobile] [data-slot=\"main.conversation\"] > [data-phase] { min-height:0; overflow:hidden; --dsh-chat-content-width:calc(var(--dsh-conversation-column-width,100vw) - 48px); }\nhtml[data-dsh-mobile] [data-phase=active] [data-conversation-scroll] { box-sizing:border-box; padding-bottom:var(--mobile-composer-height,180px); scroll-padding-bottom:12px; }\nhtml[data-dsh-mobile] [data-phase=active] [data-composer-seat] { position:absolute; bottom:0; left:0; right:0; width:auto; padding-top:8px; padding-bottom:4px; background:var(--dsw-alias-bg-base); }\nhtml[data-dsh-mobile] [data-phase=active] [data-conversation-scroll] > div:has(> [data-slot=\"conversation.session\"]) { flex:1 0 auto; }\nhtml[data-dsh-mobile] [data-phase=hero] [data-conversation-scroll] { overscroll-behavior:contain; }\nhtml[data-dsh-mobile] [data-mobile-frame] { --mobile-pane-width:min(84vw,380px); }\n[data-mobile-library-pane] { position:absolute; inset:0 auto 0 0; width:var(--mobile-pane-width,min(84vw,380px)); background:var(--dsw-alias-bg-base); pointer-events:auto; }\n[data-mobile-library-pane][hidden] { display:none; }\nhtml[data-dsh-mobile] [data-mobile-frame][data-sidebar-collapsed]:has([data-mobile-library-pane]) > div:has(> [data-slot=\"sidebar\"]) { display:none; }\n[data-mobile-library-pane] [data-mobile-library] { inset:var(--mobile-bar,64px) 0 0; }\nhtml[data-mobile-library-open] [data-mobile-connection-status] { right:calc(100% - var(--mobile-pane-width) + 12px); }\n[data-mobile-library-toolbar] { height:64px; padding:8px 16px; display:flex; align-items:center; justify-content:space-between; box-sizing:border-box; }\n[data-mobile-library-toolbar] button { display:grid; place-items:center; width:44px; height:44px; padding:0; border-radius:50%; border:1px solid var(--mobile-edge); background:var(--mobile-glass); color:var(--dsw-alias-label-primary); box-shadow:var(--mobile-shadow); }\n[data-mobile-library-pane] [data-mobile-library-header] { padding:12px 16px; gap:8px; }\n[data-mobile-library-pane] [data-mobile-library-header] h1 { font-size:26px; }\n[data-mobile-library-pane] [data-mobile-recents] { padding:0 12px 12px; }\n[data-mobile-library-pane] [data-mobile-session] { padding:12px; }\n[data-mobile-library-pane] [data-mobile-session] time { display:none; }\nhtml[data-mobile-library-open] [data-mobile-frame] > div:has(> [data-slot=\"main\"]) { transform:translate3d(var(--mobile-pane-width),0,0); border-left:1px solid var(--mobile-edge); border-radius:0 0 0 28px; }\nhtml[data-mobile-library-open] [data-mobile-toolbar] { transform:translate3d(var(--mobile-pane-width),0,0); width:100%; border-left:1px solid var(--mobile-edge); border-radius:28px 0 0 0; }\n[data-mobile-peek-close] { position:absolute; inset:0 0 0 var(--mobile-pane-width); pointer-events:auto; background:transparent; border:0; padding:0; cursor:pointer; -webkit-tap-highlight-color:transparent; z-index:30; }\n@media(max-width:959px) and (prefers-reduced-motion:no-preference) {\n html[data-dsh-mobile]:not([data-mobile-gesture]) [data-mobile-frame] > div:has(> [data-slot=\"main\"]),\n html[data-dsh-mobile]:not([data-mobile-gesture]) [data-mobile-toolbar] { transition:transform 220ms cubic-bezier(.2,.8,.2,1),border-radius 220ms ease; }\n}\n[data-mobile-title-line] { display:flex; align-items:center; justify-content:center; min-width:0; }\n[data-mobile-title-line] strong { flex:0 1 auto; }\nhtml[data-dsh-mobile] [data-mobile-rename] { display:grid; place-items:center; flex:none; width:28px; min-width:28px; height:32px; min-height:32px; padding:4px; background:none; box-shadow:none; border:0; backdrop-filter:none; }\n[data-mobile-original-rename] { display:none!important; }\n@media(min-width:960px) {\n html[data-dsh-mobile] [data-mobile-frame] { --mobile-pane-width:320px; padding-left:320px; }\n html[data-dsh-mobile] [data-mobile-library-pane][hidden] { display:block; }\n html[data-dsh-mobile] [data-mobile-toolbar] { left:320px; transform:none; width:auto; right:0; border-radius:0; }\n html[data-dsh-mobile] [data-mobile-frame] > div:has(> [data-slot=\"main\"]) { left:0; transform:none; border-left:1px solid var(--mobile-edge); border-radius:0; }\n html[data-dsh-mobile] [data-mobile-peek-close] { display:none; }\n}\n\n[data-mobile-picker-shade] { position:fixed; inset:0; z-index:1099; background:#0005; backdrop-filter:blur(3px); }\nhtml[data-dsh-mobile] [data-mobile-picker] { position:fixed!important; inset:auto 0 0!important; width:min(100%,560px)!important; margin:0 auto; max-width:100%; max-height:75dvh!important; min-width:0!important; box-sizing:border-box; z-index:1100; border-radius:26px 26px 0 0; padding:16px 16px max(20px,env(safe-area-inset-bottom)); background:var(--mobile-face); color:var(--dsw-alias-label-primary); border:1px solid var(--mobile-edge); box-shadow:0 -8px 40px #0002; overflow:auto; }\n[data-mobile-picker-chrome] { display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between; gap:12px; padding:4px 8px 16px; }\n[data-mobile-picker-chrome] strong { font-size:20px; font-weight:600; }\n[data-mobile-picker-chrome] button { border:0; background:none; color:var(--mobile-accent); min-height:44px; font:inherit; font-size:16px; }\n[data-mobile-picker-chrome] input { width:100%; min-height:46px; box-sizing:border-box; border:1px solid var(--mobile-edge); border-radius:16px; padding:10px 14px; font:inherit; font-size:17px; background:var(--mobile-soft); color:inherit; }\nhtml[data-dsh-mobile] [data-mobile-picker] > [role=presentation] { max-height:none; overflow:visible; }\nhtml[data-dsh-mobile] [data-mobile-picker] [role=menuitem] { min-height:52px; padding:12px; border-radius:14px; font-size:17px; }\nhtml[data-dsh-mobile] [data-mobile-picker] [role=menuitem][hidden] { display:none; }\nhtml[data-dsh-mobile] [data-mobile-picker=preset] [role=menuitem] span > span:last-child { font-size:14px; line-height:1.55; color:var(--dsw-alias-label-secondary); }\n\nhtml[data-mobile-gesture] [data-mobile-library-pane][hidden] { display:block; }\nhtml[data-mobile-gesture] [data-mobile-frame] > div:has(> [data-slot=\"main\"]), html[data-mobile-gesture] [data-mobile-toolbar] { transform:translate3d(var(--mobile-drag-offset),0,0)!important; width:100%; }\nhtml[data-dsh-mobile] [data-slot=\"main.conversation\"] > [data-phase] header:has([data-conversation-header-corner]) { min-height:0; padding:6px 16px 0; }\nhtml[data-dsh-mobile] [data-mobile-toolbar] [data-mobile-rename] { background:transparent; border:0; border-radius:0; box-shadow:none; -webkit-backdrop-filter:none; backdrop-filter:none; color:var(--dsw-alias-label-secondary); }\nhtml[data-dsh-mobile] [data-mobile-picker=preset] [role=menuitem] > span span:first-child { font-size:17px; font-weight:500; line-height:1.5; }\n\n/* Rename lives above the page, with a keyboard-aware viewport of its own. */\nhtml[data-dsh-mobile] [data-mobile-rename-dialog] { position:fixed; inset:calc(var(--mobile-top,0px) + var(--mobile-height,100dvh) / 2) 0 auto; transform:translateY(-50%); margin:0 auto; max-height:calc(var(--mobile-height,100dvh) - 32px); width:min(360px,calc(100vw - 40px)); padding:24px; border-radius:26px; background:var(--mobile-face); border-color:var(--mobile-edge); }\n[data-mobile-rename-dialog] h2 { font-size:20px; margin:0 0 20px; }\n[data-mobile-rename-dialog] label { font-size:14px; color:var(--dsw-alias-label-secondary); }\n[data-mobile-rename-dialog] input { background:var(--mobile-soft); color:var(--dsw-alias-label-primary); border-color:var(--mobile-edge); font-size:17px; margin-top:8px; }\nhtml[data-dsh-mobile] [data-mobile-rename-dialog] input:focus { outline:none; box-shadow:0 0 0 2px color-mix(in srgb,var(--mobile-accent) 24%,transparent); border-color:var(--mobile-accent); }\n[data-mobile-rename-dialog] footer { display:flex; justify-content:flex-end; gap:10px; margin-top:24px; }\n[data-mobile-rename-dialog] [data-mobile-primary] { background:var(--mobile-accent); color:white; border-radius:22px; padding-inline:22px; }\nhtml[data-dsh-mobile] [data-mobile-picker=preset] [role=menuitem] { border-radius:0; }\nhtml[data-dsh-mobile] [data-mobile-picker=preset] [data-mobile-picker-divider] { border-top:1px solid var(--mobile-edge); margin-top:8px; padding-top:20px; }\n\n[data-mobile-directory] { width:min(100%,520px); height:min(78dvh,720px); max-height:calc(var(--mobile-height,100dvh) - 24px); margin:auto auto 0; padding:20px 22px max(16px,env(safe-area-inset-bottom)); border-radius:28px 28px 0 0; color:var(--dsw-alias-label-primary); background:var(--mobile-face,var(--dsw-alias-bg-base)); }\n[data-mobile-directory][open] { display:flex; flex-direction:column; }\n[data-mobile-directory] header { display:flex; justify-content:space-between; align-items:center; flex:none; }\n[data-mobile-directory] header h2 { margin:0; font-size:21px; }\n[data-mobile-directory] button { font:inherit; color:inherit; cursor:pointer; background:transparent; border:0; }\n[data-mobile-directory] header button { display:grid; place-items:center; width:44px; height:44px; }\n[data-directory-tabs] { display:flex; gap:4px; padding:4px; margin:12px 0; border-radius:16px; background:var(--mobile-soft); flex:none; }\n[data-directory-tabs] button { flex:1; min-height:42px; border-radius:12px; }\n[data-directory-tabs] button[aria-pressed=true] { background:var(--mobile-face); color:var(--mobile-accent); box-shadow:0 1px 5px #0001; }\n[data-directory-scroll] { min-height:0; flex:1; overflow:auto; overscroll-behavior:contain; }\n[data-mobile-directory] [data-directory-row] { display:flex; gap:12px; align-items:center; width:100%; min-height:56px; padding:12px 2px; text-align:left; border-radius:0; border-bottom:1px solid var(--mobile-line); }\n[data-directory-row] > span { flex:1; min-width:0; overflow-wrap:anywhere; }\n[data-directory-row] strong { display:block; font-weight:500; }\n[data-directory-row] small { display:block; color:var(--dsw-alias-label-secondary); font-size:13px; margin-top:4px; }\n[data-directory-row] svg { flex:none; }\n[data-directory-current] { display:flex; align-items:center; gap:10px; font-size:14px; padding:8px 0; overflow-wrap:anywhere; }\n[data-directory-current] svg { flex:none; }\n[data-directory-manual] summary { cursor:pointer; padding:8px 0; font-size:14px; color:var(--mobile-accent); }\n[data-directory-path] { display:flex; align-items:center; gap:8px; }\n[data-directory-path] input { min-width:0; flex:1; }\n[data-mobile-directory] input { color:inherit; background:var(--mobile-soft); border-color:var(--mobile-line); margin:8px 0; }\n[data-directory-location] { display:flex; align-items:center; justify-content:space-between; gap:8px; margin:8px 0; font-size:14px; }\n[data-directory-location] button,[data-directory-location] label { display:flex; align-items:center; gap:6px; min-height:40px; }\n[data-directory-location] input { width:18px; }\n[data-mobile-directory] footer { flex:none; padding-top:10px; }\n[data-mobile-directory] [data-mobile-done] { margin-top:0; background:var(--mobile-accent); color:white; min-height:48px; }\n";
4
+ //# sourceMappingURL=styles.d.ts.map