style.css
⎇
Raw
1/* Custom layout and components on top of Pico.css */
2
3/* Scale down Pico's default sizing */
4html {
5 font-size: 16px;
6}
7
8/* Remove Pico's default bottom margin on button types */
9[type="button"],
10[type="reset"],
11[type="submit"] {
12 margin-bottom: 0;
13}
14
15/* Layout */
16body {
17 min-height: 100vh;
18 display: flex;
19 flex-direction: column;
20}
21
22body > header {
23 padding: 1rem 2rem;
24 position: sticky;
25 top: 0;
26 z-index: 100;
27 background-color: var(--pico-card-background-color);
28 border-bottom: 1px solid var(--pico-muted-border-color);
29 display: flex;
30 align-items: center;
31 gap: 2rem;
32}
33
34body > header h1 {
35 margin: 0;
36 flex-shrink: 0;
37 font-size: 1.5rem;
38}
39
40/* Brand: logo + wordmark */
41.brand {
42 display: flex;
43 align-items: center;
44 gap: 0.55rem;
45}
46
47.brand-logo {
48 display: block;
49 flex-shrink: 0;
50}
51
52nav {
53 display: flex;
54 align-items: center;
55 gap: 1rem;
56 /* Take the rest of the header row, so the sign-out button can sit at its far
57 right while the links stay next to the brand. */
58 flex: 1;
59 /* Narrow screens scroll the links instead of squashing them. */
60 overflow-x: auto;
61}
62
63.nav-signout {
64 margin-left: auto;
65}
66
67nav a,
68.nav-signout {
69 flex: none;
70 white-space: nowrap;
71}
72
73nav a {
74 color: var(--pico-muted-color);
75 text-decoration: none;
76 padding: 0.5rem 1rem;
77 border-radius: var(--pico-border-radius);
78 transition: all 0.2s;
79}
80
81nav a:hover {
82 color: var(--pico-primary);
83 background-color: var(--pico-card-sectioning-background-color);
84}
85
86nav a.active {
87 background-color: var(--pico-primary);
88 color: var(--pico-primary-inverse);
89 font-weight: 600;
90}
91
92main {
93 flex: 1;
94 padding: 2rem 1rem;
95}
96
97main > * {
98 max-width: 1400px;
99 margin-left: auto;
100 margin-right: auto;
101}
102
103footer {
104 padding: 1rem 2rem;
105 text-align: center;
106 color: var(--pico-muted-color);
107 font-size: 0.9rem;
108 background-color: var(--pico-card-background-color);
109 border-top: 1px solid var(--pico-muted-border-color);
110}
111
112/* Page headers */
113.page-header {
114 display: flex;
115 justify-content: space-between;
116 align-items: center;
117 margin-bottom: 1.5rem;
118 flex-wrap: wrap;
119 gap: 1rem;
120}
121
122.page-header h2 {
123 font-size: 1.5rem;
124 margin: 0;
125}
126
127.actions {
128 display: flex;
129 gap: 1rem;
130 align-items: center;
131 flex-wrap: wrap;
132}
133
134/* Forms */
135.form-group {
136 margin-bottom: 1rem;
137}
138
139.form-row {
140 display: grid;
141 grid-template-columns: 1fr 1fr;
142 gap: 1rem;
143}
144
145.radio-group {
146 display: flex;
147 flex-wrap: wrap;
148 gap: 1rem;
149}
150
151.radio-group label {
152 display: flex;
153 align-items: center;
154 gap: 0.3rem;
155 cursor: pointer;
156 font-weight: normal;
157 margin-bottom: 0;
158}
159
160.form-actions {
161 display: flex;
162 gap: 1rem;
163 margin-top: 1.5rem;
164}
165
166.file-selector {
167 display: flex;
168 align-items: center;
169 gap: 0.75rem;
170 flex-wrap: wrap;
171 margin-bottom: 1rem;
172}
173
174.file-selector label {
175 margin: 0;
176}
177
178.file-selector select {
179 flex: 1;
180 min-width: 0;
181 margin: 0;
182}
183
184.file-selector button {
185 margin: 0;
186 width: auto;
187 flex: none;
188}
189
190/* Buttons */
191button.small,
192[role="button"].small {
193 padding: 0.3rem 0.6rem;
194 font-size: 0.85rem;
195}
196
197button.danger,
198button.danger:hover,
199button.danger:focus,
200[role="button"].danger,
201[role="button"].danger:hover,
202[role="button"].danger:focus {
203 --pico-background-color: #c62828;
204 --pico-border-color: #c62828;
205 --pico-color: white;
206}
207
208button.danger:hover,
209button.danger:focus,
210[role="button"].danger:hover,
211[role="button"].danger:focus {
212 --pico-background-color: #b71c1c;
213 --pico-border-color: #b71c1c;
214}
215
216/* One-shot feedback banner shown after a form action (see PageData.Flash). */
217.flash {
218 padding: 0.75rem 1rem;
219 margin-bottom: 1.5rem;
220 border-radius: var(--pico-border-radius);
221 border: 1px solid transparent;
222 border-left-width: 4px;
223}
224
225.flash-success {
226 background-color: rgba(46, 125, 50, 0.12);
227 border-color: #2e7d32;
228 color: var(--pico-color);
229}
230
231.flash-error {
232 background-color: rgba(198, 40, 40, 0.12);
233 border-color: #c62828;
234 color: var(--pico-color);
235}
236
237button:disabled {
238 opacity: 0.5;
239 cursor: not-allowed;
240}
241
242/* Library */
243.breadcrumbs {
244 margin-bottom: 1rem;
245 display: flex;
246 align-items: center;
247 justify-content: flex-start;
248 gap: 0.35rem;
249 flex-wrap: wrap;
250 text-align: left;
251 width: 100%;
252}
253
254.breadcrumbs a,
255.breadcrumbs span {
256 flex-shrink: 0;
257}
258
259.breadcrumbs .current {
260 cursor: default;
261 pointer-events: none;
262}
263
264.library-grid {
265 display: grid;
266 grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
267 gap: 1rem;
268}
269
270.folder-item,
271.media-item {
272 background: var(--pico-card-background-color);
273 border: 1px solid var(--pico-card-border-color);
274 border-radius: var(--pico-border-radius);
275 overflow: hidden;
276 text-decoration: none;
277 color: var(--pico-color);
278 box-shadow: var(--pico-card-box-shadow);
279}
280
281.folder-item:hover,
282.media-item:hover {
283 background-color: var(--pico-primary-background);
284 border-color: var(--pico-primary-border);
285 box-shadow: var(--pico-card-box-shadow), 0 4px 12px rgba(0, 0, 0, 0.15);
286}
287
288.folder-item:hover .folder-name,
289.media-item:hover .media-info,
290.media-item:hover .media-title {
291 color: var(--pico-primary-inverse);
292}
293
294.media-info {
295 transition: color 0.2s;
296}
297
298.media-thumbnail {
299 aspect-ratio: 16/9;
300 background: var(--pico-card-sectioning-background-color);
301 display: flex;
302 align-items: center;
303 justify-content: center;
304 font-size: 3rem;
305 position: relative;
306}
307
308/* Each thumbnail sits in a tile so it can carry its own per-file duration
309 badge; the tile fills the container (single file) or a grid cell (multi). */
310.thumb-tile {
311 position: relative;
312 display: flex;
313 align-items: center;
314 justify-content: center;
315 overflow: hidden;
316 width: 100%;
317 height: 100%;
318 min-width: 0;
319 min-height: 0;
320}
321
322.thumb-tile .media-duration {
323 position: absolute;
324 bottom: 0.4rem;
325 right: 0.4rem;
326 background: rgba(0, 0, 0, 0.75);
327 color: #fff;
328 padding: 0.15rem 0.4rem;
329 border-radius: var(--pico-border-radius);
330 font-size: 0.7rem;
331 font-weight: 500;
332 line-height: 1;
333}
334
335.folder-icon {
336 aspect-ratio: 16/9;
337 background: var(--pico-card-sectioning-background-color);
338 display: flex;
339 align-items: center;
340 justify-content: center;
341 font-size: 3rem;
342}
343
344.thumb-tile img {
345 width: 100%;
346 height: 100%;
347 /* contain: show the whole thumbnail (letterboxed) and never overflow the
348 16/9 box, including portrait/vertical sources. */
349 object-fit: contain;
350}
351
352.thumb-tile img[src$=".svg"] {
353 width: 48px;
354 height: 48px;
355 opacity: 0.5;
356 object-fit: contain;
357}
358
359/* Multi-file items: tile each media file's thumbnail in a grid. */
360.media-thumbnail.count-2,
361.media-thumbnail.count-3,
362.media-thumbnail.count-many {
363 display: grid;
364 gap: 2px;
365}
366
367.media-thumbnail.count-2 {
368 grid-template-columns: 1fr 1fr;
369}
370
371.media-thumbnail.count-3,
372.media-thumbnail.count-many {
373 grid-template-columns: 1fr 1fr;
374 grid-template-rows: 1fr 1fr;
375}
376
377/* For 3 files, let the first thumbnail span the full top row. */
378.media-thumbnail.count-3 .thumb-tile:first-of-type {
379 grid-column: 1 / -1;
380}
381
382/* "+N" overlay on the last tile when there are more than 4 files. */
383.media-thumbnail .thumb-more {
384 position: absolute;
385 right: 0;
386 bottom: 0;
387 width: 50%;
388 height: 50%;
389 display: flex;
390 align-items: center;
391 justify-content: center;
392 background: rgba(0, 0, 0, 0.6);
393 color: #fff;
394 font-size: 1.1rem;
395 font-weight: 600;
396 pointer-events: none;
397}
398
399/* File-count badge in the top-left for multi-file items. */
400.media-thumbnail .thumb-count {
401 position: absolute;
402 top: 0.4rem;
403 left: 0.4rem;
404 background: rgba(0, 0, 0, 0.75);
405 color: #fff;
406 padding: 0.15rem 0.4rem;
407 border-radius: var(--pico-border-radius);
408 font-size: 0.7rem;
409 font-weight: 500;
410 line-height: 1;
411}
412
413.folder-name,
414.media-info {
415 padding: 0.75rem;
416}
417
418.media-title {
419 font-weight: 500;
420 margin-bottom: 0.3rem;
421 overflow: hidden;
422 text-overflow: ellipsis;
423 white-space: nowrap;
424}
425
426.media-info .media-duration {
427 display: none;
428}
429
430/* Detail view */
431.detail-view {
432 max-width: 900px;
433}
434
435.detail-header {
436 display: flex;
437 justify-content: space-between;
438 align-items: center;
439 margin-bottom: 1.5rem;
440 flex-wrap: wrap;
441 gap: 1rem;
442}
443
444.player-container {
445 background: #000;
446 border-radius: var(--pico-border-radius);
447 overflow: hidden;
448 margin-bottom: 1.5rem;
449 max-height: 80vh;
450 display: flex;
451 align-items: center;
452 justify-content: center;
453}
454
455.player-container video,
456.player-container audio {
457 max-width: 100%;
458 max-height: 80vh;
459 width: auto;
460 height: auto;
461 display: block;
462}
463
464.detail-meta dl {
465 display: grid;
466 grid-template-columns: 150px 1fr;
467 gap: 0.5rem 1rem;
468 align-items: baseline;
469}
470
471/* Render keys as understated labels so they read as keys — not just another
472 line of value text — in both the two-column and the stacked (narrow) layout. */
473.detail-meta dt {
474 font-size: 0.75rem;
475 font-weight: 600;
476 text-transform: uppercase;
477 letter-spacing: 0.04em;
478 color: var(--pico-muted-color);
479}
480
481.detail-meta dd {
482 word-break: break-all;
483 margin: 0;
484}
485
486/* Description: preserve the source line breaks; collapse long ones to ~2 lines
487 with a pure-CSS (no-JS, CSP-safe) Show more/less toggle. */
488.detail-meta dd.description {
489 margin: 0;
490}
491
492.description .desc-text {
493 white-space: pre-wrap;
494 word-break: normal;
495 overflow-wrap: anywhere;
496 line-height: 1.5;
497}
498
499/* The checkbox is the toggle state; it's driven by the label, never shown. */
500.description.collapsible .desc-toggle {
501 display: none;
502}
503
504/* Collapsed: clamp to ~2 lines (max-height works with pre-wrap; line-clamp
505 does not), with a fade so the cut reads as intentional. */
506.description.collapsible .desc-text {
507 position: relative;
508 max-height: 3em;
509 overflow: hidden;
510}
511
512.description.collapsible .desc-text::after {
513 content: "";
514 position: absolute;
515 left: 0;
516 right: 0;
517 bottom: 0;
518 height: 1.5em;
519 background: linear-gradient(to bottom, transparent, var(--pico-background-color));
520 pointer-events: none;
521}
522
523.description.collapsible .desc-toggle:checked ~ .desc-text {
524 max-height: none;
525}
526
527.description.collapsible .desc-toggle:checked ~ .desc-text::after {
528 display: none;
529}
530
531.description.collapsible .desc-toggle-label {
532 display: inline-block;
533 margin-top: 0.4rem;
534 color: var(--pico-primary);
535 font-size: 0.85rem;
536 font-weight: 600;
537 cursor: pointer;
538 user-select: none;
539}
540
541.description.collapsible .desc-toggle-label::after {
542 content: "Show more \25be";
543}
544
545.description.collapsible .desc-toggle:checked ~ .desc-toggle-label::after {
546 content: "Show less \25b4";
547}
548
549/* Engagement metadata */
550.engagement-section {
551 margin-top: 2rem;
552}
553
554.engagement-section > summary .badge {
555 margin-left: 0.35rem;
556}
557
558.comments-actions {
559 margin: 0.75rem 0;
560 text-align: right;
561}
562
563.comment-settings-group:has(input[name="write_info_json"]:not(:checked)) .comment-options {
564 display: none;
565}
566
567.comment-options:has(input[name="write_comments"]:not(:checked)) .comment-settings-fields {
568 display: none;
569}
570
571.comment-options {
572 margin-top: 1rem;
573 padding: 0.75rem 1rem 1rem;
574}
575
576.comment-options legend {
577 padding: 0 0.35rem;
578 font-weight: 600;
579}
580
581.comment-settings-fields {
582 margin: 0.75rem 0 0 1.5rem;
583 padding-left: 1rem;
584 border-left: 2px solid var(--pico-muted-border-color);
585}
586
587.comment-settings-fields small {
588 display: block;
589 margin: -0.5rem 0 0.75rem;
590 color: var(--pico-muted-color);
591}
592
593.heatmap-figure {
594 margin: 0;
595}
596
597.heatmap {
598 height: 7rem;
599 display: flex;
600 align-items: flex-end;
601 gap: 0;
602 padding: 0.5rem 0;
603 border-bottom: 1px solid var(--pico-muted-border-color);
604}
605
606.heatmap-bar {
607 flex: 0 0 auto;
608 min-width: 0;
609 background: var(--pico-primary);
610 opacity: 0.8;
611 border-radius: 2px 2px 0 0;
612}
613
614.heatmap-figure figcaption {
615 display: flex;
616 justify-content: space-between;
617 color: var(--pico-muted-color);
618 font-size: 0.8rem;
619}
620
621.comment-list {
622 display: flex;
623 flex-direction: column;
624 gap: 0.75rem;
625}
626
627.comment {
628 margin: 0;
629 padding: 0.85rem 1rem;
630 border: 1px solid var(--pico-card-border-color);
631 border-radius: var(--pico-border-radius);
632 background: var(--pico-card-background-color);
633}
634
635.comment-depth-1 {
636 margin-left: 1.25rem;
637}
638
639.comment-depth-2 {
640 margin-left: 2.5rem;
641}
642
643.comment-depth-3 {
644 margin-left: 3.75rem;
645}
646
647.comment-depth-4 {
648 margin-left: 5rem;
649}
650
651.comment header {
652 display: flex;
653 align-items: center;
654 gap: 0.5rem;
655 flex-wrap: wrap;
656}
657
658.comment time {
659 color: var(--pico-muted-color);
660 font-size: 0.85rem;
661 margin-left: auto;
662}
663
664.comment-reply-to {
665 display: block;
666 margin-top: 0.35rem;
667 color: var(--pico-muted-color);
668}
669
670.comment p {
671 white-space: pre-wrap;
672 overflow-wrap: anywhere;
673 margin: 0.5rem 0 0.25rem;
674}
675
676.comment small,
677.muted {
678 color: var(--pico-muted-color);
679}
680
681/* Queue */
682.queue-list {
683 display: flex;
684 flex-direction: column;
685 gap: 1rem;
686}
687
688.queue-item {
689 padding: 1rem;
690 margin-bottom: 0;
691 position: relative;
692 transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
693}
694
695/* Stretched link: the whole row navigates to the detail page, matching the
696 library card hover. Interactive children (Remove) sit above it via z-index. */
697.queue-link {
698 position: absolute;
699 inset: 0;
700 z-index: 1;
701}
702
703.queue-item:hover {
704 background-color: var(--pico-primary-background);
705 border-color: var(--pico-primary-border);
706 box-shadow: var(--pico-card-box-shadow), 0 4px 12px rgba(0, 0, 0, 0.15);
707 cursor: pointer;
708}
709
710/* Keep text legible on the solid primary hover background (status badges and
711 the error message keep their own colors). */
712.queue-item:hover .queue-url,
713.queue-item:hover .queue-meta {
714 color: var(--pico-primary-inverse);
715}
716
717.queue-header {
718 display: flex;
719 justify-content: space-between;
720 align-items: flex-start;
721 gap: 1rem;
722 flex-wrap: wrap;
723 margin-bottom: 0.5rem;
724}
725
726.queue-url {
727 flex: 1;
728 min-width: 0;
729 word-break: break-all;
730}
731
732.queue-status {
733 display: flex;
734 gap: 0.5rem;
735 align-items: center;
736 flex-wrap: wrap;
737}
738
739/* Keep the Remove action clickable above the stretched link overlay. */
740.queue-action {
741 position: relative;
742 z-index: 2;
743}
744
745.download-status-header {
746 display: flex;
747 align-items: center;
748 gap: 0.5rem;
749}
750
751.status-badge {
752 padding: 0.2rem 0.6rem;
753 border-radius: 12px;
754 font-size: 0.85rem;
755 font-weight: 500;
756}
757
758.status-badge.queued {
759 background: var(--pico-card-sectioning-background-color);
760 color: var(--pico-muted-color);
761}
762
763.status-badge.downloading {
764 background: var(--pico-primary);
765 color: var(--pico-primary-inverse);
766}
767
768.status-badge.completed {
769 background: var(--pico-ins-color);
770 color: white;
771}
772
773.status-badge.error {
774 background: var(--pico-del-color);
775 color: white;
776}
777
778.status-badge.cancelled {
779 background: var(--pico-muted-color);
780 color: var(--pico-background-color);
781}
782
783.error-message {
784 color: var(--pico-del-color);
785 font-size: 0.9rem;
786 margin-top: 0.5rem;
787}
788
789.error-text {
790 color: var(--pico-del-color);
791}
792
793.queue-meta {
794 margin-top: 0.5rem;
795 font-size: 0.85rem;
796 display: flex;
797 gap: 1rem;
798}
799
800/* Logs */
801.logs {
802 max-height: 500px;
803 overflow-y: auto;
804 white-space: pre-wrap;
805 word-break: break-all;
806}
807
808pre {
809 padding: 1.5rem;
810}
811
812/* Settings */
813.settings-layout {
814 display: flex;
815 flex-direction: column;
816 gap: 2rem;
817}
818
819.presets-list {
820 display: flex;
821 flex-direction: column;
822 gap: 1rem;
823 margin-bottom: 1.5rem;
824}
825
826.preset-header {
827 display: flex;
828 justify-content: space-between;
829 align-items: center;
830 margin-bottom: 0.5rem;
831}
832
833.preset-header h4 {
834 display: flex;
835 align-items: center;
836 gap: 0.5rem;
837 margin: 0;
838}
839
840.badge {
841 background: var(--pico-primary);
842 color: var(--pico-primary-inverse);
843 padding: 0.1rem 0.4rem;
844 border-radius: 10px;
845 font-size: 0.75rem;
846}
847
848.preset-actions {
849 display: flex;
850 gap: 0.5rem;
851 flex-wrap: wrap;
852 margin-top: 1rem;
853}
854
855.preset-actions > details {
856 flex: 1 1 100%;
857 min-width: 0;
858}
859
860.preset-description {
861 margin-bottom: 0.5rem;
862}
863
864.preset-flags {
865 margin-top: 0.5rem;
866}
867
868.preset-flags pre {
869 overflow-x: auto;
870 margin-top: 0.3rem;
871 margin-bottom: 0;
872}
873
874/* Nested articles need visible borders */
875.presets-list article {
876 border: 1px solid var(--pico-muted-border-color);
877}
878
879/* Suppress Pico details marker for button-like summaries */
880details:has(summary[role="button"]) summary::after {
881 display: none !important;
882}
883
884details summary[role="button"] {
885 display: inline-flex;
886 width: auto;
887}
888
889/* Toggle text: Edit vs Cancel */
890details .cancel-text {
891 display: none;
892}
893
894details[open] .edit-text {
895 display: none;
896}
897
898details[open] .cancel-text {
899 display: inline;
900}
901
902.detail-actions {
903 display: flex;
904 align-items: center;
905 gap: 0.5rem;
906}
907
908/* Overlay popover */
909.overlay {
910 position: relative;
911}
912
913.overlay summary {
914 list-style: none;
915 cursor: pointer;
916}
917
918.overlay summary::-webkit-details-marker {
919 display: none;
920}
921
922.overlay summary::after {
923 display: none !important;
924}
925
926.overlay .overlay-panel {
927 position: absolute;
928 top: calc(100% + 0.5rem);
929 right: 0;
930 z-index: 1000;
931 width: 260px;
932 background: var(--pico-background-color);
933 border: 1px solid var(--pico-muted-border-color);
934 border-radius: var(--pico-border-radius);
935 padding: 1rem;
936 box-shadow: var(--pico-dropdown-box-shadow);
937}
938
939/* Popover arrow */
940.overlay .overlay-panel::before {
941 content: '';
942 position: absolute;
943 top: -6px;
944 right: 1rem;
945 width: 10px;
946 height: 10px;
947 background: var(--pico-background-color);
948 border-left: 1px solid var(--pico-muted-border-color);
949 border-top: 1px solid var(--pico-muted-border-color);
950 transform: rotate(45deg);
951}
952
953.overlay .overlay-panel p {
954 margin-bottom: 1rem;
955 font-size: 0.9rem;
956}
957
958.overlay .overlay-panel .form-actions {
959 margin-top: 0;
960 justify-content: flex-end;
961}
962
963/* Inline edit form */
964.edit-form {
965 width: 100%;
966 box-sizing: border-box;
967 padding: 1rem;
968}
969
970/* Conditional sections (no-JS show/hide) */
971.conditional-section {
972 margin-bottom: 1rem;
973}
974
975.conditional-section .conditional-content {
976 display: none;
977 margin-top: 1rem;
978}
979
980/* Checkbox triggers */
981.conditional-section:has(input[type="checkbox"].conditional-trigger:checked) .conditional-content {
982 display: block;
983}
984
985/* Radio triggers for format mode */
986.conditional-section:has(.radio-group input[value="preset"]:checked) .conditional-content.format-preset,
987.conditional-section:has(.radio-group input[value="custom"]:checked) .conditional-content.format-custom {
988 display: block;
989}
990
991/* Subscriptions: lock the cron field unless the schedule is "Custom (cron)".
992 Pure CSS — the :has() reacts live as the <select> changes, no JS needed. */
993input[name="cron_expr"] {
994 opacity: 0.5;
995 pointer-events: none;
996}
997.form-row:has(select[name="schedule_kind"] option[value="cron"]:checked) input[name="cron_expr"] {
998 opacity: 1;
999 pointer-events: auto;
1000}
1001
1002/* Format mode selector - hidden radio inputs with button-like labels */
1003.radio-group.format-mode {
1004 display: flex;
1005 gap: 0.5rem;
1006 margin-top: 0.5rem;
1007 flex-wrap: wrap;
1008}
1009
1010.radio-group.format-mode input[type="radio"] {
1011 position: absolute;
1012 opacity: 0;
1013 width: 0;
1014 height: 0;
1015}
1016
1017.radio-group.format-mode label {
1018 padding: 0.4rem 0.8rem;
1019 border: 1px solid var(--pico-muted-border-color);
1020 border-radius: var(--pico-border-radius);
1021 cursor: pointer;
1022 background: var(--pico-background-color);
1023 transition: all 0.2s;
1024 font-weight: normal;
1025}
1026
1027.radio-group.format-mode label:hover {
1028 background: var(--pico-card-sectioning-background-color);
1029}
1030
1031.radio-group.format-mode label:has(input:checked) {
1032 background: var(--pico-primary);
1033 color: var(--pico-primary-inverse);
1034 border-color: var(--pico-primary);
1035}
1036
1037/* Inline informational note paragraph */
1038.note {
1039 font-size: 0.85rem;
1040 color: var(--pico-muted-color);
1041}
1042
1043/* Collapsible "managed yt-dlp options" notes component */
1044.ytdlp-notes {
1045 margin: 0 0 1rem;
1046 border: 1px solid var(--pico-muted-border-color);
1047 border-radius: var(--pico-border-radius);
1048 background: var(--pico-card-sectioning-background-color);
1049 overflow: hidden;
1050}
1051
1052.ytdlp-notes > summary {
1053 cursor: pointer;
1054 padding: 0.6rem 0.9rem;
1055 font-size: 0.9rem;
1056 font-weight: 600;
1057 color: var(--pico-color);
1058 user-select: none;
1059 transition: background 0.15s ease-in-out;
1060}
1061
1062.ytdlp-notes > summary:hover {
1063 background: var(--pico-card-background-color);
1064}
1065
1066.ytdlp-notes-icon {
1067 color: var(--pico-primary);
1068 font-style: normal;
1069 font-size: 1rem;
1070 margin-right: 0.4rem;
1071}
1072
1073.ytdlp-notes-body {
1074 padding: 0 0.9rem 0.6rem;
1075 border-top: 1px solid var(--pico-muted-border-color);
1076}
1077
1078.ytdlp-notes-body > p {
1079 font-size: 0.85rem;
1080 color: var(--pico-muted-color);
1081 margin: 0.7rem 0;
1082}
1083
1084.ytdlp-notes-table-wrap {
1085 overflow-x: auto;
1086}
1087
1088.ytdlp-notes-body table {
1089 margin: 0;
1090 font-size: 0.85rem;
1091}
1092
1093.ytdlp-notes-body th,
1094.ytdlp-notes-body td {
1095 padding: 0.4rem 0.6rem;
1096 vertical-align: top;
1097}
1098
1099.ytdlp-notes-body td:first-child {
1100 white-space: nowrap;
1101}
1102
1103.ytdlp-notes-body code {
1104 font-size: 0.8rem;
1105}
1106
1107/* Theme selector */
1108.theme-selector {
1109 display: flex;
1110 gap: 0.5rem;
1111}
1112
1113.theme-selector button {
1114 min-width: 80px;
1115}
1116
1117.theme-selector button.active {
1118 background: var(--pico-primary);
1119 color: var(--pico-primary-inverse);
1120 border-color: var(--pico-primary);
1121}
1122
1123/* Download form */
1124.download-form {
1125 max-width: 900px;
1126}
1127
1128.download-form form {
1129 max-width: 800px;
1130}
1131
1132/* Filter form inline */
1133.filter-form {
1134 display: flex;
1135 gap: 0.5rem;
1136 align-items: center;
1137}
1138
1139.filter-form input,
1140.filter-form select,
1141.filter-form button {
1142 margin-bottom: 0;
1143 width: auto;
1144 display: inline-block;
1145 flex-shrink: 0;
1146}
1147
1148.filter-form input[type="text"] {
1149 min-width: 200px;
1150}
1151
1152/* Empty state */
1153.empty-state {
1154 text-align: center;
1155 padding: 3rem;
1156}
1157
1158/* Login */
1159.login-page {
1160 max-width: 24rem;
1161 margin: 0 auto;
1162}
1163
1164/* The login page is one narrow column, so the flash above the form is kept to
1165 the same width instead of spanning the whole page. */
1166.login-main {
1167 display: flex;
1168 flex-direction: column;
1169 justify-content: center;
1170}
1171
1172.login-main > * {
1173 max-width: 24rem;
1174 width: 100%;
1175}
1176
1177/* Pagination */
1178.pagination {
1179 display: flex;
1180 align-items: center;
1181 justify-content: center;
1182 gap: 0.5rem;
1183 /* auto, not 0: this rule would otherwise override the centring margins that
1184 `main > *` sets, and the whole bar would sit at the left edge. */
1185 margin: 2rem auto 1rem;
1186}
1187
1188.pagination a,
1189.pagination .disabled {
1190 /* Equal width on both sides keeps the page label centred, even though
1191 "Previous" and "Next" are different lengths. */
1192 min-width: 8rem;
1193 padding: 0.4rem 0.9rem;
1194 text-align: center;
1195 border: 1px solid var(--pico-muted-border-color);
1196 border-radius: var(--pico-border-radius);
1197 text-decoration: none;
1198 white-space: nowrap;
1199}
1200
1201.pagination a {
1202 color: var(--pico-primary);
1203}
1204
1205.pagination a:hover {
1206 background-color: var(--pico-card-sectioning-background-color);
1207}
1208
1209.pagination .disabled {
1210 color: var(--pico-muted-color);
1211 opacity: 0.4;
1212}
1213
1214.pagination .page {
1215 min-width: 6rem;
1216 text-align: center;
1217 color: var(--pico-muted-color);
1218}
1219
1220/* Utility */
1221.inline {
1222 display: inline;
1223}
1224
1225/* Pico stretches submit buttons to 100%; inline forms want intrinsic width. */
1226.inline button {
1227 width: auto;
1228 margin-bottom: 0;
1229}
1230
1231/* Responsive */
1232@media (max-width: 768px) {
1233 main {
1234 padding: 1rem;
1235 }
1236
1237 .page-header {
1238 flex-direction: column;
1239 align-items: flex-start;
1240 }
1241
1242 .library-grid {
1243 grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
1244 }
1245
1246 .form-row {
1247 grid-template-columns: 1fr;
1248 }
1249
1250 .detail-meta dl {
1251 grid-template-columns: 1fr;
1252 gap: 0;
1253 }
1254
1255 /* Stacked layout: tighten key→value and space out each pair so the grouping
1256 is obvious without the column alignment to lean on. */
1257 .detail-meta dt {
1258 margin-top: 0.85rem;
1259 }
1260
1261 .detail-meta dt:first-child {
1262 margin-top: 0;
1263 }
1264
1265 .detail-meta dd {
1266 margin-top: 0.15rem;
1267 }
1268
1269 .queue-header {
1270 flex-direction: column;
1271 }
1272
1273 body > header {
1274 flex-direction: column;
1275 gap: 1rem;
1276 padding: 1rem;
1277 }
1278
1279 nav {
1280 width: 100%;
1281 /* safe: when the links overflow, fall back to flex-start so the first one
1282 stays reachable while scrolling. */
1283 justify-content: safe center;
1284 }
1285}
1286
1287.tools-table {
1288 width: 100%;
1289 border-collapse: collapse;
1290 font-size: 0.9rem;
1291 margin-bottom: 1rem;
1292}
1293
1294/* Pico gives cells their own background and a bottom rule. Both are dropped:
1295 the first column has no left padding so it lines up with the card heading,
1296 which puts any cell edge right against the first character. */
1297.tools-table th,
1298.tools-table td {
1299 padding: 0.3rem 0.6rem 0.3rem 0;
1300 border: none;
1301 background: none;
1302 text-align: left;
1303 vertical-align: top;
1304 font-weight: normal;
1305}
1306
1307.tools-table code {
1308 word-break: break-all;
1309}
1310