riptide-transfer 1.3.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
riptide/theme.py ADDED
@@ -0,0 +1,1049 @@
1
+ """Theme constants. Pure terminal transparency, coral accent, muted metadata."""
2
+ from __future__ import annotations
3
+
4
+ import textual.renderables.blank as _blank_mod
5
+ from rich.style import Style as _RichStyle
6
+ from textual.color import Color as _Color
7
+ import textual.style as _style_mod
8
+ import textual.filter as _filter_mod
9
+
10
+ # Patch Textual's Blank visual to emit Style() with no background color for transparent/alpha=0
11
+ _orig_blank_init = _blank_mod.Blank.__init__
12
+ def _transparent_blank_init(self, color: _Color | str = "transparent") -> None:
13
+ c = _Color.parse(color) if isinstance(color, str) else color
14
+ if c.is_transparent or getattr(c, "a", 1) == 0:
15
+ self._rich_style = _RichStyle()
16
+ else:
17
+ _orig_blank_init(self, color)
18
+ _blank_mod.Blank.__init__ = _transparent_blank_init
19
+
20
+ # Patch Textual's Style.rich_style and rich_style_with_offset so transparent background has bgcolor=None
21
+ _orig_rich_style_func = _style_mod.Style.rich_style.func
22
+ def _patched_rich_style(self) -> _RichStyle:
23
+ rs = _orig_rich_style_func(self)
24
+ bg = getattr(self, "background", None)
25
+ if bg is not None and (getattr(bg, "a", 1) == 0 or getattr(bg, "is_transparent", False)):
26
+ return _RichStyle(
27
+ color=rs.color,
28
+ bgcolor=None,
29
+ bold=rs.bold,
30
+ dim=rs.dim,
31
+ italic=rs.italic,
32
+ underline=rs.underline,
33
+ underline2=rs.underline2,
34
+ reverse=rs.reverse,
35
+ strike=rs.strike,
36
+ blink=rs.blink,
37
+ link=rs.link,
38
+ meta=rs.meta,
39
+ )
40
+ return rs
41
+ _style_mod.Style.rich_style = property(_patched_rich_style)
42
+
43
+ _orig_rich_style_with_offset = _style_mod.Style.rich_style_with_offset
44
+ def _patched_rich_style_with_offset(self, x: int, y: int) -> _RichStyle:
45
+ rs = _orig_rich_style_with_offset(self, x, y)
46
+ bg = getattr(self, "background", None)
47
+ if bg is not None and (getattr(bg, "a", 1) == 0 or getattr(bg, "is_transparent", False)):
48
+ return _RichStyle(
49
+ color=rs.color,
50
+ bgcolor=None,
51
+ bold=rs.bold,
52
+ dim=rs.dim,
53
+ italic=rs.italic,
54
+ underline=rs.underline,
55
+ underline2=rs.underline2,
56
+ reverse=rs.reverse,
57
+ strike=rs.strike,
58
+ blink=rs.blink,
59
+ link=rs.link,
60
+ meta=rs.meta,
61
+ )
62
+ return rs
63
+ _style_mod.Style.rich_style_with_offset = _patched_rich_style_with_offset
64
+
65
+ # Guard monochrome filter against None styles
66
+ _orig_monochrome_style = _filter_mod.monochrome_style
67
+ def _patched_monochrome_style(style: _RichStyle | None) -> _RichStyle:
68
+ if style is None:
69
+ return _RichStyle()
70
+ return _orig_monochrome_style(style)
71
+ _filter_mod.monochrome_style = _patched_monochrome_style
72
+
73
+ BACKGROUND = "transparent"
74
+ SURFACE = "transparent"
75
+ ACCENT = "#FF6B6B"
76
+ TEXT = "#E8E8E8"
77
+ DIM = "#71717A"
78
+ SUCCESS = "#78DC8C"
79
+ WARNING = "#FFD166"
80
+ ERROR = "#FF6B6B"
81
+ # Page headers, larger than body text. Terminals render all text
82
+ # at one pixel size, which Textual cannot change per widget, so
83
+ # a "larger" header here means a 5-row block-letter banner, bold
84
+ # and accent coloured, in its own taller header row. This is the
85
+ # same trick as the menu's ANSI Shadow banner, scaled to short
86
+ # page titles so it fits an 80-column terminal.
87
+
88
+
89
+
90
+
91
+ # Session roles: the Create Server side (listener) is the host,
92
+ # the Join Server side (dialler) is the client.
93
+ BANNER_HOST = r""" __ ______ __________
94
+ / // / __ \/ __/_ __/
95
+ / _ / /_/ /\ \ / /
96
+ /_//_/\____/___/ /_/"""
97
+
98
+ BANNER_CLIENT = r""" _______ _________ ________
99
+ / ___/ / / _/ __/ |/ /_ __/
100
+ / /__/ /___/ // _// / / /
101
+ \___/____/___/___/_/|_/ /_/"""
102
+
103
+ BANNER_CREATE = r""" ________ _______ __________
104
+ / ___/ _ \/ __/ _ /_ __/ __/
105
+ / /__/ , _/ _// __ |/ / / _/
106
+ \___/_/|_/___/_/ |_/_/ /___/"""
107
+
108
+ BANNER_JOIN = r""" ______ _____ __
109
+ __ / / __ \/ _/ |/ /
110
+ / // / /_/ // // /
111
+ \___/\____/___/_/|_/"""
112
+ HEADER_BANNER = """\
113
+ ██████╗ ██╗██████╗ ████████╗██╗██████╗ ███████╗
114
+ ██╔══██╗██║██╔══██╗╚══██╔══╝██║██╔══██╗██╔════╝
115
+ ██████╔╝██║██████╔╝ ██║ ██║██║ ██║█████╗
116
+ ██╔══██╗██║██╔═══╝ ██║ ██║██║ ██║██╔══╝
117
+ ██║ ██║██║██║ ██║ ██║██████╔╝███████╗
118
+ ╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═╝╚═════╝ ╚══════╝\
119
+ """
120
+
121
+ HEADER_LINES = HEADER_BANNER.splitlines()
122
+
123
+ TAGLINES = {
124
+ "home": "Direct, encrypted PC-to-PC file transfer · Zero cloud storage, zero intermediate hops",
125
+ }
126
+
127
+ CSS = """
128
+ App, Screen {
129
+ background: transparent !important;
130
+ color: #E8E8E8;
131
+ layout: vertical;
132
+ padding: 1 2;
133
+ layers: base overlay;
134
+ }
135
+ Static, Label {
136
+ background: transparent;
137
+ color: #E8E8E8;
138
+ }
139
+ .header {
140
+ color: #FF6B6B;
141
+ text-style: bold;
142
+ text-align: center;
143
+ padding: 0 0 1 0;
144
+ }
145
+ .version-tag {
146
+ color: #FF6B6B;
147
+ text-style: bold;
148
+ text-align: center;
149
+ }
150
+ .subheader {
151
+ color: #71717A;
152
+ text-align: center;
153
+ padding: 0 0 1 0;
154
+ }
155
+ .screen-title {
156
+ color: #FF6B6B;
157
+ text-style: bold;
158
+ padding: 1 0 0 0;
159
+ }
160
+ .screen-desc {
161
+ color: #71717A;
162
+ padding: 0 0 1 0;
163
+ }
164
+ .dim {
165
+ color: #71717A;
166
+ }
167
+ .accent {
168
+ color: #FF6B6B;
169
+ }
170
+ .success {
171
+ color: #78DC8C;
172
+ }
173
+ .warning {
174
+ color: #FFD166;
175
+ }
176
+ .error {
177
+ color: #FF6B6B;
178
+ }
179
+ .keymap-bar {
180
+ dock: bottom;
181
+ height: 1;
182
+ color: #71717A;
183
+ background: transparent;
184
+ padding: 0 1;
185
+ }
186
+ .keymap-key {
187
+ color: #E8E8E8;
188
+ text-style: bold;
189
+ }
190
+ /* Input fields, antigravity-cli style: a bordered composer box
191
+ with a dim label above it and a hint below it, not a bare
192
+ input. Placeholder text is grey, focus border is the accent. */
193
+ Input {
194
+ border: round #9696a3;
195
+ background: transparent;
196
+ color: #E8E8E8;
197
+ height: 3;
198
+ padding: 0 1;
199
+ margin: 0 0 1 0;
200
+ }
201
+ Input:focus {
202
+ border: round #FF6B6B;
203
+ }
204
+ Input > .input--placeholder {
205
+ color: #9696a3;
206
+ }
207
+ .composer-label {
208
+ color: #D7D7D7;
209
+ text-style: bold;
210
+ padding: 1 0 0 0;
211
+ }
212
+ .composer-hint {
213
+ color: #D0D0D0;
214
+ padding: 0 0 1 0;
215
+ }
216
+ .composer {
217
+ padding: 0 1 1 1;
218
+ margin: 1 0;
219
+ background: transparent;
220
+ }
221
+ /* Buttons - streamlined, non-bulky */
222
+ Button {
223
+ background: transparent;
224
+ color: #E8E8E8;
225
+ border: round #3F3F46;
226
+ height: 3;
227
+ margin: 0 1;
228
+ text-style: bold;
229
+ }
230
+ Button:focus {
231
+ background: transparent;
232
+ color: #FF6B6B;
233
+ border: round #FF6B6B;
234
+ }
235
+ Button.primary {
236
+ border: round #FF6B6B;
237
+ color: #FF6B6B;
238
+ }
239
+ Button.primary:focus {
240
+ background: #FF6B6B;
241
+ color: #121212;
242
+ }
243
+ Button.allow {
244
+ background: #78DC8C;
245
+ color: #121212;
246
+ text-style: bold;
247
+ border: none;
248
+ width: 22;
249
+ min-width: 22;
250
+ height: 3;
251
+ }
252
+ Button.allow:focus {
253
+ background: #8EEC9F;
254
+ color: #000000;
255
+ border: tall #FFFFFF;
256
+ }
257
+ Button.deny {
258
+ background: #FF6B6B;
259
+ color: #121212;
260
+ text-style: bold;
261
+ border: none;
262
+ width: 22;
263
+ min-width: 22;
264
+ height: 3;
265
+ }
266
+ Button.deny:focus {
267
+ background: #FF8585;
268
+ color: #000000;
269
+ border: tall #FFFFFF;
270
+ }
271
+ ProgressBar {
272
+ margin: 1 0;
273
+ }
274
+ ProgressBar > .bar--bar {
275
+ background: #FF6B6B;
276
+ }
277
+ OptionList {
278
+ background: transparent;
279
+ border: none;
280
+ padding: 1 2;
281
+ height: auto;
282
+ }
283
+ OptionList:focus {
284
+ border: none;
285
+ }
286
+ OptionList > .option-list--option {
287
+ padding: 0 1;
288
+ background: transparent;
289
+ color: #E0E0E0;
290
+ }
291
+ OptionList > .option-list--option-highlighted {
292
+ background: transparent;
293
+ color: #FF6B6B;
294
+ text-style: bold;
295
+ }
296
+ ListView {
297
+ background: transparent;
298
+ border: round #3F3F46;
299
+ padding: 0 1;
300
+ height: 16;
301
+ }
302
+ ListView:focus {
303
+ border: round #FF6B6B;
304
+ }
305
+ ListItem {
306
+ background: transparent;
307
+ padding: 0 1;
308
+ }
309
+ ListItem.-highlight,
310
+ ListItem.--highlight {
311
+ background: transparent;
312
+ }
313
+ .file-row {
314
+ width: 100%;
315
+ height: 1;
316
+ layout: horizontal;
317
+ background: transparent;
318
+ }
319
+ /* File manager colours, in priority order:
320
+ remaining files grey, selected files accent, and the hovered
321
+ (highlighted) row pure white, even if it is also selected.
322
+ The -highlight rules come last so hover/focus wins over selected. */
323
+ .file-name {
324
+ width: 1fr;
325
+ min-width: 12;
326
+ color: #E0E0E0;
327
+ }
328
+ ListItem.selected .file-name {
329
+ color: #FF6B6B;
330
+ text-style: bold;
331
+ }
332
+ ListItem.selected .file-size,
333
+ ListItem.selected .file-mtime {
334
+ color: #E0E0E0;
335
+ }
336
+ ListItem.-highlight,
337
+ ListItem.--highlight,
338
+ ListItem.-highlight *,
339
+ ListItem.--highlight *,
340
+ ListItem.-highlight Label,
341
+ ListItem.--highlight Label,
342
+ ListItem.-highlight .file-name,
343
+ ListItem.--highlight .file-name,
344
+ ListItem.-highlight .file-size,
345
+ ListItem.--highlight .file-size,
346
+ ListItem.-highlight .file-mtime,
347
+ ListItem.--highlight .file-mtime,
348
+ ListItem.selected.-highlight Label,
349
+ ListItem.selected.--highlight Label,
350
+ ListView:focus > ListItem.-highlight Label,
351
+ ListView:focus > ListItem.--highlight Label {
352
+ color: #FFFFFF !important;
353
+ text-style: bold !important;
354
+ }
355
+ .file-size {
356
+ width: 12;
357
+ text-align: right;
358
+ color: #E0E0E0;
359
+ }
360
+ .file-mtime {
361
+ width: 22;
362
+ text-align: right;
363
+ color: #E0E0E0;
364
+ }
365
+ .file-header-pointer {
366
+ width: 2;
367
+ min-width: 2;
368
+ max-width: 2;
369
+ padding: 0;
370
+ margin: 0;
371
+ }
372
+ .file-pointer {
373
+ width: 2;
374
+ min-width: 2;
375
+ max-width: 2;
376
+ color: #FF6B6B;
377
+ text-style: bold;
378
+ padding: 0;
379
+ margin: 0;
380
+ }
381
+ .file-header-row {
382
+ width: 100%;
383
+ height: 1;
384
+ layout: horizontal;
385
+ padding: 0 1;
386
+ color: #E0E0E0;
387
+ text-style: bold;
388
+ }
389
+ .file-header-name {
390
+ width: 1fr;
391
+ color: #E0E0E0;
392
+ text-style: bold;
393
+ }
394
+ .file-header-size {
395
+ width: 12;
396
+ text-align: right;
397
+ color: #E0E0E0;
398
+ text-style: bold;
399
+ }
400
+ .file-header-mtime {
401
+ width: 22;
402
+ text-align: right;
403
+ color: #E0E0E0;
404
+ text-style: bold;
405
+ }
406
+
407
+ /* Redesigned Session Screen Styles */
408
+ #session_scroll {
409
+ height: 1fr;
410
+ overflow-y: auto;
411
+ padding: 0;
412
+ margin: 0;
413
+ }
414
+ /* Create Server page: plain container, no scroll container, so
415
+ no vertical scrollbar can appear on this page. */
416
+ #create_content {
417
+ height: 1fr;
418
+ width: 100%;
419
+ padding: 0;
420
+ margin: 0;
421
+ }
422
+ #session_header_row {
423
+ width: 100%;
424
+ height: 5;
425
+ max-height: 5;
426
+ layout: horizontal;
427
+ margin: 0;
428
+ padding: 0;
429
+ }
430
+ #session_host_title {
431
+ width: auto;
432
+ height: 5;
433
+ color: #FF6B6B;
434
+ text-style: bold;
435
+ padding: 0;
436
+ margin: 0;
437
+ }
438
+ /* Router port-forwarding notice, shown only when port was closed in OS firewall.
439
+ The banner text is not bold. The banner has no bottom margin:
440
+ the 1-row gap it used to leave is now a blank widget,
441
+ #router_banner_spacer, which writes blank spaces into that
442
+ row and so covers the menu's RIPTIDE logo underneath, while
443
+ the screen itself stays transparent. Total height before the
444
+ CREATE header is unchanged: banner height plus 1 blank row. */
445
+ #router_banner {
446
+ display: none;
447
+ width: 100%;
448
+ height: auto;
449
+ background: #FFD166;
450
+ color: #121212;
451
+ text-align: center;
452
+ padding: 1 2;
453
+ margin: 0 0 0 0;
454
+ }
455
+ #router_banner_spacer {
456
+ display: none;
457
+ width: 100%;
458
+ height: 1;
459
+ background: transparent;
460
+ padding: 0;
461
+ margin: 0;
462
+ }
463
+ .session-header-text {
464
+ color: #FF6B6B;
465
+ text-style: bold;
466
+ }
467
+ #session_peer_info {
468
+ width: 1fr;
469
+ height: 5;
470
+ layout: vertical;
471
+ padding: 0;
472
+ margin: 0;
473
+ }
474
+ #peer_client_label {
475
+ width: 100%;
476
+ height: 1;
477
+ text-align: right;
478
+ color: #E8E8E8;
479
+ text-style: bold;
480
+ padding: 0;
481
+ margin: 0;
482
+ }
483
+ #peer_status_label {
484
+ width: 100%;
485
+ height: 1;
486
+ text-align: right;
487
+ padding: 0;
488
+ margin: 0;
489
+ }
490
+ #status {
491
+ width: 100%;
492
+ height: 1;
493
+ padding: 0;
494
+ margin: 0;
495
+ color: #71717A;
496
+ }
497
+
498
+ #browser_box {
499
+ width: 100%;
500
+ height: auto;
501
+ border: round #3F3F46;
502
+ background: transparent;
503
+ padding: 0 1;
504
+ margin: 1 0;
505
+ }
506
+ #browser_box:focus-within {
507
+ border: round #FF6B6B;
508
+ }
509
+ #browser_header_row {
510
+ width: 100%;
511
+ height: 1;
512
+ layout: horizontal;
513
+ padding: 0;
514
+ margin: 0;
515
+ }
516
+ #browser_path {
517
+ width: 1fr;
518
+ height: 1;
519
+ color: #E8E8E8;
520
+ text-style: bold;
521
+ padding: 0;
522
+ margin: 0;
523
+ }
524
+ #browser_search_indicator {
525
+ width: auto;
526
+ height: 1;
527
+ color: #FFD166;
528
+ text-style: bold;
529
+ padding: 0;
530
+ margin: 0;
531
+ }
532
+ #browser_separator {
533
+ width: 100%;
534
+ height: 1;
535
+ color: #3F3F46;
536
+ padding: 0;
537
+ margin: 0;
538
+ }
539
+ #browser_box ListView#cwd_list {
540
+ width: 100%;
541
+ height: 10;
542
+ border: none;
543
+ padding: 0;
544
+ margin: 0;
545
+ }
546
+ #browser_box ListView#cwd_list:focus {
547
+ border: none;
548
+ }
549
+ #browser_hint {
550
+ width: 100%;
551
+ height: 1;
552
+ padding: 0;
553
+ margin: 0;
554
+ color: #71717A;
555
+ }
556
+ #create_actions {
557
+ width: 100%;
558
+ layout: horizontal;
559
+ padding: 1 0;
560
+ margin: 0;
561
+ }
562
+ #create_actions Button {
563
+ margin: 0 1;
564
+ }
565
+
566
+ #selected_files_section,
567
+ #selected_files_list,
568
+ #selected_files_section Vertical {
569
+ width: 100%;
570
+ height: auto;
571
+ margin: 0;
572
+ padding: 0;
573
+ background: transparent;
574
+ }
575
+ #selected_header {
576
+ width: 100%;
577
+ height: 1;
578
+ margin: 0;
579
+ padding: 0;
580
+ }
581
+ .selected-file-item {
582
+ width: 100%;
583
+ height: 1;
584
+ color: #FF6B6B;
585
+ margin: 0;
586
+ padding: 0;
587
+ }
588
+
589
+ .composer {
590
+ width: 100%;
591
+ height: auto;
592
+ padding: 0;
593
+ margin: 0;
594
+ background: transparent;
595
+ }
596
+ .composer-label {
597
+ width: 100%;
598
+ height: 1;
599
+ padding: 0;
600
+ margin: 0;
601
+ color: #71717A;
602
+ text-style: bold;
603
+ }
604
+ .composer-hint {
605
+ width: 100%;
606
+ height: 1;
607
+ padding: 0;
608
+ margin: 0;
609
+ color: #71717A;
610
+ }
611
+
612
+ #download_composer {
613
+ width: 100%;
614
+ height: auto;
615
+ padding: 0;
616
+ margin: 2 0 0 0;
617
+ background: transparent;
618
+ }
619
+ #download_composer .composer-label {
620
+ width: 100%;
621
+ height: 1;
622
+ color: #D7D7D7;
623
+ text-style: bold;
624
+ padding: 0;
625
+ margin: 0;
626
+ }
627
+ #download_composer Input {
628
+ width: 100%;
629
+ height: 3;
630
+ border: round #3F3F46;
631
+ background: transparent;
632
+ color: #D7D7D7;
633
+ padding: 0 1;
634
+ margin: 0;
635
+ }
636
+ #download_composer Input > .input--placeholder {
637
+ color: #D7D7D7;
638
+ }
639
+ #download_composer Input:focus {
640
+ border: round #FF6B6B;
641
+ }
642
+ #download_denied_message {
643
+ display: none;
644
+ width: 100%;
645
+ height: auto;
646
+ color: #FF6B6B;
647
+ text-style: bold;
648
+ padding: 0;
649
+ margin: 0;
650
+ }
651
+ #download_denied_message.active {
652
+ display: block;
653
+ }
654
+ #download_composer.disabled {
655
+ opacity: 0.35;
656
+ }
657
+ #download_composer.disabled Input {
658
+ border: round #27272A;
659
+ color: #52525B;
660
+ }
661
+ #download_composer.disabled .composer-label {
662
+ color: #52525B;
663
+ }
664
+
665
+ #progress_section {
666
+ width: 100%;
667
+ height: auto;
668
+ margin: 1 0 0 0;
669
+ padding: 0;
670
+ display: none;
671
+ }
672
+ #progress_section ProgressBar#bar,
673
+ ProgressBar#bar,
674
+ ProgressBar {
675
+ width: 100% !important;
676
+ min-width: 100% !important;
677
+ margin: 0 !important;
678
+ padding: 0 !important;
679
+ }
680
+ ProgressBar > Bar {
681
+ width: 1fr !important;
682
+ }
683
+ ProgressBar > .bar--bar {
684
+ width: 100% !important;
685
+ background: #FF6B6B;
686
+ }
687
+ #transfer_complete_message {
688
+ width: 100%;
689
+ height: auto;
690
+ text-align: center;
691
+ color: #78DC8C;
692
+ text-style: bold;
693
+ margin: 1 0;
694
+ display: none;
695
+ }
696
+ #progress_metrics_row {
697
+ width: 100%;
698
+ height: 1;
699
+ layout: horizontal;
700
+ margin: 0;
701
+ padding: 0;
702
+ }
703
+ .progress-metric {
704
+ width: 1fr;
705
+ text-align: center;
706
+ color: #FF6B6B;
707
+ }
708
+ .progress-metric-left {
709
+ width: 1fr;
710
+ text-align: left;
711
+ color: #FF6B6B;
712
+ }
713
+ .progress-metric-right {
714
+ width: 1fr;
715
+ text-align: right;
716
+ color: #FF6B6B;
717
+ }
718
+ #progress_file_row {
719
+ width: 100%;
720
+ height: 1;
721
+ layout: horizontal;
722
+ margin: 0;
723
+ padding: 0;
724
+ }
725
+ #progress_file_name {
726
+ width: 1fr;
727
+ min-width: 12;
728
+ height: 1;
729
+ color: #E8E8E8;
730
+ text-style: bold;
731
+ }
732
+ #progress_file_size {
733
+ width: auto;
734
+ height: 1;
735
+ text-align: right;
736
+ color: #71717A;
737
+ }
738
+ #session_scroll {
739
+ layer: base;
740
+ }
741
+
742
+ /* Download Request Modal Popup (centered, blank background).
743
+ A terminal cell has one solid background colour, so true alpha
744
+ blending over the page below is not possible: rgba(0,0,0,0.5)
745
+ did not dim the page, it just rendered as an opaque layer.
746
+ Instead of a solid dark grey overlay, the overlay is
747
+ transparent: its full-screen widget still writes blank spaces
748
+ into the cells outside the card, covering the page below,
749
+ while the background stays the terminal background. The card
750
+ itself stays solid, with a red border on top. */
751
+ #download_modal_overlay {
752
+ layer: overlay;
753
+ display: none;
754
+ align: center middle;
755
+ width: 100%;
756
+ height: 100%;
757
+ background: transparent;
758
+ }
759
+ #download_modal_overlay.active {
760
+ display: block;
761
+ }
762
+ #download_modal_card {
763
+ width: 60;
764
+ max-width: 90%;
765
+ height: auto;
766
+ border: none;
767
+ /* Popup inside is dark grey, #3F3F46, so the card still
768
+ stands out against the blank background outside it,
769
+ with its red border. */
770
+ background: #3F3F46;
771
+ padding: 1 2;
772
+ align: center middle;
773
+ }
774
+ #download_modal_title {
775
+ width: 100%;
776
+ text-align: center;
777
+ color: #FFD166;
778
+ text-style: bold;
779
+ margin: 0 0 1 0;
780
+ }
781
+ #download_modal_card #download_approval {
782
+ width: 100%;
783
+ text-align: center;
784
+ color: #E8E8E8;
785
+ margin: 0 0 1 0;
786
+ }
787
+ #download_modal_actions {
788
+ width: 100%;
789
+ height: auto;
790
+ align: center middle;
791
+ margin: 1 0;
792
+ }
793
+ #download_modal_actions Button {
794
+ margin: 0 2;
795
+ min-width: 16;
796
+ }
797
+ #download_modal_actions Button.allow {
798
+ background: #78DC8C;
799
+ color: #121212;
800
+ text-style: bold;
801
+ }
802
+ #download_modal_actions Button.allow:focus {
803
+ background: #8EEC9F;
804
+ color: #000000;
805
+ border: tall #FFFFFF;
806
+ }
807
+ #download_modal_actions Button.deny {
808
+ background: #FF6B6B;
809
+ color: #121212;
810
+ text-style: bold;
811
+ }
812
+ #download_modal_actions Button.deny:focus {
813
+ background: #FF8787;
814
+ color: #000000;
815
+ border: tall #FFFFFF;
816
+ }
817
+ #download_modal_footer {
818
+ width: 100%;
819
+ text-align: center;
820
+ color: #71717A;
821
+ margin: 1 0 0 0;
822
+ }
823
+
824
+ #footer_bar {
825
+ dock: bottom;
826
+ width: 100%;
827
+ height: 1;
828
+ layout: horizontal;
829
+ background: transparent;
830
+ padding: 0 1;
831
+ margin: 0;
832
+ }
833
+ .keymap-item {
834
+ width: 1fr;
835
+ text-align: center;
836
+ color: #71717A;
837
+ }
838
+ .keymap-left {
839
+ text-align: left;
840
+ }
841
+ .keymap-right {
842
+ text-align: right;
843
+ }
844
+
845
+ /* Join Screen Redesign Styles */
846
+ #public_ip {
847
+ width: 100%;
848
+ height: 1;
849
+ color: #E8E8E8;
850
+ text-style: bold;
851
+ margin: 0 0 1 0;
852
+ padding: 0;
853
+ }
854
+ #incoming_card {
855
+ width: 100%;
856
+ height: auto;
857
+ border: round #3F3F46;
858
+ background: transparent;
859
+ padding: 1 2;
860
+ margin: 1 0;
861
+ }
862
+ #incoming_card.active {
863
+ border: round #78DC8C;
864
+ }
865
+ #incoming {
866
+ width: 100%;
867
+ height: auto;
868
+ margin: 0;
869
+ padding: 0;
870
+ color: #E8E8E8;
871
+ }
872
+ #create_actions {
873
+ width: 100%;
874
+ height: auto;
875
+ layout: horizontal;
876
+ align: center middle;
877
+ margin: 1 0 0 0;
878
+ padding: 0;
879
+ }
880
+ #create_actions Button {
881
+ width: 22;
882
+ min-width: 22;
883
+ height: 3;
884
+ margin: 0 2;
885
+ text-style: bold;
886
+ border: none;
887
+ }
888
+
889
+ /* Join Server Styles */
890
+ #join_body {
891
+ width: 100%;
892
+ height: 1fr;
893
+ layout: vertical;
894
+ padding: 1 2;
895
+ margin: 0;
896
+ }
897
+ #join_top_section {
898
+ width: 100%;
899
+ height: 3fr;
900
+ layout: vertical;
901
+ padding: 0;
902
+ margin: 0;
903
+ }
904
+ .create-section-title {
905
+ width: 100%;
906
+ height: 1;
907
+ color: #E8E8E8;
908
+ text-style: bold;
909
+ margin: 0 0 1 0;
910
+ }
911
+ #saved_devices {
912
+ width: 100%;
913
+ height: 1fr;
914
+ max-height: 100%;
915
+ overflow-y: auto;
916
+ padding: 0;
917
+ margin: 0;
918
+ }
919
+ .device-item {
920
+ width: 100%;
921
+ height: 1;
922
+ color: #71717A;
923
+ margin: 0 0 1 0;
924
+ }
925
+ #empty_devices {
926
+ width: 100%;
927
+ height: auto;
928
+ color: #71717A;
929
+ }
930
+ #join_input_section {
931
+ width: 100%;
932
+ height: auto;
933
+ align-horizontal: center;
934
+ margin: 0;
935
+ padding: 0;
936
+ }
937
+ #join_input_section Input {
938
+ width: 80;
939
+ max-width: 95%;
940
+ height: 5;
941
+ padding: 1 1;
942
+ margin: 0;
943
+ }
944
+ #join_input_section .composer-label {
945
+ width: 80;
946
+ max-width: 95%;
947
+ color: #FF6B6B;
948
+ text-style: bold;
949
+ text-align: left;
950
+ padding: 0 0 1 0;
951
+ }
952
+ #join_input_section .composer-hint {
953
+ width: 80;
954
+ max-width: 95%;
955
+ color: #71717A;
956
+ padding: 1 0 0 0;
957
+ }
958
+ #join_bottom_section {
959
+ width: 100%;
960
+ height: 1fr;
961
+ align-horizontal: center;
962
+ padding: 1 0 0 0;
963
+ }
964
+ #join_bottom_section #status {
965
+ width: 60;
966
+ max-width: 90%;
967
+ text-align: center;
968
+ color: #71717A;
969
+ margin: 0 0 1 0;
970
+ }
971
+ /* Fingerprint Approval Modal Popup, like the download request modal.
972
+ Blank background, for the same reason as the download overlay:
973
+ the overlay widget writes blank spaces outside the card, while
974
+ the background stays the terminal background. */
975
+ #fingerprint_modal_overlay {
976
+ layer: overlay;
977
+ display: none;
978
+ align: center middle;
979
+ width: 100%;
980
+ height: 100%;
981
+ background: transparent;
982
+ }
983
+ #fingerprint_modal_overlay.active {
984
+ display: block;
985
+ }
986
+ #fingerprint_modal_card {
987
+ width: 60;
988
+ max-width: 90%;
989
+ height: auto;
990
+ border: none;
991
+ /* Same dark grey as the download card, standing out against
992
+ the blank background outside it. */
993
+ background: #3F3F46;
994
+ padding: 1 2;
995
+ align: center middle;
996
+ }
997
+ #fingerprint_modal_title {
998
+ width: 100%;
999
+ text-align: center;
1000
+ color: #FFD166;
1001
+ text-style: bold;
1002
+ margin: 0 0 1 0;
1003
+ }
1004
+ #fingerprint_modal_card #fingerprint_modal_body {
1005
+ width: 100%;
1006
+ text-align: center;
1007
+ color: #E8E8E8;
1008
+ margin: 0 0 1 0;
1009
+ }
1010
+ #fingerprint_modal_actions {
1011
+ width: 100%;
1012
+ height: auto;
1013
+ align: center middle;
1014
+ margin: 1 0;
1015
+ }
1016
+ #fingerprint_modal_actions Button {
1017
+ margin: 0 2;
1018
+ min-width: 16;
1019
+ }
1020
+ #fingerprint_modal_actions Button.allow {
1021
+ background: #78DC8C;
1022
+ color: #121212;
1023
+ text-style: bold;
1024
+ }
1025
+ #fingerprint_modal_actions Button.allow:focus {
1026
+ background: #8EEC9F;
1027
+ color: #000000;
1028
+ border: tall #FFFFFF;
1029
+ }
1030
+ #fingerprint_modal_actions Button.deny {
1031
+ background: #FF6B6B;
1032
+ color: #121212;
1033
+ text-style: bold;
1034
+ }
1035
+ #fingerprint_modal_actions Button.deny:focus {
1036
+ background: #FF8787;
1037
+ color: #000000;
1038
+ border: tall #FFFFFF;
1039
+ }
1040
+ #fingerprint_modal_footer {
1041
+ width: 100%;
1042
+ text-align: center;
1043
+ color: #71717A;
1044
+ margin: 1 0 0 0;
1045
+ }
1046
+ #join_bottom_section #join {
1047
+ display: none;
1048
+ }
1049
+ """