@oxvo/ai-live-assist 7.4.36 → 7.4.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/ui.js CHANGED
@@ -13,6 +13,7 @@ const CAPTION_HEIGHT_GLIDE_MS = 250;
13
13
  const ASSISTANT_READY_VISUAL_GRACE_MS = 1200;
14
14
  const FEEDBACK_EXIT_FADE_MS = 180;
15
15
  const AMBIENT_IDLE_GRACE_MS = 700;
16
+ const VOICE_CARD_EFFECT_SETTLE_MS = 720;
16
17
  const OMAGO_SOURCE_CONTENT_FADE_MS = 16;
17
18
  const OMAGO_BOX_IN_HOLD_MS = 130;
18
19
  const OMAGO_BOX_IN_GEOMETRY_MS = 550;
@@ -76,6 +77,21 @@ const style = `
76
77
  --glass-control-border: rgba(255, 255, 255, .76);
77
78
  --conversation-bubble-background: #fff;
78
79
  --conversation-bubble-text: #3a3542;
80
+ --conversation-bubble-shadow: 0 2px 10px rgba(103, 42, 150, .06);
81
+ --caption-background: rgba(255, 255, 255, .82);
82
+ --caption-border: rgba(255, 255, 255, .65);
83
+ --caption-text: #17151b;
84
+ --prompt-pill-background: #1d1031;
85
+ --prompt-pill-border: #3c2359;
86
+ --prompt-pill-text: #ecdffa;
87
+ --input-material-background: #010201;
88
+ --glass-highlight: rgba(255, 255, 255, .65);
89
+ --glass-highlight-subtle: rgba(255, 255, 255, .64);
90
+ --glass-highlight-strong: rgba(255, 255, 255, .8);
91
+ --glass-highlight-terminal: rgba(255, 255, 255, .72);
92
+ --danger-control-text: #9d2947;
93
+ --danger-control-background: rgba(255, 245, 248, .7);
94
+ --danger-control-border: rgba(196, 87, 117, .24);
79
95
  --soft-surface-background: rgba(255, 255, 255, .48);
80
96
  --soft-surface-border: rgba(255, 255, 255, .72);
81
97
  --soft-surface-strong-background: rgba(255, 255, 255, .58);
@@ -83,6 +99,10 @@ const style = `
83
99
  linear-gradient(145deg, rgba(255, 255, 255, .94), rgba(250, 244, 252, .88));
84
100
  --dialog-surface-border: rgba(255, 255, 255, .86);
85
101
  --mode-active-background: #fff;
102
+ --non-iridescent-panel-background: #f7f4f8;
103
+ --non-iridescent-panel-border: #d9d4dc;
104
+ --non-iridescent-panel-shadow: 0 12px 28px rgba(15, 23, 42, .16);
105
+ --brand-mark-border: rgba(255, 255, 255, .8);
86
106
  --surface-material-plane: 0;
87
107
  --surface-content-plane: 10;
88
108
  --skel: rgba(255, 255, 255, .55);
@@ -90,50 +110,95 @@ const style = `
90
110
  }
91
111
  :host([data-theme="dark"]) {
92
112
  color-scheme: dark;
93
- --assist-text: #f6f1f8;
94
- --assist-muted: #b9b0bf;
95
- --assist-border: rgba(255, 255, 255, .12);
96
- --assist-surface: #17131b;
97
- --assist-surface-muted: #201a25;
98
- --conversation-glass-background: rgba(28, 22, 34, .7);
99
- --conversation-glass-border: 1px solid rgba(255, 255, 255, .12);
113
+ --assist-text: #f2edf8;
114
+ --assist-muted: #9c92ad;
115
+ --assist-border: rgba(255, 255, 255, .08);
116
+ --assist-surface: #150a22;
117
+ --assist-surface-muted: #1d102e;
118
+ --conversation-glass-background: rgba(255, 255, 255, .05);
119
+ --conversation-glass-border: 1px solid rgba(255, 255, 255, .16);
100
120
  --expanded-panel-background:
101
- radial-gradient(72% 48% at 50% 45%, rgba(116, 82, 136, .2), transparent 72%),
102
- linear-gradient(
103
- 168deg,
104
- color-mix(in srgb, var(--accent) 8%, #211a26) 0%,
105
- color-mix(in srgb, var(--accent) 12%, #1b151f) 48%,
106
- color-mix(in srgb, var(--accent) 15%, #141017) 100%
107
- );
108
- --expanded-panel-border: rgba(255, 255, 255, .12);
121
+ radial-gradient(65% 42% at 52% 46%, rgba(168, 85, 247, .13), rgba(255, 255, 255, 0) 70%),
122
+ linear-gradient(168deg, #271741 0%, #1d102e 45%, #150a22 100%);
123
+ --expanded-panel-border: rgba(255, 255, 255, .08);
109
124
  --expanded-panel-shadow:
110
- 0 24px 70px rgba(4, 2, 8, .48),
111
- 0 4px 16px color-mix(in srgb, var(--accent) 15%, transparent);
112
- --glass-control-background: rgba(34, 27, 40, .72);
113
- --glass-control-border: rgba(255, 255, 255, .13);
114
- --conversation-bubble-background: rgba(31, 25, 36, .94);
115
- --conversation-bubble-text: #f3eef6;
116
- --soft-surface-background: rgba(31, 24, 37, .68);
117
- --soft-surface-border: rgba(255, 255, 255, .12);
118
- --soft-surface-strong-background: rgba(38, 30, 45, .82);
125
+ 0 24px 70px rgba(0, 0, 0, .55),
126
+ 0 4px 14px rgba(0, 0, 0, .3);
127
+ --glass-control-background: rgba(255, 255, 255, .05);
128
+ --glass-control-border: rgba(255, 255, 255, .12);
129
+ --conversation-bubble-background: #2a1c3e;
130
+ --conversation-bubble-text: #e6def2;
131
+ --conversation-bubble-shadow: 0 2px 10px rgba(0, 0, 0, .28);
132
+ --caption-background: rgba(40, 25, 62, .88);
133
+ --caption-border: rgba(255, 255, 255, .08);
134
+ --caption-text: #f2edf8;
135
+ --prompt-pill-background: rgba(255, 255, 255, .05);
136
+ --prompt-pill-border: rgba(255, 255, 255, .16);
137
+ --prompt-pill-text: #d9a1f5;
138
+ --input-material-background: linear-gradient(176deg, #221136, #12081f);
139
+ --glass-highlight: rgba(255, 255, 255, .08);
140
+ --glass-highlight-subtle: rgba(255, 255, 255, .08);
141
+ --glass-highlight-strong: rgba(255, 255, 255, .08);
142
+ --glass-highlight-terminal: rgba(255, 255, 255, .08);
143
+ --danger-control-text: #ff9aad;
144
+ --danger-control-background: rgba(255, 122, 143, .08);
145
+ --danger-control-border: rgba(255, 122, 143, .22);
146
+ --soft-surface-background: rgba(255, 255, 255, .05);
147
+ --soft-surface-border: rgba(255, 255, 255, .16);
148
+ --soft-surface-strong-background: rgba(255, 255, 255, .05);
119
149
  --dialog-surface-background:
120
- linear-gradient(145deg, rgba(39, 31, 46, .98), rgba(24, 19, 29, .96));
121
- --dialog-surface-border: rgba(255, 255, 255, .13);
122
- --mode-active-background: rgba(45, 36, 52, .98);
150
+ linear-gradient(145deg, rgba(42, 28, 62, .98), rgba(21, 10, 34, .96));
151
+ --dialog-surface-border: rgba(255, 255, 255, .16);
152
+ --mode-active-background: #33214a;
153
+ --non-iridescent-panel-background: #1d102e;
154
+ --non-iridescent-panel-border: rgba(255, 255, 255, .08);
155
+ --non-iridescent-panel-shadow:
156
+ 0 24px 70px rgba(0, 0, 0, .55),
157
+ 0 4px 14px rgba(0, 0, 0, .3);
158
+ --brand-mark-border: transparent;
123
159
  --skel: rgba(255, 255, 255, .06);
124
160
  --shimmer: rgba(255, 255, 255, .1);
125
161
  }
126
162
  :host([data-theme="dark"]) .mode-option:not([aria-pressed="true"]):not(:disabled):hover {
127
163
  background: rgba(255, 255, 255, .08);
128
164
  }
165
+ :host([data-theme="dark"]) .brand-mark {
166
+ border-color: var(--brand-mark-border);
167
+ }
168
+ :host([data-theme="dark"]) .tags button,
169
+ :host([data-theme="dark"]) .tags.welcome-actions button {
170
+ color: var(--prompt-pill-text);
171
+ background: var(--prompt-pill-background);
172
+ border-color: var(--prompt-pill-border);
173
+ }
174
+ :host([data-theme="dark"]) .tags button:not(:disabled):hover,
175
+ :host([data-theme="dark"]) .tags button:not(:disabled):focus-visible,
176
+ :host([data-theme="dark"]) .tags.welcome-actions button:not(:disabled):hover,
177
+ :host([data-theme="dark"]) .tags.welcome-actions button:not(:disabled):focus-visible {
178
+ background: var(--mode-active-background);
179
+ }
180
+ :host([data-theme="dark"]) .intro-composer,
181
+ :host([data-theme="dark"]) .compact-chat-actions,
182
+ :host([data-theme="dark"]) .compact-chat-card::before,
183
+ :host([data-theme="dark"]) .composer::before,
184
+ :host([data-theme="dark"]) .panel-transition-inner-clone .chatbox,
185
+ :host([data-theme="dark"]) .panel.open:not(.compact) .chatbox,
186
+ :host([data-theme="dark"]) .panel.active-session.compact:is(.voice-session, .starting-voice) .header,
187
+ :host([data-theme="dark"]) .panel.active-session.compact:is(.voice-session, .starting-voice)::before {
188
+ background: var(--input-material-background);
189
+ }
190
+ :host([data-theme="dark"]) .intro-composer-frame.omago-transition-source,
191
+ :host([data-theme="dark"]) .panel.panel-transition-compact-clone:not(.voice-session) .compact-chat-actions {
192
+ background: var(--input-material-background) !important;
193
+ }
129
194
  :host([data-theme="dark"]) .panel.open.voice-session:not(.compact) .line:not(.bubble) {
130
- color: var(--assist-text);
131
- background: rgba(32, 25, 38, .9);
132
- border-color: rgba(255, 255, 255, .11);
195
+ color: var(--caption-text);
196
+ background: var(--caption-background);
197
+ border-color: var(--caption-border);
133
198
  }
134
199
  :host([data-theme="dark"]) .panel.open.voice-session:not(.compact) .line.user:not(.bubble) {
135
- color: var(--assist-text);
136
- background: rgba(40, 32, 47, .88);
200
+ color: var(--caption-text);
201
+ background: var(--caption-background);
137
202
  }
138
203
  .support-reply-notice,
139
204
  .compact-support-reply,
@@ -252,10 +317,15 @@ const style = `
252
317
  }
