-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathoverlay.css
More file actions
992 lines (938 loc) · 47.5 KB
/
Copy pathoverlay.css
File metadata and controls
992 lines (938 loc) · 47.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
/* SPDX-License-Identifier: GPL-3.0-or-later */
/* overlay.css - ZeroScript Free in-page UI. Scoped under #zs-root / .zs-* */
#zs-root {
position: fixed;
z-index: 2147483600;
font-family: ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif;
}
/* ── status bar (anchored above the composer; left/top/width set inline) ──── */
#zs-bar {
position: fixed;
display: flex;
align-items: center;
gap: 9px;
box-sizing: border-box;
padding: 7px 9px 7px 12px;
background: linear-gradient(180deg, rgba(19, 26, 37, 0.97), rgba(12, 15, 20, 0.97));
color: #e4eaf2;
border: 1px solid rgba(148, 163, 184, 0.22);
border-radius: 10px;
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.42), inset 0 1px 0 rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
font-size: 12px;
user-select: none;
}
/* In-flow mode: the bar is a real, full-width node in the composer layout that
pushes content down instead of floating. Two looks:
• default (mounted ABOVE the input box, e.g. Gemini) → a subtle surface card so
it reads as a panel and doesn't float in empty space;
• .zs-bar-inside (mounted INSIDE the input box, e.g. DeepSeek) → transparent
with just a divider, so it blends into the composer surface it lives in. */
#zs-bar.zs-bar-inline {
position: static;
width: 100%;
left: auto; top: auto;
margin: 0 0 8px;
box-sizing: border-box;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.10);
border-radius: 12px;
box-shadow: none;
backdrop-filter: none;
padding: 7px 12px;
}
html.zs-light #zs-bar.zs-bar-inline {
background: rgba(0, 0, 0, 0.04);
border-color: rgba(0, 0, 0, 0.10);
}
#zs-bar.zs-bar-inline.zs-bar-inside {
margin: 0 0 6px;
background: transparent;
border: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 0;
/* Inset to match the composer's own text padding (≈16px) so the content lines
up with the input and the right-side buttons clear the rounded corner. */
padding: 4px 16px 10px;
}
html.zs-light #zs-bar.zs-bar-inline.zs-bar-inside {
background: transparent;
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}
/* Anchored mode: the bar keeps position:fixed (it must NOT enter the site's
framework-managed composer DOM, e.g. Kimi's Vue subtree) but the core sizes
and positions it to hug the composer's top edge at full width, with reserved
padding on the composer so it reads as in-flow. Transparent like the
.zs-bar-inside look, so it blends into the composer surface. */
#zs-bar.zs-bar-anchored {
background: transparent;
border: none;
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 0;
box-shadow: none;
backdrop-filter: none;
/* A touch of vertical room so the bar doesn't feel cramped against the input
(matches the roomier DeepSeek inline look). The reserved strip in placeBar
(bar height + gap) tracks this automatically. */
padding: 9px 16px;
}
html.zs-light #zs-bar.zs-bar-anchored {
background: transparent;
border-bottom: 1px solid rgba(0, 0, 0, 0.08);
}
/* Per-site tuning. On Gemini the default system stack looked foreign next to
Google Sans, and weight 700 read heavy - match the host for a native feel.
DeepSeek is left exactly as-is (it already blends well). */
#zs-bar.zs-prov-gemini {
font-family: "Google Sans Text", "Google Sans", Roboto, ui-sans-serif, -apple-system, "Segoe UI", sans-serif;
}
#zs-bar.zs-prov-gemini #zs-brand,
#zs-bar.zs-prov-gemini #zs-action,
#zs-bar.zs-prov-gemini #zs-state b { font-weight: 500; }
/* Meta AI's composer card has a large corner radius (rounded-32 = 32px), so the
full-width anchored bar's left/right ends run under the curve - the brand and
the Discord/switch/support icons crowd the rounding. Inset the content by ~the
radius so both edges clear the corners cleanly. */
#zs-bar.zs-bar-anchored.zs-prov-meta { padding-left: 30px; padding-right: 30px; }
#zs-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; cursor: help; }
#zs-dot.on { background: #2eb872; box-shadow: 0 0 8px #2eb872; }
#zs-dot.warn { background: #f0b429; box-shadow: 0 0 8px #f0b429; }
#zs-dot.off { background: #5c6a7d; }
#zs-brand { font-weight: 700; letter-spacing: 0.2px; flex: none; font-size: 12.5px; }
.zs-free {
font-size: 9.5px; font-weight: 600; letter-spacing: 0.3px;
color: #f43f5e; background: rgba(225, 29, 72, 0.10); border: 1px solid rgba(225, 29, 72, 0.32);
border-radius: 4px; padding: 1px 5px; margin-left: 4px; vertical-align: middle;
font-family: ui-monospace, "Cascadia Mono", monospace;
}
/* provider instability warning (Gemini / Kimi): a small amber pill that FLOATS
just above the bar (positioned by placeUnstable each frame) instead of sitting
inside it - so it never crowds the row on narrow composers. Click / hover for
the full explanation (toast + title tooltip). */
#zs-unstable {
position: fixed; z-index: 2147483601;
display: inline-flex; align-items: center; cursor: pointer;
font-size: 10px; font-weight: 700; letter-spacing: 0.3px; white-space: nowrap;
color: #fbbf24; background: rgba(28, 24, 12, 0.97);
border: 1px solid rgba(251, 191, 36, 0.4); border-radius: 6px;
padding: 3px 8px; line-height: 1.3;
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.4);
transition: background 0.14s ease;
}
#zs-unstable:hover { background: rgba(44, 37, 16, 0.98); }
html.zs-light #zs-unstable {
color: #92610a; background: rgba(255, 251, 240, 0.98);
border-color: rgba(180, 130, 10, 0.45);
box-shadow: 0 6px 18px rgba(15, 23, 42, 0.16);
}
/* state line: takes the slack, single line, ellipsis if it can't fit */
#zs-state {
flex: 1; min-width: 0;
display: flex; align-items: center; gap: 6px;
font-size: 11.5px; line-height: 1.3; opacity: 0.85;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.zs-state-txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
#zs-state b { font-weight: 700; opacity: 1; color: #8fb6d9; }
#zs-state.zs-state-warn { opacity: 1; color: #fca5a5; }
#zs-state.zs-state-warn b { color: #fecaca; }
#zs-bar.tone-active #zs-state b { color: #2eb872; }
/* live + idle dots inside the state line */
.zs-live-dot {
width: 8px; height: 8px; border-radius: 50%; background: #2eb872; flex: none;
box-shadow: 0 0 0 0 rgba(46, 184, 114, 0.6);
animation: zs-live 1.8s ease-out infinite;
}
@keyframes zs-live {
0% { box-shadow: 0 0 0 0 rgba(46, 184, 114, 0.55); }
100% { box-shadow: 0 0 0 7px rgba(46, 184, 114, 0); }
}
.zs-live-dot.idle { background: #5c6a7d; animation: none; box-shadow: none; }
/* primary action button (Start) */
#zs-action {
flex: none;
padding: 7px 13px;
border-radius: 9px; border: 1px solid transparent;
font-size: 12.5px; font-weight: 700; cursor: pointer; white-space: nowrap;
transition: filter 0.15s ease, background 0.15s ease;
}
#zs-action[data-kind="start"] {
background: linear-gradient(135deg, #be123c, #e11d48); color: #fff; border-color: transparent;
box-shadow: 0 2px 12px rgba(225, 29, 72, 0.35);
}
#zs-action[data-kind="start"]:hover { filter: brightness(1.08); }
/* Degraded start: Roblox is down but another MCP server is live. Neutral surface
with crimson text to signal "startable, but not the full setup" - distinct from
the solid-crimson full-ready start. */
#zs-action[data-kind="start-degraded"] {
background: rgba(225, 29, 72, 0.12); color: #f43f5e; border-color: rgba(225, 29, 72, 0.42);
box-shadow: none;
}
#zs-action[data-kind="start-degraded"]:hover { filter: brightness(1.08); }
#zs-action:disabled {
background: rgba(255, 255, 255, 0.08); color: rgba(255, 255, 255, 0.45);
border-color: rgba(255, 255, 255, 0.10); box-shadow: none; cursor: not-allowed;
}
/* attention flash when the user sends on a fresh chat without starting */
#zs-action.zs-flash { animation: zs-flash 0.4s ease-in-out 3; }
@keyframes zs-flash {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.06); box-shadow: 0 0 0 4px rgba(225, 29, 72, 0.55); }
}
/* stop button (replaces the action button while the agent is busy) */
#zs-stop {
flex: none; padding: 7px 13px;
background: #ef4444; color: #fff; border: 0; border-radius: 9px;
font-size: 12.5px; font-weight: 700; cursor: pointer; white-space: nowrap;
}
#zs-stop:hover { background: #dc2626; }
/* Winding-down state: the loop is finishing its in-flight step after a Stop
click. Dimmed + not-allowed so it reads as "registered, please wait". */
#zs-stop[data-state="stopping"] {
background: #be123c; cursor: progress; opacity: 0.85;
}
#zs-stop[data-state="stopping"]:hover { background: #be123c; }
/* bar controls: one neutral icon-button family (Discord, support, switch) */
#zs-discord, #zs-support {
flex: none; width: 28px; height: 28px; padding: 0;
display: flex; align-items: center; justify-content: center;
background: rgba(148, 163, 184, 0.08); color: #9fb0c3;
border: 1px solid rgba(148, 163, 184, 0.16); border-radius: 7px;
cursor: pointer; text-decoration: none;
transition: background 0.14s ease, color 0.14s ease;
}
#zs-discord:hover, #zs-support:hover { background: rgba(148, 163, 184, 0.16); color: #e4eaf2; }
/* model switcher: names the current AI and opens the panel at Switch AI */
#zs-switch {
flex: none; display: flex; align-items: center; gap: 5px;
height: 28px; padding: 0 9px;
background: rgba(148, 163, 184, 0.08); color: #c3cfdd;
border: 1px solid rgba(148, 163, 184, 0.16); border-radius: 7px;
font-size: 12px; font-weight: 600; cursor: pointer; white-space: nowrap;
transition: background 0.14s ease;
}
#zs-switch:hover { background: rgba(148, 163, 184, 0.16); }
#zs-switch svg { opacity: 0.55; }
/* ── the "more" menu popover (right/bottom set inline) ────────────────────── */
#zs-menu {
position: fixed;
box-sizing: border-box;
width: 274px; overflow-y: auto;
padding: 0 0 6px;
background: linear-gradient(180deg, #10151d, #0b0e13);
color: #e4eaf2;
border: 1px solid rgba(148, 163, 184, 0.18); border-radius: 12px;
box-shadow: 0 16px 44px rgba(0, 0, 0, 0.5);
font-size: 12px;
animation: zs-pop 0.16s ease-out;
}
@keyframes zs-pop { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
/* discreet dark scrollbar (default white one looks out of place) */
#zs-menu { scrollbar-width: thin; scrollbar-color: rgba(255,255,255,0.22) transparent; }
#zs-menu::-webkit-scrollbar { width: 8px; }
#zs-menu::-webkit-scrollbar-track { background: transparent; }
#zs-menu::-webkit-scrollbar-thumb {
background: rgba(255,255,255,0.18); border-radius: 8px;
border: 2px solid transparent; background-clip: padding-box;
}
#zs-menu::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,0.30); background-clip: padding-box; }
html.zs-light #zs-menu { scrollbar-color: rgba(0,0,0,0.25) transparent; }
html.zs-light #zs-menu::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.2); background-clip: padding-box; }
/* header strip: quiet product line, no coloured chips */
.zs-menu-head {
display: flex; align-items: baseline; gap: 7px;
padding: 12px 14px 11px;
border-bottom: 1px solid rgba(148, 163, 184, 0.12);
background: linear-gradient(90deg, rgba(225, 29, 72, 0.08), transparent 55%);
border-radius: 12px 12px 0 0;
}
.zs-menu-logo { font-weight: 700; font-size: 13px; letter-spacing: -0.1px; color: #f2f5f9; }
.zs-menu-tag { font-size: 10px; font-weight: 600; color: #f43f5e; font-family: ui-monospace, "Cascadia Mono", monospace; }
.zs-menu-sec { padding: 12px 14px; }
.zs-menu-sec + .zs-menu-sec { border-top: 1px solid rgba(148, 163, 184, 0.09); }
/* section label: monospaced uppercase ticker, the gearhead signature */
.zs-sec-label { margin-bottom: 8px; }
.zs-sec-label span {
font-size: 9.5px; font-weight: 700; letter-spacing: 0.8px; text-transform: uppercase;
color: #7c8aa0; font-family: ui-monospace, "Cascadia Mono", monospace;
}
.zs-menu-note { font-size: 10.5px; color: #6b6b73; line-height: 1.45; margin: 0 0 9px; }
/* AI site rows: plain list, subtle surface on hover */
.zs-site-opt {
width: 100%; box-sizing: border-box; margin: 1px 0; padding: 8px 10px;
display: flex; align-items: center; justify-content: space-between; gap: 8px;
border: 0; border-radius: 6px; background: transparent;
color: #b9c4d3; font-size: 12.5px; font-weight: 500; cursor: pointer; text-align: left;
transition: background 0.13s ease;
}
button.zs-site-opt:hover { background: rgba(148, 163, 184, 0.09); }
.zs-site-name { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.zs-site-name > span:first-child { color: #e4eaf2; font-weight: 600; }
.zs-site-host {
font-size: 10px; font-weight: 400; color: #6b6b73; letter-spacing: 0.1px;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.zs-site-go {
flex: none; font-size: 14px; color: #6b6b73;
opacity: 0; transform: translateX(-3px);
transition: opacity 0.13s ease, transform 0.13s ease;
}
button.zs-site-opt:hover .zs-site-go { opacity: 1; transform: translateX(0); }
.zs-site-here {
cursor: default;
background: rgba(225, 29, 72, 0.08);
box-shadow: inset 2px 0 0 #e11d48;
}
.zs-site-here .zs-site-badge {
color: #f43f5e; border-color: rgba(225, 29, 72, 0.40); background: rgba(225, 29, 72, 0.08);
}
.zs-site-badge {
flex: none; font-size: 10px; font-weight: 500; color: #7a7a82;
border: 1px solid rgba(255, 255, 255, 0.12); padding: 1px 7px; border-radius: 5px;
}
#zs-set-text {
width: 100%; box-sizing: border-box; resize: vertical; min-height: 58px;
background: rgba(255, 255, 255, 0.04); color: #e5e5e8;
border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 8px;
padding: 8px 10px; font-size: 12px; font-family: inherit; line-height: 1.45;
}
#zs-set-text:focus { outline: none; border-color: rgba(225, 29, 72, 0.45); box-shadow: 0 0 0 2px rgba(225, 29, 72, 0.12); }
.zs-set-row { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
#zs-set-save, #zs-mcp-add {
background: rgba(255, 255, 255, 0.09); color: #ededf0;
border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 8px;
padding: 6px 15px; font-size: 12px; font-weight: 600; cursor: pointer;
transition: background 0.13s ease;
}
#zs-set-save:hover, #zs-mcp-add:hover { background: rgba(255, 255, 255, 0.15); }
#zs-set-status, #zs-mcp-status { font-size: 11px; color: #8a8a92; font-weight: 500; }
/* support actions: neutral rows, differentiated by the aside text, not colour */
.zs-tip-opt {
width: 100%; margin: 5px 0; padding: 9px 11px;
display: flex; align-items: center; justify-content: space-between; gap: 8px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 8px;
color: #e4e4e8; font-size: 12.5px; font-weight: 600; cursor: pointer; text-align: left;
transition: background 0.13s ease;
}
.zs-tip-opt:hover { background: rgba(255, 255, 255, 0.09); }
.zs-tip-sub { font-size: 10px; font-weight: 400; color: #7a7a82; white-space: nowrap; }
.zs-rbx-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.zs-tip-rbx {
justify-content: center; gap: 3px; margin: 0; padding: 8px 6px;
font-size: 12px; font-weight: 500; color: #c8c8ce;
}
.zs-rbx-cur { color: #7a7a82; font-weight: 400; }
.zs-tip-sep {
font-size: 10px; color: #6b6b73; margin: 11px 0 8px; text-align: center;
}
/* ── custom MCP servers list (add-your-own, same shell as Custom prompt) ── */
.zs-mcp-item {
display: flex; align-items: center; gap: 8px;
padding: 7px 10px; margin: 0 0 5px;
background: rgba(255, 255, 255, 0.04); border: 1px solid rgba(255, 255, 255, 0.09);
border-radius: 7px;
}
.zs-mcp-health {
flex: none; width: 7px; height: 7px; border-radius: 50%; background: #5c6a7d;
}
.zs-mcp-health-on { background: #2eb872; box-shadow: 0 0 5px rgba(46, 184, 114, 0.5); }
.zs-mcp-health-off { background: #f87171; }
.zs-mcp-health-unknown { background: #5c6a7d; }
/* Roblox: always first, greyed out - no health dot (own status lives in the
main ZeroScript dot) and no remove button (protected bridge-side too). */
.zs-mcp-item-primary { opacity: 0.55; background: rgba(255, 255, 255, 0.02); }
.zs-mcp-item-primary .zs-mcp-name { font-weight: 500; }
.zs-mcp-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.zs-mcp-sep { height: 1px; background: rgba(255, 255, 255, 0.07); margin: 4px 0 10px; }
.zs-mcp-name { font-size: 12px; font-weight: 600; color: #e5e5e8; }
.zs-mcp-url {
font-size: 10px; color: #6b6b73; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.zs-mcp-remove {
flex: none; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center;
background: transparent; border: 0; border-radius: 5px; color: #7a7a82; cursor: pointer; font-size: 13px;
transition: background 0.13s ease, color 0.13s ease;
}
.zs-mcp-remove:hover { background: rgba(255, 255, 255, 0.08); color: #e5e5e8; }
.zs-mcp-field {
width: 100%; box-sizing: border-box; background: rgba(255, 255, 255, 0.04); color: #e5e5e8;
border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 8px;
padding: 7px 9px; font-size: 12px; font-family: inherit; margin-bottom: 6px;
}
.zs-mcp-field:focus { outline: none; border-color: rgba(225, 29, 72, 0.45); box-shadow: 0 0 0 2px rgba(225, 29, 72, 0.12); }
/* small inline spinner shown next to #zs-mcp-add while the bridge restarts */
.zs-mcp-spin-row { display: inline-flex; align-items: center; gap: 6px; }
.zs-mcp-spin {
width: 11px; height: 11px; flex: none; border-radius: 50%;
border: 2px solid rgba(255, 255, 255, 0.2); border-top-color: #b8b8c0;
animation: zs-mcp-spin-rotate 0.7s linear infinite;
}
@keyframes zs-mcp-spin-rotate { to { transform: rotate(360deg); } }
/* ── composer mode enforcement (force Expert / DeepThink etc.) ────────────── */
.zs-hide-el { display: none !important; }
/* ── input cover: fully hides the text the extension types + sends ──
background colour is set inline at runtime to match the input box,
so the masked input simply looks empty. */
#zs-input-cover {
position: fixed; z-index: 2147483500;
display: flex; align-items: center; gap: 8px;
box-sizing: border-box; padding-left: 16px;
border-radius: 14px;
background: #ffffff;
color: rgba(140, 140, 150, 0.9);
font-size: 12px; font-family: ui-sans-serif, "Segoe UI", sans-serif;
white-space: nowrap; overflow: hidden;
/* Capture pointer events: the cover sits over the composer while the agent
works, so eating clicks/focus stops the user from clicking THROUGH it into
the input box and typing (contenteditable=false alone leaks - Vue/Angular
re-renders can reset it). The place() loop hides the cover whenever a modal
or captcha is up, so this never traps clicks the user actually needs. */
pointer-events: auto;
cursor: default;
}
/* belt-and-suspenders: the typed text itself is rendered invisible
(DeepSeek's composer is a <textarea>; the Kimi build used a contenteditable) */
textarea.zs-typing,
div[contenteditable='true'].zs-typing,
div[contenteditable='true'].zs-typing * { color: transparent !important; }
textarea.zs-typing,
div[contenteditable='true'].zs-typing { caret-color: transparent !important; }
/* Keep the composer from ballooning while the extension injects the (large)
system prompt or a big tool output. The typed text is transparent and hidden
under #zs-input-cover anyway, so there is nothing to see - but without a cap
the editor grows to fit every line (e.g. Kimi's inner .chat-input-editor hit
~1500px), which then makes the cover (sized to the editor rect) a giant white
slab over the page, and on composers with no clipping ancestor (DeepSeek's
textarea, Gemini's Quill) balloons the visible box itself. Clipping the height
only affects DISPLAY; the full value/content is intact and still sent. The
class is present only during agent injection, never while the user types, so
this never clips real typing. */
textarea.zs-typing,
div[contenteditable='true'].zs-typing {
max-height: 140px !important;
overflow-y: hidden !important;
}
/* ── spinner element ───────────────────────────────────────── */
.zs-spin {
width: 12px; height: 12px; flex: none; display: inline-block;
border: 2px solid rgba(255, 255, 255, 0.18);
border-top-color: #c8c8ce;
border-radius: 50%;
animation: zs-rot 0.7s linear infinite;
}
.zs-spin.big { width: 26px; height: 26px; border-width: 3px; }
@keyframes zs-rot { to { transform: rotate(360deg); } }
/* ── tool cards (replace tool JSON / sys prompt / results) ──────── */
.zs-hidden > *:not(.zs-chip) { display: none !important; }
/* hide the code block / paragraph(s) containing the raw tool call */
.zs-tool-hide { display: none !important; }
/* Gemini: Angular recreates the <code-block> elements inside a reply (once at
the end-of-stream markdown settle, once again when the next turn is sent),
wiping any per-element .zs-tool-hide class - the raw command flashes until
the next sweep. <message-content> itself keeps its identity through those
re-renders (validated live, 2026-06), so the provider marks IT with
.zs-cmd-mask and this rule keeps every recreated code-block hidden with no
flash. Inert on DeepSeek (no such elements). */
message-content.zs-cmd-mask code-block { display: none !important; }
/* GLM / Z.ai (Svelte): the reply's markdown subtree is recreated on stream
updates and on the next send, wiping any per-element .zs-tool-hide class. The
reply root (.chat-assistant) keeps its identity, so the provider marks IT with
.zs-cmd-mask and this rule keeps every recreated code-block wrapper (a
rounded-xl box carrying a copy-code button) hidden with no flash. Inert
elsewhere. */
.chat-assistant.zs-cmd-mask div[class*="rounded-xl"]:has(.copy-code-button) { display: none !important; }
/* Kimi (Vue): the reply's markdown subtree is recreated on stream updates,
wiping any per-element .zs-tool-hide class. The assistant turn
(.segment-assistant) keeps its identity, so the provider marks IT with
.zs-cmd-mask and this rule keeps every recreated fenced-code wrapper
(.segment-code) hidden with no flash. Inert elsewhere. */
.segment-assistant.zs-cmd-mask .segment-code { display: none !important; }
/* Qwen (React + Ant Design): the reply markdown subtree is recreated on stream
updates. The assistant turn (.qwen-chat-message-assistant) keeps its identity,
so the provider marks IT with .zs-cmd-mask and this rule re-hides recreated
Monaco code blocks (pre.qwen-markdown-code) with no flash. Inert elsewhere. */
.qwen-chat-message-assistant.zs-cmd-mask pre.qwen-markdown-code { display: none !important; }
/* Arena (arena.ai, React): React recreates the reply's rendered code subtree on
stream settle and on the next send, wiping any per-element .zs-tool-hide class.
The assistant turn <div> keeps its identity (the chip is anchored at item
level), so the provider marks IT with .zs-cmd-mask and this rule keeps every
recreated fenced-code wrapper (a .not-prose box holding a <pre>) hidden with no
flash. Inert elsewhere. */
.zs-cmd-mask div.not-prose:has(pre) { display: none !important; }
/* Meta AI (www.meta.ai, React): React recreates the reply's rendered code subtree
on stream settle and on the next send, wiping any per-element .zs-tool-hide
class. The assistant-message body keeps its identity (the chip is anchored at
item level), so the provider marks IT with .zs-cmd-mask and this rule keeps
every recreated command wrapper (the .ur-code-block that holds either the JSON
viewer widget or a plain <pre>) hidden with no flash. Inert elsewhere. */
.zs-cmd-mask .ur-code-block { display: none !important; }
/* Meta AI whole-turn chips (result / sys) alignment. A whole:true chip is pinned
as a direct child of the TURN ROOT, but Meta's turn root is FULL width (~1608px)
while the reply body lives in a nested `mx-auto max-w-3xl` (768px) centered
column. So a result chip's collapsible body stretched the chip to the full page
width, and the "Starting Up" sys chip sat at the raw page-left edge - neither
lined up with the tool chip (which anchors inside that centered column). Re-seat
whole chips onto the same 768px column: push the left edge in by the column's
own centering offset and cap the width to the column. `max()` keeps it sane on
narrow viewports where the column is full-width. */
html.zs-site-meta .zs-hidden > .zs-chip {
margin-left: max(0px, calc((100% - 768px) / 2));
max-width: 768px;
}
/* Qwen (Ant Design) renders its model / thinking-mode select popup AND the
composer "+" attachment menu (Upload attachment / Deep Research / Create
image / Web Dev / Slides / More) at z-index 1050-1150 - far below #zs-root
(2147483600) - so the ZeroScript bar covered the bottom of whichever menu was
open (reported live: the "+" menu's "More" row and the bar's own "Tools"
toggle drew on top of each other). Both popups are portalled to <body>, so
raising their z-index above the bar lifts them back on top. Inert when a
menu is closed (Ant adds .ant-select-dropdown-hidden / removes the node). */
.qwen-select-dropdown,
.mode-select-dropdown { z-index: 2147483646 !important; }
/* Qwen's model list has an "Expand more models" fly-out submenu (the Qwen3.6
family etc.) rendered as a SEPARATE body-portalled `.ant-dropdown` at z-index
1050 - NOT the `.qwen-select-dropdown` above - so the ZeroScript bar drew on
top of it (reported live: the bar's "Start Roblox agent" row covered the
Qwen3.6-Max-Preview description). Scoped with :has() to the dropdown that
actually holds model rows, so unrelated Ant dropdowns/tooltips are untouched. */
.ant-dropdown:has([class*="model-item"]) { z-index: 2147483646 !important; }
/* Kimi (Naive UI) portals its popovers - the model picker (K2.6 Instant /
Thinking / Agent / Swarm), the composer "+" toolkit menu (Add files &
photos / Presets / Plugins / Skills / Web search), and that same button's
OWN hover tooltip ("Add files & photos…") - into a
.v-binder-follower-container at z-index ~20-2001, far below #zs-root
(2147483600) - so the ZeroScript bar/pill covered the open menu/tooltip
(reported live: opening "+", or just hovering it, while the agent was
working drew the "unstable" pill and composer cover through it). Lift the
container above the bar. :has scopes this to those known popovers
specifically so other Naive tooltips/popovers on the page keep their normal
stacking. */
.v-binder-follower-container:has(.models-popover),
.v-binder-follower-container:has(.toolkit-popover),
.v-binder-follower-container:has(.toolkit-tooltip),
.v-binder-follower-container:has(.model-tooltip) { z-index: 2147483646 !important; }
/* Kimi's OWN lightweight tooltip system (not Naive UI) - e.g. the send button's
"Please enter your question" and the model-picker's hover tooltip - renders
as a body-level .kimi-tooltip at z-index 20, same problem as the Naive
popovers above. Inactive instances (one per icon button, e.g. every "Copy"
button) sit at opacity:0 permanently, so raising every .kimi-tooltip's
z-index is safe - it only matters once the active one's opacity flips to 1. */
.kimi-tooltip { z-index: 2147483646 !important; }
/* GLM / Z.ai (bits-ui floating library) portals its composer-toolbar popovers -
the Search / Advanced Search hover card, and similar tooltips/dropdowns - into
a [data-bits-floating-content-wrapper] at z-index ~9999, far below #zs-root
(2147483600), so the ZeroScript bar sat in front of them (the popover appeared
"behind" the bar on hover). The wrapper is the positioned/stacking element, so
lifting it above the bar fixes every bits-ui popover anchored near the bar. */
[data-bits-floating-content-wrapper] { z-index: 2147483646 !important; }
/* Gemini (Angular Material) portals its composer "+" menu (Import files /
Create image / Canvas / Deep Research…) and its other dialogs into a single
body-level .cdk-overlay-container at z-index 1000 - far below #zs-root
(2147483600) / #zs-unstable (2147483601). The ZeroScript bar and its
floating "unstable" pill sat OVER the open menu (reported live: opening "+"
while the agent was working drew the pill straight through the menu).
Lift the whole overlay container above every ZeroScript surface. */
.cdk-overlay-container { z-index: 2147483646 !important; }
/* DeepSeek (its own "ds-" design system) portals tooltips and popovers - e.g.
the "Think before responding…" tooltip on the DeepThink pill - into a
body-level .ds-floating-container at z-index 1024, far below #zs-root
(2147483600) and #zs-input-cover (2147483500). While the composer cover sits
over the input during agent activity, it visually covered the tooltip
(reported live: hovering DeepThink while the agent was working showed the
tooltip clipped/behind the bar). Lift every DeepSeek floating portal above
ZeroScript's own overlays. */
.ds-floating-container { z-index: 2147483646 !important; }
/* Arena (Radix UI) portals its header dropdowns - the model picker and the
conversation-mode select - into a [data-radix-popper-content-wrapper] at
z-index ~50, far below #zs-root (2147483600). The model list is tall enough to
reach down into the anchored bar's band, so its lower entries sat behind the
bar. Lift every Radix popper above the bar. (Radix DIALOGS are handled
separately: arena.js overlayBlocking() hides the bar while one is open.) */
[data-radix-popper-content-wrapper] { z-index: 2147483646 !important; }
/* Arena: a tool-call chip normally lands inside a turn wrapper classed
`mx-auto max-w-[800px] w-full`, matching the ~800px centered column every
other message reads in. When Arena instead renders that SAME command turn
as its "Max" two-model A/B comparison (validated live: e.g. minimax-m3 vs
gpt-5.5 both drafting the same tool call), the turn hosting the chip loses
that wrapper - it is just `w-full`, uncapped - so the chip stretched to the
FULL comparison width instead of the narrow message column, breaking the
visual rhythm (a near-full-width chip sandwiched between normal ~800px-wide
ones). Centering it read worse than expected (floats in empty space, no
visual tie to either candidate) - left-align it instead, inset by the same
1rem (`pl-4`) the candidate panels themselves use, so its left edge lines up
with the candidate cards' left edge instead of the turn's raw edge.
`:not(.mx-auto)` scopes this to exactly the carousel-hosted case; every
normal turn is untouched. */
ol.flex-col-reverse > div.w-full:not(.mx-auto) > .zs-chip {
max-width: 800px;
margin-left: 1rem;
margin-right: auto;
}
/* Chips read as one calm family: a neutral slate surface for every tool. The
CATEGORY paints only the 2px left spine + head icon (via --cat and the
cat-* palette below); STATE still wins the tint - green when done, red on
error - because the state classes come later and override --cat. */
.zs-chip {
--cat: #94a3b8;
position: relative;
display: block; width: fit-content; max-width: 100%;
/* Never stretch to the container width: some sites (Meta AI) render the reply
body as a flex column, and a block child with `width:fit-content` gets
stretched to full width by the default `align-items:stretch`. Pinning
align-self keeps the chip hugging its label. No-op in block/grid parents. */
align-self: flex-start;
margin: 5px 0; padding: 0;
font-size: 13px; font-family: ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif;
border-radius: 8px; line-height: 1.3;
background: rgba(148, 163, 184, 0.06);
border: 1px solid rgba(148, 163, 184, 0.16);
/* category spine: a 2px rail down the left edge, recoloured per cat-* class */
box-shadow: inset 2px 0 0 0 var(--cat);
color: #d3dae4;
overflow: hidden;
transition: background 0.18s ease, border-color 0.18s ease;
}
.zs-chip:hover { background: rgba(148, 163, 184, 0.11); }
/* category palette: spine + head icon only (state classes below win on top) */
.zs-chip.cat-read { --cat: #38bdf8; }
.zs-chip.cat-edit { --cat: #4ade80; }
.zs-chip.cat-generate { --cat: #ffb224; }
.zs-chip.cat-roblox { --cat: #f97316; }
.zs-chip.cat-screen { --cat: #2dd4bf; }
.zs-chip-head {
display: flex; align-items: center; gap: 9px;
padding: 8px 13px 8px 15px;
}
.zs-chip-ic {
display: inline-flex; align-items: center; justify-content: center;
width: 16px; height: 16px; flex: none; color: var(--cat);
}
.zs-chip-ic svg { width: 16px; height: 16px; }
.zs-chip-tx { font-weight: 600; letter-spacing: 0.1px; }
.zs-chip-dt {
opacity: 0.6; font-size: 11px; margin-left: 2px; flex: 1;
font-family: ui-monospace, "Cascadia Code", "Cascadia Mono", monospace;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.zs-chip-dt:empty { display: none; }
.zs-chip-cv {
display: inline-flex; flex: none; opacity: 0.45;
transition: transform 0.2s ease;
}
.zs-chip-cv svg { width: 15px; height: 15px; }
.zs-chip.open .zs-chip-cv { transform: rotate(180deg); }
/* expandable body: real args / output */
.zs-chip-body {
max-height: 0; overflow: hidden;
transition: max-height 0.22s ease;
border-top: 1px solid transparent;
}
.zs-chip.open .zs-chip-body {
max-height: 460px; overflow: auto;
border-top-color: color-mix(in srgb, var(--cat) 20%, transparent);
}
.zs-chip-body pre {
margin: 0; padding: 10px 13px;
font-family: ui-monospace, "Cascadia Code", monospace;
font-size: 12px; line-height: 1.5; color: #cdd2e0;
white-space: pre-wrap; word-break: break-word;
}
/* state themes (override the category spine/icon, so state always wins) */
.zs-chip.done { --cat: #2eb872; }
.zs-chip.err { --cat: #ef6b6b; border-color: rgba(239, 68, 68, 0.38); color: #f0b8b8; }
.zs-chip.result { --cat: #7c8aa0; color: #9fb0c3; }
.zs-chip.sys { --cat: #7c8aa0; color: #9fb0c3; }
/* Orphaned command we won't execute (e.g. reload left it un-run): neutral grey,
never a green ✓ that would imply the tool succeeded. */
.zs-chip.idle { --cat: #7c8aa0; color: #9fb0c3; }
/* running shimmer, seamless: a REPEATING gradient (period = 210px) scrolled by
exactly one period in LINEAR time, so the last frame is pixel-identical to the
first - no visible seam or pause between cycles. background-position animates
only the image; the base colour stays put. */
.zs-chip.run {
background-color: rgba(255, 255, 255, 0.05);
background-image: linear-gradient(90deg,
transparent 0%, rgba(255, 255, 255, 0.09) 50%, transparent 100%);
/* Fixed 210px tile (NOT tied to the chip width), repeated. This is what makes
the sweep width-independent: when the chip grows as its detail arrives, the
tile origin doesn't shift, so the gradient no longer "teleports". */
background-repeat: repeat;
background-size: 210px 100%;
animation: zs-shimmer 1.6s linear infinite;
}
/* scroll by exactly one tile → last frame == first frame → seamless loop */
@keyframes zs-shimmer { from { background-position: 0 0; } to { background-position: 210px 0; } }
/* scanline: while a tool runs, a short category-coloured comet travels down the
chip's left spine - the build-pipeline heartbeat. Rests on .zs-chip's
position:relative + overflow:hidden; invisible for every other phase. */
.zs-chip.run::after {
content: ""; position: absolute; left: 0; top: -34%;
width: 2px; height: 34%;
background: linear-gradient(180deg, transparent, var(--cat), transparent);
animation: zs-scan 1.5s ease-in-out infinite;
pointer-events: none;
}
@keyframes zs-scan { from { top: -34%; } to { top: 100%; } }
/* ── toast ─────────────────────────────────────────────────── */
.zs-toast {
position: fixed; right: 18px; top: 80px;
max-width: 300px; padding: 9px 13px;
background: rgba(13, 17, 23, 0.96); color: #e4eaf2;
border: 1px solid rgba(148, 163, 184, 0.16); border-radius: 10px;
font-size: 12px; box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4);
opacity: 0; transform: translateY(8px); transition: all 0.25s ease;
}
.zs-toast.show { opacity: 1; transform: translateY(0); }
/* ── banner (errors / limits) ──────────────────────────────── */
.zs-banner {
position: fixed; right: 18px; top: 18px; width: 320px;
padding: 14px 16px; border-radius: 12px;
background: linear-gradient(180deg, #10151d, #0b0e13); color: #e4eaf2;
border: 1px solid rgba(148, 163, 184, 0.18);
box-shadow: 0 16px 44px rgba(0, 0, 0, 0.5);
font-size: 13px; z-index: 2147483601;
}
/* semantic state kept, but as a thin muted stripe rather than a bright bar */
.zs-banner.limit { border-left: 2px solid rgba(239, 68, 68, 0.55); }
.zs-banner.warn { border-left: 2px solid rgba(240, 180, 41, 0.5); }
.zs-banner-t { font-weight: 600; color: #f2f5f9; margin-bottom: 6px; }
.zs-banner-m { color: #9a9aa2; line-height: 1.5; margin-bottom: 12px; }
.zs-banner-acts { display: flex; gap: 8px; }
.zs-banner-acts button {
flex: 1; padding: 7px; border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 8px;
cursor: pointer; font-size: 12px; font-weight: 600;
background: transparent; color: #a0a0a8; transition: background 0.13s ease;
}
.zs-banner-x { background: transparent; color: #a0a0a8; }
.zs-banner-x:hover { background: rgba(255, 255, 255, 0.06); }
/* Setup-tutorial link embedded in the bridge-lost banner (styled like a button,
sits in the actions row so it never overlaps the alert). */
.zs-banner-video {
flex: 1; padding: 7px; border-radius: 8px; font-size: 12px; font-weight: 600;
text-align: center; text-decoration: none; box-sizing: border-box;
background: rgba(255, 255, 255, 0.06); color: #e4e4e8;
border: 1px solid rgba(255, 255, 255, 0.1); transition: background 0.13s ease;
}
.zs-banner-video:hover { background: rgba(255, 255, 255, 0.11); }
/* ── first-time onboarding card (bridge missing; pinned top-right) ───────── */
#zs-setup {
position: fixed;
top: 18px; right: 18px;
width: 288px;
padding: 0 0 14px;
background: linear-gradient(180deg, #10151d, #0b0e13);
color: #e4eaf2;
border: 1px solid rgba(148, 163, 184, 0.18);
border-radius: 12px;
box-shadow: 0 16px 44px rgba(0, 0, 0, 0.5);
font-size: 12px;
z-index: 2147483600;
animation: zs-pop 0.2s ease-out;
}
#zs-setup-head {
display: flex; align-items: baseline; gap: 7px;
padding: 12px 15px 11px; border-bottom: 1px solid rgba(148, 163, 184, 0.12);
background: linear-gradient(90deg, rgba(225, 29, 72, 0.08), transparent 55%);
border-radius: 12px 12px 0 0;
}
#zs-setup-logo { font-weight: 700; font-size: 13px; letter-spacing: -0.1px; color: #f2f5f9; }
#zs-setup-tag { font-size: 10px; font-weight: 600; color: #f43f5e; font-family: ui-monospace, "Cascadia Mono", monospace; }
#zs-setup-sub { color: #9a9aa2; font-size: 11.5px; line-height: 1.5; margin: 12px 15px 12px; }
/* the steps ARE a real sequence, so numbered markers earn their place here */
#zs-setup-steps {
list-style: none; margin: 0 15px 13px; padding: 0;
counter-reset: zs-step; font-size: 11.5px; line-height: 1.4;
}
#zs-setup-steps li {
counter-increment: zs-step;
display: flex; align-items: flex-start; gap: 10px;
padding: 6px 0; color: #cacacf;
}
#zs-setup-steps li + li { border-top: 1px solid rgba(255, 255, 255, 0.05); }
#zs-setup-steps li::before {
content: counter(zs-step);
flex: none; font-size: 11px; font-weight: 600; color: #7a7a82;
min-width: 14px;
}
#zs-setup-steps code {
background: rgba(255, 255, 255, 0.08); padding: 0 4px; border-radius: 4px;
font-family: ui-monospace, "Cascadia Mono", monospace; font-size: 10.5px;
}
.zs-setup-copy-row { display: flex; gap: 6px; margin: 0 15px 10px; }
.zs-setup-copy-row input {
flex: 1; min-width: 0;
background: rgba(255, 255, 255, 0.04); border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 7px; color: #b8b8bf; font-size: 10px;
padding: 6px 8px; font-family: ui-monospace, "Cascadia Mono", monospace;
outline: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#zs-setup-copy {
background: rgba(255, 255, 255, 0.09); color: #ededf0;
border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 7px;
padding: 6px 11px; font-size: 11px; font-weight: 600; cursor: pointer;
white-space: nowrap; transition: background 0.13s ease;
}
#zs-setup-copy:hover { background: rgba(255, 255, 255, 0.15); }
#zs-setup-video {
display: block; margin: 0 15px 10px; padding: 8px; box-sizing: border-box;
background: rgba(255, 255, 255, 0.05); color: #e4e4e8;
border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 8px;
font-size: 12px; font-weight: 600; text-align: center; text-decoration: none;
transition: background 0.13s ease;
}
#zs-setup-video:hover { background: rgba(255, 255, 255, 0.09); }
#zs-setup-dismiss {
display: block; width: calc(100% - 30px); margin: 0 15px; padding: 8px;
border-radius: 8px; border: 1px solid rgba(255, 255, 255, 0.1);
background: transparent; color: #a0a0a8;
font-size: 11px; font-weight: 600; cursor: pointer;
transition: background 0.13s ease;
}
#zs-setup-dismiss:hover { background: rgba(255, 255, 255, 0.06); }
/* ── capture preview popup (left-hand, ZeroScript style) ─────── */
.zs-shot {
position: fixed; left: 18px; top: 72px; width: 300px; max-width: 32vw;
background: linear-gradient(180deg, #10151d, #0b0e13); color: #e4eaf2;
border: 1px solid rgba(148, 163, 184, 0.18);
border-radius: 12px;
box-shadow: 0 16px 44px rgba(0, 0, 0, 0.5);
z-index: 2147483601; overflow: hidden;
}
.zs-shot-hdr {
display: flex; align-items: center; justify-content: space-between;
padding: 10px 12px; border-bottom: 1px solid rgba(148, 163, 184, 0.12);
}
.zs-shot-ttl {
font-size: 12px; font-weight: 600; color: #e4eaf2;
font-family: ui-monospace, "Cascadia Code", monospace;
}
.zs-shot-x {
background: none; border: none; color: #8b8b93; cursor: pointer;
font-size: 13px; line-height: 1; padding: 2px 4px;
}
.zs-shot-x:hover { color: #f2f5f9; }
.zs-shot-body {
padding: 10px; max-height: 70vh; overflow-y: auto;
display: flex; flex-direction: column; gap: 8px;
}
.zs-shot-img { display: block; width: 100%; height: auto; border-radius: 8px; background: rgba(0, 0, 0, 0.25); }
html.zs-light .zs-shot { background: #ffffff; color: #1d232e; border-color: rgba(0,0,0,0.1); }
html.zs-light .zs-shot-hdr { border-bottom-color: rgba(0,0,0,0.08); }
html.zs-light .zs-shot-ttl { color: #1d232e; }
/* ══════════════════════════════════════════════════════════════
LIGHT MODE
Toggled by core/main.js adding `.zs-light` to <html> when the host
page's effective background is light. Dark mode (the default) is
untouched.
══════════════════════════════════════════════════════════════ */
/* in-conversation tool/result/sys chips */
html.zs-light .zs-chip {
color: #2b313d;
background: rgba(0, 0, 0, 0.03);
border-color: rgba(0, 0, 0, 0.12);
}
html.zs-light .zs-chip:hover { background: rgba(0, 0, 0, 0.055); }
html.zs-light .zs-chip.err { border-color: rgba(220, 38, 38, 0.4); }
html.zs-light .zs-chip-body pre { color: #2b313d; }
html.zs-light .zs-chip-body { border-top-color: color-mix(in srgb, var(--cat) 30%, #ffffff); }
html.zs-light .zs-chip.err { color: #7f1d1d; }
html.zs-light .zs-chip.run {
background-color: rgba(0, 0, 0, 0.04);
background-image: linear-gradient(90deg,
transparent 0%, rgba(0, 0, 0, 0.06) 50%, transparent 100%);
/* MUST re-declare: the light `.zs-chip` base uses the `background` shorthand
(resets size to auto) at a HIGHER specificity than `.zs-chip.run`, so without
this the tile falls back to auto (width-tied) and the sweep teleports on
resize - the dark theme was unaffected only because its base is lower spec. */
background-repeat: repeat;
background-size: 210px 100%;
}
html.zs-light .zs-spin { border-color: rgba(0, 0, 0, 0.15); border-top-color: #6b6b73; }
/* status bar + menu + setup card */
html.zs-light #zs-bar {
background: rgba(255, 255, 255, 0.97);
color: #1f2430;
border-color: rgba(148, 163, 184, 0.42);
box-shadow: 0 8px 30px rgba(15, 23, 42, 0.16);
}
html.zs-light #zs-brand { color: #1f2430; }
html.zs-light .zs-free { color: #be123c; background: rgba(225, 29, 72, 0.08); border-color: rgba(225, 29, 72, 0.30); }
html.zs-light #zs-state { color: #4b5563; }
html.zs-light #zs-state b { color: #be123c; }
html.zs-light #zs-state.zs-state-warn { color: #b91c1c; }
html.zs-light #zs-bar.tone-active #zs-state b { color: #059669; }
html.zs-light #zs-discord,
html.zs-light #zs-support,
html.zs-light #zs-switch {
background: rgba(0, 0, 0, 0.05); color: #4b5563;
border-color: rgba(0, 0, 0, 0.12);
}
html.zs-light #zs-discord:hover,
html.zs-light #zs-support:hover,
html.zs-light #zs-switch:hover { background: rgba(0, 0, 0, 0.09); color: #1f2430; }
html.zs-light #zs-action:disabled {
background: rgba(0, 0, 0, 0.05); color: rgba(0, 0, 0, 0.35); border-color: rgba(0, 0, 0, 0.08);
}
html.zs-light #zs-menu,
html.zs-light #zs-setup {
background: linear-gradient(180deg, #fbfcfe, #f2f5f9);
color: #1f2430;
border-color: rgba(148, 163, 184, 0.45);
box-shadow: 0 12px 40px rgba(15, 23, 42, 0.18);
}
html.zs-light .zs-menu-head,
html.zs-light #zs-setup-head { border-bottom-color: rgba(0, 0, 0, 0.08); background: linear-gradient(90deg, rgba(225, 29, 72, 0.08), transparent 55%); }
html.zs-light .zs-menu-logo,
html.zs-light #zs-setup-logo { color: #1f2430; }
html.zs-light .zs-menu-tag,
html.zs-light #zs-setup-tag { color: #be123c; }
html.zs-light .zs-menu-sec + .zs-menu-sec { border-top-color: rgba(0, 0, 0, 0.07); }
html.zs-light .zs-sec-label span { color: #6b6b73; }
html.zs-light .zs-menu-note { color: #6b7280; }
html.zs-light #zs-set-text,
html.zs-light .zs-mcp-field {
background: #ffffff; color: #1f2430; border-color: rgba(0, 0, 0, 0.14);
}
html.zs-light .zs-mcp-item { background: #ffffff; border-color: rgba(0, 0, 0, 0.1); }
html.zs-light .zs-mcp-name { color: #1f2430; }
html.zs-light .zs-mcp-url { color: #6b7280; }
html.zs-light .zs-mcp-remove { color: #8a8a92; }
html.zs-light .zs-mcp-remove:hover { background: rgba(0, 0, 0, 0.06); color: #1f2430; }
html.zs-light .zs-mcp-sep { background: rgba(0, 0, 0, 0.08); }
html.zs-light .zs-mcp-spin { border-color: rgba(0, 0, 0, 0.15); border-top-color: #4b5563; }
html.zs-light #zs-setup-sub { color: #4b5563; }
html.zs-light #zs-setup-steps li { color: #374151; }
html.zs-light #zs-setup-steps li + li { border-top-color: rgba(0, 0, 0, 0.06); }
html.zs-light #zs-setup-steps li::before { color: #8a8a92; }
html.zs-light #zs-setup-steps code { background: rgba(0, 0, 0, 0.06); }
html.zs-light #zs-setup-dismiss { border-color: rgba(0, 0, 0, 0.12); color: #4b5563; }
html.zs-light #zs-setup-dismiss:hover { background: rgba(0, 0, 0, 0.05); }
/* Menu contents in light theme: neutral grays, subtle surfaces on hover */
html.zs-light .zs-site-opt { color: #4b5563; }
html.zs-light .zs-site-name > span:first-child { color: #1f2430; }
html.zs-light .zs-site-host { color: #9ca3af; }
html.zs-light button.zs-site-opt:hover { background: rgba(0, 0, 0, 0.05); }
html.zs-light .zs-site-badge { color: #6b7280; border-color: rgba(0, 0, 0, 0.14); }
html.zs-light .zs-site-here {
background: rgba(225, 29, 72, 0.06);
box-shadow: inset 2px 0 0 #e11d48;
}
html.zs-light .zs-site-here .zs-site-badge {
color: #be123c; border-color: rgba(225, 29, 72, 0.35); background: rgba(225, 29, 72, 0.08);
}
html.zs-light .zs-site-go { color: #9ca3af; }
html.zs-light #zs-set-save,
html.zs-light #zs-mcp-add,
html.zs-light .zs-tip-opt {
background: rgba(0, 0, 0, 0.05); color: #1f2430; border-color: rgba(0, 0, 0, 0.12);
}
html.zs-light #zs-set-save:hover,
html.zs-light #zs-mcp-add:hover,
html.zs-light .zs-tip-opt:hover { background: rgba(0, 0, 0, 0.09); }
html.zs-light #zs-set-status,
html.zs-light #zs-mcp-status,
html.zs-light .zs-tip-sub,
html.zs-light .zs-rbx-cur,
html.zs-light .zs-tip-sep { color: #6b7280; }
html.zs-light .zs-tip-rbx { color: #374151; }