main
html 1,541 lines 52 KB
Raw
1 <html class="browser-modal">
2
3 <head>
4 <title>Browser</title>
5 <script type="module">
6 import { store } from "/plugins/_browser/webui/browser-store.js";
7 </script>
8 </head>
9
10 <body class="browser-modal-body">
11 <div x-data>
12 <template x-if="$store.browserPage">
13 <div class="browser-panel" x-create="$store.browserPage.onOpen($el, xAttrs($el) || {})" x-destroy="$store.browserPage.cleanup()"
14 x-effect="$store.browserPage.handleSelectedContextChange($store.chats?.selected)"
15 @keydown.window="$store.browserPage.handleKeydown($event)">
16 <div class="browser-meta">
17 <div class="browser-meta-top">
18 <div class="browser-session-tabs" role="tablist" aria-label="Browser sessions">
19 <template x-for="browser in $store.browserPage.visibleBrowsers()" :key="$store.browserPage.browserTabKey(browser)">
20 <div class="browser-tab-shell" :class="{ 'is-active': $store.browserPage.isActiveBrowser(browser) }">
21 <button type="button" class="browser-tab" role="tab"
22 :aria-selected="$store.browserPage.isActiveBrowser(browser).toString()"
23 :aria-busy="$store.browserPage.isBrowserLoading(browser).toString()"
24 :title="$store.browserPage.browserTabTooltip(browser)"
25 @click="$store.browserPage.selectBrowser(browser.id, browser.context_id)">
26 <x-icon class="browser-tab-icon" aria-hidden="true" name="language"></x-icon>
27 <span class="browser-tab-title" x-text="$store.browserPage.browserTabTitle(browser)"></span>
28 </button>
29 <x-icon class="browser-tab-loading" aria-hidden="true"
30 :class="{ 'is-visible': $store.browserPage.isBrowserLoading(browser), 'spinning': $store.browserPage.isBrowserLoading(browser) }"
31 name="progress_activity"></x-icon>
32 <button type="button" class="browser-tab-close"
33 :title="'Close ' + $store.browserPage.browserTabLabel(browser)"
34 :aria-label="'Close ' + $store.browserPage.browserTabLabel(browser)"
35 :disabled="$store.browserPage.isClosingBrowser(browser.id, browser.context_id)"
36 @pointerdown.stop
37 @click.stop="$store.browserPage.closeBrowser(browser.id, browser.context_id)">
38 <x-icon name="close"></x-icon>
39 </button>
40 </div>
41 </template>
42 <button type="button" class="browser-new-tab" title="New Browser" aria-label="New Browser"
43 :disabled="$store.browserPage.isBusy()"
44 @click="$store.browserPage.openNewBrowser()">
45 <x-icon name="add"></x-icon>
46 </button>
47 </div>
48
49 </div>
50 </div>
51
52 <div class="browser-toolbar">
53 <div class="browser-navigation">
54 <button class="btn btn-icon-action" title="Back" @click="$store.browserPage.command('back')"
55 :disabled="!$store.browserPage.activeBrowserId || $store.browserPage.isBusy()">
56 <x-icon name="arrow_back"></x-icon>
57 </button>
58 <button class="btn btn-icon-action" title="Forward" @click="$store.browserPage.command('forward')"
59 :disabled="!$store.browserPage.activeBrowserId || $store.browserPage.isBusy()">
60 <x-icon name="arrow_forward"></x-icon>
61 </button>
62 <button class="btn btn-icon-action" title="Reload" @click="$store.browserPage.command('reload')"
63 :disabled="!$store.browserPage.activeBrowserId || $store.browserPage.isBusy()">
64 <x-icon name="refresh"></x-icon>
65 </button>
66 </div>
67
68 <div class="browser-session-controls">
69 <button type="button" class="btn browser-annotate-toggle" title="Annotate" aria-label="Annotate"
70 :aria-pressed="$store.browserPage.annotating.toString()"
71 :class="{ 'is-active': $store.browserPage.annotating }"
72 :disabled="!$store.browserPage.canAnnotate() && !$store.browserPage.annotating"
73 @click="$store.browserPage.toggleAnnotationMode()">
74 <x-icon aria-hidden="true"
75 :name="$store.browserPage.annotating ? 'rate_review' : 'edit_note'"></x-icon>
76 <span x-text="$store.browserPage.annotating ? 'Annotating' : 'Annotate'"></span>
77 </button>
78 <div class="browser-extension-menu" @click.outside="$store.browserPage.closeExtensionsMenu()"
79 @keydown.escape.window="$store.browserPage.closeExtensionsMenu()">
80 <button type="button" class="btn btn-icon-action browser-extensions" title="Browser settings"
81 aria-label="Browser settings" @click.stop="$store.browserPage.toggleExtensionsMenu()"
82 :aria-expanded="$store.browserPage.extensionMenuOpen.toString()"
83 :class="{ 'is-active': $store.browserPage.status?.extensions?.active }">
84 <x-icon name="tune"></x-icon>
85 </button>
86 <div class="browser-extension-dropdown" x-show="$store.browserPage.extensionMenuOpen" x-transition
87 style="display: none;">
88 <div class="browser-extension-preset">
89 <label for="browser-model-preset">Browser LLM Preset</label>
90 <select id="browser-model-preset" x-model="$store.browserPage.modelPreset"
91 @change="$store.browserPage.setBrowserModelPreset($event.target.value)"
92 :disabled="$store.browserPage.modelPresetSaving">
93 <option value="">Default Main Model</option>
94 <template x-for="preset in $store.browserPage.modelPresetOptions" :key="preset.name">
95 <option :value="preset.name" x-text="preset.label"></option>
96 </template>
97 </select>
98 <div class="browser-extension-preset-summary" x-text="$store.browserPage.modelPresetSummary()">
99 </div>
100 </div>
101 <div class="browser-extension-section-title">Chrome Extensions</div>
102 <button type="button" class="dropdown-item" @click="$store.browserPage.createExtensionWithAgent()">
103 <x-icon name="add_circle"></x-icon>
104 <span>Create New Extension with A0</span>
105 </button>
106 <div class="browser-extension-url">
107 <label for="browser-extension-url">Input a Chrome Web Store URL</label>
108 <input id="browser-extension-url" type="url" x-model="$store.browserPage.extensionInstallUrl"
109 @keydown.enter.prevent="$store.browserPage.installExtensionFromUrl()"
110 placeholder="https://chromewebstore.google.com/detail/..." />
111 <div class="browser-extension-url-actions">
112 <button type="button" class="btn btn-ok" @click="$store.browserPage.installExtensionFromUrl()"
113 :disabled="$store.browserPage.extensionActionLoading"
114 :aria-busy="$store.browserPage.extensionActionLoading.toString()">
115 <x-icon
116 :class="{ spinning: $store.browserPage.extensionActionLoading }"
117 :name="$store.browserPage.extensionActionLoading ? 'progress_activity' : 'download'"></x-icon>
118 <span x-text="$store.browserPage.extensionActionLoading ? 'Installing…' : 'Install URL'">Install URL</span>
119 </button>
120 <button type="button" class="btn btn-field"
121 @click="$store.browserPage.askAgentInstallExtension()">
122 <x-icon name="psychology_alt"></x-icon>
123 <span x-text="$store.browserPage.extensionAssistantActionLabel()">Scan with A0</span>
124 </button>
125 </div>
126 <div class="browser-extension-warning" x-show="$store.browserPage.hasExtensionInstallUrl()"
127 x-transition style="display: none;">
128 <x-icon name="warning"></x-icon>
129 <span>
130 Extensions run inside the Docker browser sandbox, but malicious or buggy extensions can still
131 damage that environment. Review what you install.
132 </span>
133 </div>
134 </div>
135 <div class="browser-extension-list"
136 x-show="$store.browserPage.extensionsListLoading || $store.browserPage.extensionsList.length"
137 style="display: none;">
138 <div class="browser-extension-list-header">
139 <span>Installed extensions</span>
140 <x-icon class="spinning"
141 x-show="$store.browserPage.extensionsListLoading" name="progress_activity"></x-icon>
142 </div>
143 <template x-for="extension in $store.browserPage.extensionsList" :key="extension.path">
144 <div class="browser-extension-row" :title="extension.path">
145 <span class="browser-extension-row-text">
146 <span class="browser-extension-name" x-text="extension.name || 'Unnamed extension'"></span>
147 <span class="browser-extension-meta"
148 x-text="$store.browserPage.extensionVersionLabel(extension)"></span>
149 </span>
150 <span class="browser-extension-row-actions">
151 <button type="button" class="browser-extension-open"
152 x-show="$store.browserPage.extensionHasOpenUi(extension)"
153 :title="$store.browserPage.extensionOpenTitle(extension)"
154 :aria-label="$store.browserPage.extensionOpenTitle(extension)"
155 :disabled="!extension.enabled || $store.browserPage.isBusy()"
156 @click.stop="$store.browserPage.openExtensionUi(extension)">
157 <x-icon name="open_in_new"></x-icon>
158 <span>Open</span>
159 </button>
160 <label class="browser-extension-toggle">
161 <input type="checkbox" :checked="extension.enabled"
162 :disabled="$store.browserPage.extensionToggleLoadingPath === extension.path"
163 @change="$store.browserPage.setExtensionEnabled(extension, $event.target.checked, $event.target)" />
164 <span class="browser-extension-switch"></span>
165 </label>
166 </span>
167 </div>
168 </template>
169 </div>
170 <button type="button" class="dropdown-item" @click="$store.browserPage.openExtensionsSettings()">
171 <x-icon name="tune"></x-icon>
172 <span>Settings</span>
173 </button>
174 <div class="browser-extension-message" x-show="$store.browserPage.extensionActionMessage"
175 x-text="$store.browserPage.extensionActionMessage"></div>
176 <div class="browser-extension-error" x-show="$store.browserPage.extensionActionError"
177 x-text="$store.browserPage.extensionActionError"></div>
178 </div>
179 </div>
180 </div>
181
182 <form class="browser-address-form" aria-label="Browser navigation" @submit.prevent="$store.browserPage.go()">
183 <x-icon class="browser-address-icon" name="language"></x-icon>
184 <input class="browser-address" aria-label="Browser address" name="browser_address" x-model="$store.browserPage.address"
185 @focus="$store.browserPage.onAddressFocus()" @blur="$store.browserPage.onAddressBlur()"
186 @keydown.enter.prevent="$store.browserPage.go()"
187 :disabled="$store.browserPage.isBusy()"
188 placeholder="https://example.com" autocomplete="off" />
189 </form>
190 </div>
191
192 <div class="browser-stage" tabindex="0" @click="$el.focus()"
193 :class="{ 'is-annotating': $store.browserPage.annotating }"
194 @wheel.prevent="$store.browserPage.handleStageWheel($event)">
195 <template x-if="$store.browserPage.isInteractiveSurface($el.parentElement)">
196 <iframe class="browser-interactive-frame"
197 :src="$store.browserPage.interactiveViewUrl"
198 aria-label="Browser viewport"
199 allow="clipboard-read; clipboard-write"
200 @load="$store.browserPage.onInteractiveViewLoad()"></iframe>
201 </template>
202 <canvas class="browser-frame browser-frame-canvas"
203 x-show="!$store.browserPage.usesInteractiveTransport() && $store.browserPage.frameCanvasReady"
204 x-init="$store.browserPage.attachFrameCanvas($el)"
205 @click="$store.browserPage.sendMouse('click', $event)"
206 @mousemove.throttle.250ms="$store.browserPage.sendMouse('move', $event)"></canvas>
207 <template x-if="!$store.browserPage.usesInteractiveTransport() && $store.browserPage.frameSrc">
208 <img class="browser-frame browser-frame-image" :src="$store.browserPage.frameSrc"
209 @click="$store.browserPage.sendMouse('click', $event)"
210 @mousemove.throttle.250ms="$store.browserPage.sendMouse('move', $event)" draggable="false" />
211 </template>
212 <template x-if="$store.browserPage.annotating && $store.browserPage.hasFrame()">
213 <div class="browser-annotation-layer"
214 :class="{ 'is-busy': $store.browserPage.annotationBusy }"
215 @pointerdown.stop.prevent="$store.browserPage.startAnnotationSelection($event)"
216 @pointermove.stop.prevent="$store.browserPage.moveAnnotationSelection($event)"
217 @pointerup.stop.prevent="$store.browserPage.finishAnnotationSelection($event)"
218 @pointercancel.stop.prevent="$store.browserPage.cancelAnnotationSelection($event)"
219 @pointerleave="$store.browserPage.clearAnnotationHover()">
220 <template x-if="$store.browserPage.annotationHover && !$store.browserPage.annotationDraft && !$store.browserPage.annotationDragRect">
221 <div class="browser-annotation-box is-hover"
222 :style="$store.browserPage.annotationBoxStyle($store.browserPage.annotationHover.rect)">
223 <span class="browser-annotation-hover-label"
224 x-text="$store.browserPage.annotationHoverLabel()"></span>
225 </div>
226 </template>
227 <template x-for="annotation in $store.browserPage.visibleAnnotations()" :key="annotation.id">
228 <div class="browser-annotation-box is-saved"
229 :style="$store.browserPage.annotationBoxStyle(annotation.rect)">
230 <span class="browser-annotation-number" x-text="annotation.index"></span>
231 </div>
232 </template>
233 <template x-if="$store.browserPage.annotationDragRect">
234 <div class="browser-annotation-box is-draft"
235 :style="$store.browserPage.annotationBoxStyle($store.browserPage.annotationDragRect)">
236 </div>
237 </template>
238 </div>
239 </template>
240 <template x-if="$store.browserPage.annotationDraft">
241 <div class="browser-annotation-popover"
242 :style="$store.browserPage.annotationPopoverStyle()"
243 @click.stop @pointerdown.stop @keydown.stop>
244 <div class="browser-annotation-popover-title">
245 <span class="browser-annotation-popover-heading">
246 <span class="browser-annotation-number" x-text="$store.browserPage.nextAnnotationIndex()"></span>
247 <span x-text="$store.browserPage.annotationDraftTitle()"></span>
248 </span>
249 <button type="button" class="browser-annotation-popover-close"
250 title="Cancel annotation" aria-label="Cancel annotation"
251 @click="$store.browserPage.cancelAnnotationDraft()">
252 <x-icon name="close"></x-icon>
253 </button>
254 </div>
255 <textarea x-model="$store.browserPage.annotationDraftText" placeholder="Comment"
256 maxlength="1200" x-init="$nextTick(() => $el.focus())"></textarea>
257 <div class="browser-annotation-actions">
258 <button type="button" class="browser-annotation-mic mic-inactive"
259 data-whisper-microphone title="Record annotation comment"
260 aria-label="Record annotation comment"
261 x-init="$nextTick(() => $store.browserPage.syncAnnotationMicrophoneUI())"
262 @click="$store.browserPage.startAnnotationVoice(true)">
263 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 18" fill="currentColor" aria-hidden="true">
264 <path d="m8,12c1.66,0,3-1.34,3-3V3c0-1.66-1.34-3-3-3s-3,1.34-3,3v6c0,1.66,1.34,3,3,3Zm-1,1.9c-2.7-.4-4.8-2.6-5-5.4H0c.2,3.8,3.1,6.9,7,7.5v2h2v-2c3.9-.6,6.8-3.7,7-7.5h-2c-.2,2.8-2.3,5-5,5.4h-2Z" />
265 </svg>
266 </button>
267 <button type="button" class="browser-annotation-send"
268 title="Add annotation" aria-label="Add annotation"
269 :disabled="!String($store.browserPage.annotationDraftText || '').trim()"
270 @click="$store.browserPage.addAnnotationComment()">
271 <x-icon name="arrow_forward"></x-icon>
272 </button>
273 </div>
274 </div>
275 </template>
276 <div class="browser-annotation-tray"
277 x-show="$store.browserPage.pendingAnnotations().length"
278 :class="{ 'is-floating': $store.browserPage.annotationTrayPosition, 'is-dragging': $store.browserPage.annotationTrayDragging }"
279 :style="$store.browserPage.annotationTrayStyle()"
280 x-transition style="display: none;"
281 @click.stop @pointerdown.stop @keydown.stop
282 @pointermove.window="$store.browserPage.moveAnnotationTrayDrag($event)"
283 @pointerup.window="$store.browserPage.finishAnnotationTrayDrag($event)"
284 @pointercancel.window="$store.browserPage.finishAnnotationTrayDrag($event)">
285 <div class="browser-annotation-tray-header"
286 @pointerdown.stop="$store.browserPage.startAnnotationTrayDrag($event)">
287 <span x-text="$store.browserPage.annotationBatchLabel()"></span>
288 <button type="button" class="browser-annotation-clear" title="Clear annotations"
289 aria-label="Clear annotations" @click="$store.browserPage.clearPendingAnnotations()">
290 <x-icon name="delete"></x-icon>
291 </button>
292 </div>
293 <div class="browser-annotation-chips">
294 <template x-for="annotation in $store.browserPage.pendingAnnotations()" :key="annotation.id">
295 <div class="browser-annotation-chip" :title="annotation.title + ' — ' + annotation.url">
296 <span class="browser-annotation-number" x-text="annotation.index"></span>
297 <span class="browser-annotation-chip-text" x-text="annotation.comment"></span>
298 <button type="button" title="Remove annotation" aria-label="Remove annotation"
299 @click="$store.browserPage.removeAnnotationComment(annotation.id)">
300 <x-icon name="close"></x-icon>
301 </button>
302 </div>
303 </template>
304 </div>
305 <div class="browser-annotation-tray-actions">
306 <button type="button" class="browser-annotation-mic mic-inactive"
307 data-whisper-microphone title="Record annotation instruction"
308 aria-label="Record annotation instruction"
309 x-init="$nextTick(() => $store.browserPage.syncAnnotationMicrophoneUI())"
310 @click="$store.browserPage.startAnnotationVoice()">
311 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 18" fill="currentColor" aria-hidden="true">
312 <path d="m8,12c1.66,0,3-1.34,3-3V3c0-1.66-1.34-3-3-3s-3,1.34-3,3v6c0,1.66,1.34,3,3,3Zm-1,1.9c-2.7-.4-4.8-2.6-5-5.4H0c.2,3.8,3.1,6.9,7,7.5v2h2v-2c3.9-.6,6.8-3.7,7-7.5h-2c-.2,2.8-2.3,5-5,5.4h-2Z" />
313 </svg>
314 </button>
315 <button type="button" class="browser-annotation-send"
316 title="Send annotations" aria-label="Send annotations"
317 @click="$store.browserPage.sendAnnotationsToChat()">
318 <x-icon name="arrow_forward"></x-icon>
319 </button>
320 </div>
321 </div>
322 <template x-if="!$store.browserPage.hasFrame() && !$store.browserPage.isBusy()">
323 <div class="browser-empty">
324 <x-icon name="captive_portal"></x-icon>
325 <button class="btn btn-field" @click="$store.browserPage.command('open')">Open
326 Browser</button>
327 </div>
328 </template>
329 <template x-if="!$store.browserPage.hasFrame() && $store.browserPage.isBusy()">
330 <div class="browser-empty browser-starting" role="status" aria-live="polite">
331 <x-icon class="spinning" name="progress_activity"></x-icon>
332 <span x-text="$store.browserPage.browserLoadingLabel()"></span>
333 </div>
334 </template>
335 </div>
336
337 <template x-if="$store.browserPage.error">
338 <div class="browser-bottom-status has-error">
339 <div class="browser-error" x-text="$store.browserPage.error" :title="$store.browserPage.error"></div>
340 </div>
341 </template>
342 </div>
343 </template>
344 </div>
345
346 <style>
347 .modal-inner.browser-modal {
348 box-sizing: border-box;
349 container-type: inline-size;
350 width: min(78vw, 1120px);
351 height: min(88vh, 900px);
352 min-width: min(320px, calc(100vw - 16px));
353 min-height: min(480px, calc(100vh - 16px));
354 max-width: calc(100vw - 16px);
355 max-height: calc(100vh - 16px);
356 resize: both;
357 border: 1px solid color-mix(in srgb, var(--color-border) 75%, transparent);
358 border-radius: 7px;
359 box-shadow: 0 18px 48px rgba(0, 0, 0, 0.32);
360 background: color-mix(in srgb, var(--color-background) 94%, #000 6%);
361 }
362
363 .modal-inner.browser-modal.is-focus-mode {
364 resize: none;
365 border-radius: 6px;
366 }
367
368 .modal-inner.browser-modal.is-focus-mode .browser-modal-focus-button {
369 color: var(--color-text);
370 border-color: color-mix(in srgb, var(--color-primary) 42%, var(--color-border));
371 background: color-mix(in srgb, var(--color-primary) 16%, var(--color-background));
372 }
373
374 .modal.modal-floating {
375 pointer-events: none;
376 }
377
378 .modal.modal-floating .modal-inner {
379 pointer-events: auto;
380 }
381
382 .modal-inner.browser-modal .modal-header {
383 min-height: 34px;
384 padding: 0.35rem 0.75rem 0.35rem 1rem;
385 cursor: move;
386 user-select: none;
387 background: color-mix(in srgb, var(--color-background) 92%, #000 8%);
388 border-bottom: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
389 }
390
391 .modal-inner.browser-modal .modal-close {
392 font-size: 1.35rem;
393 line-height: 1;
394 }
395
396 .modal-inner.browser-modal .modal-scroll {
397 flex: 1 1 auto;
398 min-height: 0;
399 overflow: hidden;
400 padding: 0;
401 }
402
403 .modal-inner.browser-modal .modal-bd.browser-modal-body {
404 box-sizing: border-box;
405 display: flex;
406 flex-direction: column;
407 height: 100%;
408 padding: 0;
409 min-height: 0;
410 }
411
412 .modal-inner.browser-modal .modal-bd.browser-modal-body>x-component,
413 .modal-inner.browser-modal .modal-bd.browser-modal-body>x-component>div,
414 .modal-inner.browser-modal .modal-bd.browser-modal-body>div {
415 display: flex;
416 flex: 1 1 auto;
417 width: 100%;
418 height: 100%;
419 min-width: 0;
420 min-height: 0;
421 }
422
423 .modal-inner.browser-modal .browser-panel {
424 height: 100%;
425 max-height: 100%;
426 overflow: hidden;
427 }
428
429 .browser-panel {
430 --browser-chrome-surface: color-mix(in srgb, var(--color-background) 92%, #000 8%);
431 --browser-chrome-border: color-mix(in srgb, var(--color-border) 58%, transparent);
432 --browser-tab-hover-border: color-mix(in srgb, var(--color-border) 78%, transparent);
433 --browser-control-size: 34px;
434 --browser-address-height: 34px;
435 --browser-tab-height: 36px;
436 --browser-tab-close-size: 32px;
437 --browser-control-radius: 0.55rem;
438 box-sizing: border-box;
439 container-type: inline-size;
440 display: flex;
441 flex: 1 1 auto;
442 flex-direction: column;
443 gap: 0;
444 height: 100%;
445 min-height: 0;
446 position: relative;
447 }
448
449 .browser-toolbar {
450 display: grid;
451 grid-template-columns: auto minmax(0, 1fr) auto;
452 grid-template-areas: "nav address controls";
453 gap: 8px;
454 align-items: center;
455 padding: 8px 10px 9px;
456 border-bottom: 0;
457 background: transparent;
458 }
459
460 .browser-navigation {
461 grid-area: nav;
462 display: flex;
463 gap: 6px;
464 }
465
466 .browser-panel .btn-icon-action,
467 .browser-new-tab {
468 width: var(--browser-control-size);
469 min-width: var(--browser-control-size);
470 height: var(--browser-control-size);
471 min-height: var(--browser-control-size);
472 border-radius: var(--browser-control-radius);
473 }
474
475 .browser-panel .btn-icon-action {
476 color: color-mix(in srgb, var(--color-text) 72%, var(--color-primary) 28%);
477 background: color-mix(in srgb, var(--color-background) 26%, transparent);
478 border-color: var(--browser-chrome-border);
479 }
480
481 .browser-panel .btn-icon-action:hover:not(:disabled) {
482 color: var(--color-text);
483 border-color: color-mix(in srgb, var(--color-primary) 34%, var(--browser-chrome-border));
484 background: color-mix(in srgb, var(--color-background-hover) 62%, transparent);
485 box-shadow: none;
486 }
487
488 .browser-panel .btn-icon-action .material-symbols-outlined {
489 font-size: 1.12rem;
490 }
491
492 .browser-address-form {
493 grid-area: address;
494 min-width: 0;
495 position: relative;
496 margin: 0;
497 }
498
499 .browser-address-icon {
500 position: absolute;
501 left: 10px;
502 top: 50%;
503 transform: translateY(-50%);
504 font-size: 18px;
505 opacity: 0.58;
506 pointer-events: none;
507 }
508
509 .browser-address {
510 width: 100%;
511 min-height: var(--browser-address-height);
512 padding: 5px 10px 5px 34px;
513 border-radius: var(--browser-control-radius);
514 border: 1px solid var(--browser-chrome-border);
515 background: var(--color-input);
516 color: var(--color-text);
517 font: inherit;
518 }
519
520 .browser-meta {
521 display: grid;
522 grid-template-columns: minmax(0, 1fr);
523 gap: 0;
524 padding: 7px 10px 0;
525 border-bottom: 1px solid var(--browser-chrome-border);
526 background: var(--browser-chrome-surface);
527 }
528
529 .browser-meta-top {
530 display: grid;
531 grid-template-columns: minmax(0, 1fr);
532 gap: 10px;
533 align-items: end;
534 }
535
536 .browser-session-tabs {
537 display: flex;
538 align-items: end;
539 gap: 4px;
540 min-width: 0;
541 overflow-x: auto;
542 padding: 1px 0 0;
543 scrollbar-width: thin;
544 overflow-y: hidden;
545 }
546
547 .browser-session-tabs::-webkit-scrollbar {
548 height: 4px;
549 }
550
551 .browser-session-tabs::-webkit-scrollbar-track {
552 background: transparent;
553 }
554
555 .browser-session-tabs::-webkit-scrollbar-thumb {
556 background: color-mix(in srgb, var(--color-border) 78%, transparent);
557 border-radius: 999px;
558 }
559
560 .browser-new-tab {
561 display: inline-flex;
562 align-items: center;
563 border: 1px solid transparent;
564 color: var(--color-text);
565 cursor: pointer;
566 transition: background-color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
567 border-color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
568 color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
569 opacity 0.18s cubic-bezier(0.4, 0, 0.2, 1);
570 }
571
572 .browser-tab-shell {
573 flex: 0 1 210px;
574 position: relative;
575 display: grid;
576 grid-template-columns: minmax(0, 1fr) 18px var(--browser-tab-close-size);
577 align-items: center;
578 gap: 3px;
579 min-width: 128px;
580 max-width: 250px;
581 height: var(--browser-tab-height);
582 padding: 0 7px 0 10px;
583 border: 1px solid transparent;
584 border-radius: var(--browser-control-radius) var(--browser-control-radius) 0 0;
585 background: transparent;
586 opacity: 0.72;
587 transition: border-color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
588 color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
589 opacity 0.18s cubic-bezier(0.4, 0, 0.2, 1);
590 }
591
592 .browser-tab-shell:hover,
593 .browser-tab-shell:focus-within {
594 border-color: var(--browser-tab-hover-border);
595 opacity: 0.94;
596 }
597
598 .browser-tab-shell.is-active {
599 z-index: 2;
600 margin-bottom: -1px;
601 border-color: var(--browser-chrome-border);
602 background: transparent;
603 opacity: 1;
604 box-shadow: none;
605 }
606
607 .browser-tab {
608 display: inline-flex;
609 align-items: center;
610 justify-content: flex-start;
611 gap: 8px;
612 min-width: 0;
613 width: 100%;
614 height: 100%;
615 padding: 0;
616 border: 0;
617 border-radius: 0;
618 background: transparent;
619 color: inherit;
620 cursor: pointer;
621 font: inherit;
622 text-align: left;
623 }
624
625 .browser-tab:hover {
626 background: transparent;
627 }
628
629 .browser-tab:focus-visible,
630 .browser-tab-close:focus-visible {
631 outline: 1px solid color-mix(in srgb, var(--color-primary) 70%, transparent);
632 outline-offset: 1px;
633 }
634
635 .browser-tab-icon {
636 flex: 0 0 auto;
637 color: color-mix(in srgb, var(--color-text) 72%, var(--color-primary) 28%);
638 font-size: 1.04rem;
639 line-height: 1;
640 }
641
642 .browser-tab-title {
643 min-width: 0;
644 overflow: hidden;
645 text-overflow: ellipsis;
646 white-space: nowrap;
647 font-size: 0.88rem;
648 font-weight: 600;
649 }
650
651 .browser-tab-loading {
652 justify-self: center;
653 color: color-mix(in srgb, var(--color-text) 66%, var(--color-primary) 34%);
654 font-size: 0.96rem;
655 line-height: 1;
656 opacity: 0;
657 visibility: hidden;
658 }
659
660 .browser-tab-loading.is-visible {
661 opacity: 1;
662 visibility: visible;
663 }
664
665 .browser-tab-close {
666 display: inline-flex;
667 align-items: center;
668 justify-content: center;
669 width: var(--browser-tab-close-size);
670 min-width: var(--browser-tab-close-size);
671 height: var(--browser-tab-close-size);
672 min-height: var(--browser-tab-close-size);
673 padding: 0;
674 border: 0;
675 border-radius: 6px;
676 background: transparent;
677 color: color-mix(in srgb, var(--color-text) 52%, var(--color-primary) 48%);
678 cursor: pointer;
679 opacity: 0.72;
680 transition: background-color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
681 color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
682 opacity 0.18s cubic-bezier(0.4, 0, 0.2, 1);
683 }
684
685 .browser-tab-close:hover,
686 .browser-tab-close.confirming {
687 background: color-mix(in srgb, var(--color-background-hover) 70%, transparent);
688 color: var(--color-text);
689 opacity: 1;
690 }
691
692 .browser-tab-close .material-symbols-outlined {
693 font-size: 1rem;
694 line-height: 1;
695 }
696
697 .browser-new-tab {
698 flex: 0 0 var(--browser-control-size);
699 justify-content: center;
700 padding: 0;
701 border-color: transparent;
702 border-radius: var(--browser-control-radius);
703 background: transparent;
704 color: color-mix(in srgb, var(--color-text) 62%, var(--color-primary) 38%);
705 }
706
707 .browser-new-tab:hover {
708 background: color-mix(in srgb, var(--color-background-hover) 58%, transparent);
709 color: var(--color-text);
710 }
711
712 .browser-new-tab .material-symbols-outlined {
713 font-size: 1.18rem;
714 }
715
716 .browser-session-controls {
717 grid-area: controls;
718 display: flex;
719 align-items: center;
720 justify-content: flex-end;
721 gap: 6px;
722 min-width: 0;
723 }
724
725 .browser-annotate-toggle {
726 display: inline-flex;
727 align-items: center;
728 justify-content: center;
729 gap: 6px;
730 min-width: 0;
731 min-height: var(--browser-control-size);
732 padding: 0 10px;
733 border: 1px solid var(--browser-chrome-border);
734 border-radius: var(--browser-control-radius);
735 background: color-mix(in srgb, var(--color-background) 26%, transparent);
736 color: color-mix(in srgb, var(--color-text) 74%, var(--color-primary) 26%);
737 font-size: 0.82rem;
738 font-weight: 650;
739 white-space: nowrap;
740 }
741
742 .browser-annotate-toggle:hover:not(:disabled),
743 .browser-annotate-toggle.is-active {
744 border-color: color-mix(in srgb, var(--color-primary) 48%, var(--browser-chrome-border));
745 background: color-mix(in srgb, var(--color-primary) 16%, var(--color-background));
746 color: var(--color-text);
747 }
748
749 .browser-annotate-toggle .material-symbols-outlined {
750 font-size: 1.05rem;
751 }
752
753 .browser-session-controls .browser-extensions.is-active {
754 color: #2e7d32;
755 }
756
757 .browser-extension-menu {
758 position: relative;
759 display: flex;
760 flex: 0 0 auto;
761 }
762
763 .browser-extension-dropdown {
764 position: absolute;
765 top: calc(100% + 6px);
766 right: 0;
767 z-index: 40;
768 display: flex;
769 flex-direction: column;
770 gap: 7px;
771 width: min(360px, calc(100vw - 24px));
772 max-height: min(72vh, 560px);
773 overflow-y: auto;
774 padding: 10px;
775 border: 1px solid color-mix(in srgb, var(--color-border) 78%, transparent);
776 border-radius: 7px;
777 background: var(--color-background);
778 box-shadow: 0 16px 38px rgba(0, 0, 0, 0.28);
779 }
780
781 .browser-extension-dropdown .dropdown-item {
782 display: flex;
783 align-items: center;
784 gap: 8px;
785 width: 100%;
786 min-height: 34px;
787 padding: 7px 9px;
788 border: 0;
789 border-radius: 6px;
790 background: transparent;
791 color: var(--color-text);
792 font-weight: 600;
793 text-align: left;
794 cursor: pointer;
795 }
796
797 .browser-extension-dropdown .dropdown-item:hover {
798 background: color-mix(in srgb, var(--color-panel) 82%, transparent);
799 }
800
801 .browser-extension-warning,
802 .browser-extension-message,
803 .browser-extension-error {
804 display: flex;
805 align-items: flex-start;
806 gap: 8px;
807 padding: 9px 10px;
808 border-radius: 7px;
809 font-size: 0.8rem;
810 line-height: 1.35;
811 }
812
813 .browser-extension-warning {
814 border: 1px solid color-mix(in srgb, #d97706 42%, var(--color-border));
815 background: color-mix(in srgb, #d97706 14%, var(--color-background));
816 color: color-mix(in srgb, var(--color-text) 86%, #92400e);
817 }
818
819 .browser-extension-warning .material-symbols-outlined {
820 color: #b45309;
821 font-size: 19px;
822 }
823
824 .browser-extension-url {
825 display: flex;
826 flex-direction: column;
827 gap: 7px;
828 padding: 8px;
829 border: 1px solid color-mix(in srgb, var(--color-border) 58%, transparent);
830 border-radius: 7px;
831 background: var(--color-panel);
832 }
833
834 .browser-extension-url label {
835 font-size: 0.76rem;
836 color: var(--color-text-secondary);
837 }
838
839 .browser-extension-url input {
840 min-width: 0;
841 min-height: 32px;
842 padding: 6px 8px;
843 border: 1px solid color-mix(in srgb, var(--color-border) 72%, transparent);
844 border-radius: 6px;
845 background: var(--color-input);
846 color: var(--color-text);
847 }
848
849 .browser-extension-url-actions {
850 display: grid;
851 grid-template-columns: repeat(2, minmax(0, 1fr));
852 gap: 7px;
853 }
854
855 .browser-extension-url-actions .btn {
856 display: inline-flex;
857 align-items: center;
858 justify-content: center;
859 gap: 6px;
860 width: 100%;
861 min-width: 0;
862 min-height: 30px;
863 }
864
865 .browser-extension-preset,
866 .browser-extension-list {
867 display: flex;
868 flex-direction: column;
869 gap: 7px;
870 }
871
872 .browser-extension-section-title {
873 padding: 6px 2px 0;
874 color: var(--color-text-secondary);
875 font-size: 0.76rem;
876 font-weight: 700;
877 }
878
879 .browser-extension-preset label,
880 .browser-extension-list-header {
881 font-size: 0.76rem;
882 font-weight: 650;
883 color: var(--color-text-secondary);
884 }
885
886 .browser-extension-preset select {
887 width: 100%;
888 min-height: 32px;
889 padding: 5px 8px;
890 border: 1px solid color-mix(in srgb, var(--color-border) 72%, transparent);
891 border-radius: 6px;
892 background: var(--color-input);
893 color: var(--color-text);
894 }
895
896 .browser-extension-preset-summary,
897 .browser-extension-meta {
898 color: var(--color-text-secondary);
899 font-size: 0.75rem;
900 padding-left: var(--spacing-xxs);
901 }
902
903 .browser-extension-list-header {
904 display: flex;
905 align-items: center;
906 justify-content: space-between;
907 gap: 8px;
908 }
909
910 .browser-extension-list-header .material-symbols-outlined {
911 font-size: 16px;
912 }
913
914 .browser-extension-row {
915 display: grid;
916 grid-template-columns: minmax(0, 1fr) auto;
917 align-items: center;
918 gap: 10px;
919 min-height: 34px;
920 padding: 5px 0;
921 }
922
923 .browser-extension-row+.browser-extension-row {
924 border-top: 1px solid color-mix(in srgb, var(--color-border) 42%, transparent);
925 }
926
927 .browser-extension-row-text {
928 display: flex;
929 min-width: 0;
930 flex-direction: column;
931 gap: 2px;
932 }
933
934 .browser-extension-name {
935 overflow: hidden;
936 text-overflow: ellipsis;
937 white-space: nowrap;
938 font-size: 0.82rem;
939 font-weight: 650;
940 color: var(--color-text);
941 }
942
943 .browser-extension-row-actions {
944 display: inline-flex;
945 align-items: center;
946 gap: 7px;
947 }
948
949 .browser-extension-open {
950 display: inline-flex;
951 align-items: center;
952 justify-content: center;
953 gap: 4px;
954 min-width: 0;
955 min-height: 28px;
956 padding: 0 8px;
957 border: 1px solid color-mix(in srgb, var(--color-border) 70%, transparent);
958 border-radius: 6px;
959 background: color-mix(in srgb, var(--color-panel) 70%, transparent);
960 color: var(--color-text);
961 font: inherit;
962 font-size: 0.76rem;
963 font-weight: 650;
964 cursor: pointer;
965 }
966
967 .browser-extension-open:hover:not(:disabled) {
968 border-color: color-mix(in srgb, var(--color-primary) 42%, var(--color-border));
969 background: color-mix(in srgb, var(--color-primary) 13%, var(--color-background));
970 }
971
972 .browser-extension-open:disabled {
973 cursor: not-allowed;
974 opacity: 0.52;
975 }
976
977 .browser-extension-open .material-symbols-outlined {
978 font-size: 15px;
979 }
980
981 .browser-extension-toggle {
982 position: relative;
983 display: inline-flex;
984 flex: 0 0 auto;
985 align-items: center;
986 width: 38px;
987 height: 22px;
988 }
989
990 .browser-extension-toggle input {
991 position: absolute;
992 inset: 0;
993 margin: 0;
994 opacity: 0;
995 cursor: pointer;
996 }
997
998 .browser-extension-toggle input:disabled {
999 cursor: wait;
1000 }
1001
1002 .browser-extension-switch {
1003 width: 100%;
1004 height: 100%;
1005 border-radius: 999px;
1006 background: color-mix(in srgb, var(--color-border) 78%, transparent);
1007 transition: background-color 0.18s cubic-bezier(0.4, 0, 0.2, 1),
1008 opacity 0.18s cubic-bezier(0.4, 0, 0.2, 1);
1009 }
1010
1011 .browser-extension-switch::after {
1012 content: "";
1013 position: absolute;
1014 top: 3px;
1015 left: 3px;
1016 width: 16px;
1017 height: 16px;
1018 border-radius: 50%;
1019 background: var(--color-background);
1020 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.24);
1021 transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);
1022 }
1023
1024 .browser-extension-toggle input:checked+.browser-extension-switch {
1025 background: color-mix(in srgb, var(--color-primary) 76%, #16a34a);
1026 }
1027
1028 .browser-extension-toggle input:checked+.browser-extension-switch::after {
1029 transform: translateX(16px);
1030 }
1031
1032 .browser-extension-toggle input:disabled+.browser-extension-switch {
1033 opacity: 0.58;
1034 }
1035
1036 .browser-extension-message {
1037 background: color-mix(in srgb, #15803d 12%, var(--color-background));
1038 color: color-mix(in srgb, var(--color-text) 88%, #166534);
1039 }
1040
1041 .browser-extension-error {
1042 background: color-mix(in srgb, #be123c 12%, var(--color-background));
1043 color: #9f1239;
1044 }
1045
1046 .browser-stage {
1047 flex: 1 1 auto;
1048 min-height: 0;
1049 overflow: hidden;
1050 position: relative;
1051 contain: size layout paint;
1052 outline: none;
1053 }
1054
1055 .browser-stage.is-annotating {
1056 cursor: crosshair;
1057 }
1058
1059 .browser-frame {
1060 display: block;
1061 position: absolute;
1062 inset: 0;
1063 width: 100%;
1064 height: 100%;
1065 min-width: 0;
1066 min-height: 0;
1067 object-fit: contain;
1068 image-rendering: auto;
1069 user-select: none;
1070 background: #fff;
1071 }
1072
1073 .browser-interactive-frame {
1074 display: block;
1075 position: absolute;
1076 inset: 0;
1077 z-index: 1;
1078 box-sizing: border-box;
1079 width: 100%;
1080 height: 100%;
1081 border: 0;
1082 background: #fff;
1083 }
1084
1085 .browser-annotation-layer {
1086 position: absolute;
1087 inset: 0;
1088 z-index: 12;
1089 cursor: crosshair;
1090 touch-action: none;
1091 background: rgba(37, 99, 235, 0.035);
1092 }
1093
1094 .browser-annotation-layer.is-busy {
1095 cursor: progress;
1096 }
1097
1098 .browser-annotation-box {
1099 position: absolute;
1100 box-sizing: border-box;
1101 min-width: 8px;
1102 min-height: 8px;
1103 border: 2px solid #3399ff;
1104 background: rgba(51, 153, 255, 0.16);
1105 box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.52), 0 8px 22px rgba(0, 0, 0, 0.18);
1106 pointer-events: none;
1107 }
1108
1109 .browser-annotation-box.is-draft {
1110 border-style: dashed;
1111 background: rgba(51, 153, 255, 0.1);
1112 }
1113
1114 .browser-annotation-box.is-hover {
1115 border-color: #22c55e;
1116 background: rgba(34, 197, 94, 0.12);
1117 box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.58);
1118 }
1119
1120 .browser-annotation-hover-label {
1121 position: absolute;
1122 top: 2px;
1123 left: 2px;
1124 max-width: min(320px, calc(100vw - 24px));
1125 overflow: hidden;
1126 padding: 2px 5px;
1127 border-radius: 4px;
1128 background: rgba(6, 78, 59, 0.92);
1129 color: #fff;
1130 font-size: 0.7rem;
1131 font-weight: 700;
1132 line-height: 1.3;
1133 text-overflow: ellipsis;
1134 white-space: nowrap;
1135 }
1136
1137 .browser-annotation-number {
1138 display: inline-flex;
1139 align-items: center;
1140 justify-content: center;
1141 width: 22px;
1142 min-width: 22px;
1143 height: 22px;
1144 min-height: 22px;
1145 border-radius: 50%;
1146 background: #3399ff;
1147 color: #fff;
1148 font-size: 0.74rem;
1149 font-weight: 800;
1150 line-height: 1;
1151 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28);
1152 }
1153
1154 .browser-annotation-box .browser-annotation-number {
1155 position: absolute;
1156 top: -12px;
1157 left: -12px;
1158 }
1159
1160 .browser-annotation-popover,
1161 .browser-annotation-tray {
1162 position: absolute;
1163 border: 1px solid color-mix(in srgb, var(--color-border) 76%, transparent);
1164 border-radius: 7px;
1165 background: color-mix(in srgb, var(--color-background) 96%, #000 4%);
1166 color: var(--color-text);
1167 box-shadow: 0 16px 38px rgba(0, 0, 0, 0.28);
1168 }
1169
1170 .browser-annotation-popover {
1171 z-index: 24;
1172 display: flex;
1173 flex-direction: column;
1174 gap: 8px;
1175 padding: 10px;
1176 }
1177
1178 .browser-annotation-popover-title,
1179 .browser-annotation-tray-header {
1180 display: flex;
1181 align-items: center;
1182 gap: 8px;
1183 min-width: 0;
1184 font-size: 0.82rem;
1185 font-weight: 750;
1186 }
1187
1188 .browser-annotation-popover-title {
1189 justify-content: space-between;
1190 }
1191
1192 .browser-annotation-popover-heading {
1193 display: inline-flex;
1194 align-items: center;
1195 gap: 8px;
1196 min-width: 0;
1197 }
1198
1199 .browser-annotation-popover textarea {
1200 width: 100%;
1201 min-height: 82px;
1202 max-height: 160px;
1203 resize: vertical;
1204 padding: 8px;
1205 border: 1px solid color-mix(in srgb, var(--color-border) 74%, transparent);
1206 border-radius: 6px;
1207 background: var(--color-input);
1208 color: var(--color-text);
1209 font: inherit;
1210 line-height: 1.35;
1211 }
1212
1213 .browser-annotation-actions,
1214 .browser-annotation-tray-actions {
1215 display: flex;
1216 justify-content: flex-end;
1217 gap: 7px;
1218 }
1219
1220 .browser-annotation-tray-actions .btn {
1221 min-height: 30px;
1222 padding: 0 10px;
1223 white-space: nowrap;
1224 }
1225
1226 .browser-annotation-tray {
1227 z-index: 20;
1228 right: 10px;
1229 bottom: 10px;
1230 display: flex;
1231 flex-direction: column;
1232 gap: 9px;
1233 width: min(360px, calc(100% - 20px));
1234 max-height: min(48%, 310px);
1235 padding: 10px;
1236 }
1237
1238 .browser-annotation-tray.is-dragging {
1239 user-select: none;
1240 }
1241
1242 .browser-annotation-tray-header {
1243 justify-content: space-between;
1244 cursor: grab;
1245 user-select: none;
1246 }
1247
1248 .browser-annotation-tray.is-dragging .browser-annotation-tray-header {
1249 cursor: grabbing;
1250 }
1251
1252 .browser-annotation-popover-close,
1253 .browser-annotation-clear,
1254 .browser-annotation-chip button {
1255 display: inline-flex;
1256 align-items: center;
1257 justify-content: center;
1258 width: 24px;
1259 height: 24px;
1260 min-width: 24px;
1261 min-height: 24px;
1262 padding: 0;
1263 border: 0;
1264 border-radius: 6px;
1265 background: transparent;
1266 color: color-mix(in srgb, var(--color-text) 64%, transparent);
1267 cursor: pointer;
1268 }
1269
1270 .browser-annotation-popover-close:hover,
1271 .browser-annotation-clear:hover,
1272 .browser-annotation-chip button:hover {
1273 background: color-mix(in srgb, var(--color-panel) 82%, transparent);
1274 color: var(--color-text);
1275 }
1276
1277 .browser-annotation-popover-close .material-symbols-outlined,
1278 .browser-annotation-clear .material-symbols-outlined,
1279 .browser-annotation-chip button .material-symbols-outlined {
1280 font-size: 16px;
1281 }
1282
1283 .browser-annotation-chips {
1284 display: flex;
1285 flex-direction: column;
1286 gap: 6px;
1287 min-height: 0;
1288 overflow: auto;
1289 }
1290
1291 .browser-annotation-chip {
1292 display: grid;
1293 grid-template-columns: auto minmax(0, 1fr) auto;
1294 align-items: center;
1295 gap: 7px;
1296 min-height: 32px;
1297 padding: 5px 6px;
1298 border: 1px solid color-mix(in srgb, var(--color-border) 54%, transparent);
1299 border-radius: 7px;
1300 background: color-mix(in srgb, var(--color-panel) 74%, transparent);
1301 }
1302
1303 .browser-annotation-chip .browser-annotation-number {
1304 width: 20px;
1305 min-width: 20px;
1306 height: 20px;
1307 min-height: 20px;
1308 font-size: 0.68rem;
1309 }
1310
1311 .browser-annotation-chip-text {
1312 min-width: 0;
1313 overflow: hidden;
1314 text-overflow: ellipsis;
1315 white-space: nowrap;
1316 font-size: 0.78rem;
1317 line-height: 1.25;
1318 }
1319
1320 .browser-annotation-actions,
1321 .browser-annotation-tray-actions {
1322 align-items: center;
1323 gap: 0.58rem;
1324 }
1325
1326 .browser-annotation-mic,
1327 .browser-annotation-send {
1328 display: inline-flex;
1329 flex: 0 0 3.15rem;
1330 align-items: center;
1331 justify-content: center;
1332 width: 3.15rem;
1333 min-width: 3.15rem;
1334 height: 3.15rem;
1335 margin: 0;
1336 padding: 0;
1337 border: 1px solid transparent;
1338 color: #fff;
1339 cursor: pointer;
1340 transition: background-color 0.2s ease, color 0.2s ease, transform 0.12s ease;
1341 }
1342
1343 .browser-annotation-mic {
1344 border-radius: 12px;
1345 background: transparent;
1346 color: grey;
1347 }
1348
1349 .browser-annotation-mic svg {
1350 transform-origin: center;
1351 transition: color 0.2s ease, transform 0.12s ease-in-out;
1352 }
1353
1354 .browser-annotation-mic.mic-disabled {
1355 color: #5f6368;
1356 cursor: not-allowed;
1357 opacity: 0.58;
1358 }
1359
1360 .browser-annotation-mic.mic-activating,
1361 .browser-annotation-mic.mic-processing {
1362 animation: browser-mic-pulse 0.8s infinite;
1363 }
1364
1365 .browser-annotation-mic.mic-activating { color: silver; }
1366 .browser-annotation-mic.mic-listening { color: red; }
1367 .browser-annotation-mic.mic-recording { color: green; }
1368 .browser-annotation-mic.mic-waiting { color: teal; }
1369 .browser-annotation-mic.mic-processing { color: darkcyan; }
1370
1371 @media (hover: hover) {
1372 .browser-annotation-mic:not(.mic-disabled):hover svg { transform: scale(1.08); }
1373 }
1374
1375 .browser-annotation-mic:not(.mic-disabled):active svg { transform: scale(0.92); }
1376
1377 .browser-annotation-send {
1378 border-radius: 12px;
1379 background: #4248f1;
1380 }
1381
1382 .browser-annotation-send:hover { background: #353bc5; }
1383 .browser-annotation-send:active { background: #2b309c; transform: translateY(1px) scale(0.98); }
1384 .browser-annotation-send:disabled {
1385 background: #4248f1;
1386 cursor: not-allowed;
1387 opacity: 0.5;
1388 }
1389
1390 .browser-annotation-mic svg,
1391 .browser-annotation-send .material-symbols-outlined {
1392 width: 1.5rem;
1393 height: 1.5rem;
1394 font-size: 1.78rem;
1395 }
1396
1397 @keyframes browser-mic-pulse {
1398 50% { transform: scale(1.1); }
1399 }
1400
1401 .browser-empty {
1402 display: flex;
1403 align-items: center;
1404 gap: 8px;
1405 min-height: 42px;
1406 font-size: 0.88rem;
1407 }
1408
1409 .browser-bottom-status {
1410 display: flex;
1411 align-items: center;
1412 flex: 0 0 24px;
1413 min-height: 24px;
1414 max-height: 24px;
1415 min-width: 0;
1416 padding: 0 10px;
1417 overflow: hidden;
1418 border-top: 1px solid color-mix(in srgb, var(--color-border) 58%, transparent);
1419 background: color-mix(in srgb, var(--color-background) 95%, #000 5%);
1420 color: color-mix(in srgb, var(--color-text) 74%, transparent);
1421 font-size: 0.76rem;
1422 line-height: 1;
1423 }
1424
1425 .browser-bottom-status.has-error {
1426 color: #fca5a5;
1427 background: color-mix(in srgb, #7f1d1d 22%, var(--color-background));
1428 }
1429
1430 .browser-error {
1431 display: inline-flex;
1432 align-items: center;
1433 gap: 6px;
1434 min-width: 0;
1435 max-width: 100%;
1436 overflow: hidden;
1437 white-space: nowrap;
1438 }
1439
1440 .browser-error {
1441 min-width: 0;
1442 overflow: hidden;
1443 text-overflow: ellipsis;
1444 }
1445
1446 .browser-modal .spinning,
1447 .browser-panel .spinning {
1448 display: inline-block;
1449 transform-origin: center;
1450 animation: browser-spin 0.8s linear infinite;
1451 }
1452
1453 @keyframes browser-spin {
1454 to {
1455 transform: rotate(360deg);
1456 }
1457 }
1458
1459 .browser-empty {
1460 display: grid;
1461 flex: 1 1 auto;
1462 width: 100%;
1463 min-height: 0;
1464 justify-items: center;
1465 align-content: center;
1466 text-align: center;
1467 padding: 24px;
1468 color: var(--color-text);
1469 }
1470
1471 .browser-starting .material-symbols-outlined {
1472 font-size: 1.45rem;
1473 }
1474
1475 @container (max-width: 460px) {
1476 .browser-toolbar {
1477 grid-template-columns: auto minmax(0, 1fr) auto;
1478 grid-template-areas:
1479 "nav . controls"
1480 "address address address";
1481 align-items: center;
1482 gap: 7px;
1483 }
1484
1485 .browser-navigation {
1486 justify-content: flex-start;
1487 }
1488
1489 .browser-address-form {
1490 width: 100%;
1491 }
1492
1493 .browser-meta-top {
1494 grid-template-columns: minmax(0, 1fr);
1495 }
1496
1497 .browser-session-controls {
1498 width: auto;
1499 justify-content: flex-end;
1500 }
1501
1502 .browser-session-tabs {
1503 width: 100%;
1504 }
1505
1506 .browser-tab-shell {
1507 flex-basis: 170px;
1508 min-width: 142px;
1509 }
1510
1511 .browser-new-tab,
1512 .browser-session-controls .btn-icon-action {
1513 width: var(--browser-control-size);
1514 height: var(--browser-control-size);
1515 }
1516
1517 .browser-annotate-toggle {
1518 width: var(--browser-control-size);
1519 min-width: var(--browser-control-size);
1520 padding: 0;
1521 }
1522
1523 .browser-annotate-toggle span:not(.material-symbols-outlined) {
1524 display: none;
1525 }
1526
1527 .browser-extension-dropdown {
1528 right: 0;
1529 left: auto;
1530 top: calc(var(--browser-control-size) + var(--browser-address-height) + 13px);
1531 width: min(296px, calc(100vw - 72px));
1532 }
1533
1534 .browser-address {
1535 min-height: var(--browser-address-height);
1536 }
1537 }
1538 </style>
1539 </body>
1540
1541 </html>