app.css
⎇
Raw
1/* Theme palettes. The base is light; dark is applied either by the OS
2 preference (theme = auto, the default) or forced by the theme toggle,
3 which puts `light`/`dark` on <html> (see web/src/theme.rs). Keep the two
4 dark blocks in sync. */
5:root {
6 color-scheme: light;
7 --bg: #f6f7f9;
8 --panel: #ffffff;
9 --text: #1a1d21;
10 --muted: #6b7280;
11 --accent: #3b82f6;
12 --accent-hover: #2563eb;
13 --accent-border: #1d4ed8;
14 --danger: #ef4444;
15 --danger-border: #dc2626;
16 --border: #e5e7eb;
17 --topbar-h: 48px;
18 --select-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2.5' stroke-linecap='square'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
19}
20
21:root.dark {
22 color-scheme: dark;
23 --bg: #0f1115;
24 --panel: #171a20;
25 --text: #e5e7eb;
26 --muted: #9ca3af;
27 --accent: #60a5fa;
28 --accent-hover: #3b82f6;
29 --accent-border: #79b5fc;
30 --danger: #f87171;
31 --danger-border: #fa8b8b;
32 --border: #2a2f3a;
33 --select-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2.5' stroke-linecap='square'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
34}
35
36@media (prefers-color-scheme: dark) {
37 :root:not(.light) {
38 color-scheme: dark;
39 --bg: #0f1115;
40 --panel: #171a20;
41 --text: #e5e7eb;
42 --muted: #9ca3af;
43 --accent: #60a5fa;
44 --accent-hover: #3b82f6;
45 --accent-border: #79b5fc;
46 --danger: #f87171;
47 --danger-border: #fa8b8b;
48 --border: #2a2f3a;
49 --select-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239ca3af' stroke-width='2.5' stroke-linecap='square'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
50 }
51}
52
53* {
54 box-sizing: border-box;
55 /* The design language is sharp: everything stays square. */
56 border-radius: 0;
57}
58
59body {
60 margin: 0;
61 font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
62 background: var(--bg);
63 color: var(--text);
64 font-size: 15px;
65}
66
67.muted {
68 color: var(--muted);
69}
70
71.card {
72 background: var(--panel);
73 border: 1px solid var(--border);
74 padding: 24px;
75}
76
77.center-screen {
78 min-height: 100vh;
79 display: flex;
80 flex-direction: column;
81 align-items: center;
82 justify-content: center;
83 padding: 16px;
84 text-align: center;
85}
86
87.auth-card {
88 width: 100%;
89 max-width: 380px;
90}
91
92.auth-card h1 {
93 margin: 0 0 8px;
94 font-size: 22px;
95}
96
97.auth-logo {
98 width: 44px;
99 height: 44px;
100 margin-bottom: 12px;
101}
102
103.auth-card p {
104 margin: 0 0 20px;
105 font-size: 13px;
106}
107
108.field {
109 display: block;
110 margin-bottom: 14px;
111}
112
113.field span {
114 display: block;
115 font-size: 13px;
116 color: var(--muted);
117 margin-bottom: 4px;
118}
119
120input {
121 width: 100%;
122 padding: 10px 12px;
123 border: 1px solid var(--border);
124 background: var(--bg);
125 color: var(--text);
126 font-size: 14px;
127}
128
129input:focus {
130 outline: 2px solid var(--accent);
131 outline-offset: -1px;
132}
133
134/* Square checkboxes — native controls are rounded, the theme is sharp. */
135input[type="checkbox"] {
136 appearance: none;
137 -webkit-appearance: none;
138 width: 16px;
139 height: 16px;
140 margin: 0;
141 padding: 0;
142 flex: none;
143 border: 1px solid var(--border);
144 background: var(--panel);
145 cursor: pointer;
146 position: relative;
147 vertical-align: -3px;
148}
149
150input[type="checkbox"]:checked {
151 background: var(--accent);
152 border-color: var(--accent-border);
153}
154
155input[type="checkbox"]:checked::after {
156 content: "";
157 position: absolute;
158 left: 4px;
159 top: 1px;
160 width: 4px;
161 height: 8px;
162 border: solid #fff;
163 border-width: 0 2px 2px 0;
164 transform: rotate(45deg);
165}
166
167button {
168 font: inherit;
169 cursor: pointer;
170 display: inline-flex;
171 align-items: center;
172 justify-content: center;
173 gap: 6px;
174 border: 1px solid var(--border);
175 background: var(--panel);
176 color: var(--text);
177 padding: 9px 14px;
178}
179
180button:hover {
181 border-color: var(--muted);
182}
183
184button:disabled {
185 opacity: 0.6;
186 cursor: default;
187}
188
189.btn-primary {
190 width: 100%;
191 background: var(--accent);
192 /* One step away from the fill, per theme (see palette above), so the
193 button's edge reads the same as on neutral buttons. */
194 border-color: var(--accent-border);
195 color: #fff;
196 font-weight: 600;
197}
198
199.btn-primary:hover {
200 background: var(--accent-hover);
201 border-color: var(--accent-border);
202}
203
204.error {
205 color: var(--danger);
206 font-size: 13px;
207 min-height: 18px;
208 margin: 0 0 10px;
209}
210
211/* layout (signed-in): full-width topbar, then sidebar + content below */
212
213.layout {
214 min-height: 100vh;
215 display: flex;
216 flex-direction: column;
217}
218
219.topbar {
220 flex: none;
221 position: sticky;
222 top: 0;
223 z-index: 130;
224 height: var(--topbar-h);
225 display: flex;
226 align-items: center;
227 justify-content: space-between;
228 gap: 12px;
229 padding: 0 16px;
230 background: var(--panel);
231 border-bottom: 1px solid var(--border);
232}
233
234.topbar-left {
235 display: flex;
236 align-items: center;
237 gap: 10px;
238 min-width: 0;
239}
240
241.icon-btn.nav-toggle {
242 display: none;
243}
244
245.body-row {
246 flex: 1;
247 display: flex;
248 align-items: stretch;
249}
250
251/* ---- sidebar ---- */
252
253.sidebar {
254 flex: none;
255 width: 224px;
256 display: flex;
257 flex-direction: column;
258 background: var(--panel);
259 border-right: 1px solid var(--border);
260 position: sticky;
261 top: var(--topbar-h);
262 height: calc(100vh - var(--topbar-h));
263}
264
265.brand {
266 display: flex;
267 align-items: center;
268 gap: 10px;
269 font-weight: 700;
270 white-space: nowrap;
271 color: inherit;
272 text-decoration: none;
273 cursor: pointer;
274}
275
276.brand:hover {
277 opacity: 0.8;
278}
279
280.brand-name {
281 overflow: hidden;
282 text-overflow: ellipsis;
283}
284
285.logo {
286 width: 26px;
287 height: 26px;
288 flex: none;
289 display: block;
290}
291
292.nav {
293 flex: 1;
294 overflow-y: auto;
295 padding: 14px 8px 16px;
296 display: flex;
297 flex-direction: column;
298 gap: 20px;
299}
300
301.sidebar-user {
302 padding: 0 10px 2px;
303 font-size: 14px;
304 font-weight: 600;
305 overflow: hidden;
306 text-overflow: ellipsis;
307 white-space: nowrap;
308}
309
310.nav-section-label {
311 font-size: 11px;
312 font-weight: 700;
313 text-transform: uppercase;
314 letter-spacing: 0.08em;
315 color: var(--muted);
316 padding: 0 10px 6px;
317}
318
319/* Section header with a right-aligned action (the Files refresh). */
320.nav-section-head {
321 display: flex;
322 align-items: center;
323 justify-content: space-between;
324 gap: 6px;
325 margin-bottom: 4px;
326}
327
328.nav-section-head .nav-section-label {
329 flex: 1;
330 padding-bottom: 2px;
331}
332
333.nav-section-refresh {
334 color: var(--muted);
335 background: none;
336 border-color: transparent;
337 padding: 3px 5px;
338}
339
340.nav-section-refresh:hover {
341 color: var(--text);
342 border-color: var(--border);
343}
344
345.nav-tab {
346 display: flex;
347 align-items: center;
348 justify-content: flex-start;
349 gap: 10px;
350 width: 100%;
351 margin-bottom: 2px;
352 padding: 8px 10px;
353 text-align: left;
354 background: none;
355 border: none;
356 color: var(--muted);
357 font-size: 14px;
358}
359
360.nav-tab:hover {
361 background: var(--bg);
362 color: var(--text);
363}
364
365.nav-tab.active {
366 background: var(--accent);
367 border-color: var(--accent);
368 color: #fff;
369}
370
371.ic-tab {
372 width: 18px;
373 height: 18px;
374 flex: none;
375}
376
377.nav-tab.active .icon {
378 color: #fff;
379}
380
381.nav-tab-name {
382 flex: 1;
383 min-width: 0;
384 overflow: hidden;
385 text-overflow: ellipsis;
386 white-space: nowrap;
387}
388
389.nav-tab-note {
390 flex: none;
391 font-size: 10px;
392 font-weight: 700;
393 padding: 1px 5px;
394 background: var(--bg);
395 border: 1px solid var(--border);
396 color: var(--muted);
397}
398
399.nav-tab.active .nav-tab-note {
400 background: rgb(255 255 255 / 18%);
401 border-color: rgb(255 255 255 / 30%);
402 color: #fff;
403}
404
405.nav-backdrop {
406 display: none;
407}
408
409/* Sidebar footer: theme toggle, log out, and the project version.
410 Sits at the bottom of the sidebar, below the manage section. */
411.sidebar-footer {
412 flex: none;
413 border-top: 1px solid var(--border);
414 padding: 8px;
415}
416
417.sidebar-footer .nav-tab {
418 margin-bottom: 0;
419}
420
421.sidebar-action.logout {
422 color: var(--danger);
423}
424
425.sidebar-action.logout:hover {
426 color: var(--danger);
427}
428
429.sidebar-version {
430 margin-top: 8px;
431 padding: 0 10px;
432 font-size: 11.5px;
433 color: var(--muted);
434 white-space: nowrap;
435 overflow: hidden;
436 text-overflow: ellipsis;
437}
438
439.badge {
440 font-size: 11px;
441 padding: 2px 8px;
442 background: var(--bg);
443 border: 1px solid var(--border);
444 color: var(--muted);
445}
446
447.content {
448 flex: 1;
449 min-width: 0;
450 min-height: 0;
451 display: flex;
452 flex-direction: column;
453 padding: 20px;
454}
455
456/* While a file is open the app is a fixed-height frame: the file view
457 * (editor, image, …) scrolls inside, the page itself never grows. */
458.layout.file-mode {
459 height: 100vh;
460 overflow: hidden;
461}
462
463.layout.file-mode .body-row {
464 min-height: 0;
465}
466
467/* Narrow screens: the sidebar becomes an off-canvas drawer that only
468 covers the content, below the (always visible) topbar. */
469@media (max-width: 860px) {
470 .sidebar {
471 position: fixed;
472 top: var(--topbar-h);
473 bottom: 0;
474 left: 0;
475 right: auto;
476 height: auto;
477 z-index: 120;
478 transform: translateX(-100%);
479 transition: transform 0.15s ease;
480 }
481
482 .sidebar.open {
483 transform: translateX(0);
484 box-shadow: 0 0 48px rgb(0 0 0 / 35%);
485 }
486
487 .nav-backdrop {
488 display: block;
489 position: fixed;
490 top: var(--topbar-h);
491 bottom: 0;
492 left: 0;
493 right: 0;
494 z-index: 110;
495 background: rgb(0 0 0 / 40%);
496 }
497
498 .icon-btn.nav-toggle {
499 display: inline-flex;
500 }
501
502 .content {
503 padding: 14px;
504 }
505}
506
507/* ---- file browser ---- */
508
509.browser {
510 width: 100%;
511 max-width: 1200px;
512 margin: 0 auto;
513 flex: 1;
514 display: flex;
515 flex-direction: column;
516 min-height: 0;
517}
518
519.icon {
520 width: 20px;
521 height: 20px;
522 display: inline-block;
523 vertical-align: middle;
524}
525
526.ic-folder {
527 color: var(--accent);
528}
529
530.ic-muted {
531 color: var(--muted);
532}
533
534.crumbs {
535 display: flex;
536 align-items: center;
537 gap: 2px;
538 padding: 6px 0 12px;
539 font-size: 15px;
540 flex-wrap: wrap;
541}
542
543.crumb {
544 cursor: pointer;
545 color: var(--muted);
546 padding: 3px 6px;
547}
548
549.crumb:hover {
550 color: var(--text);
551 background: var(--panel);
552}
553
554.crumb.current {
555 color: var(--text);
556 font-weight: 600;
557 cursor: default;
558 background: none;
559}
560
561.crumb-sep {
562 color: var(--muted);
563 padding: 0 1px;
564}
565
566.toolbar {
567 display: flex;
568 align-items: center;
569 justify-content: space-between;
570 gap: 6px;
571 padding-bottom: 12px;
572}
573
574.toolbar-right {
575 display: flex;
576 gap: 6px;
577}
578
579.icon-btn {
580 padding: 7px 9px;
581 border: 1px solid var(--border);
582 background: var(--panel);
583 color: var(--muted);
584 display: inline-flex;
585 align-items: center;
586}
587
588.icon-btn:hover {
589 border-color: var(--muted);
590}
591
592.icon-btn.active {
593 background: var(--accent);
594 border-color: var(--accent);
595 color: #fff;
596}
597
598.ic-btn {
599 width: 18px;
600 height: 18px;
601 color: inherit;
602}
603
604.entries-area {
605 flex: 1;
606 min-height: 240px;
607}
608
609.center-note {
610 text-align: center;
611 padding: 48px 0;
612}
613
614/* Server-side listing cap notice, under the paging footer. */
615.list-note {
616 padding: 8px 14px 0;
617 font-size: 12px;
618}
619
620.error-card {
621 display: flex;
622 align-items: center;
623 justify-content: space-between;
624 gap: 16px;
625 color: var(--danger);
626 font-size: 14px;
627}
628
629/* root tiles were replaced by the sidebar's folder tabs */
630
631/* grid view */
632
633.entries-grid {
634 display: grid;
635 grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
636 gap: 10px;
637}
638
639.tile {
640 background: var(--panel);
641 border: 1px solid var(--border);
642 padding: 16px 10px 12px;
643 text-align: center;
644 cursor: pointer;
645 user-select: none;
646}
647
648.tile:hover {
649 border-color: var(--muted);
650}
651
652.tile-icon {
653 width: 42px;
654 height: 42px;
655 margin: 0 auto 10px;
656 display: block;
657}
658
659.tile-name {
660 font-size: 13px;
661 line-height: 1.3;
662 word-break: break-word;
663 /* Uniform tile height: the name area always takes two lines and
664 never overflows (the full name is in the title tooltip). */
665 min-height: calc(2 * 1.3em);
666 display: -webkit-box;
667 -webkit-line-clamp: 2;
668 -webkit-box-orient: vertical;
669 overflow: hidden;
670}
671
672/* list view */
673
674.entries-list {
675 background: var(--panel);
676 border: 1px solid var(--border);
677 overflow: hidden;
678}
679
680.row {
681 display: grid;
682 grid-template-columns: 28px minmax(0, 1fr) 90px 150px;
683 gap: 12px;
684 align-items: center;
685 padding: 9px 14px;
686 border-bottom: 1px solid var(--border);
687 cursor: pointer;
688 font-size: 14px;
689 user-select: none;
690}
691
692.row:last-child {
693 border-bottom: none;
694}
695
696.row:hover {
697 background: var(--bg);
698}
699
700.row-icon {
701 width: 20px;
702 height: 20px;
703}
704
705.row-name {
706 overflow: hidden;
707 text-overflow: ellipsis;
708 white-space: nowrap;
709}
710
711.row-size,
712.row-date {
713 font-size: 13px;
714 text-align: right;
715}
716
717@media (max-width: 640px) {
718 .row {
719 grid-template-columns: 28px minmax(0, 1fr) 90px;
720 }
721
722 .row-date {
723 display: none;
724 }
725}
726
727/* context menu */
728
729.ctx-menu {
730 position: fixed;
731 z-index: 100;
732 min-width: 190px;
733 background: var(--panel);
734 border: 1px solid var(--border);
735 padding: 5px;
736 box-shadow: 0 8px 24px rgb(0 0 0 / 18%);
737}
738
739.ctx-item {
740 display: flex;
741 align-items: center;
742 gap: 10px;
743 padding: 8px 12px;
744 font-size: 14px;
745 cursor: pointer;
746}
747
748.ic-ctx {
749 width: 18px;
750 height: 18px;
751 flex: none;
752}
753
754.ctx-item:hover {
755 background: var(--bg);
756}
757
758.ctx-item.disabled {
759 opacity: 0.45;
760 cursor: default;
761}
762
763.ctx-item.disabled:hover {
764 background: none;
765}
766
767/* toolbar selection actions (top right) */
768
769.sel-actions {
770 display: flex;
771 align-items: center;
772 gap: 6px;
773 position: relative;
774}
775
776.sel-actions .icon-btn:disabled {
777 opacity: 0.45;
778 cursor: default;
779}
780
781.sel-actions .icon-btn:disabled:hover {
782 border-color: var(--border);
783 color: var(--muted);
784}
785
786.sel-more-wrap {
787 position: relative;
788}
789
790.sel-more-menu {
791 position: absolute;
792 right: 0;
793 top: calc(100% + 6px);
794 z-index: 100;
795 min-width: 190px;
796 background: var(--panel);
797 border: 1px solid var(--border);
798 padding: 5px;
799 box-shadow: 0 8px 24px rgb(0 0 0 / 18%);
800}
801
802.sel-more-menu.hidden {
803 display: none;
804}
805
806/* selection actions in the top bar */
807
808.topbar .sel-actions {
809 min-height: 0;
810}
811
812.topbar .sel-actions .icon-btn {
813 padding: 5px 7px;
814}
815
816/* selection highlight in the grid and list */
817
818.tile.selected {
819 border-color: var(--accent);
820 background: color-mix(in srgb, var(--accent) 12%, var(--panel));
821}
822
823.row.selected {
824 background: color-mix(in srgb, var(--accent) 12%, var(--panel));
825 box-shadow: inset 2px 0 0 var(--accent);
826}
827
828/* settings tabs (profile / server) */
829
830.settings-tabs {
831 display: flex;
832 gap: 8px;
833}
834
835.settings-tab-btn {
836 padding: 7px 14px;
837 border: 1px solid var(--border);
838 background: var(--panel);
839 color: var(--muted);
840 font-size: 13px;
841 font-weight: 600;
842}
843
844.settings-tab-btn:hover {
845 border-color: var(--muted);
846 color: var(--text);
847}
848
849.settings-tab-btn.active {
850 border-color: var(--accent);
851 color: var(--accent);
852 background: color-mix(in srgb, var(--accent) 10%, var(--panel));
853}
854
855/* toast */
856
857.toast {
858 position: fixed;
859 bottom: 20px;
860 right: 20px;
861 z-index: 200;
862 background: var(--panel);
863 color: var(--text);
864 border: 1px solid var(--border);
865 padding: 11px 16px;
866 font-size: 14px;
867 box-shadow: 0 8px 24px rgb(0 0 0 / 18%);
868 max-width: 320px;
869}
870
871.toast-error {
872 background: color-mix(in srgb, var(--danger) 12%, var(--panel));
873 border-color: var(--danger-border);
874 color: var(--danger);
875}
876
877
878/* ---- modals ---- */
879
880/* The shell is a native <dialog> opened with showModal(): the browser puts
881 it in the top layer and paints ::backdrop, so there is no overlay element
882 to position and no z-index to keep in order. The reset below strips the
883 UA's own box so the .modal card inside is the only thing that shows. */
884.modal-host {
885 padding: 0;
886 border: none;
887 background: none;
888 /* The UA caps an open dialog's size; the card sets its own. */
889 max-width: none;
890 max-height: none;
891 /* Centre it in the inset-0 box, as the old flex overlay did. */
892 margin: auto;
893 overflow: visible;
894}
895
896.modal-host::backdrop {
897 background: rgb(0 0 0 / 45%);
898}
899
900.modal {
901 width: 440px;
902 max-width: calc(100vw - 32px);
903 padding: 20px;
904 background: var(--panel);
905 border: 1px solid var(--border);
906 box-shadow: 0 12px 44px rgb(0 0 0 / 35%);
907}
908
909.modal.picker {
910 width: 640px;
911}
912
913.modal-title {
914 margin: 0 0 12px;
915 font-size: 16px;
916}
917
918.modal-label {
919 display: block;
920 font-size: 13px;
921 color: var(--muted);
922 margin-bottom: 6px;
923}
924
925.modal .input {
926 width: 100%;
927 box-sizing: border-box;
928 margin-bottom: 16px;
929}
930
931.modal-label.error,
932.dialog-error {
933 color: var(--danger);
934 font-size: 13px;
935}
936
937.dialog-error {
938 margin-top: 8px;
939}
940
941.modal-message {
942 white-space: pre-line;
943 font-size: 14px;
944 margin: 0 0 8px;
945}
946
947.modal-actions {
948 display: flex;
949 justify-content: flex-end;
950 gap: 8px;
951 margin-top: 16px;
952}
953
954.btn-danger {
955 background: var(--danger);
956 /* A visible border (one step away from the fill, per theme) so the
957 button's edge reads the same as on neutral buttons. */
958 border-color: var(--danger-border);
959 color: #fff;
960}
961
962.btn-danger:hover {
963 background: color-mix(in srgb, var(--danger) 85%, black);
964}
965
966.btn:disabled {
967 opacity: 0.5;
968 cursor: not-allowed;
969}
970
971.conflict-list {
972 max-height: 200px;
973 overflow-y: auto;
974 margin: 8px 0;
975 padding-left: 20px;
976 font-size: 13px;
977}
978
979/* Folder picker: roots on the left, the selected root's tree on the right. */
980
981.picker-body {
982 display: grid;
983 grid-template-columns: 180px minmax(0, 1fr);
984 border: 1px solid var(--border);
985 height: 320px;
986}
987
988.picker-roots {
989 display: flex;
990 flex-direction: column;
991 gap: 2px;
992 padding: 6px;
993 border-right: 1px solid var(--border);
994 background: var(--bg);
995 min-height: 0;
996 overflow-y: auto;
997}
998
999.picker-root {
1000 display: flex;
1001 align-items: center;
1002 justify-content: flex-start;
1003 gap: 8px;
1004 padding: 7px 8px;
1005 border: none;
1006 background: transparent;
1007 color: var(--text);
1008 font: inherit;
1009 font-size: 13px;
1010 text-align: left;
1011 cursor: pointer;
1012 min-width: 0;
1013}
1014
1015.picker-root:hover {
1016 background: var(--panel);
1017}
1018
1019.picker-root.active {
1020 background: var(--accent);
1021 color: #fff;
1022}
1023
1024.picker-root.ro .picker-root-name {
1025 opacity: 0.6;
1026 text-decoration: line-through dotted;
1027}
1028
1029.picker-root-ic {
1030 width: 16px;
1031 height: 16px;
1032 flex: none;
1033}
1034
1035.picker-root-name {
1036 overflow: hidden;
1037 text-overflow: ellipsis;
1038 white-space: nowrap;
1039}
1040
1041.picker-main {
1042 display: flex;
1043 flex-direction: column;
1044 min-width: 0;
1045 /* Grid items default to min-height:auto, which would let a long
1046 folder list stretch the dialog instead of scrolling. */
1047 min-height: 0;
1048}
1049
1050.picker-crumbs {
1051 padding: 8px 10px;
1052 font-size: 13px;
1053 border-bottom: 1px solid var(--border);
1054 flex: none;
1055}
1056
1057.picker-entries {
1058 flex: 1;
1059 min-height: 0;
1060 overflow-y: auto;
1061}
1062
1063.picker-row {
1064 display: flex;
1065 align-items: center;
1066 gap: 10px;
1067 padding: 8px 12px;
1068 cursor: pointer;
1069 font-size: 14px;
1070 user-select: none;
1071}
1072
1073.picker-row:hover {
1074 background: var(--bg);
1075}
1076
1077.picker-row .row-name {
1078 flex: 1;
1079}
1080
1081/* A right-pointing chevron drawn with borders (no icon needed). */
1082.picker-chev {
1083 width: 7px;
1084 height: 7px;
1085 border-right: 1.5px solid var(--muted);
1086 border-bottom: 1.5px solid var(--muted);
1087 transform: rotate(-45deg);
1088 flex: none;
1089}
1090
1091.picker-empty {
1092 height: 100%;
1093 display: flex;
1094 flex-direction: column;
1095 align-items: center;
1096 justify-content: center;
1097 gap: 8px;
1098 font-size: 13px;
1099}
1100
1101.picker-empty-ic {
1102 width: 32px;
1103 height: 32px;
1104 opacity: 0.5;
1105}
1106
1107.picker-root.active .picker-root-ic {
1108 color: #fff;
1109}
1110
1111@media (max-width: 640px) {
1112 .picker-body {
1113 grid-template-columns: 1fr;
1114 grid-template-rows: auto minmax(0, 1fr);
1115 height: 380px;
1116 }
1117
1118 .picker-roots {
1119 flex-direction: row;
1120 flex-wrap: wrap;
1121 border-right: none;
1122 border-bottom: 1px solid var(--border);
1123 }
1124}
1125
1126/* ---------------------------------------------------------------------------
1127 * Full-page file view (preview / editor / "no preview"). The top bar carries
1128 * the title + actions; the content area below is edge to edge.
1129 * ------------------------------------------------------------------------- */
1130.content.file-open {
1131 padding: 0;
1132 overflow: hidden;
1133}
1134
1135/* The browser stays mounted (state, fetch callback) but hidden. */
1136.content.file-open .browser {
1137 display: none;
1138}
1139
1140.file-view {
1141 flex: 1;
1142 min-height: 0;
1143 display: flex;
1144 flex-direction: column;
1145}
1146
1147.file-title {
1148 display: flex;
1149 align-items: center;
1150 gap: 8px;
1151 min-width: 0;
1152}
1153
1154.file-title-icon {
1155 width: 18px;
1156 height: 18px;
1157 flex: none;
1158 color: var(--muted);
1159}
1160
1161.file-title-name {
1162 font-weight: 600;
1163 font-size: 14px;
1164 white-space: nowrap;
1165 overflow: hidden;
1166 text-overflow: ellipsis;
1167}
1168
1169.file-actions {
1170 display: flex;
1171 align-items: center;
1172 gap: 10px;
1173 flex: none;
1174}
1175
1176.file-close,
1177.file-download {
1178 border: none;
1179 background: transparent;
1180 color: var(--muted);
1181 padding: 6px 8px;
1182}
1183
1184.file-close:hover,
1185.file-download:hover {
1186 color: var(--text);
1187 background: var(--bg);
1188}
1189.preview-body {
1190 flex: 1;
1191 min-height: 0;
1192 overflow: auto;
1193 display: flex;
1194 background: var(--bg);
1195}
1196.preview-img {
1197 max-width: 100%;
1198 max-height: 100%;
1199 display: block;
1200 margin: auto;
1201}
1202.preview-pdf {
1203 width: 100%;
1204 height: 100%;
1205 border: none;
1206 background: #fff;
1207}
1208.preview-video {
1209 width: 100%;
1210 max-height: 100%;
1211 background: #000;
1212}
1213.preview-audio {
1214 display: flex;
1215 align-items: center;
1216 justify-content: center;
1217 width: 100%;
1218 padding: 24px;
1219}
1220.preview-audio audio {
1221 width: 100%;
1222 max-width: 480px;
1223}
1224
1225/* CodeMirror (text editor) */
1226.cm-container {
1227 height: 100%;
1228}
1229.cm-container .cm-editor {
1230 height: 100%;
1231}
1232/* Load/save failure: dims the editor and shows the message in a card
1233 * (the top-bar Save button stays reachable to retry). */
1234.cm-error {
1235 position: absolute;
1236 inset: 0;
1237 z-index: 5;
1238 display: flex;
1239 align-items: center;
1240 justify-content: center;
1241 padding: 24px;
1242 background: rgb(0 0 0 / 45%);
1243}
1244
1245.cm-error-card {
1246 position: relative;
1247 max-width: 440px;
1248 min-width: 200px;
1249 background: var(--panel);
1250 border: 1px solid var(--border);
1251 box-shadow: 0 12px 44px rgb(0 0 0 / 35%);
1252}
1253
1254.cm-error-close {
1255 position: absolute;
1256 top: 7px;
1257 right: 7px;
1258 display: inline-flex;
1259 align-items: center;
1260 justify-content: center;
1261 border: none;
1262 background: transparent;
1263 color: var(--muted);
1264 padding: 3px;
1265}
1266
1267.cm-error-close:hover {
1268 color: var(--text);
1269 background: var(--bg);
1270}
1271
1272.cm-error-close .ic-btn {
1273 width: 16px;
1274 height: 16px;
1275}
1276
1277.cm-error-text {
1278 padding: 16px 40px 16px 20px;
1279 font-size: 14px;
1280 text-align: center;
1281 overflow-wrap: anywhere;
1282}
1283
1284/* ---------------------------------------------------------------------------
1285 * Text editor (full page; title/save/close live in the top bar)
1286 * ------------------------------------------------------------------------- */
1287.file-editor {
1288 flex: 1;
1289 min-height: 0;
1290 display: flex;
1291 position: relative;
1292 background: var(--bg);
1293}
1294.file-editor .cm-container {
1295 width: 100%;
1296 height: 100%;
1297}
1298/* "No preview" fallback (binaries, archives). */
1299.file-nopreview {
1300 flex: 1;
1301 display: flex;
1302 align-items: center;
1303 justify-content: center;
1304}
1305.file-nopreview .btn-primary {
1306 width: auto;
1307 margin-top: 14px;
1308}
1309/* Conflict / discard dialogs render above the file view. */
1310.editor-sub-overlay {
1311 z-index: 101;
1312 background: rgb(0 0 0 / 25%);
1313}
1314
1315/* ---------------------------------------------------------------------------
1316 * Download format dialog
1317 * ------------------------------------------------------------------------- */
1318.dl-formats {
1319 display: flex;
1320 flex-direction: column;
1321 gap: 8px;
1322 margin-bottom: 8px;
1323}
1324.dl-fmt {
1325 justify-content: flex-start;
1326}
1327
1328/* ---------------------------------------------------------------------------
1329 * Item info dialog
1330 * ------------------------------------------------------------------------- */
1331.info-list {
1332 margin: 8px 0 16px;
1333 display: grid;
1334 grid-template-columns: 90px 1fr;
1335 row-gap: 8px;
1336 column-gap: 12px;
1337}
1338.info-list dt {
1339 color: var(--muted);
1340}
1341.info-list dd {
1342 margin: 0;
1343 word-break: break-word;
1344}
1345
1346/* ---------------------------------------------------------------------------
1347 Shares (milestone 6)
1348 --------------------------------------------------------------------------- */
1349
1350.share-modal {
1351 width: 480px;
1352}
1353
1354.share-link-row {
1355 display: flex;
1356 gap: 8px;
1357 margin: 12px 0;
1358}
1359
1360.share-link-input {
1361 flex: 1;
1362 font-family: ui-monospace, monospace;
1363 font-size: 12.5px;
1364 padding: 8px 10px;
1365 border: 1px solid var(--border);
1366 background: var(--bg);
1367 color: var(--text);
1368 min-width: 0;
1369}
1370
1371.share-check {
1372 display: flex;
1373 align-items: center;
1374 gap: 8px;
1375 margin: 4px 0 14px;
1376 font-size: 14px;
1377}
1378
1379.share-check input {
1380 width: 16px;
1381 height: 16px;
1382}
1383
1384.share-expiry-row {
1385 display: flex;
1386 align-items: center;
1387 gap: 10px;
1388 margin: 0 0 10px;
1389}
1390
1391.share-expiry-row label {
1392 font-size: 13px;
1393 color: var(--muted);
1394 min-width: 52px;
1395}
1396
1397.share-expiry-row select,
1398.share-expiry-row input {
1399 flex: 1;
1400 padding: 8px 10px;
1401 border: 1px solid var(--border);
1402 background: var(--panel);
1403 color: var(--text);
1404 font: inherit;
1405}
1406
1407.share-expiry-note {
1408 margin: 4px 0 0;
1409 font-size: 12.5px;
1410}
1411
1412.btn-sm {
1413 padding: 5px 10px;
1414 font-size: 12.5px;
1415}
1416
1417.icon-btn-sm {
1418 padding: 4px 6px;
1419}
1420
1421/* "Your shares" manage view */
1422
1423.shares-view {
1424 width: 100%;
1425 max-width: 960px;
1426 margin: 0 auto;
1427}
1428
1429.view-header {
1430 margin-bottom: 16px;
1431}
1432
1433.view-header .admin-section-title {
1434 margin-bottom: 0;
1435}
1436
1437.view-hint {
1438 margin: 4px 0 0;
1439 font-size: 13px;
1440 max-width: 64ch;
1441}
1442
1443.share-list {
1444 display: flex;
1445 flex-direction: column;
1446 gap: 10px;
1447}
1448
1449.share-item {
1450 display: flex;
1451 align-items: center;
1452 justify-content: space-between;
1453 gap: 12px;
1454 padding: 10px 12px;
1455 border: 1px solid var(--border);
1456 background: var(--panel);
1457}
1458
1459.share-item-main {
1460 min-width: 0;
1461}
1462
1463.share-item-name {
1464 display: flex;
1465 align-items: center;
1466 gap: 8px;
1467 font-weight: 600;
1468 font-size: 14px;
1469 overflow: hidden;
1470 text-overflow: ellipsis;
1471 white-space: nowrap;
1472}
1473
1474.ic-row {
1475 width: 18px;
1476 height: 18px;
1477 flex: none;
1478}
1479
1480.share-item-meta {
1481 font-size: 12px;
1482 margin-top: 2px;
1483 overflow: hidden;
1484 text-overflow: ellipsis;
1485 white-space: nowrap;
1486}
1487
1488.share-item-actions {
1489 display: flex;
1490 gap: 6px;
1491 flex-shrink: 0;
1492}
1493
1494/* ------------------------------------------------------------------ */
1495/* Admin (milestone 7) */
1496/* ------------------------------------------------------------------ */
1497
1498.admin-view {
1499 display: flex;
1500 flex-direction: column;
1501 gap: 16px;
1502 width: 100%;
1503 max-width: 960px;
1504 margin: 0 auto;
1505}
1506
1507.admin-section-title {
1508 margin: 0 0 14px;
1509 font-size: 15px;
1510}
1511
1512.users-header {
1513 display: flex;
1514 align-items: center;
1515 justify-content: space-between;
1516 margin-bottom: 4px;
1517}
1518
1519.users-header .admin-section-title {
1520 margin-bottom: 0;
1521}
1522
1523.users-header .btn-primary {
1524 width: auto;
1525}
1526
1527.user-list {
1528 display: flex;
1529 flex-direction: column;
1530 gap: 10px;
1531}
1532
1533.user-row {
1534 display: flex;
1535 align-items: center;
1536 justify-content: space-between;
1537 gap: 12px;
1538 padding: 12px 14px;
1539 border: 1px solid var(--border);
1540}
1541
1542.user-row-main {
1543 min-width: 0;
1544}
1545
1546.user-row-name {
1547 display: flex;
1548 align-items: center;
1549 gap: 6px;
1550 font-weight: 600;
1551 font-size: 14px;
1552 flex-wrap: wrap;
1553}
1554
1555.ic-admin {
1556 width: 16px;
1557 height: 16px;
1558 flex: none;
1559}
1560
1561.user-row-actions {
1562 display: flex;
1563 gap: 6px;
1564 flex-shrink: 0;
1565}
1566
1567.badge-off {
1568 background: color-mix(in srgb, var(--danger) 15%, var(--panel));
1569 border-color: var(--danger);
1570 color: var(--danger);
1571}
1572
1573.setting-row {
1574 display: flex;
1575 align-items: center;
1576 gap: 10px;
1577 padding: 14px;
1578 border: 1px solid var(--border);
1579 cursor: pointer;
1580}
1581
1582.setting-row input {
1583 margin-left: auto;
1584}
1585
1586.setting-label {
1587 display: block;
1588 font-weight: 600;
1589 font-size: 14px;
1590}
1591
1592.setting-desc {
1593 display: block;
1594 font-size: 12px;
1595 color: var(--muted);
1596 margin-top: 2px;
1597}
1598
1599/* Setting row whose control is a select, pushed to the right. */
1600.setting-row-select {
1601 cursor: default;
1602}
1603
1604.setting-row-select > span {
1605 flex: 1;
1606}
1607
1608.setting-row-select select {
1609 appearance: none;
1610 margin-left: auto;
1611 padding: 10px 42px 10px 12px;
1612 border: 1px solid var(--border);
1613 background-color: var(--panel);
1614 background-image: var(--select-arrow);
1615 background-repeat: no-repeat;
1616 background-position: right 12px center;
1617 background-size: 14px 14px;
1618 color: var(--text);
1619 font: inherit;
1620 max-width: 190px;
1621}
1622
1623/* User create/edit form */
1624
1625.user-form {
1626 width: 520px;
1627}
1628
1629.field-input {
1630 width: 100%;
1631 box-sizing: border-box;
1632}
1633
1634.field-hint {
1635 font-size: 12px;
1636 margin: -2px 0 8px;
1637}
1638
1639.check-row {
1640 display: flex;
1641 align-items: center;
1642 gap: 8px;
1643 font-size: 14px;
1644 margin-bottom: 12px;
1645 cursor: pointer;
1646}
1647
1648.form-error {
1649 color: var(--danger);
1650 font-size: 13px;
1651 margin: 4px 0 8px;
1652}
1653
1654.roots-editor {
1655 display: flex;
1656 flex-direction: column;
1657 gap: 6px;
1658}
1659
1660.root-draft {
1661 display: flex;
1662 align-items: center;
1663 gap: 8px;
1664}
1665
1666.root-draft-path {
1667 flex: 1;
1668 font-size: 13px;
1669 overflow: hidden;
1670 text-overflow: ellipsis;
1671 white-space: nowrap;
1672}
1673
1674.root-draft-mode {
1675 width: auto;
1676 padding: 6px 8px;
1677}
1678
1679.root-add {
1680 align-self: flex-start;
1681 margin-top: 4px;
1682}
1683
1684/* ------------------------------------------------------------------ */
1685/* Empty state + keyboard focus (milestone 8) */
1686/* ------------------------------------------------------------------ */
1687
1688.empty-state {
1689 display: flex;
1690 flex-direction: column;
1691 align-items: center;
1692 justify-content: center;
1693 gap: 8px;
1694 padding: 64px 20px;
1695 text-align: center;
1696}
1697
1698.empty-glyph {
1699 width: 52px;
1700 height: 52px;
1701}
1702
1703.empty-state h3 {
1704 margin: 0;
1705 font-size: 16px;
1706}
1707
1708/* Visible keyboard focus on selectable file/folder entries. The ring is
1709 inset (negative offset) so the scroll container never clips it. */
1710.tile:focus-visible,
1711.row:focus-visible {
1712 outline: 2px solid var(--accent);
1713 outline-offset: -2px;
1714}
1715
1716/* ------------------------------------------------------------------ */
1717/* Search view (#/search) */
1718/* ------------------------------------------------------------------ */
1719
1720.search-view {
1721 display: flex;
1722 flex-direction: column;
1723 gap: 14px;
1724}
1725
1726/* Query bar ------------------------------------------------------ */
1727
1728.query-bar {
1729 display: flex;
1730 align-items: stretch;
1731 gap: 8px;
1732}
1733
1734.query-input {
1735 flex: 1;
1736 display: flex;
1737 align-items: center;
1738 gap: 8px;
1739 background: var(--panel);
1740 border: 1px solid var(--border);
1741 padding: 0 10px;
1742 min-width: 0;
1743}
1744
1745.query-input .qi-icon {
1746 width: 18px;
1747 height: 18px;
1748 color: var(--muted);
1749 flex: none;
1750}
1751
1752.query-input input {
1753 flex: 1;
1754 min-width: 0;
1755 border: none;
1756 outline: none;
1757 background: transparent;
1758 color: var(--text);
1759 font: inherit;
1760 font-size: 14px;
1761 height: 38px;
1762 padding: 0;
1763}
1764
1765.query-input input::placeholder {
1766 color: var(--muted);
1767}
1768
1769/* Segmented Name / Content / Both control */
1770
1771.seg {
1772 display: flex;
1773 border: 1px solid var(--border);
1774 background: var(--panel);
1775}
1776
1777.seg button {
1778 appearance: none;
1779 border: none;
1780 border-right: 1px solid var(--border);
1781 background: transparent;
1782 color: var(--muted);
1783 font: inherit;
1784 font-size: 13px;
1785 padding: 0 14px;
1786 cursor: pointer;
1787}
1788
1789.seg button:last-child {
1790 border-right: none;
1791}
1792
1793.seg button:hover {
1794 background: var(--bg);
1795}
1796
1797.seg button.on {
1798 background: var(--accent);
1799 color: #fff;
1800}
1801
1802/* Start folder --------------------------------------------------- */
1803
1804/* The folder a search starts in; opens the folder picker. */
1805.folder-pick {
1806 flex: none;
1807 display: flex;
1808 align-items: center;
1809 gap: 8px;
1810 max-width: 260px;
1811 border: 1px solid var(--border);
1812 background: var(--panel);
1813 color: var(--text);
1814 font: inherit;
1815 font-size: 13px;
1816 padding: 0 10px;
1817 cursor: pointer;
1818}
1819
1820.folder-pick:hover {
1821 border-color: var(--muted);
1822}
1823
1824.folder-pick .fp-icon {
1825 width: 16px;
1826 height: 16px;
1827 color: var(--muted);
1828 flex: none;
1829}
1830
1831.folder-pick .fp-path {
1832 overflow: hidden;
1833 text-overflow: ellipsis;
1834 white-space: nowrap;
1835}
1836
1837.ms {
1838 position: relative;
1839 display: flex;
1840}
1841
1842.ms-btn {
1843 display: flex;
1844 align-items: center;
1845 gap: 6px;
1846 border: 1px solid var(--border);
1847 background: var(--panel);
1848 color: var(--text);
1849 font: inherit;
1850 font-size: 13px;
1851 padding: 0 10px;
1852 cursor: pointer;
1853 max-width: 180px;
1854}
1855
1856.ms-btn:hover {
1857 background: var(--bg);
1858}
1859
1860.ms-btn > span {
1861 overflow: hidden;
1862 text-overflow: ellipsis;
1863 white-space: nowrap;
1864}
1865
1866/* Square caret drawn with borders (the icon set has no chevron). */
1867.ms-caret {
1868 flex: none;
1869 width: 8px;
1870 height: 8px;
1871 border-right: 2px solid var(--muted);
1872 border-bottom: 2px solid var(--muted);
1873 transform: rotate(45deg) translate(-1px, -1px);
1874}
1875
1876.ms-backdrop {
1877 position: fixed;
1878 inset: 0;
1879 z-index: 40;
1880}
1881
1882.ms-drop {
1883 position: absolute;
1884 right: 0;
1885 top: calc(100% + 4px);
1886 z-index: 41;
1887 min-width: 200px;
1888 max-height: 280px;
1889 overflow: auto;
1890 background: var(--panel);
1891 border: 1px solid var(--border);
1892 padding: 4px 0;
1893}
1894
1895.ms-opt {
1896 display: flex;
1897 align-items: center;
1898 gap: 8px;
1899 padding: 7px 12px;
1900 font-size: 14px;
1901 cursor: pointer;
1902 user-select: none;
1903}
1904
1905.ms-opt:hover {
1906 background: var(--bg);
1907}
1908
1909.ms-opt span {
1910 overflow: hidden;
1911 text-overflow: ellipsis;
1912 white-space: nowrap;
1913}
1914
1915/* Run / stop ------------------------------------------------------- */
1916
1917.btn-run {
1918 border: 1px solid var(--accent-border);
1919 background: var(--accent);
1920 color: #fff;
1921 font: inherit;
1922 font-size: 13px;
1923 font-weight: 600;
1924 padding: 0 18px;
1925 cursor: pointer;
1926}
1927
1928.btn-run:hover {
1929 background: var(--accent-hover);
1930}
1931
1932.btn-stop {
1933 display: flex;
1934 align-items: center;
1935 gap: 6px;
1936 border: 1px solid var(--danger-border);
1937 background: var(--danger);
1938 color: #fff;
1939 font: inherit;
1940 font-size: 13px;
1941 font-weight: 600;
1942 padding: 0 14px;
1943 cursor: pointer;
1944}
1945
1946.btn-stop:hover {
1947 opacity: 0.9;
1948}
1949
1950.btn-stop .ic-stop {
1951 width: 14px;
1952 height: 14px;
1953}
1954
1955/* Status line ------------------------------------------------------ */
1956
1957.status-line {
1958 display: flex;
1959 align-items: center;
1960 gap: 8px;
1961 font-size: 13px;
1962 color: var(--muted);
1963}
1964
1965.status-line .dot {
1966 width: 8px;
1967 height: 8px;
1968 background: var(--accent);
1969 animation: search-pulse 1s ease-in-out infinite;
1970}
1971
1972@keyframes search-pulse {
1973 0%,
1974 100% {
1975 opacity: 1;
1976 }
1977 50% {
1978 opacity: 0.3;
1979 }
1980}
1981
1982.status-line .skip {
1983 opacity: 0.75;
1984}
1985
1986/* Group labels ----------------------------------------------------- */
1987
1988.group-label {
1989 display: flex;
1990 align-items: center;
1991 gap: 8px;
1992 font-size: 12px;
1993 font-weight: 600;
1994 letter-spacing: 0.04em;
1995 text-transform: uppercase;
1996 color: var(--muted);
1997}
1998
1999/* Result group: a `display:flex` (or `none`, from the inline style) flex
2000 item of `.search-view` that re-establishes the column layout for its
2001 label/list/more-row children. */
2002.result-group {
2003 flex-direction: column;
2004 gap: 14px;
2005}
2006
2007.group-label .gl-icon {
2008 width: 15px;
2009 height: 15px;
2010}
2011
2012.group-label .n {
2013 font-weight: 400;
2014 text-transform: none;
2015 letter-spacing: 0;
2016}
2017
2018.group-label .grow {
2019 flex: 1;
2020}
2021
2022.collapse-all {
2023 appearance: none;
2024 border: 1px solid var(--border);
2025 background: transparent;
2026 color: var(--muted);
2027 font: inherit;
2028 font-size: 12px;
2029 text-transform: none;
2030 letter-spacing: 0;
2031 padding: 3px 10px;
2032 cursor: pointer;
2033}
2034
2035.collapse-all:hover {
2036 background: var(--bg);
2037 color: var(--text);
2038}
2039
2040/* Name-result rows --------------------------------------------------- */
2041
2042.srow {
2043 display: grid;
2044 /* icon | name+dir | size | goto */
2045 grid-template-columns: 28px minmax(0, 1fr) 90px 30px;
2046 gap: 12px;
2047 align-items: center;
2048 padding: 9px 14px;
2049 border-bottom: 1px solid var(--border);
2050 cursor: pointer;
2051 font-size: 14px;
2052 user-select: none;
2053}
2054
2055.srow:last-child {
2056 border-bottom: none;
2057}
2058
2059.srow:hover {
2060 background: var(--bg);
2061}
2062
2063.srow-icon {
2064 width: 20px;
2065 height: 20px;
2066}
2067
2068.srow-main {
2069 min-width: 0;
2070 display: flex;
2071 flex-direction: column;
2072 line-height: 1.3;
2073}
2074
2075.srow-name {
2076 overflow: hidden;
2077 text-overflow: ellipsis;
2078 white-space: nowrap;
2079}
2080
2081/* Highlighted query hits (plain fragments render as bare spans). */
2082mark.hl-hit {
2083 background: color-mix(in srgb, var(--accent) 25%, transparent);
2084 color: inherit;
2085}
2086
2087/* The directory-path line (the name line lives inside .srow-name). */
2088.srow-dir {
2089 font-size: 12px;
2090 color: var(--muted);
2091 overflow: hidden;
2092 text-overflow: ellipsis;
2093 white-space: nowrap;
2094}
2095
2096.srow-dir mark.hl-hit {
2097 color: inherit;
2098}
2099
2100.ssize {
2101 font-size: 13px;
2102 color: var(--muted);
2103 text-align: right;
2104}
2105
2106/* Paging footer: position in the results on the left, the action on the
2107 right. Separated from the list by its own border so the button never reads
2108 as another result row. */
2109.page-foot {
2110 display: flex;
2111 align-items: center;
2112 justify-content: space-between;
2113 gap: 12px;
2114 padding: 10px 14px;
2115 border-top: 1px solid var(--border);
2116 font-size: 12px;
2117 color: var(--muted);
2118}
2119
2120.page-foot .pf-count {
2121 font-variant-numeric: tabular-nums;
2122}
2123
2124.page-foot .pf-more {
2125 appearance: none;
2126 padding: 5px 12px;
2127 border: 1px solid var(--border);
2128 background: var(--panel);
2129 font: inherit;
2130 font-weight: 500;
2131 color: var(--text);
2132 cursor: pointer;
2133}
2134
2135.page-foot .pf-more:hover {
2136 border-color: var(--accent);
2137 color: var(--accent);
2138}
2139
2140/* Content matches ----------------------------------------------------- */
2141
2142.match-card {
2143 background: var(--panel);
2144 border: 1px solid var(--border);
2145 border-top: none;
2146}
2147
2148/* The first card is the one right after the group label; `:first-of-type`
2149 cannot be used because the label is an earlier `div` sibling. */
2150.group-label + .match-card {
2151 border-top: 1px solid var(--border);
2152}
2153
2154/* The header opens the file; the matched lines below are text to read. */
2155.match-head {
2156 display: flex;
2157 align-items: center;
2158 gap: 10px;
2159 padding: 9px 14px;
2160 font-size: 14px;
2161 cursor: pointer;
2162}
2163
2164.match-head:hover {
2165 background: var(--bg);
2166}
2167
2168.match-head .mi {
2169 width: 18px;
2170 height: 18px;
2171 color: var(--muted);
2172 flex: none;
2173}
2174
2175/* Takes the slack, so the count and the two buttons sit at the right edge. */
2176.mpath {
2177 flex: 1;
2178 min-width: 0;
2179 overflow: hidden;
2180 text-overflow: ellipsis;
2181 white-space: nowrap;
2182}
2183
2184.mpath b {
2185 font-weight: 600;
2186}
2187
2188.mcount {
2189 flex: none;
2190 font-size: 12px;
2191 color: var(--muted);
2192}
2193
2194/* "Show in folder", in both the name rows and the match-card headers. */
2195.goto-btn {
2196 appearance: none;
2197 flex: none;
2198 justify-self: end;
2199 display: flex;
2200 align-items: center;
2201 justify-content: center;
2202 width: 26px;
2203 height: 26px;
2204 padding: 0;
2205 border: 1px solid transparent;
2206 background: transparent;
2207 cursor: pointer;
2208}
2209
2210.goto-btn:hover {
2211 border-color: var(--border);
2212}
2213
2214.goto-btn .goto-ic {
2215 width: 16px;
2216 height: 16px;
2217 color: var(--muted);
2218}
2219
2220.goto-btn:hover .goto-ic {
2221 color: var(--accent);
2222}
2223
2224.chev {
2225 appearance: none;
2226 border: 1px solid var(--border);
2227 background: transparent;
2228 width: 26px;
2229 height: 26px;
2230 display: flex;
2231 align-items: center;
2232 justify-content: center;
2233 cursor: pointer;
2234 flex: none;
2235}
2236
2237.chev:hover {
2238 background: var(--bg);
2239}
2240
2241.chev .chev-down,
2242.chev .chev-up {
2243 display: block;
2244 width: 10px;
2245 height: 10px;
2246 border-right: 2px solid var(--muted);
2247 border-bottom: 2px solid var(--muted);
2248}
2249
2250.chev .chev-down {
2251 transform: rotate(45deg) translate(-1px, -1px);
2252}
2253
2254.chev .chev-up {
2255 transform: rotate(-135deg) translate(-1px, -1px);
2256}
2257
2258.match-lines {
2259 border-top: 1px solid var(--border);
2260 background: var(--bg);
2261 font-family: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
2262 font-size: 12.5px;
2263}
2264
2265/* Matched lines are text to read, not a control: the card header is what
2266 opens the file, so no pointer cursor and no hover here. */
2267.mline {
2268 display: grid;
2269 grid-template-columns: 52px minmax(0, 1fr);
2270 gap: 12px;
2271 padding: 5px 14px;
2272 border-bottom: 1px solid var(--border);
2273 white-space: pre;
2274 user-select: text;
2275}
2276
2277.mline:last-child {
2278 border-bottom: none;
2279}
2280
2281.mline .ln {
2282 color: var(--muted);
2283 text-align: right;
2284 user-select: none;
2285}
2286
2287.mline .tx {
2288 overflow: hidden;
2289 text-overflow: ellipsis;
2290}
2291
2292.search-empty {
2293 padding: 48px 20px;
2294 text-align: center;
2295 color: var(--muted);
2296 font-size: 14px;
2297}
2298