253
318
  .panel.omago-awaiting {
254
319
  opacity: 0;
320
+ visibility: hidden;
255
321
  pointer-events: none;
256
322
  transition: none !important;
257
323
  }
324
+ .panel.omago-awaiting * {
325
+ visibility: hidden !important;
326
+ }
258
327
  .panel.omago-destination-reveal {
328
+ visibility: visible;
259
329
  transition: opacity .24s ease;
260
330
  }
261
331
  .panel.compact.omago-destination-reveal {
@@ -752,9 +822,9 @@ const style = `
752
822
  max-height: 180px;
753
823
  max-width: 100%;
754
824
  padding: 9px 13px;
755
- color: #17151b;
756
- background: rgba(255, 255, 255, .82);
757
- border: 1px solid rgba(255, 255, 255, .65);
825
+ color: var(--caption-text);
826
+ background: var(--caption-background);
827
+ border: 1px solid var(--caption-border);
758
828
  border-radius: 16px;
759
829
  box-shadow: 0 10px 30px rgba(60, 20, 100, .25);
760
830
  backdrop-filter: blur(14px);
@@ -871,7 +941,7 @@ const style = `
871
941
  background:
872
942
  radial-gradient(circle at 30% 18%, rgba(255, 255, 255, .62), transparent 28%),
873
943
  linear-gradient(145deg, color-mix(in srgb, var(--accent) 72%, #c85ddf), var(--accent));
874
- border: 1px solid rgba(255, 255, 255, .8);
944
+ border: 1px solid var(--brand-mark-border);
875
945
  border-radius: 50%;
876
946
  box-shadow: 0 7px 18px color-mix(in srgb, var(--accent) 30%, transparent);
877
947
  }
@@ -926,6 +996,15 @@ const style = `
926
996
  border-radius: 50%;
927
997
  }
928
998
  .panel.open:not(.compact) .close:hover { background: #24232a; }
999
+ :host([data-theme="dark"]) .panel.open:not(.compact) .close {
1000
+ color: var(--assist-text);
1001
+ background: var(--glass-control-background);
1002
+ border-color: var(--glass-control-border);
1003
+ box-shadow: none;
1004
+ }
1005
+ :host([data-theme="dark"]) .panel.open:not(.compact) .close:hover {
1006
+ background: var(--mode-active-background);
1007
+ }
929
1008
  .panel.active-session.compact .brand-mark {
930
1009
  width: 42px;
931
1010
  height: 42px;
@@ -1217,7 +1296,7 @@ const style = `
1217
1296
  border-radius: 999px;
1218
1297
  box-shadow:
1219
1298
  0 12px 30px rgba(15, 23, 42, .15),
1220
- inset 0 1px 0 rgba(255, 255, 255, .72);
1299
+ inset 0 1px 0 var(--glass-highlight-terminal);
1221
1300
  -webkit-backdrop-filter: blur(16px) saturate(1.08);
1222
1301
  backdrop-filter: blur(16px) saturate(1.08);
1223
1302
  font-size: 12px;
@@ -1336,7 +1415,7 @@ const style = `
1336
1415
  line-height: 0;
1337
1416
  }
1338
1417
  .button-icon svg, .menu-icon svg, .turn-icon svg { display: block; }
1339
- .body { min-height: 0; padding: 12px; overflow: auto; overflow-x: hidden; }
1418
+ .body { grid-area: 2 / 1; min-height: 0; padding: 12px; overflow: auto; overflow-x: hidden; }
1340
1419
  .intro {
1341
1420
  position: fixed;
1342
1421
  inset-inline-end: 20px;
@@ -2045,6 +2124,16 @@ const style = `
2045
2124
  :host(:is([data-activity="connecting"], [data-activity="listening"], [data-activity="thinking"], [data-activity="speaking"], [data-activity="acting"]):not([data-effects-paused="true"]):not([data-effect-motion="off"])) .input-effect-host > :is(.intro-effect, .composer-effect)::before {
2046
2125
  animation: original-border-busy 3.2s linear infinite;
2047
2126
  }
2127
+ :host([data-voice-effect-settle="captured"]) .panel.active-session.compact.voice-session > .voice-card-fx.intro-effect::before {
2128
+ animation: none !important;
2129
+ transform: var(--voice-effect-captured-transform) !important;
2130
+ transition: none !important;
2131
+ }
2132
+ :host([data-voice-effect-settle="settling"]) .panel.active-session.compact.voice-session > .voice-card-fx.intro-effect::before {
2133
+ animation: none !important;
2134
+ transform: translate(-50%, -50%) rotate(var(--effect-rest-angle)) !important;
2135
+ transition: transform .72s cubic-bezier(.22, .72, .28, 1) !important;
2136
+ }
2048
2137
  .intro-composer-frame:focus-within {
2049
2138
  outline: 1px solid rgba(160, 153, 216, .55);
2050
2139
  outline-offset: 3px;
@@ -2321,30 +2410,49 @@ const style = `
2321
2410
  .legal-links { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 12px; }
2322
2411
  .legal-links a { color: #185ea8; font-size: 11px; font-weight: 600; }
2323
2412
  .page-assistance-overlay {
2324
- position: absolute;
2325
- inset: 0;
2413
+ position: relative;
2414
+ grid-area: 2 / 1;
2326
2415
  z-index: 6;
2327
2416
  display: grid;
2417
+ width: 100%;
2418
+ height: 100%;
2328
2419
  min-width: 0;
2329
- place-items: center;
2330
- padding: 14px;
2331
- background: rgba(15, 23, 42, .42);
2332
- border-radius: inherit;
2420
+ min-height: 0;
2421
+ place-items: end center;
2422
+ padding: 12px 8px 8px;
2423
+ background:
2424
+ radial-gradient(80% 52% at 50% 100%, color-mix(in srgb, var(--accent) 9%, transparent), transparent 72%),
2425
+ color-mix(in srgb, var(--assist-surface) 48%, transparent);
2426
+ border-radius: 18px;
2333
2427
  overflow: hidden;
2334
- animation: page-assistance-backdrop-in .16s ease-out both;
2428
+ overscroll-behavior: contain;
2429
+ -webkit-backdrop-filter: blur(10px) saturate(1.08);
2430
+ backdrop-filter: blur(10px) saturate(1.08);
2431
+ animation: page-assistance-backdrop-in .24s ease-out both;
2335
2432
  }
2336
2433
  .page-assistance-dialog {
2337
2434
  width: min(100%, 430px);
2338
- max-height: calc(100% - 12px);
2435
+ max-height: calc(100% - 8px);
2339
2436
  min-width: 0;
2340
2437
  overflow: auto;
2341
- padding: 18px;
2438
+ overscroll-behavior: contain;
2439
+ padding: 16px;
2342
2440
  color: var(--assist-text);
2343
- background: var(--assist-surface);
2344
- border: 1px solid var(--assist-border);
2345
- border-radius: inherit;
2346
- box-shadow: 0 18px 42px rgba(15, 23, 42, .26);
2347
- animation: page-assistance-dialog-in .18s cubic-bezier(.2, .8, .3, 1) both;
2441
+ background:
2442
+ linear-gradient(
2443
+ 145deg,
2444
+ color-mix(in srgb, var(--assist-surface) 86%, transparent),
2445
+ color-mix(in srgb, var(--assist-surface-muted) 74%, transparent)
2446
+ );
2447
+ border: 1px solid var(--dialog-surface-border);
2448
+ border-radius: 20px;
2449
+ box-shadow:
2450
+ 0 20px 48px color-mix(in srgb, var(--accent) 16%, transparent),
2451
+ 0 4px 16px rgba(15, 23, 42, .14),
2452
+ inset 0 1px 0 var(--glass-highlight-strong);
2453
+ -webkit-backdrop-filter: blur(18px) saturate(1.1);
2454
+ backdrop-filter: blur(18px) saturate(1.1);
2455
+ animation: page-assistance-dialog-in .32s cubic-bezier(.2, .8, .3, 1) both;
2348
2456
  }
2349
2457
  .page-assistance-header {
2350
2458
  display: grid;
@@ -2355,8 +2463,8 @@ const style = `
2355
2463
  .page-assistance-header-copy { min-width: 0; }
2356
2464
  .page-assistance-header h3 {
2357
2465
  margin: 0;
2358
- font-size: 18px;
2359
- line-height: 24px;
2466
+ font-size: 16px;
2467
+ line-height: 22px;
2360
2468
  font-weight: 720;
2361
2469
  }
2362
2470
  .page-assistance-action-copy {
@@ -2375,11 +2483,12 @@ const style = `
2375
2483
  .page-assistance-footer {
2376
2484
  display: grid;
2377
2485
  gap: 6px;
2378
- margin-top: 12px;
2379
- padding: 10px 12px;
2380
- background: var(--assist-surface-muted);
2381
- border: 1px solid var(--assist-border);
2382
- border-radius: 12px;
2486
+ margin-top: 13px;
2487
+ padding: 11px 0 0;
2488
+ background: transparent;
2489
+ border: 0;
2490
+ border-top: 1px solid var(--soft-surface-border);
2491
+ border-radius: 0;
2383
2492
  }
2384
2493
  .page-assistance-always {
2385
2494
  display: grid;
@@ -2467,6 +2576,38 @@ const style = `
2467
2576
  color: #fbbf24;
2468
2577
  background: rgba(245, 158, 11, .18);
2469
2578
  }
2579
+ :host([data-theme="dark"]) .end,
2580
+ :host([data-theme="dark"]) .panel.active-session.compact:is(.voice-session, .starting-voice) .end {
2581
+ color: #ff7a8f;
2582
+ background: rgba(255, 255, 255, .06);
2583
+ border-color: rgba(255, 255, 255, .12);
2584
+ box-shadow: none;
2585
+ backdrop-filter: blur(8px);
2586
+ }
2587
+ :host([data-theme="dark"]) .end:not(:disabled):hover,
2588
+ :host([data-theme="dark"]) .panel.active-session.compact:is(.voice-session, .starting-voice) .end:not(:disabled):hover {
2589
+ color: #ff7a8f;
2590
+ background: rgba(255, 255, 255, .13);
2591
+ border-color: rgba(255, 255, 255, .12);
2592
+ box-shadow: none;
2593
+ }
2594
+ :host([data-theme="dark"]) .end:focus-visible,
2595
+ :host([data-theme="dark"]) .panel.active-session.compact:is(.voice-session, .starting-voice) .end:focus-visible {
2596
+ color: #ff7a8f;
2597
+ background: rgba(255, 255, 255, .13);
2598
+ border-color: rgba(255, 255, 255, .12);
2599
+ box-shadow: none;
2600
+ outline-color: rgba(217, 161, 245, .72);
2601
+ }
2602
+ :host([data-theme="dark"]) .end:disabled,
2603
+ :host([data-theme="dark"]) .end[aria-busy="true"],
2604
+ :host([data-theme="dark"]) .panel.active-session.compact:is(.voice-session, .starting-voice) .end:disabled,
2605
+ :host([data-theme="dark"]) .panel.active-session.compact:is(.voice-session, .starting-voice) .end[aria-busy="true"] {
2606
+ color: rgba(255, 122, 143, .68);
2607
+ background: rgba(255, 255, 255, .04);
2608
+ border-color: rgba(255, 255, 255, .08);
2609
+ box-shadow: none;
2610
+ }
2470
2611
  .page-assistance-actions {
2471
2612
  display: flex;
2472
2613
  justify-content: flex-end;
@@ -2620,7 +2761,7 @@ const style = `
2620
2761
  background: var(--conversation-bubble-background);
2621
2762
  border: 0;
2622
2763
  border-radius: 16px;
2623
- box-shadow: 0 2px 10px rgba(103, 42, 150, .06);
2764
+ box-shadow: var(--conversation-bubble-shadow);
2624
2765
  font-family: Poppins, system-ui, "Segoe UI", sans-serif;
2625
2766
  font-size: 12.5px;
2626
2767
  line-height: 1.6;
@@ -2788,6 +2929,7 @@ const style = `
2788
2929
  .empty { display: grid; min-height: 140px; place-items: center; color: #6a7480; font-size: 12px; text-align: center; }
2789
2930
  .controls {
2790
2931
  position: relative;
2932
+ grid-area: 3 / 1;
2791
2933
  z-index: 4;
2792
2934
  display: none;
2793
2935
  padding: 0 12px max(10px, env(safe-area-inset-bottom));
@@ -3286,7 +3428,7 @@ const style = `
3286
3428
  }
3287
3429
  @keyframes page-assistance-backdrop-in { from { opacity: 0; } }
3288
3430
  @keyframes page-assistance-dialog-in {
3289
- from { opacity: 0; transform: translateY(6px) scale(.985); }
3431
+ from { opacity: 0; transform: translateY(10px) scale(.98); }
3290
3432
  }
3291
3433
  @keyframes pop { from { opacity: 0; transform: translateY(8px); } }
3292
3434
  @keyframes attribution-in { from { opacity: 0; transform: translateY(3px); } }
@@ -3326,7 +3468,11 @@ const style = `
3326
3468
  .confirmation strong { color: #17212b; }
3327
3469
  .confirmation-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 10px; }
3328
3470
  .confirmation [data-role="approve"], .visual-request [data-role="visual-share"] { background: #16a34a; border-color: #16a34a; }
3329
- .confirmation [data-role="decline"], .visual-request [data-role="visual-decline"] { color: #b91c1c; background: #fef2f2; border-color: #fecaca; }
3471
+ .confirmation [data-role="decline"], .visual-request [data-role="visual-decline"] {
3472
+ color: var(--danger-control-text);
3473
+ background: var(--danger-control-background);
3474
+ border-color: var(--danger-control-border);
3475
+ }
3330
3476
  .visual-request { display: none; padding: 12px; border: 2px solid #55758c; border-radius: 12px; background: white; }
3331
3477
  .visual-request.visible { display: block; }
3332
3478
  .visual-request.preparing .confirmation-actions { display: none; }
@@ -3391,7 +3537,7 @@ const style = `
3391
3537
  background: var(--soft-surface-background);
3392
3538
  border: 1px solid var(--soft-surface-border);
3393
3539
  border-radius: 18px;
3394
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, .64);
3540
+ box-shadow: inset 0 1px 0 var(--glass-highlight-subtle);
3395
3541
  backdrop-filter: blur(12px);
3396
3542
  }
3397
3543
  .panel.open:not(.compact) .status-card.visible { padding: 14px 16px; }
@@ -3405,26 +3551,16 @@ const style = `
3405
3551
  background: rgba(39, 22, 47, .34);
3406
3552
  backdrop-filter: blur(12px);
3407
3553
  }
3408
- .panel.open:not(.compact) .page-assistance-overlay {
3409
- inset: 0;
3410
- padding: 16px;
3411
- background: rgba(39, 22, 47, .34);
3412
- border-radius: inherit;
3413
- overflow: hidden;
3414
- backdrop-filter: blur(12px);
3415
- }
3416
- .panel.open:not(.compact) .legal-dialog,
3417
- .panel.open:not(.compact) .page-assistance-dialog {
3554
+ .panel.open:not(.compact) .legal-dialog {
3418
3555
  padding: 18px;
3419
3556
  background: var(--dialog-surface-background);
3420
3557
  border: 1px solid var(--dialog-surface-border);
3421
3558
  box-shadow:
3422
3559
  0 24px 60px rgba(49, 26, 58, .24),
3423
- inset 0 1px 0 rgba(255, 255, 255, .8);
3560
+ inset 0 1px 0 var(--glass-highlight-strong);
3424
3561
  backdrop-filter: blur(18px);
3425
3562
  }
3426
3563
  .panel.open:not(.compact) .legal-dialog { border-radius: 22px; }
3427
- .panel.open:not(.compact) .page-assistance-dialog { border-radius: inherit; }
3428
3564
  .panel.open:not(.compact) .legal-header h3 {
3429
3565
  color: color-mix(in srgb, var(--assist-text) 88%, var(--accent));
3430
3566
  font-size: 16px;
@@ -3432,8 +3568,8 @@ const style = `
3432
3568
  }
3433
3569
  .panel.open:not(.compact) .page-assistance-header h3 {
3434
3570
  color: color-mix(in srgb, var(--assist-text) 88%, var(--accent));
3435
- font-size: 18px;
3436
- line-height: 24px;
3571
+ font-size: 16px;
3572
+ line-height: 22px;
3437
3573
  }
3438
3574
  .panel.open:not(.compact) .legal-close {
3439
3575
  color: var(--assist-text);
@@ -3478,7 +3614,7 @@ const style = `
3478
3614
  background: var(--soft-surface-background);
3479
3615
  border: 1px solid var(--soft-surface-border);
3480
3616
  border-radius: 18px;
3481
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, .65);
3617
+ box-shadow: inset 0 1px 0 var(--glass-highlight);
3482
3618
  backdrop-filter: blur(12px);
3483
3619
  }
3484
3620
  .panel.open:not(.compact) .confirmation p,
@@ -3488,11 +3624,13 @@ const style = `
3488
3624
  .panel.open:not(.compact) .confirmation strong { color: var(--assist-text); }
3489
3625
  .panel.open:not(.compact) .confirmation [data-role="decline"],
3490
3626
  .panel.open:not(.compact) .visual-request [data-role="visual-decline"] {
3491
- color: #9d2947;
3492
- background: rgba(255, 245, 248, .7);
3493
- border-color: rgba(196, 87, 117, .24);
3627
+ color: var(--danger-control-text);
3628
+ background: var(--danger-control-background);
3629
+ border-color: var(--danger-control-border);
3494
3630
  }
3495
3631
  .panel.open:not(.compact) .feedback.visible { margin-top: 2px; }
3632
+ .panel.page-assistance-state .header,
3633
+ .panel.page-assistance-state .controls { pointer-events: none; }
3496
3634
  .panel.open:not(.compact) .feedback-options button {
3497
3635
  color: color-mix(in srgb, var(--assist-text) 74%, var(--accent));
3498
3636
  background: var(--soft-surface-strong-background);
@@ -3509,9 +3647,9 @@ const style = `
3509
3647
  display: none;
3510
3648
  }
3511
3649
  .panel.active-session.compact .compact-caption {
3512
- color: #17151b;
3513
- background: rgba(255, 255, 255, .82);
3514
- border-color: rgba(255, 255, 255, .65);
3650
+ color: var(--caption-text);
3651
+ background: var(--caption-background);
3652
+ border-color: var(--caption-border);
3515
3653
  border-radius: 16px;
3516
3654
  box-shadow: 0 10px 30px rgba(60, 20, 100, .25);
3517
3655
  backdrop-filter: blur(14px);
@@ -3519,9 +3657,9 @@ const style = `
3519
3657
  .panel.active-session.compact .compact-caption.assistant { border-end-start-radius: 6px; }
3520
3658
  .panel.active-session.compact .compact-caption.user,
3521
3659
  .panel.active-session.compact .compact-caption.user.pending {
3522
- color: #17151b;
3523
- background: rgba(255, 255, 255, .82);
3524
- border-color: rgba(255, 255, 255, .65);
3660
+ color: var(--caption-text);
3661
+ background: var(--caption-background);
3662
+ border-color: var(--caption-border);
3525
3663
  border-end-end-radius: 6px;
3526
3664
  }
3527
3665
  .widget-corner-glow {
@@ -3680,6 +3818,17 @@ const style = `
3680
3818
  border-color: var(--assist-border);
3681
3819
  box-shadow: 0 12px 28px rgba(15, 23, 42, .16);
3682
3820
  }
3821
+ .panel.open:not(.compact) .page-assistance-overlay {
3822
+ background: color-mix(in srgb, var(--assist-surface) 90%, transparent);
3823
+ -webkit-backdrop-filter: none;
3824
+ backdrop-filter: none;
3825
+ }
3826
+ .panel.open:not(.compact) .page-assistance-dialog {
3827
+ background: var(--assist-surface);
3828
+ box-shadow: 0 12px 28px rgba(15, 23, 42, .16);
3829
+ -webkit-backdrop-filter: none;
3830
+ backdrop-filter: none;
3831
+ }
3683
3832
  .panel.open:not(.compact) .brand-mark,
3684
3833
  .panel.open:not(.compact) .mode-switch,
3685
3834
  .panel.open:not(.compact) .voice-state-chip {
@@ -3713,9 +3862,9 @@ const style = `
3713
3862
  .intro-composer-frame:focus-within,
3714
3863
  .compact-chat-card:focus-within { box-shadow: none; }
3715
3864
  .panel.open.compact.ending-state .compact-error-notice.visible {
3716
- background: #fff;
3717
- border-color: #d9d4dc;
3718
- box-shadow: 0 8px 20px rgba(15, 23, 42, .12);
3865
+ background: var(--assist-surface);
3866
+ border-color: var(--assist-border);
3867
+ box-shadow: var(--non-iridescent-panel-shadow);
3719
3868
  -webkit-backdrop-filter: none;
3720
3869
  backdrop-filter: none;
3721
3870
  }
@@ -3740,6 +3889,20 @@ const style = `
3740
3889
  border: 2px solid CanvasText !important;
3741
3890
  box-shadow: none !important;
3742
3891
  }
3892
+ .panel.open:not(.compact) .page-assistance-overlay {
3893
+ background: transparent;
3894
+ -webkit-backdrop-filter: none;
3895
+ backdrop-filter: none;
3896
+ }
3897
+ .panel.open:not(.compact) .page-assistance-dialog {
3898
+ color: CanvasText;
3899
+ background: Canvas;
3900
+ border: 2px solid CanvasText;
3901
+ box-shadow: none;
3902
+ -webkit-backdrop-filter: none;
3903
+ backdrop-filter: none;
3904
+ forced-color-adjust: auto;
3905
+ }
3743
3906
  .panel.active-session.compact:is(.voice-session, .starting-voice) .header {
3744
3907
  background: Canvas;
3745
3908
  border: 2px solid CanvasText;
@@ -3813,7 +3976,7 @@ const style = `
3813
3976
  .header-actions { gap: 4px; }
3814
3977
  .duration { min-width: 48px; padding-inline: 6px; }
3815
3978
  .feedback-options { grid-template-columns: repeat(2, minmax(0, 1fr)); }
3816
- .page-assistance-overlay { place-items: end center; padding: 8px; }
3979
+ .page-assistance-overlay { place-items: end center; padding: 8px 6px 6px; }
3817
3980
  .page-assistance-dialog { width: 100%; max-height: calc(100% - 4px); }
3818
3981
  .page-assistance-actions { display: grid; grid-template-columns: minmax(0, 1fr); }
3819
3982
  .page-assistance-actions button { width: 100%; }
@@ -3926,7 +4089,7 @@ const style = `
3926
4089
  height: auto;
3927
4090
  max-height: calc(100dvh - 16px - env(safe-area-inset-bottom));
3928
4091
  padding: 14px;
3929
- border: 1px solid rgba(255, 255, 255, .72);
4092
+ border: 1px solid var(--expanded-panel-border);
3930
4093
  border-radius: 24px;
3931
4094
  }
3932
4095
  .panel.open.compact.error-state {
@@ -3956,9 +4119,9 @@ const style = `
3956
4119
  }
3957
4120
  }
3958
4121
  :host([data-iridescence="false"]) .panel.open:not(.compact) {
3959
- background: #f7f4f8;
3960
- border-color: #d9d4dc;
3961
- box-shadow: 0 12px 28px rgba(15, 23, 42, .16);
4122
+ background: var(--non-iridescent-panel-background);
4123
+ border-color: var(--non-iridescent-panel-border);
4124
+ box-shadow: var(--non-iridescent-panel-shadow);
3962
4125
  }
3963
4126
  :host([data-iridescence="false"]) .panel.open:not(.compact) .brand-mark,
3964
4127
  :host([data-iridescence="false"]) .panel.open:not(.compact) .mode-switch,
@@ -4016,6 +4179,7 @@ export class WidgetView {
4016
4179
  this.currentHandoffContextRequest = null;
4017
4180
  this.handoffRequestPreparing = false;
4018
4181
  this.currentPageAssistanceRequest = null;
4182
+ this.pageAssistancePresentationSnapshot = null;
4019
4183
  this.safetyInteractionIdentity = null;
4020
4184
  this.introComposing = false;
4021
4185
  this.legalOpenedPanel = false;
@@ -4030,6 +4194,7 @@ export class WidgetView {
4030
4194
  this.tooltipTarget = null;
4031
4195
  this.tooltipTimer = null;
4032
4196
  this.ambientHideTimer = null;
4197
+ this.voiceCardEffectSettleTimer = null;
4033
4198
  this.attributionTimer = null;
4034
4199
  this.feedbackExitTimer = null;
4035
4200
  this.assistantReadyVisualTimer = null;
@@ -4391,6 +4556,16 @@ export class WidgetView {
4391
4556
  void this.playRemoteAudio();
4392
4557
  }
4393
4558
  playRemoteAudio() {
4559
+ // Text sessions keep a receive-only audio section for the realtime
4560
+ // transport, so an attached stream alone never authorizes playback.
4561
+ const remoteStream = this.audio.srcObject;
4562
+ const hasLiveAudioTrack = typeof remoteStream?.getAudioTracks === "function" &&
4563
+ remoteStream
4564
+ .getAudioTracks()
4565
+ .some((track) => track.readyState === "live");
4566
+ if (!this.active || !this.voiceActive || !hasLiveAudioTrack) {
4567
+ return Promise.resolve();
4568
+ }
4394
4569
  if (this.playbackResumePending)
4395
4570
  return Promise.resolve();
4396
4571
  const generation = this.playbackGeneration;
@@ -4422,9 +4597,12 @@ export class WidgetView {
4422
4597
  this.playbackBlocked = false;
4423
4598
  this.playbackResumePending = false;
4424
4599
  }
4425
- resetRemotePlayback() {
4600
+ pauseRemotePlayback() {
4426
4601
  this.invalidateRemotePlayback();
4427
4602
  this.audio.pause();
4603
+ }
4604
+ resetRemotePlayback() {
4605
+ this.pauseRemotePlayback();
4428
4606
  this.audio.srcObject = null;
4429
4607
  }
4430
4608
  playbackEventIsCurrent() {
@@ -4516,9 +4694,75 @@ export class WidgetView {
4516
4694
  applyActivity(value) {
4517
4695
  if (this.activity === value)
4518
4696
  return;
4697
+ const wasBusy = this.effectActivityIsBusy(this.activity);
4698
+ const willBeBusy = this.effectActivityIsBusy(value);
4699
+ if (willBeBusy) {
4700
+ this.clearVoiceCardEffectSettle();
4701
+ }
4702
+ else if (wasBusy && value === "ready") {
4703
+ this.beginVoiceCardEffectSettle();
4704
+ }
4705
+ else {
4706
+ this.clearVoiceCardEffectSettle();
4707
+ }
4519
4708
  this.activity = value;
4520
4709
  this.host.dataset.activity = value;
4521
4710
  }
4711
+ effectActivityIsBusy(value) {
4712
+ return (value === "connecting" ||
4713
+ value === "listening" ||
4714
+ value === "thinking" ||
4715
+ value === "speaking" ||
4716
+ value === "acting");
4717
+ }
4718
+ beginVoiceCardEffectSettle() {
4719
+ this.clearVoiceCardEffectSettle();
4720
+ if (!this.active ||
4721
+ !this.voiceActive ||
4722
+ !this.compact ||
4723
+ !this.panel.classList.contains("voice-session") ||
4724
+ !this.effectsCanRun()) {
4725
+ return;
4726
+ }
4727
+ const effects = this.voiceCardEffectElements();
4728
+ if (effects.length === 0)
4729
+ return;
4730
+ let captures;
4731
+ try {
4732
+ captures = effects.map((effect) => ({
4733
+ effect,
4734
+ transform: getComputedStyle(effect, "::before").transform,
4735
+ }));
4736
+ }
4737
+ catch {
4738
+ return;
4739
+ }
4740
+ if (captures.some(({ transform }) => !transform || transform === "none")) {
4741
+ return;
4742
+ }
4743
+ for (const { effect, transform } of captures) {
4744
+ effect.style.setProperty("--voice-effect-captured-transform", transform);
4745
+ }
4746
+ this.host.dataset.voiceEffectSettle = "captured";
4747
+ void this.panel.offsetWidth;
4748
+ this.host.dataset.voiceEffectSettle = "settling";
4749
+ this.voiceCardEffectSettleTimer = setTimeout(() => {
4750
+ this.voiceCardEffectSettleTimer = null;
4751
+ this.clearVoiceCardEffectSettle();
4752
+ }, VOICE_CARD_EFFECT_SETTLE_MS);
4753
+ }
4754
+ clearVoiceCardEffectSettle() {
4755
+ if (this.voiceCardEffectSettleTimer !== null) {
4756
+ clearTimeout(this.voiceCardEffectSettleTimer);
4757
+ this.voiceCardEffectSettleTimer = null;
4758
+ }
4759
+ delete this.host.dataset.voiceEffectSettle;
4760
+ this.voiceCardEffectElements().forEach((effect) => effect.style.removeProperty("--voice-effect-captured-transform"));
4761
+ }
4762
+ voiceCardEffectElements() {
4763
+ return [...this.panel.children].filter((element) => element instanceof HTMLElement &&
4764
+ element.matches(".voice-card-fx.intro-effect"));
4765
+ }
4522
4766
  effectsCanRun() {
4523
4767
  return (this.capabilityTier === "standard" &&
4524
4768
  !this.isReducedMotionRequested() &&
@@ -4535,6 +4779,8 @@ export class WidgetView {
4535
4779
  ? "on"
4536
4780
  : "off";
4537
4781
  this.host.dataset.effectsPaused = String(!shouldRun);
4782
+ if (!shouldRun)
4783
+ this.clearVoiceCardEffectSettle();
4538
4784
  }
4539
4785
  message(key) {
4540
4786
  return this.messages[key];
@@ -4546,8 +4792,9 @@ export class WidgetView {
4546
4792
  open(mode = "text") {
4547
4793
  const requestedMode = mode === "voice" && this.config.capabilities?.voice ? "voice" : "text";
4548
4794
  if (!this.active) {
4549
- if (this.introMinimized)
4795
+ if (this.introMinimized && !this.compactEntryEnabled()) {
4550
4796
  this.setIntroMinimized(false);
4797
+ }
4551
4798
  this.syncLauncherState();
4552
4799
  queueMicrotask(() => this.focusIntroControl(requestedMode));
4553
4800
  return;
@@ -5671,10 +5918,8 @@ export class WidgetView {
5671
5918
  const alwaysControl = this.require('[data-role="page-assistance-always-control"]');
5672
5919
  alwaysControl.hidden = !value.persistenceEligible;
5673
5920
  this.syncPageAssistanceFooter();
5674
- this.require('[data-role="page-assistance-overlay"]').hidden =
5675
- false;
5921
+ const overlay = this.syncPageAssistancePresentation();
5676
5922
  this.syncHeaderActions();
5677
- const overlay = this.require('[data-role="page-assistance-overlay"]');
5678
5923
  this.dialogFocus.present({
5679
5924
  surface: overlay,
5680
5925
  initialFocus: () => this.require('[data-role="page-assistance-decline"]'),
@@ -5684,6 +5929,55 @@ export class WidgetView {
5684
5929
  },
5685
5930
  });
5686
5931
  }
5932
+ syncPageAssistancePresentation() {
5933
+ const overlay = this.require('[data-role="page-assistance-overlay"]');
5934
+ const visible = this.currentPageAssistanceRequest !== null;
5935
+ overlay.hidden = !visible;
5936
+ this.panel.classList.toggle("page-assistance-state", visible);
5937
+ const backgroundElements = [
5938
+ this.require(".header"),
5939
+ ...[...this.body.children].filter((child) => child instanceof HTMLElement),
5940
+ this.controls,
5941
+ ];
5942
+ if (visible) {
5943
+ if (!this.pageAssistancePresentationSnapshot) {
5944
+ this.pageAssistancePresentationSnapshot = {
5945
+ inert: new Map(),
5946
+ bodyOverflow: this.body.style.overflow,
5947
+ bodyOverflowX: this.body.style.overflowX,
5948
+ bodyOverflowY: this.body.style.overflowY,
5949
+ bodyOverscrollBehavior: this.body.style.overscrollBehavior,
5950
+ bodyScrollTop: this.body.scrollTop,
5951
+ bodyScrollLeft: this.body.scrollLeft,
5952
+ };
5953
+ }
5954
+ for (const element of backgroundElements) {
5955
+ if (!this.pageAssistancePresentationSnapshot.inert.has(element)) {
5956
+ this.pageAssistancePresentationSnapshot.inert.set(element, element.inert);
5957
+ }
5958
+ element.inert = true;
5959
+ }
5960
+ this.body.style.overflow = "hidden";
5961
+ this.body.style.overflowX = "hidden";
5962
+ this.body.style.overflowY = "hidden";
5963
+ this.body.style.overscrollBehavior = "contain";
5964
+ return overlay;
5965
+ }
5966
+ const snapshot = this.pageAssistancePresentationSnapshot;
5967
+ if (!snapshot)
5968
+ return overlay;
5969
+ for (const [element, inert] of snapshot.inert) {
5970
+ element.inert = inert;
5971
+ }
5972
+ this.body.style.overflow = snapshot.bodyOverflow;
5973
+ this.body.style.overflowX = snapshot.bodyOverflowX;
5974
+ this.body.style.overflowY = snapshot.bodyOverflowY;
5975
+ this.body.style.overscrollBehavior = snapshot.bodyOverscrollBehavior;
5976
+ this.body.scrollTop = snapshot.bodyScrollTop;
5977
+ this.body.scrollLeft = snapshot.bodyScrollLeft;
5978
+ this.pageAssistancePresentationSnapshot = null;
5979
+ return overlay;
5980
+ }
5687
5981
  syncPageAssistanceFooter() {
5688
5982
  const alwaysControl = this.require('[data-role="page-assistance-always-control"]');
5689
5983
  const agreement = this.require('[data-role="page-assistance-agreement"]');
@@ -5802,6 +6096,12 @@ export class WidgetView {
5802
6096
  ? this.createPrimarySurfaceTransitionClone(compactModeSource, true)
5803
6097
  : null;
5804
6098
  this.voiceActive = voiceActive;
6099
+ if (wasVoiceActive && !voiceActive) {
6100
+ this.resetRemotePlayback();
6101
+ }
6102
+ else if (!wasVoiceActive && voiceActive) {
6103
+ void this.playRemoteAudio();
6104
+ }
5805
6105
  this.modeTransitionPending = null;
5806
6106
  if (committingStartingVoice) {
5807
6107
  this.discardStartingVoicePresentation();
@@ -5874,8 +6174,13 @@ export class WidgetView {
5874
6174
  this.syncHeaderActions();
5875
6175
  }
5876
6176
  setModeTransitionPending(mode) {
6177
+ const previousMode = this.modeTransitionPending;
5877
6178
  this.modeTransitionPending = mode;
5878
6179
  if (mode === "voice" && this.active && !this.voiceActive) {
6180
+ // A text session can still own a live recv-only stream. Detach it before
6181
+ // the prepared Voice transport supplies its own authoritative stream.
6182
+ if (previousMode !== "voice")
6183
+ this.resetRemotePlayback();
5879
6184
  this.beginStartingVoicePresentation();
5880
6185
  }
5881
6186
  else if (mode === null &&
@@ -6376,11 +6681,14 @@ export class WidgetView {
6376
6681
  document.visibilityState === "hidden") {
6377
6682
  return false;
6378
6683
  }
6379
- const surface = this.confirmation.classList.contains("visible")
6380
- ? this.confirmation
6381
- : this.visualRequest.classList.contains("visible")
6382
- ? this.visualRequest
6383
- : this.panel;
6684
+ const pageAssistance = this.require('[data-role="page-assistance-overlay"]');
6685
+ const surface = this.currentPageAssistanceRequest && !pageAssistance.hidden
6686
+ ? pageAssistance
6687
+ : this.confirmation.classList.contains("visible")
6688
+ ? this.confirmation
6689
+ : this.visualRequest.classList.contains("visible")
6690
+ ? this.visualRequest
6691
+ : this.panel;
6384
6692
  const rect = surface.getBoundingClientRect();
6385
6693
  const computed = getComputedStyle(surface);
6386
6694
  if (rect.width < 2 ||
@@ -6410,7 +6718,7 @@ export class WidgetView {
6410
6718
  return false;
6411
6719
  }
6412
6720
  const shadowTop = shadowFromPoint?.(x, y) ?? null;
6413
- return !shadowTop || this.panel.contains(shadowTop);
6721
+ return !shadowTop || surface.contains(shadowTop);
6414
6722
  });
6415
6723
  }
6416
6724
  destroy() {
@@ -6425,6 +6733,7 @@ export class WidgetView {
6425
6733
  this.reducedMotionQuery?.removeEventListener?.("change", this.onReducedMotionChange);
6426
6734
  this.hideTooltip();
6427
6735
  this.clearAssistantReadyVisualTimer();
6736
+ this.clearVoiceCardEffectSettle();
6428
6737
  this.clearFeedbackExitFade();
6429
6738
  this.cancelPanelDrag();
6430
6739
  this.resetRemotePlayback();
@@ -6451,6 +6760,7 @@ export class WidgetView {
6451
6760
  this.hideAttribution();
6452
6761
  this.panel.removeEventListener("pointerdown", this.onPlaybackActivation, true);
6453
6762
  this.currentPageAssistanceRequest = null;
6763
+ this.pageAssistancePresentationSnapshot = null;
6454
6764
  this.dialogFocus.destroy();
6455
6765
  this.host.remove();
6456
6766
  this.currentConfirmation = null;
@@ -6557,28 +6867,6 @@ export class WidgetView {
6557
6867
  <div class="legal-links" data-role="legal-links"><a data-role="legal-privacy" target="_blank" rel="noopener noreferrer"></a><a data-role="legal-terms" target="_blank" rel="noopener noreferrer"></a></div>
6558
6868
  </section>
6559
6869
  </div>
6560
- <div class="page-assistance-overlay" data-role="page-assistance-overlay" hidden>
6561
- <section class="page-assistance-dialog" role="dialog" aria-modal="true" aria-labelledby="oxvo-ai-page-assistance-title" aria-describedby="oxvo-ai-page-assistance-action">
6562
- <div class="page-assistance-header">
6563
- <div class="page-assistance-header-copy">
6564
- <h3 id="oxvo-ai-page-assistance-title" data-role="page-assistance-title"></h3>
6565
- <p id="oxvo-ai-page-assistance-action" class="page-assistance-action-copy"><span data-role="page-assistance-action"></span><span class="page-assistance-target" data-role="page-assistance-target"></span></p>
6566
- </div>
6567
- <button type="button" class="legal-close icon-button" data-role="page-assistance-close"><span class="button-icon" data-icon aria-hidden="true"></span></button>
6568
- </div>
6569
- <div class="page-assistance-footer" hidden>
6570
- <label class="page-assistance-always" data-role="page-assistance-always-control" hidden>
6571
- <input type="checkbox" data-role="page-assistance-always">
6572
- <span data-role="page-assistance-always-label"></span>
6573
- </label>
6574
- <p id="oxvo-ai-page-assistance-agreement" class="page-assistance-agreement" data-role="page-assistance-agreement"><span data-role="page-assistance-agreement-prefix"></span><a data-role="privacy" target="_blank" rel="noopener noreferrer"></a><span data-role="page-assistance-agreement-connector"></span><a data-role="terms" target="_blank" rel="noopener noreferrer"></a><span data-role="page-assistance-agreement-terminator"></span></p>
6575
- </div>
6576
- <div class="page-assistance-actions">
6577
- <button type="button" class="secondary" data-role="page-assistance-decline"></button>
6578
- <button type="button" class="primary" data-role="page-assistance-allow"></button>
6579
- </div>
6580
- </section>
6581
- </div>
6582
6870
  <div class="body" id="oxvo-ai-live-assist-content">
6583
6871
  <div class="support-reply-notice" data-role="support-reply-notice" role="status" aria-live="polite" aria-atomic="true" hidden>
6584
6872
  <span data-role="support-reply-message"></span>
@@ -6613,6 +6901,28 @@ export class WidgetView {
6613
6901
  <div class="attribution-bubble" data-role="attribution" role="status" hidden><a href="https://oxvo.com/" target="_blank" rel="noopener noreferrer">OXVO</a></div>
6614
6902
  </div>
6615
6903
  </div>
6904
+ <div class="page-assistance-overlay" data-role="page-assistance-overlay" hidden>
6905
+ <section class="page-assistance-dialog" role="dialog" aria-modal="true" aria-labelledby="oxvo-ai-page-assistance-title" aria-describedby="oxvo-ai-page-assistance-action">
6906
+ <div class="page-assistance-header">
6907
+ <div class="page-assistance-header-copy">
6908
+ <h3 id="oxvo-ai-page-assistance-title" data-role="page-assistance-title"></h3>
6909
+ <p id="oxvo-ai-page-assistance-action" class="page-assistance-action-copy"><span data-role="page-assistance-action"></span><span class="page-assistance-target" data-role="page-assistance-target"></span></p>
6910
+ </div>
6911
+ <button type="button" class="legal-close icon-button" data-role="page-assistance-close"><span class="button-icon" data-icon aria-hidden="true"></span></button>
6912
+ </div>
6913
+ <div class="page-assistance-footer" hidden>
6914
+ <label class="page-assistance-always" data-role="page-assistance-always-control" hidden>
6915
+ <input type="checkbox" data-role="page-assistance-always">
6916
+ <span data-role="page-assistance-always-label"></span>
6917
+ </label>
6918
+ <p id="oxvo-ai-page-assistance-agreement" class="page-assistance-agreement" data-role="page-assistance-agreement"><span data-role="page-assistance-agreement-prefix"></span><a data-role="privacy" target="_blank" rel="noopener noreferrer"></a><span data-role="page-assistance-agreement-connector"></span><a data-role="terms" target="_blank" rel="noopener noreferrer"></a><span data-role="page-assistance-agreement-terminator"></span></p>
6919
+ </div>
6920
+ <div class="page-assistance-actions">
6921
+ <button type="button" class="secondary" data-role="page-assistance-decline"></button>
6922
+ <button type="button" class="primary" data-role="page-assistance-allow"></button>
6923
+ </div>
6924
+ </section>
6925
+ </div>
6616
6926
  <footer class="controls">
6617
6927
  <div class="composer-shell">
6618
6928
  <div class="voice-hud" data-role="voice-hud" hidden>
@@ -6654,7 +6964,7 @@ export class WidgetView {
6654
6964
  </div>
6655
6965
  </div>
6656
6966
  </footer>
6657
- <audio autoplay></audio>
6967
+ <audio></audio>
6658
6968
  `;
6659
6969
  fragment.append(intro, highlight, panel, tooltip);
6660
6970
  return fragment;
@@ -6706,12 +7016,8 @@ export class WidgetView {
6706
7016
  }
6707
7017
  if (!this.active || this.voiceActive || !this.compact)
6708
7018
  return;
7019
+ this.preferredFocusAfterTransition = this.require('[data-role="text-input"]');
6709
7020
  this.setCompact(false);
6710
- queueMicrotask(() => {
6711
- if (this.active && !this.voiceActive && !this.compact) {
6712
- this.require('[data-role="text-input"]').focus();
6713
- }
6714
- });
6715
7021
  });
6716
7022
  this.require('[data-role="compact-voice"]').addEventListener("click", () => {
6717
7023
  if (this.panel.classList.contains("error-state")) {
@@ -6874,8 +7180,11 @@ export class WidgetView {
6874
7180
  });
6875
7181
  composer.addEventListener("submit", (event) => {
6876
7182
  event.preventDefault();
6877
- if (textInput.disabled)
7183
+ if (textInput.disabled ||
7184
+ this.panel.inert ||
7185
+ this.panel.getAttribute("aria-hidden") === "true") {
6878
7186
  return;
7187
+ }
6879
7188
  const value = textInput.value.trim();
6880
7189
  if (!value)
6881
7190
  return;
@@ -7041,8 +7350,10 @@ export class WidgetView {
7041
7350
  this.messages.privacyPolicy;
7042
7351
  this.require('[data-role="legal-terms"]').textContent =
7043
7352
  this.messages.termsOfService;
7044
- this.require('[data-role="empty"]').textContent =
7045
- this.messages.emptyConversation;
7353
+ const emptyConversation = this.captions.querySelector('[data-role="empty"]');
7354
+ if (emptyConversation) {
7355
+ emptyConversation.textContent = this.messages.emptyConversation;
7356
+ }
7046
7357
  const end = this.require('[data-role="end"]');
7047
7358
  end.setAttribute("aria-label", this.messages.end);
7048
7359
  this.setTooltip(end, this.messages.end);
@@ -7095,10 +7406,12 @@ export class WidgetView {
7095
7406
  const introMinimize = this.require('[data-role="intro-minimize"]');
7096
7407
  const introExpand = this.require('[data-role="intro-expand"]');
7097
7408
  const introCompactVoice = this.require('[data-role="intro-compact-voice"]');
7409
+ const compactEntryEnabled = appearance?.compactEntryEnabled === true;
7098
7410
  const textEntryEnabled = this.config.capabilities?.text === true;
7099
7411
  const voiceEntryEnabled = this.config.capabilities?.voice === true;
7100
7412
  introEntry.hidden = !textEntryEnabled && !voiceEntryEnabled;
7101
7413
  introEntry.dataset.textEnabled = String(textEntryEnabled);
7414
+ introEntry.dataset.compactEntryEnabled = String(compactEntryEnabled);
7102
7415
  introInput.hidden = !textEntryEnabled;
7103
7416
  introInput.placeholder =
7104
7417
  entryEnabled && entry?.inputPlaceholder.trim()
@@ -7130,6 +7443,10 @@ export class WidgetView {
7130
7443
  this.require('[data-role="intro-compact-group"]').setAttribute("aria-label", this.messages.conversationStarters);
7131
7444
  this.require('[data-role="proactive-prompts"]').setAttribute("aria-label", this.messages.conversationStarters);
7132
7445
  this.require('[data-role="suggested-prompts"]').setAttribute("aria-label", this.messages.conversationStarters);
7446
+ if (!this.active) {
7447
+ this.clearIntroTransition();
7448
+ this.introMinimized = compactEntryEnabled;
7449
+ }
7133
7450
  this.syncIntroMinimizedState();
7134
7451
  this.syncIntroSendState();
7135
7452
  const send = this.require('[data-role="send"]');
@@ -7377,6 +7694,11 @@ export class WidgetView {
7377
7694
  setIntroMinimized(value, moveFocus = false) {
7378
7695
  if (value && (this.active || this.launcherSuppressed))
7379
7696
  return;
7697
+ if (!value && this.compactEntryEnabled()) {
7698
+ if (moveFocus)
7699
+ this.focusIntroView(true);
7700
+ return;
7701
+ }
7380
7702
  if (this.introTransitionTarget === value)
7381
7703
  return;
7382
7704
  if (this.introTransitionTarget !== null && this.introMinimized === value) {
@@ -7561,6 +7883,20 @@ export class WidgetView {
7561
7883
  focusIntroControl(mode) {
7562
7884
  const input = this.require('[data-role="intro-text-input"]');
7563
7885
  const voice = this.require('[data-role="intro-voice"]');
7886
+ const compactChat = this.require('[data-role="intro-expand"]');
7887
+ const compactVoice = this.require('[data-role="intro-compact-voice"]');
7888
+ if (this.introMinimized && this.compactEntryEnabled()) {
7889
+ const compactCandidates = mode === "voice"
7890
+ ? [compactVoice, compactChat]
7891
+ : [compactChat, compactVoice];
7892
+ for (const candidate of compactCandidates) {
7893
+ if (candidate.hidden || candidate.hasAttribute("disabled"))
7894
+ continue;
7895
+ candidate.focus({ preventScroll: true });
7896
+ return;
7897
+ }
7898
+ return;
7899
+ }
7564
7900
  const candidates = mode === "voice" ? [voice, input] : [input, voice];
7565
7901
  for (const candidate of candidates) {
7566
7902
  if (candidate.hidden || candidate.hasAttribute("disabled"))
@@ -7574,10 +7910,8 @@ export class WidgetView {
7574
7910
  if (!request)
7575
7911
  return;
7576
7912
  this.currentPageAssistanceRequest = null;
7577
- this.require('[data-role="page-assistance-overlay"]').hidden =
7578
- true;
7913
+ const overlay = this.syncPageAssistancePresentation();
7579
7914
  this.require('[data-role="page-assistance-always"]').checked = false;
7580
- const overlay = this.require('[data-role="page-assistance-overlay"]');
7581
7915
  this.dialogFocus.dismiss(overlay);
7582
7916
  this.restoreVoicePresenceAfterPrompt();
7583
7917
  this.syncHeaderActions();
@@ -8863,6 +9197,9 @@ export class WidgetView {
8863
9197
  this.syncProactiveEngagementVisibility();
8864
9198
  this.syncSurfaceEffectOwner();
8865
9199
  }
9200
+ compactEntryEnabled() {
9201
+ return this.config.appearance?.compactEntryEnabled === true;
9202
+ }
8866
9203
  cancelPendingConfirmation() {
8867
9204
  if (!this.resolvePendingConfirmation(false))
8868
9205
  return false;
@@ -9056,7 +9393,7 @@ export class WidgetView {
9056
9393
  introInput.value = "";
9057
9394
  introInput.setAttribute("aria-invalid", "false");
9058
9395
  this.clearIntroTransition();
9059
- this.introMinimized = false;
9396
+ this.introMinimized = this.compactEntryEnabled();
9060
9397
  this.syncIntroMinimizedState();
9061
9398
  this.panel.classList.remove("voice-session");
9062
9399
  this.panel.removeAttribute("data-presentation");