返回 DeepSeek-Reasonix
heartbeat.css
根目录 / desktop / frontend / src / custom / features / heartbeat / heartbeat.css
1 /* ===================================================================
2 * heartbeat 模块 — 定时任务配置面板
3 *
4 * 所有选择器以 .heartbeat- 为前缀,不与上游样式冲突。
5 * 区域注释格式:/* ── <模块名> ── */ 方便合并时定位。
6 * ================================================================ */
7
8 /* ── backdrop ─────────────────────────────────────────────────── */
9
10 .heartbeat-backdrop {
11 position: fixed;
12 inset: 0;
13 z-index: 1000;
14 display: flex;
15 align-items: center;
16 justify-content: center;
17 background: rgba(0, 0, 0, 0.4);
18 backdrop-filter: blur(3px);
19 }
20
21 /* ── modal ────────────────────────────────────────────────────── */
22
23 .heartbeat-modal {
24 display: flex;
25 flex-direction: column;
26 width: min(640px, 92vw);
27 max-height: min(780px, 92vh);
28 background: var(--bg);
29 border: 1px solid var(--border);
30 border-radius: 14px;
31 box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
32 overflow: hidden;
33 }
34
35 .heartbeat-modal__header {
36 display: flex;
37 align-items: center;
38 gap: 8px;
39 padding: 14px 16px;
40 font-size: 14px;
41 font-weight: 600;
42 border-bottom: 1px solid var(--border);
43 color: var(--fg);
44 flex-shrink: 0;
45 }
46
47 .heartbeat-modal__back,
48 .heartbeat-modal__close {
49 display: flex;
50 align-items: center;
51 justify-content: center;
52 width: 26px;
53 height: 26px;
54 border: none;
55 border-radius: 6px;
56 background: transparent;
57 color: var(--fg-muted);
58 cursor: pointer;
59 }
60
61 .heartbeat-modal__back:hover,
62 .heartbeat-modal__close:hover {
63 background: var(--hover-bg);
64 color: var(--fg);
65 }
66
67 .heartbeat-modal__close {
68 margin-left: auto;
69 }
70
71 .heartbeat-modal__header-actions {
72 display: flex;
73 align-items: center;
74 gap: 4px;
75 margin-left: auto;
76 }
77
78 .heartbeat-btn--mini {
79 display: inline-flex;
80 align-items: center;
81 justify-content: center;
82 width: 28px;
83 height: 28px;
84 border: 1px solid var(--border);
85 border-radius: 7px;
86 background: transparent;
87 color: var(--fg-dim);
88 cursor: pointer;
89 flex-shrink: 0;
90 transition: background 0.12s, color 0.12s;
91 }
92 .heartbeat-btn--mini:hover {
93 background: var(--hover-bg);
94 color: var(--fg);
95 }
96 .heartbeat-btn--mini-primary {
97 background: var(--accent);
98 color: #fff;
99 border-color: var(--accent);
100 }
101 .heartbeat-btn--mini-primary:hover {
102 opacity: 0.88;
103 }
104
105 .heartbeat-modal__body {
106 flex: 1;
107 overflow-y: auto;
108 padding: 16px;
109 display: flex;
110 flex-direction: column;
111 gap: 12px;
112 }
113
114 /* ── toolbar ──────────────────────────────────────────────────── */
115
116 .heartbeat-toolbar {
117 display: flex;
118 align-items: center;
119 gap: 6px;
120 flex-shrink: 0;
121 flex-wrap: wrap;
122 }
123
124 /* All toolbar children share height: 28px for visual consistency */
125 .heartbeat-toolbar__btn,
126 .heartbeat-toolbar__search,
127 .heartbeat-toolbar__status-btn {
128 height: 28px;
129 box-sizing: border-box;
130 }
131
132 .heartbeat-toolbar__btn {
133 display: inline-flex;
134 align-items: center;
135 gap: 4px;
136 padding: 0 10px;
137 font-size: 12px;
138 font-weight: 500;
139 border: 1px solid var(--border);
140 border-radius: 6px;
141 background: var(--bg);
142 color: var(--fg);
143 cursor: pointer;
144 white-space: nowrap;
145 flex-shrink: 0;
146 transition: background 0.12s, border-color 0.12s, color 0.12s;
147 font-family: inherit;
148 }
149 /* Icon-only buttons in toolbar: minimal width */
150 .heartbeat-toolbar__btn--icon {
151 width: 28px;
152 padding: 0;
153 justify-content: center;
154 }
155 .heartbeat-toolbar__btn:hover {
156 background: var(--hover-bg);
157 color: var(--fg);
158 }
159 .heartbeat-toolbar__btn:disabled {
160 opacity: 0.45;
161 cursor: default;
162 }
163
164 .heartbeat-toolbar__btn--primary {
165 background: var(--accent);
166 color: #fff;
167 border-color: var(--accent);
168 }
169 .heartbeat-toolbar__btn--primary:hover {
170 opacity: 0.88;
171 }
172
173 .heartbeat-toolbar__btn--select {
174 min-width: 76px;
175 max-width: 130px;
176 padding: 0 8px 0 10px;
177 }
178 .heartbeat-toolbar__btn--select > span {
179 flex: 1;
180 text-align: left;
181 overflow: hidden;
182 text-overflow: ellipsis;
183 white-space: nowrap;
184 }
185
186 .heartbeat-toolbar__search {
187 display: flex;
188 align-items: center;
189 gap: 4px;
190 flex: 1;
191 min-width: 120px;
192 max-width: 200px;
193 padding: 0 8px;
194 border: 1px solid var(--border);
195 border-radius: 6px;
196 background: var(--bg);
197 color: var(--fg-muted);
198 transition: border-color 0.15s;
199 }
200 .heartbeat-toolbar__search:focus-within {
201 border-color: var(--accent);
202 }
203
204 .heartbeat-toolbar__search-icon {
205 flex-shrink: 0;
206 }
207
208 .heartbeat-toolbar__search-input {
209 flex: 1;
210 min-width: 0;
211 border: none;
212 background: transparent;
213 color: var(--fg);
214 font-size: 12px;
215 font-family: inherit;
216 outline: none;
217 height: 100%;
218 }
219 .heartbeat-toolbar__search-input::placeholder {
220 color: var(--fg-faint);
221 }
222
223 .heartbeat-toolbar__search-clear {
224 display: flex;
225 align-items: center;
226 justify-content: center;
227 width: 18px;
228 height: 18px;
229 border: none;
230 border-radius: 4px;
231 background: transparent;
232 color: var(--fg-faint);
233 cursor: pointer;
234 flex-shrink: 0;
235 padding: 0;
236 }
237 .heartbeat-toolbar__search-clear:hover {
238 background: var(--hover-bg);
239 color: var(--fg);
240 }
241
242 .heartbeat-toolbar__status {
243 display: flex;
244 gap: 2px;
245 flex-shrink: 0;
246 }
247
248 .heartbeat-toolbar__status-btn {
249 padding: 0 8px;
250 font-size: 11px;
251 font-weight: 500;
252 border: 1px solid var(--border);
253 border-radius: 5px;
254 background: transparent;
255 color: var(--fg-muted);
256 cursor: pointer;
257 transition: background 0.1s, border-color 0.1s, color 0.1s;
258 white-space: nowrap;
259 font-family: inherit;
260 }
261 .heartbeat-toolbar__status-btn:hover {
262 background: var(--hover-bg);
263 color: var(--fg);
264 }
265 .heartbeat-toolbar__status-btn--active {
266 background: rgba(128, 128, 128, 0.08);
267 border-color: var(--accent);
268 color: var(--accent);
269 }
270
271 .heartbeat-scope-filter {
272 position: relative;
273 }
274
275 /* ── generic button (used in editor) ─────────────────────────── */
276
277 .heartbeat-btn {
278 display: inline-flex;
279 align-items: center;
280 gap: 6px;
281 height: 32px;
282 padding: 0 14px;
283 font-size: 12.5px;
284 font-weight: 500;
285 border: 1px solid var(--border);
286 border-radius: 7px;
287 background: var(--card-bg);
288 color: var(--fg);
289 cursor: pointer;
290 white-space: nowrap;
291 transition: background 0.12s, border-color 0.12s;
292 font-family: inherit;
293 box-sizing: border-box;
294 }
295 .heartbeat-btn:hover {
296 background: var(--hover-bg);
297 border-color: var(--border-focus);
298 }
299 .heartbeat-btn:disabled {
300 opacity: 0.45;
301 cursor: default;
302 }
303 .heartbeat-btn--primary {
304 background: var(--accent);
305 color: #fff;
306 border-color: var(--accent);
307 }
308 .heartbeat-btn--primary:hover {
309 opacity: 0.88;
310 background: var(--accent);
311 }
312 .heartbeat-btn--danger {
313 background: transparent;
314 border-color: var(--border);
315 color: var(--err);
316 }
317 .heartbeat-btn--danger:hover {
318 background: color-mix(in srgb, var(--err) 10%, transparent);
319 border-color: var(--err);
320 }
321
322 .heartbeat-editor__confirm-del {
323 display: inline-flex;
324 align-items: center;
325 gap: 6px;
326 font-size: 12px;
327 color: var(--fg-muted);
328 }
329
330 /* ── empty / loading ──────────────────────────────────────────── */
331
332 .heartbeat-empty {
333 display: flex;
334 flex-direction: column;
335 align-items: center;
336 gap: 12px;
337 padding: 40px 0;
338 color: var(--fg-muted);
339 font-size: 13px;
340 }
341
342 @keyframes heartbeat-keyframe-pulse {
343 0%, 100% { opacity: 0.3; transform: scale(1); }
344 50% { opacity: 0.7; transform: scale(1.08); }
345 }
346 .heartbeat-pulse {
347 animation: heartbeat-keyframe-pulse 1.2s ease-in-out infinite;
348 }
349
350 @keyframes heartbeat-keyframe-spin {
351 to { transform: rotate(360deg); }
352 }
353 .heartbeat-spin {
354 animation: heartbeat-keyframe-spin 0.8s linear infinite;
355 }
356
357 /* ── filter menu (popover) ──────────────────────────────────── */
358
359 .heartbeat-filter-menu {
360 display: flex;
361 flex-direction: column;
362 gap: 2px;
363 min-width: 120px;
364 max-height: 200px;
365 overflow-y: auto;
366 background: var(--bg);
367 border: 1px solid var(--border);
368 border-radius: 8px;
369 padding: 4px;
370 box-shadow: 0 4px 12px rgba(0,0,0,0.15);
371 }
372 .heartbeat-filter-menu__option {
373 display: flex;
374 align-items: center;
375 gap: 6px;
376 padding: 6px 8px;
377 font-size: 12px;
378 border-radius: 4px;
379 border: none;
380 background: transparent;
381 color: var(--fg);
382 cursor: pointer;
383 text-align: left;
384 width: 100%;
385 }
386 .heartbeat-filter-menu__option:hover {
387 background: var(--accent-soft, rgba(128,128,128,0.1));
388 }
389 .heartbeat-filter-menu__option--selected {
390 color: var(--accent);
391 font-weight: 600;
392 }
393 .heartbeat-filter-menu__check {
394 margin-left: auto;
395 flex-shrink: 0;
396 }
397
398 /* ── tasklist ─────────────────────────────────────────────────── */
399
400 .heartbeat-tasklist {
401 list-style: none;
402 margin: 0;
403 padding: 0;
404 display: flex;
405 flex-direction: column;
406 gap: 4px;
407 }
408
409 /* ── card ─────────────────────────────────────────────────────── */
410
411 .heartbeat-card {
412 display: flex;
413 flex-direction: column;
414 gap: 6px;
415 padding: 10px 14px;
416 background: var(--card-bg);
417 border: 1px solid var(--border-soft);
418 border-radius: 10px;
419 transition: border-color 0.15s;
420 }
421
422 .heartbeat-card:hover {
423 border-color: var(--border);
424 }
425
426 .heartbeat-card--disabled {
427 opacity: 0.55;
428 }
429
430 .heartbeat-card__head {
431 display: flex;
432 align-items: center;
433 gap: 8px;
434 }
435
436 .heartbeat-card__dot {
437 width: 8px;
438 height: 8px;
439 border-radius: 50%;
440 flex-shrink: 0;
441 background: var(--fg-faint);
442 }
443
444 .heartbeat-card__dot--on {
445 background: #4caf50;
446 box-shadow: 0 0 4px rgba(76, 175, 80, 0.5);
447 }
448
449 .heartbeat-card__title {
450 display: flex;
451 align-items: center;
452 gap: 6px;
453 flex: 1;
454 min-width: 0;
455 overflow: hidden;
456 }
457
458 .heartbeat-card__title-text {
459 overflow: hidden;
460 text-overflow: ellipsis;
461 white-space: nowrap;
462 font-size: 13.5px;
463 font-weight: 600;
464 color: var(--fg);
465 }
466
467 .heartbeat-card__title-btn {
468 display: flex;
469 align-items: center;
470 gap: 6px;
471 min-width: 0;
472 flex: 1;
473 border: none;
474 background: transparent;
475 color: inherit;
476 cursor: pointer;
477 padding: 2px 4px;
478 border-radius: 4px;
479 text-align: left;
480 font: inherit;
481 transition: background 0.12s;
482 overflow: hidden;
483 }
484 .heartbeat-card__title-btn:hover {
485 background: var(--hover-bg);
486 }
487
488 .heartbeat-card__title-scope {
489 flex-shrink: 0;
490 font-size: 11.5px;
491 color: var(--fg-faint);
492 white-space: nowrap;
493 line-height: 1.5;
494 }
495
496 .heartbeat-card__head-actions {
497 display: flex;
498 align-items: center;
499 gap: 4px;
500 flex-shrink: 0;
501 }
502
503 /* Hover reveal: buttons in head-actions hidden by default, show on card hover */
504 .heartbeat-card:hover .heartbeat-card__head-actions .heartbeat-card__open-btn {
505 opacity: 1;
506 pointer-events: auto;
507 }
508 .heartbeat-card .heartbeat-card__head-actions .heartbeat-card__open-btn {
509 opacity: 0;
510 pointer-events: none;
511 transition: opacity 0.12s;
512 }
513 /* Toggle always visible */
514 .heartbeat-card .heartbeat-card__head-actions .heartbeat-card__toggle,
515 .heartbeat-card:hover .heartbeat-card__head-actions .heartbeat-card__toggle {
516 opacity: 1;
517 pointer-events: auto;
518 }
519 /* Open topic button always visible when not disabled */
520 .heartbeat-card__open-btn:not(:disabled) {
521 opacity: 1 !important;
522 pointer-events: auto !important;
523 }
524
525 .heartbeat-card__open-btn {
526 display: inline-flex;
527 align-items: center;
528 justify-content: center;
529 width: 26px;
530 height: 26px;
531 border: 1px solid var(--border);
532 border-radius: 6px;
533 background: transparent;
534 color: var(--fg-muted);
535 cursor: pointer;
536 transition: background 0.12s, border-color 0.12s, color 0.12s;
537 flex-shrink: 0;
538 }
539 .heartbeat-card__open-btn:hover:not(:disabled) {
540 background: var(--hover-bg);
541 border-color: var(--accent);
542 color: var(--accent);
543 }
544 .heartbeat-card__open-btn:disabled {
545 opacity: 0.3;
546 cursor: default;
547 }
548
549 .heartbeat-card__badge {
550 font-size: 10px;
551 font-weight: 600;
552 padding: 2px 7px;
553 border-radius: 4px;
554 background: var(--border-soft);
555 color: var(--fg-muted);
556 text-transform: uppercase;
557 letter-spacing: 0.04em;
558 flex-shrink: 0;
559 }
560
561 .heartbeat-card__badge--on {
562 background: rgba(76, 175, 80, 0.15);
563 color: #4caf50;
564 }
565
566 /* ── toggle ───────────────────────────────────────────────────── */
567
568 .heartbeat-card__toggle {
569 position: relative;
570 width: 32px;
571 height: 18px;
572 flex-shrink: 0;
573 border: none;
574 border-radius: 9px;
575 background: var(--border);
576 cursor: pointer;
577 transition: background 0.2s;
578 padding: 0;
579 }
580
581 .heartbeat-card__toggle:hover {
582 background: var(--fg-faint);
583 }
584
585 .heartbeat-card__toggle--on {
586 background: #4caf50;
587 }
588
589 .heartbeat-card__toggle--on:hover {
590 background: #43a047;
591 }
592
593 .heartbeat-card__toggle-knob {
594 position: absolute;
595 top: 2px;
596 left: 2px;
597 width: 14px;
598 height: 14px;
599 border-radius: 50%;
600 background: #fff;
601 transition: transform 0.2s ease;
602 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
603 }
604
605 .heartbeat-card__toggle--on .heartbeat-card__toggle-knob {
606 transform: translateX(14px);
607 }
608
609 /* ── compact meta in single row ──────────────────────────────── */
610
611 .heartbeat-card__meta-item--compact {
612 display: inline-flex;
613 align-items: center;
614 gap: 4px;
615 font-size: 11px;
616 color: var(--fg-faint);
617 flex-shrink: 0;
618 white-space: nowrap;
619 }
620
621 .heartbeat-card__meta-sep {
622 color: var(--border);
623 }
624
625 .heartbeat-card__btn {
626 display: inline-flex;
627 align-items: center;
628 gap: 4px;
629 padding: 4px 10px;
630 font-size: 11.5px;
631 font-weight: 500;
632 border: none;
633 border-radius: 5px;
634 background: transparent;
635 color: var(--fg-muted);
636 cursor: pointer;
637 transition: background 0.1s, color 0.1s;
638 }
639
640 .heartbeat-card__btn:hover {
641 background: var(--hover-bg);
642 color: var(--fg);
643 }
644
645 .heartbeat-card__btn--danger:hover {
646 color: var(--err);
647 background: rgba(128, 128, 128, 0.1);
648 }
649
650 .heartbeat-card__confirm {
651 display: inline-flex;
652 align-items: center;
653 gap: 4px;
654 font-size: 11.5px;
655 color: var(--err);
656 }
657
658 /* ── editor ───────────────────────────────────────────────────── */
659
660 .heartbeat-editor {
661 display: flex;
662 flex-direction: column;
663 flex: 1;
664 min-height: 0;
665 overflow-y: auto;
666 padding: 16px 16px 0;
667 }
668
669 .heartbeat-editor__fields {
670 display: flex;
671 flex-direction: column;
672 gap: 14px;
673 }
674
675 .heartbeat-editor__field {
676 display: flex;
677 flex-direction: column;
678 gap: 5px;
679 }
680
681 .heartbeat-editor__field > label {
682 font-size: 11.5px;
683 font-weight: 600;
684 color: var(--fg-muted);
685 text-transform: uppercase;
686 letter-spacing: 0.05em;
687 }
688
689 /* ── editor text inputs ───────────────────────────────────────── */
690
691 .heartbeat-editor__input {
692 height: 32px;
693 padding: 0 11px;
694 font-size: 13px;
695 border: 1px solid var(--border);
696 border-radius: 7px;
697 background: var(--bg);
698 color: var(--fg);
699 font-family: inherit;
700 transition: border-color 0.15s;
701 box-sizing: border-box;
702 }
703
704 .heartbeat-editor__textarea {
705 padding: 8px 11px;
706 font-size: 13px;
707 border: 1px solid var(--border);
708 border-radius: 7px;
709 background: var(--bg);
710 color: var(--fg);
711 font-family: inherit;
712 transition: border-color 0.15s;
713 box-sizing: border-box;
714 }
715
716 .heartbeat-editor__input:focus,
717 .heartbeat-editor__textarea:focus {
718 outline: none;
719 border-color: var(--accent);
720 }
721
722 .heartbeat-editor__textarea {
723 resize: none;
724 min-height: 80px;
725 max-height: 180px;
726 overflow-y: auto;
727 }
728
729 /* ── editor rows ──────────────────────────────────────────────── */
730
731 .heartbeat-editor__row {
732 display: flex;
733 gap: 12px;
734 }
735
736 .heartbeat-editor__row > .heartbeat-editor__field {
737 flex: 0;
738 }
739
740 .heartbeat-editor__field--grow {
741 flex: 1 !important;
742 min-width: 0;
743 }
744
745 .heartbeat-editor__field--auto {
746 flex: 0 1 auto !important;
747 }
748
749 .heartbeat-editor__field--toggle {
750 min-width: 180px;
751 }
752
753 .heartbeat-editor__optional {
754 font-weight: 400;
755 text-transform: none;
756 letter-spacing: normal;
757 color: var(--fg-faint);
758 font-size: 10.5px;
759 }
760
761 .heartbeat-editor__mode-hint {
762 font-size: 11px;
763 color: var(--fg-muted);
764 line-height: 1.4;
765 }
766
767 .heartbeat-editor__tw-add {
768 cursor: pointer;
769 color: var(--fg-faint);
770 }
771
772 .heartbeat-editor__tw-sep {
773 font-size: 11px;
774 }
775
776 .heartbeat-editor__tw-clear {
777 padding: 0 4px;
778 font-size: 13px;
779 line-height: 20px;
780 color: var(--fg-muted);
781 border: none;
782 background: none;
783 cursor: pointer;
784 }
785
786 /* ── frequency: unified components ──────────────────────────────── */
787 /* All freq-* components share height: 32px for visual consistency */
788
789 .heartbeat-editor__freq-interval,
790 .heartbeat-editor__cycle-row {
791 display: flex;
792 align-items: center;
793 gap: 6px;
794 }
795
796 .heartbeat-editor__freq-label {
797 font-size: 13px;
798 color: var(--fg-dim);
799 white-space: nowrap;
800 }
801
802 .heartbeat-editor__freq-input {
803 height: 32px;
804 padding: 0 10px;
805 font-size: 13px;
806 border: 1px solid var(--border);
807 border-radius: 7px;
808 background: var(--bg);
809 color: var(--fg);
810 font-family: var(--mono);
811 transition: border-color 0.15s;
812 box-sizing: border-box;
813 width: 60px;
814 }
815 .heartbeat-editor__freq-input:focus {
816 outline: none;
817 border-color: var(--accent);
818 }
819 .heartbeat-editor__freq-input--time {
820 width: 100px;
821 font-family: var(--font-ui);
822 }
823
824 .heartbeat-editor__freq-select {
825 height: 32px;
826 padding: 0 10px;
827 font-size: 13px;
828 border: 1px solid var(--border);
829 border-radius: 7px;
830 background: var(--bg);
831 color: var(--fg);
832 cursor: pointer;
833 box-sizing: border-box;
834 }
835 .heartbeat-editor__freq-select:focus {
836 outline: none;
837 border-color: var(--accent);
838 }
839
840 /* ── weekday buttons ──────────────────────────────────────────── */
841
842 .heartbeat-editor__weekdays {
843 display: flex;
844 gap: 4px;
845 flex-wrap: wrap;
846 }
847
848 .heartbeat-editor__weekday-btn {
849 height: 32px;
850 min-width: 38px;
851 padding: 0 8px;
852 font-size: 12px;
853 font-weight: 500;
854 border: 1px solid var(--border);
855 border-radius: 6px;
856 background: transparent;
857 color: var(--fg-muted);
858 cursor: pointer;
859 transition: background 0.12s, border-color 0.12s, color 0.12s;
860 }
861 .heartbeat-editor__weekday-btn:hover {
862 background: var(--hover-bg);
863 }
864 .heartbeat-editor__weekday-btn--on {
865 background: var(--accent);
866 border-color: var(--accent);
867 color: #fff;
868 }
869 .heartbeat-editor__weekday-btn--on:hover {
870 opacity: 0.88;
871 }
872
873 /* ── cycle wrap ────────────────────────────────────────────────── */
874
875 .heartbeat-editor__cycle-wrap {
876 display: flex;
877 flex-direction: column;
878 gap: 8px;
879 }
880
881 /* ── editor toggle switch ─────────────────────────────────────── */
882
883 .heartbeat-editor__toggle-row {
884 display: flex;
885 align-items: center;
886 gap: 8px;
887 padding-top: 4px;
888 }
889
890 .heartbeat-editor__toggle {
891 position: relative;
892 width: 36px;
893 height: 20px;
894 flex-shrink: 0;
895 border: none;
896 border-radius: 10px;
897 background: var(--border);
898 cursor: pointer;
899 transition: background 0.2s;
900 padding: 0;
901 }
902
903 .heartbeat-editor__toggle:hover {
904 background: var(--fg-faint);
905 }
906
907 .heartbeat-editor__toggle--on {
908 background: #4caf50;
909 }
910
911 .heartbeat-editor__toggle--on:hover {
912 background: #43a047;
913 }
914
915 .heartbeat-editor__toggle-knob {
916 position: absolute;
917 top: 2px;
918 left: 2px;
919 width: 16px;
920 height: 16px;
921 border-radius: 50%;
922 background: #fff;
923 transition: transform 0.2s ease;
924 box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
925 }
926
927 .heartbeat-editor__toggle--on .heartbeat-editor__toggle-knob {
928 transform: translateX(16px);
929 }
930
931 .heartbeat-editor__toggle-label {
932 font-size: 12px;
933 color: var(--fg-muted);
934 white-space: nowrap;
935 }
936
937 /* ── editor actions ───────────────────────────────────────────── */
938
939 .heartbeat-editor__actions {
940 display: flex;
941 align-items: center;
942 gap: 8px;
943 padding: 24px 0 16px;
944 }
945
946 /* ── scope selector ───────────────────────────────────────────── */
947
948 .heartbeat-editor__scope-row {
949 display: flex;
950 align-items: center;
951 gap: 6px;
952 }
953
954 .heartbeat-scope-btn {
955 display: inline-flex;
956 align-items: center;
957 gap: 5px;
958 height: 32px;
959 padding: 0 12px;
960 font-size: 12px;
961 font-weight: 500;
962 border: 1px solid var(--border);
963 border-radius: 7px;
964 background: var(--bg);
965 color: var(--fg-muted);
966 cursor: pointer;
967 transition: background 0.12s, border-color 0.12s, color 0.12s;
968 box-sizing: border-box;
969 }
970
971 .heartbeat-scope-btn:hover {
972 background: var(--hover-bg);
973 border-color: var(--border-focus);
974 }
975
976 .heartbeat-scope-btn--active {
977 background: rgba(128, 128, 128, 0.08);
978 border-color: var(--border);
979 color: var(--fg);
980 }
981
982 /* ── project dropdown ─────────────────────────────────────────── */
983
984 .heartbeat-project-wrap {
985 position: relative;
986 }
987
988 .heartbeat-project-menu {
989 position: absolute;
990 top: calc(100% + 4px);
991 left: 0;
992 z-index: 10;
993 min-width: 220px;
994 max-height: 240px;
995 overflow-y: auto;
996 background: var(--bg);
997 border: 1px solid var(--border);
998 border-radius: 8px;
999 box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
1000 padding: 4px;
1001 }
1002
1003 .heartbeat-project-menu__item {
1004 display: flex;
1005 align-items: center;
1006 justify-content: space-between;
1007 width: 100%;
1008 padding: 7px 10px;
1009 font-size: 12.5px;
1010 border: none;
1011 border-radius: 5px;
1012 background: transparent;
1013 color: var(--fg);
1014 cursor: pointer;
1015 text-align: left;
1016 }
1017
1018 .heartbeat-project-menu__item:hover {
1019 background: var(--hover-bg);
1020 }
1021
1022 .heartbeat-project-menu__item--active {
1023 background: rgba(128, 128, 128, 0.08);
1024 color: var(--accent);
1025 }
1026
1027 .heartbeat-project-menu__current {
1028 font-size: 10px;
1029 color: var(--fg-faint);
1030 margin-left: 8px;
1031 }
1032
1033 .heartbeat-project-menu__empty {
1034 padding: 12px;
1035 text-align: center;
1036 font-size: 12px;
1037 color: var(--fg-faint);
1038 }
1039
1040 /* ── Sidebar header automation button ── */
1041
1042 .sidebar__hb-header {
1043 display: flex;
1044 align-items: center;
1045 padding: 0 12px;
1046 gap: 2px;
1047 }
1048
1049 .sidebar__hb-header--new {
1050 padding-top: 2px;
1051 padding-bottom: 0;
1052 }
1053
1054 .sidebar__hb-add {
1055 display: flex;
1056 align-items: center;
1057 justify-content: center;
1058 width: 24px;
1059 height: 24px;
1060 border: none;
1061 border-radius: 5px;
1062 background: transparent;
1063 color: var(--fg-faint);
1064 cursor: pointer;
1065 flex-shrink: 0;
1066 transition: background 0.12s, color 0.12s;
1067 }
1068
1069 .sidebar__hb-add:hover {
1070 background: var(--hover-bg);
1071 color: var(--fg);
1072 }
1073
1074 .sidebar__hb-btn {
1075 display: flex;
1076 align-items: center;
1077 gap: 9px;
1078 width: 100%;
1079 height: 30px;
1080 padding: 0 8px;
1081 font-size: 13px;
1082 font-weight: 400;
1083 border: none;
1084 border-radius: 7px;
1085 background: transparent;
1086 color: var(--fg-dim);
1087 cursor: pointer;
1088 font-family: inherit;
1089 text-align: left;
1090 transition: color 0.12s, background 0.12s;
1091 }
1092
1093 .sidebar__hb-btn:hover {
1094 background: var(--sidebar-hover);
1095 color: var(--fg);
1096 }
1097
1098 /* ── Project collapsible section ── */
1099
1100 .sidebar__project-section {
1101 margin-top: 8px;
1102 padding: 0 12px;
1103 position: relative;
1104 display: flex;
1105 flex-direction: column;
1106 flex: 1;
1107 min-height: 0;
1108 }
1109
1110 .sidebar__project-section .project-tree__header-title {
1111 display: none;
1112 }
1113
1114 .sidebar__project-section .project-tree__header {
1115 position: absolute;
1116 top: 2px;
1117 right: 12px;
1118 border: none;
1119 padding: 0;
1120 background: transparent;
1121 display: flex;
1122 align-items: center;
1123 gap: 2px;
1124 opacity: 0;
1125 transition: opacity 0.12s;
1126 }
1127
1128 .sidebar__project-section:hover .project-tree__header {
1129 opacity: 1;
1130 }
1131
1132 .sidebar__project-section .project-tree {
1133 --project-tree-edge-gap: 12px;
1134 }
1135
1136 .sidebar__project-section .sidebar__section--projects {
1137 flex: 1;
1138 min-height: 0;
1139 overflow-y: auto;
1140 }
1141
1142 .sidebar__project-section .project-tree > .project-tree__list {
1143 margin: 0;
1144 padding: 0;
1145 }
1146
1147 /* 项目树行与顶部菜单宽度对齐 */
1148 :root[data-theme-style] .sidebar__project-section .project-tree__folder,
1149 :root[data-theme-style] .sidebar__project-section .project-tree__topic {
1150 margin-right: 8px;
1151 }
1152
1153 :root[data-theme-style] .project-tree__search {
1154 margin: 0 12px;
1155 }
1156
1157 :root[data-theme-style] .project-tree__topic {
1158 padding-right: 0;
1159 }
1160
1161 /* 项目文件夹右侧的新建话题按钮悬停显示(上游 styles.css 已内置) */
1162
1163 :root[data-theme-style] .project-tree__topic-label {
1164 font-size: 13px;
1165 font-weight: 400;
1166 }
1167
1168 :root[data-theme-style] .project-tree__folder-label {
1169 font-size: 13px;
1170 font-weight: 400;
1171 }
1172
1173 /* 项目文件夹右侧 + 图标默认隐藏,悬停显示 */
1174 .sidebar__project-section .project-tree__new-topic {
1175 opacity: 0;
1176 pointer-events: none;
1177 transition: opacity 0.12s;
1178 }
1179
1180 .sidebar__project-section .project-tree__folder:hover .project-tree__new-topic,
1181 .sidebar__project-section .project-tree__folder:focus-within .project-tree__new-topic {
1182 opacity: 1;
1183 pointer-events: auto;
1184 }
1185
1186 :root[data-theme-style] .project-tree__topic--active .project-tree__topic-label {
1187 color: var(--fg);
1188 font-weight: 400;
1189 }
1190
1191 .sidebar__project-head {
1192 display: flex;
1193 align-items: center;
1194 gap: 4px;
1195 flex-shrink: 0;
1196 height: 30px;
1197 }
1198
1199 .sidebar__project-header {
1200 display: flex;
1201 align-items: center;
1202 gap: 6px;
1203 height: 30px;
1204 padding: 0 8px;
1205 font-size: 13px;
1206 font-weight: 400;
1207 border: none;
1208 border-radius: 7px;
1209 background: transparent;
1210 color: var(--fg-dim);
1211 cursor: pointer;
1212 font-family: inherit;
1213 text-align: left;
1214 transition: color 0.12s;
1215 }
1216
1217 .sidebar__project-header:hover {
1218 color: var(--fg);
1219 }
1220
1221 .sidebar__hb-label {
1222 flex: 1;
1223 text-align: left;
1224 }
1225
1226 .sidebar__hb-hint {
1227 font-size: 10px;
1228 font-weight: 400;
1229 color: var(--fg-faint);
1230 letter-spacing: normal;
1231 }
1232
1232 lines CSS