@softium/calendar 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1732 @@
1
+ /**
2
+ * @softium/calendar — single-import stylesheet.
3
+ *
4
+ * import '@softium/calendar/styles.css';
5
+ *
6
+ * Shared tokens/theme (@softium/styles) + the calendar component styles.
7
+ */
8
+
9
+ /**
10
+ * softium-ui shared styles — single import.
11
+ *
12
+ * import '@softium/styles';
13
+ *
14
+ * Design tokens + dark theme + a minimal opt-in base layer.
15
+ */
16
+
17
+ /**
18
+ * softium-ui — shared design tokens
19
+ *
20
+ * Theme via CSS custom properties only (no Tailwind hard-dependency, AG-Grid style).
21
+ * Every visual value across the libraries resolves to one of these `--sft-*` vars,
22
+ * so a host app re-skins everything by overriding tokens — nothing else.
23
+ *
24
+ * Naming follows an Apple-adjacent / Phosphor convention: semantic over literal.
25
+ * Package-specific tokens (e.g. `--sft-table-*`) live in their own package.
26
+ */
27
+
28
+ :root {
29
+ /* ── color: neutral ramp ─────────────────────────────── */
30
+ --sft-color-bg: #ffffff;
31
+ --sft-color-bg-subtle: #f7f8fa;
32
+ --sft-color-bg-hover: #f0f2f5;
33
+ --sft-color-bg-selected: #eaf2ff;
34
+ --sft-color-surface: #ffffff;
35
+ --sft-color-border: #e3e6ea;
36
+ --sft-color-border-strong: #c9ced6;
37
+
38
+ /* ── color: text ─────────────────────────────────────── */
39
+ --sft-color-text: #1d2127;
40
+ --sft-color-text-secondary: #5b6470;
41
+ --sft-color-text-muted: #8a93a0;
42
+ --sft-color-text-on-accent: #ffffff;
43
+
44
+ /* ── color: accent / state ───────────────────────────── */
45
+ --sft-color-accent: #2f6bff;
46
+ --sft-color-accent-hover: #1f57e6;
47
+ --sft-color-accent-subtle: #eaf2ff;
48
+ --sft-color-danger: #e5484d;
49
+ --sft-color-success: #30a46c;
50
+ --sft-color-warning: #f2a31b;
51
+
52
+ /* ── typography ──────────────────────────────────────── */
53
+ --sft-font-family: -apple-system, BlinkMacSystemFont, "Pretendard", "Segoe UI", Roboto,
54
+ "Helvetica Neue", Arial, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
55
+ --sft-font-family-mono: "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
56
+ --sft-font-size-xs: 11px;
57
+ --sft-font-size-sm: 12px;
58
+ --sft-font-size-md: 13px;
59
+ --sft-font-size-lg: 15px;
60
+ --sft-font-size-xl: 20px;
61
+ --sft-font-weight-regular: 400;
62
+ --sft-font-weight-medium: 500;
63
+ --sft-font-weight-bold: 600;
64
+ --sft-line-height: 1.45;
65
+
66
+ /* ── spacing (4px base) ──────────────────────────────── */
67
+ --sft-space-1: 4px;
68
+ --sft-space-2: 8px;
69
+ --sft-space-3: 12px;
70
+ --sft-space-4: 16px;
71
+ --sft-space-5: 24px;
72
+ --sft-space-6: 32px;
73
+ --sft-space-7: 48px;
74
+ --sft-space-8: 64px;
75
+
76
+ /* ── radius ──────────────────────────────────────────── */
77
+ --sft-radius-sm: 4px;
78
+ --sft-radius-md: 8px;
79
+ --sft-radius-lg: 12px;
80
+ --sft-radius-full: 9999px;
81
+
82
+ /* ── elevation ───────────────────────────────────────── */
83
+ --sft-shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.06);
84
+ --sft-shadow-md: 0 4px 12px rgba(16, 24, 40, 0.1);
85
+ --sft-shadow-overlay: 0 8px 28px rgba(16, 24, 40, 0.16);
86
+
87
+ /* ── motion ──────────────────────────────────────────── */
88
+ --sft-duration-fast: 120ms;
89
+ --sft-duration-base: 200ms;
90
+ --sft-ease: cubic-bezier(0.2, 0, 0, 1);
91
+
92
+ /* ── shared z-index scale ────────────────────────────── */
93
+ --sft-z-header: 2;
94
+ --sft-z-pinned: 3;
95
+ --sft-z-overlay: 10;
96
+ --sft-z-modal: 100;
97
+ }
98
+
99
+ /**
100
+ * softium-ui — dark theme overrides (shared)
101
+ *
102
+ * Two activation paths:
103
+ * 1. Explicit: <html data-theme="dark"> (host controls the toggle)
104
+ * 2. Automatic: prefers-color-scheme, only when the host hasn't forced a theme
105
+ *
106
+ * Dark mode re-points the SAME `--sft-*` tokens — components never branch on theme.
107
+ */
108
+
109
+ [data-theme="dark"] {
110
+ --sft-color-bg: #16181d;
111
+ --sft-color-bg-subtle: #1c1f26;
112
+ --sft-color-bg-hover: #232730;
113
+ --sft-color-bg-selected: #1e2c4a;
114
+ --sft-color-surface: #1a1d23;
115
+ --sft-color-border: #2a2f38;
116
+ --sft-color-border-strong: #3a414d;
117
+
118
+ --sft-color-text: #eceef2;
119
+ --sft-color-text-secondary: #aab2bf;
120
+ --sft-color-text-muted: #6f7884;
121
+ --sft-color-text-on-accent: #ffffff;
122
+
123
+ --sft-color-accent: #5b8bff;
124
+ --sft-color-accent-hover: #6f9bff;
125
+ --sft-color-accent-subtle: #1e2c4a;
126
+ --sft-color-danger: #ff6166;
127
+ --sft-color-success: #46c98a;
128
+ --sft-color-warning: #f5b542;
129
+
130
+ --sft-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
131
+ --sft-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.45);
132
+ --sft-shadow-overlay: 0 8px 28px rgba(0, 0, 0, 0.55);
133
+ }
134
+
135
+ @media (prefers-color-scheme: dark) {
136
+ :root:not([data-theme="light"]):not([data-theme="dark"]) {
137
+ --sft-color-bg: #16181d;
138
+ --sft-color-bg-subtle: #1c1f26;
139
+ --sft-color-bg-hover: #232730;
140
+ --sft-color-bg-selected: #1e2c4a;
141
+ --sft-color-surface: #1a1d23;
142
+ --sft-color-border: #2a2f38;
143
+ --sft-color-border-strong: #3a414d;
144
+
145
+ --sft-color-text: #eceef2;
146
+ --sft-color-text-secondary: #aab2bf;
147
+ --sft-color-text-muted: #6f7884;
148
+
149
+ --sft-color-accent: #5b8bff;
150
+ --sft-color-accent-hover: #6f9bff;
151
+ --sft-color-accent-subtle: #1e2c4a;
152
+ --sft-color-danger: #ff6166;
153
+ --sft-color-success: #46c98a;
154
+ --sft-color-warning: #f5b542;
155
+ }
156
+ }
157
+
158
+ /**
159
+ * softium-ui — minimal base layer (opt-in).
160
+ *
161
+ * Only sets sane defaults scoped to the app shell, not a global reset, so dropping
162
+ * the library into an existing app doesn't fight the host's own resets.
163
+ */
164
+
165
+ .sft-app {
166
+ color: var(--sft-color-text);
167
+ background: var(--sft-color-bg);
168
+ font-family: var(--sft-font-family);
169
+ font-size: var(--sft-font-size-md);
170
+ line-height: var(--sft-line-height);
171
+ -webkit-font-smoothing: antialiased;
172
+ transition: background var(--sft-duration-base) var(--sft-ease), color var(--sft-duration-base)
173
+ var(--sft-ease);
174
+ }
175
+
176
+ .sft-app *,
177
+ .sft-app *::before,
178
+ .sft-app *::after {
179
+ box-sizing: border-box;
180
+ }
181
+
182
+ /**
183
+ * @softium/calendar — component styles.
184
+ *
185
+ * Token-driven (see @softium/styles): the whole calendar re-skins on theme with
186
+ * zero component churn. Ported from the calendary project's Tailwind styling into
187
+ * plain CSS on the shared --sft-* tokens.
188
+ */
189
+
190
+ :root {
191
+ --sft-cal-accent: var(--sft-color-accent);
192
+ --sft-cal-sun: var(--sft-color-danger);
193
+ --sft-cal-sat: #3b82f6;
194
+ --sft-cal-row-h: 40px;
195
+ --sft-cal-input-h: 36px;
196
+ /* one uniform height for every item inside a month cell: date head,
197
+ period bar, day chip, "+N more", "+ new event". Keep in sync with
198
+ EVENT_H in MonthView.tsx. */
199
+ --sft-cal-event-h: 22px;
200
+ }
201
+
202
+ [data-theme="dark"] {
203
+ --sft-cal-sat: #5b8bff;
204
+ }
205
+
206
+ .sft-cal {
207
+ display: flex;
208
+ flex-direction: column;
209
+ width: 100%;
210
+ height: 100%;
211
+ min-height: 0;
212
+ min-width: 0;
213
+ font-family: var(--sft-font-family);
214
+ font-size: var(--sft-font-size-md);
215
+ color: var(--sft-color-text);
216
+ }
217
+
218
+ /* ── toolbar ─────────────────────────────────────────────── */
219
+
220
+ .sft-cal__toolbar {
221
+ display: flex;
222
+ align-items: center;
223
+ justify-content: space-between;
224
+ gap: var(--sft-space-3);
225
+ flex-wrap: wrap;
226
+ flex: none;
227
+ margin-bottom: var(--sft-space-3);
228
+ }
229
+
230
+ .sft-cal__toolbar-left,
231
+ .sft-cal__toolbar-right {
232
+ display: flex;
233
+ align-items: center;
234
+ gap: var(--sft-space-3);
235
+ }
236
+
237
+ .sft-cal__title {
238
+ margin: 0;
239
+ font-size: 22px;
240
+ font-weight: var(--sft-font-weight-bold);
241
+ color: var(--sft-color-text);
242
+ white-space: nowrap;
243
+ }
244
+
245
+ .sft-cal__nav {
246
+ display: flex;
247
+ align-items: center;
248
+ gap: 2px;
249
+ }
250
+
251
+ .sft-cal__navbtn {
252
+ display: inline-flex;
253
+ align-items: center;
254
+ justify-content: center;
255
+ width: 32px;
256
+ height: 32px;
257
+ border: none;
258
+ border-radius: var(--sft-radius-md);
259
+ background: transparent;
260
+ color: var(--sft-color-text-secondary);
261
+ cursor: pointer;
262
+ transition: background var(--sft-duration-fast) var(--sft-ease);
263
+ }
264
+
265
+ .sft-cal__navbtn:hover {
266
+ background: var(--sft-color-bg-hover);
267
+ color: var(--sft-color-text);
268
+ }
269
+
270
+ .sft-cal__navbtn:disabled {
271
+ opacity: 0.4;
272
+ cursor: default;
273
+ }
274
+
275
+ .sft-cal__navbtn:disabled:hover {
276
+ background: transparent;
277
+ color: var(--sft-color-text-secondary);
278
+ }
279
+
280
+ .sft-cal__search {
281
+ display: flex;
282
+ align-items: center;
283
+ }
284
+
285
+ .sft-cal__searchbox {
286
+ position: relative;
287
+ display: flex;
288
+ align-items: center;
289
+ }
290
+
291
+ .sft-cal__searchicon {
292
+ position: absolute;
293
+ left: 10px;
294
+ color: var(--sft-color-text-muted);
295
+ pointer-events: none;
296
+ }
297
+
298
+ .sft-cal__searchinput {
299
+ height: 32px;
300
+ width: 190px;
301
+ border: 1px solid var(--sft-color-border);
302
+ border-radius: var(--sft-radius-md);
303
+ background: var(--sft-color-surface);
304
+ color: var(--sft-color-text);
305
+ font: inherit;
306
+ font-size: var(--sft-font-size-sm);
307
+ padding: 0 30px 0 30px;
308
+ outline: none;
309
+ }
310
+
311
+ .sft-cal__searchinput:focus {
312
+ border-color: var(--sft-cal-accent);
313
+ }
314
+
315
+ .sft-cal__searchclose {
316
+ position: absolute;
317
+ right: 6px;
318
+ display: inline-flex;
319
+ border: none;
320
+ background: transparent;
321
+ color: var(--sft-color-text-muted);
322
+ cursor: pointer;
323
+ }
324
+
325
+ .sft-cal__searchclose:hover {
326
+ color: var(--sft-color-text);
327
+ }
328
+
329
+ .sft-cal__view {
330
+ flex: 1;
331
+ min-height: 0;
332
+ display: flex;
333
+ flex-direction: column;
334
+ }
335
+
336
+ /* ── buttons ─────────────────────────────────────────────── */
337
+
338
+ .sft-cal-btn {
339
+ display: inline-flex;
340
+ align-items: center;
341
+ justify-content: center;
342
+ gap: var(--sft-space-1);
343
+ height: var(--sft-cal-input-h);
344
+ padding: 0 var(--sft-space-3);
345
+ border: 1px solid transparent;
346
+ border-radius: var(--sft-radius-md);
347
+ background: transparent;
348
+ color: var(--sft-color-text);
349
+ font: inherit;
350
+ font-size: var(--sft-font-size-sm);
351
+ font-weight: var(--sft-font-weight-medium);
352
+ cursor: pointer;
353
+ white-space: nowrap;
354
+ transition: background var(--sft-duration-fast) var(--sft-ease), border-color
355
+ var(--sft-duration-fast) var(--sft-ease), opacity var(--sft-duration-fast) var(--sft-ease);
356
+ }
357
+
358
+ .sft-cal-btn--sm {
359
+ height: 32px;
360
+ padding: 0 var(--sft-space-3);
361
+ }
362
+
363
+ .sft-cal-btn--block {
364
+ flex: 1;
365
+ }
366
+
367
+ .sft-cal-btn--icon {
368
+ width: var(--sft-cal-input-h);
369
+ padding: 0;
370
+ flex: none;
371
+ }
372
+
373
+ .sft-cal-btn:disabled {
374
+ opacity: 0.5;
375
+ cursor: default;
376
+ }
377
+
378
+ .sft-cal-btn--outline {
379
+ border-color: var(--sft-color-border);
380
+ background: var(--sft-color-surface);
381
+ color: var(--sft-color-text);
382
+ }
383
+
384
+ .sft-cal-btn--outline:not(:disabled):hover {
385
+ background: var(--sft-color-bg-hover);
386
+ }
387
+
388
+ .sft-cal-btn--primary {
389
+ background: var(--sft-cal-accent);
390
+ border-color: var(--sft-cal-accent);
391
+ color: var(--sft-color-text-on-accent);
392
+ }
393
+
394
+ .sft-cal-btn--primary:not(:disabled):hover {
395
+ background: var(--sft-color-accent-hover);
396
+ border-color: var(--sft-color-accent-hover);
397
+ }
398
+
399
+ .sft-cal-btn--danger {
400
+ background: var(--sft-color-danger);
401
+ border-color: var(--sft-color-danger);
402
+ color: #fff;
403
+ }
404
+
405
+ .sft-cal-btn--danger:not(:disabled):hover {
406
+ filter: brightness(0.94);
407
+ }
408
+
409
+ /* ── shared field bits ───────────────────────────────────── */
410
+
411
+ .sft-cal-label {
412
+ font-size: var(--sft-font-size-sm);
413
+ color: var(--sft-color-text-muted);
414
+ }
415
+
416
+ .sft-cal-field {
417
+ display: flex;
418
+ flex-direction: column;
419
+ gap: 6px;
420
+ }
421
+
422
+ .sft-cal-input {
423
+ height: var(--sft-cal-input-h);
424
+ box-sizing: border-box;
425
+ padding: 0 var(--sft-space-3);
426
+ border: 1px solid var(--sft-color-border);
427
+ border-radius: var(--sft-radius-md);
428
+ background: var(--sft-color-surface);
429
+ color: var(--sft-color-text);
430
+ font: inherit;
431
+ font-size: var(--sft-font-size-sm);
432
+ outline: none;
433
+ }
434
+
435
+ .sft-cal-input:focus {
436
+ border-color: var(--sft-cal-accent);
437
+ }
438
+
439
+ .sft-cal-input--static {
440
+ display: flex;
441
+ align-items: center;
442
+ background: var(--sft-color-bg-subtle);
443
+ color: var(--sft-color-text-muted);
444
+ }
445
+
446
+ .sft-cal-textarea {
447
+ width: 100%;
448
+ box-sizing: border-box;
449
+ resize: none;
450
+ padding: var(--sft-space-2) var(--sft-space-3);
451
+ border: 1px solid var(--sft-color-border);
452
+ border-radius: var(--sft-radius-md);
453
+ background: var(--sft-color-surface);
454
+ color: var(--sft-color-text);
455
+ font: inherit;
456
+ font-size: var(--sft-font-size-sm);
457
+ outline: none;
458
+ }
459
+
460
+ .sft-cal-textarea:focus {
461
+ border-color: var(--sft-cal-accent);
462
+ }
463
+
464
+ /* checkbox rendered as an iOS switch */
465
+
466
+ .sft-cal-switch {
467
+ appearance: none;
468
+ position: relative;
469
+ width: 34px;
470
+ height: 20px;
471
+ border-radius: var(--sft-radius-full);
472
+ background: var(--sft-color-border-strong);
473
+ cursor: pointer;
474
+ transition: background var(--sft-duration-fast) var(--sft-ease);
475
+ flex: none;
476
+ }
477
+
478
+ .sft-cal-switch::after {
479
+ content: "";
480
+ position: absolute;
481
+ top: 2px;
482
+ left: 2px;
483
+ width: 16px;
484
+ height: 16px;
485
+ border-radius: 50%;
486
+ background: #fff;
487
+ box-shadow: var(--sft-shadow-sm);
488
+ transition: transform var(--sft-duration-fast) var(--sft-ease);
489
+ }
490
+
491
+ .sft-cal-switch:checked {
492
+ background: var(--sft-cal-accent);
493
+ }
494
+
495
+ .sft-cal-switch:checked::after {
496
+ transform: translateX(14px);
497
+ }
498
+
499
+ /* day-of-week color helpers */
500
+
501
+ .sft-cal-sun {
502
+ color: var(--sft-cal-sun);
503
+ }
504
+
505
+ .sft-cal-sat {
506
+ color: var(--sft-cal-sat);
507
+ }
508
+
509
+ /* ── segmented tabs ──────────────────────────────────────── */
510
+
511
+ .sft-cal-seg {
512
+ display: inline-flex;
513
+ height: 36px;
514
+ padding: 4px;
515
+ border-radius: var(--sft-radius-md);
516
+ background: var(--sft-color-bg-subtle);
517
+ }
518
+
519
+ .sft-cal-seg--block {
520
+ display: flex;
521
+ width: 100%;
522
+ }
523
+
524
+ .sft-cal-seg__btn {
525
+ flex: 1;
526
+ border: none;
527
+ background: transparent;
528
+ color: var(--sft-color-text-secondary);
529
+ font: inherit;
530
+ font-size: var(--sft-font-size-md);
531
+ padding: 0 var(--sft-space-5);
532
+ border-radius: var(--sft-radius-sm);
533
+ cursor: pointer;
534
+ white-space: nowrap;
535
+ transition: color var(--sft-duration-fast) var(--sft-ease);
536
+ }
537
+
538
+ .sft-cal-seg--block .sft-cal-seg__btn {
539
+ padding: 0 var(--sft-space-2);
540
+ }
541
+
542
+ .sft-cal-seg__btn:hover {
543
+ color: var(--sft-color-text);
544
+ }
545
+
546
+ .sft-cal-seg__btn[data-active] {
547
+ background: var(--sft-color-surface);
548
+ color: var(--sft-cal-accent);
549
+ font-weight: var(--sft-font-weight-medium);
550
+ box-shadow: var(--sft-shadow-sm);
551
+ }
552
+
553
+ /* ── recurrence editor ───────────────────────────────────── */
554
+
555
+ .sft-cal-recur {
556
+ display: flex;
557
+ flex-direction: column;
558
+ gap: var(--sft-space-2);
559
+ }
560
+
561
+ .sft-cal-recur__block {
562
+ display: flex;
563
+ flex-direction: column;
564
+ gap: 6px;
565
+ }
566
+
567
+ .sft-cal-recur__weekdays {
568
+ display: grid;
569
+ grid-template-columns: repeat(7, 1fr);
570
+ gap: 4px;
571
+ }
572
+
573
+ .sft-cal-recur__weekday {
574
+ height: var(--sft-cal-row-h);
575
+ border: none;
576
+ border-radius: var(--sft-radius-md);
577
+ background: var(--sft-color-bg-subtle);
578
+ color: var(--sft-color-text-secondary);
579
+ font: inherit;
580
+ font-size: var(--sft-font-size-sm);
581
+ cursor: pointer;
582
+ transition: background var(--sft-duration-fast) var(--sft-ease);
583
+ }
584
+
585
+ .sft-cal-recur__weekday:hover {
586
+ background: var(--sft-color-bg-hover);
587
+ }
588
+
589
+ .sft-cal-recur__weekday[data-active] {
590
+ background: var(--sft-cal-accent);
591
+ color: var(--sft-color-text-on-accent);
592
+ }
593
+
594
+ .sft-cal-recur__end {
595
+ display: grid;
596
+ grid-template-columns: 1fr 1fr;
597
+ gap: var(--sft-space-2);
598
+ }
599
+
600
+ .sft-cal-recur__count {
601
+ display: flex;
602
+ align-items: center;
603
+ justify-content: flex-end;
604
+ gap: 6px;
605
+ }
606
+
607
+ .sft-cal-recur__count-input {
608
+ width: 80px;
609
+ }
610
+
611
+ .sft-cal-recur__count-unit {
612
+ font-size: var(--sft-font-size-sm);
613
+ color: var(--sft-color-text-muted);
614
+ }
615
+
616
+ /* ── category rows ───────────────────────────────────────── */
617
+
618
+ .sft-cal-catrow {
619
+ position: relative;
620
+ display: flex;
621
+ align-items: center;
622
+ gap: var(--sft-space-3);
623
+ height: var(--sft-cal-row-h);
624
+ padding: 0 var(--sft-space-3);
625
+ border-radius: var(--sft-radius-md);
626
+ cursor: grab;
627
+ }
628
+
629
+ .sft-cal-catrow:hover {
630
+ background: var(--sft-color-bg-subtle);
631
+ }
632
+
633
+ .sft-cal-catrow--editing {
634
+ border: 2px solid var(--sft-cal-accent);
635
+ cursor: default;
636
+ }
637
+
638
+ .sft-cal-catrow--editing:hover {
639
+ background: transparent;
640
+ }
641
+
642
+ .sft-cal-catrow__main {
643
+ display: flex;
644
+ align-items: center;
645
+ gap: var(--sft-space-3);
646
+ flex: 1;
647
+ min-width: 0;
648
+ border: none;
649
+ background: transparent;
650
+ color: inherit;
651
+ font: inherit;
652
+ text-align: left;
653
+ cursor: pointer;
654
+ padding: 0;
655
+ }
656
+
657
+ .sft-cal-catrow__dot {
658
+ display: inline-flex;
659
+ align-items: center;
660
+ justify-content: center;
661
+ width: 16px;
662
+ height: 16px;
663
+ flex: none;
664
+ border-radius: var(--sft-radius-sm);
665
+ border: 2px solid;
666
+ color: #fff;
667
+ background: transparent;
668
+ }
669
+
670
+ .sft-cal-catrow__dot:not([data-checked]) {
671
+ background: transparent !important;
672
+ }
673
+
674
+ .sft-cal-catrow__name {
675
+ font-size: var(--sft-font-size-md);
676
+ color: var(--sft-color-text);
677
+ overflow: hidden;
678
+ text-overflow: ellipsis;
679
+ white-space: nowrap;
680
+ }
681
+
682
+ .sft-cal-catrow__menu {
683
+ position: relative;
684
+ margin-left: auto;
685
+ }
686
+
687
+ .sft-cal-catrow__menu-trigger {
688
+ display: inline-flex;
689
+ padding: 4px;
690
+ border: none;
691
+ border-radius: var(--sft-radius-sm);
692
+ background: transparent;
693
+ color: var(--sft-color-text-muted);
694
+ cursor: pointer;
695
+ opacity: 0;
696
+ transition: opacity var(--sft-duration-fast) var(--sft-ease);
697
+ }
698
+
699
+ .sft-cal-catrow:hover .sft-cal-catrow__menu-trigger {
700
+ opacity: 1;
701
+ }
702
+
703
+ .sft-cal-catrow__menu-trigger:hover {
704
+ background: var(--sft-color-bg-hover);
705
+ }
706
+
707
+ .sft-cal-catrow__colorwrap {
708
+ position: relative;
709
+ flex: none;
710
+ }
711
+
712
+ .sft-cal-catrow__swatch {
713
+ width: 16px;
714
+ height: 16px;
715
+ border-radius: var(--sft-radius-sm);
716
+ border: 2px solid;
717
+ cursor: pointer;
718
+ transition: transform var(--sft-duration-fast) var(--sft-ease);
719
+ }
720
+
721
+ .sft-cal-catrow__swatch:hover {
722
+ transform: scale(1.1);
723
+ }
724
+
725
+ .sft-cal-catrow__name-input {
726
+ flex: 1;
727
+ min-width: 0;
728
+ height: 28px;
729
+ border: none;
730
+ background: transparent;
731
+ color: var(--sft-color-text);
732
+ font: inherit;
733
+ font-size: var(--sft-font-size-sm);
734
+ outline: none;
735
+ padding: 0;
736
+ }
737
+
738
+ /* color-swatch popover grid (5 columns) */
739
+
740
+ .sft-cal-colorgrid {
741
+ position: absolute;
742
+ top: calc(100% + 6px);
743
+ left: 0;
744
+ z-index: var(--sft-z-modal);
745
+ display: grid;
746
+ grid-template-columns: repeat(5, 1fr);
747
+ gap: var(--sft-space-2);
748
+ padding: var(--sft-space-2);
749
+ background: var(--sft-color-surface);
750
+ border: 1px solid var(--sft-color-border);
751
+ border-radius: var(--sft-radius-md);
752
+ box-shadow: var(--sft-shadow-overlay);
753
+ }
754
+
755
+ .sft-cal-colorgrid__swatch {
756
+ width: 28px;
757
+ height: 28px;
758
+ border: none;
759
+ border-radius: var(--sft-radius-md);
760
+ cursor: pointer;
761
+ transition: transform var(--sft-duration-fast) var(--sft-ease);
762
+ }
763
+
764
+ .sft-cal-colorgrid__swatch:hover {
765
+ transform: scale(1.1);
766
+ }
767
+
768
+ .sft-cal-colorgrid__swatch[data-active] {
769
+ outline: 2px solid var(--sft-cal-accent);
770
+ outline-offset: 2px;
771
+ }
772
+
773
+ /* row context menu */
774
+
775
+ .sft-cal-menu {
776
+ position: absolute;
777
+ top: calc(100% + 2px);
778
+ right: 0;
779
+ z-index: var(--sft-z-modal);
780
+ min-width: 120px;
781
+ padding: var(--sft-space-1);
782
+ background: var(--sft-color-surface);
783
+ border: 1px solid var(--sft-color-border);
784
+ border-radius: var(--sft-radius-md);
785
+ box-shadow: var(--sft-shadow-overlay);
786
+ }
787
+
788
+ .sft-cal-menu__item {
789
+ display: flex;
790
+ align-items: center;
791
+ gap: var(--sft-space-2);
792
+ width: 100%;
793
+ padding: var(--sft-space-2);
794
+ border: none;
795
+ border-radius: var(--sft-radius-sm);
796
+ background: transparent;
797
+ color: var(--sft-color-text);
798
+ font: inherit;
799
+ font-size: var(--sft-font-size-sm);
800
+ text-align: left;
801
+ cursor: pointer;
802
+ }
803
+
804
+ .sft-cal-menu__item:hover {
805
+ background: var(--sft-color-bg-hover);
806
+ }
807
+
808
+ .sft-cal-menu__item--danger {
809
+ color: var(--sft-color-danger);
810
+ }
811
+
812
+ /* ── overlay + modal ─────────────────────────────────────── */
813
+
814
+ .sft-cal-overlay {
815
+ position: fixed;
816
+ inset: 0;
817
+ z-index: var(--sft-z-modal);
818
+ display: flex;
819
+ align-items: center;
820
+ justify-content: center;
821
+ padding: var(--sft-space-4);
822
+ background: rgba(16, 24, 40, 0.28);
823
+ }
824
+
825
+ .sft-cal-modal {
826
+ width: 380px;
827
+ max-width: 100%;
828
+ max-height: 90vh;
829
+ overflow-y: auto;
830
+ box-sizing: border-box;
831
+ display: flex;
832
+ flex-direction: column;
833
+ gap: var(--sft-space-3);
834
+ padding: 20px;
835
+ background: var(--sft-color-surface);
836
+ border: 1px solid var(--sft-color-border);
837
+ border-radius: var(--sft-radius-lg);
838
+ box-shadow: var(--sft-shadow-overlay);
839
+ }
840
+
841
+ .sft-cal-modal__titlewrap {
842
+ position: relative;
843
+ display: flex;
844
+ align-items: center;
845
+ gap: var(--sft-space-3);
846
+ padding-bottom: var(--sft-space-2);
847
+ }
848
+
849
+ .sft-cal-modal__title {
850
+ flex: 1;
851
+ min-width: 0;
852
+ border: none;
853
+ background: transparent;
854
+ color: var(--sft-color-text);
855
+ font: inherit;
856
+ font-size: var(--sft-font-size-xl);
857
+ font-weight: var(--sft-font-weight-bold);
858
+ outline: none;
859
+ padding: 0;
860
+ }
861
+
862
+ .sft-cal-modal__title::placeholder {
863
+ color: var(--sft-color-text-muted);
864
+ opacity: 0.5;
865
+ }
866
+
867
+ .sft-cal-modal__close {
868
+ display: inline-flex;
869
+ align-items: center;
870
+ justify-content: center;
871
+ width: 30px;
872
+ height: 30px;
873
+ flex: none;
874
+ border: none;
875
+ border-radius: var(--sft-radius-md);
876
+ background: var(--sft-color-bg-subtle);
877
+ color: var(--sft-color-text-muted);
878
+ cursor: pointer;
879
+ }
880
+
881
+ .sft-cal-modal__close:hover {
882
+ background: var(--sft-color-bg-hover);
883
+ color: var(--sft-color-text);
884
+ }
885
+
886
+ .sft-cal-modal__underline {
887
+ position: absolute;
888
+ bottom: 0;
889
+ left: 0;
890
+ right: 0;
891
+ height: 1px;
892
+ background: var(--sft-color-border);
893
+ transition: background var(--sft-duration-base) var(--sft-ease);
894
+ }
895
+
896
+ .sft-cal-modal__underline[data-active] {
897
+ background: var(--sft-cal-accent);
898
+ }
899
+
900
+ .sft-cal-modal__repeat {
901
+ display: flex;
902
+ align-items: center;
903
+ justify-content: flex-end;
904
+ gap: 6px;
905
+ font-size: var(--sft-font-size-sm);
906
+ color: var(--sft-color-text-muted);
907
+ cursor: pointer;
908
+ }
909
+
910
+ .sft-cal-modal__grid2 {
911
+ display: grid;
912
+ grid-template-columns: 1fr 1fr;
913
+ gap: var(--sft-space-2);
914
+ }
915
+
916
+ .sft-cal-modal__category {
917
+ display: flex;
918
+ flex-direction: column;
919
+ gap: 6px;
920
+ }
921
+
922
+ .sft-cal-modal__cathead {
923
+ display: flex;
924
+ align-items: center;
925
+ justify-content: space-between;
926
+ }
927
+
928
+ .sft-cal-modal__catlist {
929
+ max-height: 240px;
930
+ overflow-y: auto;
931
+ }
932
+
933
+ .sft-cal-modal__ghostrow {
934
+ display: flex;
935
+ align-items: center;
936
+ gap: var(--sft-space-3);
937
+ width: 100%;
938
+ height: var(--sft-cal-row-h);
939
+ padding: 0 var(--sft-space-3);
940
+ border: none;
941
+ border-radius: var(--sft-radius-md);
942
+ background: transparent;
943
+ color: var(--sft-color-text-muted);
944
+ font: inherit;
945
+ font-size: var(--sft-font-size-sm);
946
+ text-align: left;
947
+ cursor: pointer;
948
+ transition: background var(--sft-duration-fast) var(--sft-ease), color var(--sft-duration-fast)
949
+ var(--sft-ease);
950
+ }
951
+
952
+ .sft-cal-modal__ghostrow:hover {
953
+ background: var(--sft-color-bg-subtle);
954
+ color: var(--sft-cal-accent);
955
+ }
956
+
957
+ .sft-cal-modal__collapse {
958
+ display: inline-flex;
959
+ align-items: center;
960
+ gap: 4px;
961
+ border: none;
962
+ background: transparent;
963
+ color: var(--sft-color-text-muted);
964
+ font: inherit;
965
+ font-size: var(--sft-font-size-sm);
966
+ cursor: pointer;
967
+ }
968
+
969
+ .sft-cal-modal__collapse:hover {
970
+ color: var(--sft-cal-accent);
971
+ }
972
+
973
+ .sft-cal-modal__divider {
974
+ border-top: 1px dashed var(--sft-color-border);
975
+ margin: var(--sft-space-1) 0;
976
+ }
977
+
978
+ .sft-cal-modal__actions {
979
+ display: flex;
980
+ gap: var(--sft-space-2);
981
+ }
982
+
983
+ /* ── confirm / delete-scope dialog ───────────────────────── */
984
+
985
+ .sft-cal-confirm {
986
+ width: 320px;
987
+ max-width: 100%;
988
+ box-sizing: border-box;
989
+ padding: 20px;
990
+ background: var(--sft-color-surface);
991
+ border: 1px solid var(--sft-color-border);
992
+ border-radius: var(--sft-radius-lg);
993
+ box-shadow: var(--sft-shadow-overlay);
994
+ }
995
+
996
+ .sft-cal-confirm__title {
997
+ font-size: var(--sft-font-size-lg);
998
+ font-weight: var(--sft-font-weight-bold);
999
+ text-align: center;
1000
+ margin-bottom: var(--sft-space-2);
1001
+ }
1002
+
1003
+ .sft-cal-confirm__options {
1004
+ display: flex;
1005
+ flex-direction: column;
1006
+ gap: 6px;
1007
+ padding: var(--sft-space-2) 0;
1008
+ }
1009
+
1010
+ .sft-cal-confirm__actions {
1011
+ display: flex;
1012
+ gap: var(--sft-space-2);
1013
+ padding-top: var(--sft-space-2);
1014
+ }
1015
+
1016
+ .sft-cal-delopt {
1017
+ display: flex;
1018
+ align-items: center;
1019
+ gap: var(--sft-space-2);
1020
+ width: 100%;
1021
+ padding: 10px var(--sft-space-3);
1022
+ border: 1px solid transparent;
1023
+ border-radius: var(--sft-radius-md);
1024
+ background: transparent;
1025
+ color: var(--sft-color-text);
1026
+ font: inherit;
1027
+ font-size: var(--sft-font-size-sm);
1028
+ text-align: left;
1029
+ cursor: pointer;
1030
+ }
1031
+
1032
+ .sft-cal-delopt:hover {
1033
+ background: var(--sft-color-bg-subtle);
1034
+ }
1035
+
1036
+ .sft-cal-delopt[data-active] {
1037
+ background: color-mix(in srgb, var(--sft-color-danger) 10%, var(--sft-color-surface));
1038
+ border-color: color-mix(in srgb, var(--sft-color-danger) 30%, transparent);
1039
+ color: var(--sft-color-danger);
1040
+ }
1041
+
1042
+ .sft-cal-delopt__radio {
1043
+ width: 16px;
1044
+ height: 16px;
1045
+ flex: none;
1046
+ border-radius: 50%;
1047
+ border: 2px solid var(--sft-color-border-strong);
1048
+ position: relative;
1049
+ }
1050
+
1051
+ .sft-cal-delopt[data-active] .sft-cal-delopt__radio {
1052
+ border-color: var(--sft-color-danger);
1053
+ }
1054
+
1055
+ .sft-cal-delopt[data-active] .sft-cal-delopt__radio::after {
1056
+ content: "";
1057
+ position: absolute;
1058
+ inset: 3px;
1059
+ border-radius: 50%;
1060
+ background: var(--sft-color-danger);
1061
+ }
1062
+
1063
+ /* non-destructive variant (e.g. the recurring-event move scope picker) —
1064
+ same shape, primary accent color instead of danger red */
1065
+
1066
+ .sft-cal-delopt--accent[data-active] {
1067
+ background: color-mix(in srgb, var(--sft-cal-accent) 10%, var(--sft-color-surface));
1068
+ border-color: color-mix(in srgb, var(--sft-cal-accent) 30%, transparent);
1069
+ color: var(--sft-cal-accent);
1070
+ }
1071
+
1072
+ .sft-cal-delopt--accent[data-active] .sft-cal-delopt__radio {
1073
+ border-color: var(--sft-cal-accent);
1074
+ }
1075
+
1076
+ .sft-cal-delopt--accent[data-active] .sft-cal-delopt__radio::after {
1077
+ background: var(--sft-cal-accent);
1078
+ }
1079
+
1080
+ /* ── category filter (header popover) ────────────────────── */
1081
+
1082
+ .sft-cal-catfilter {
1083
+ position: relative;
1084
+ }
1085
+
1086
+ .sft-cal-catfilter__trigger {
1087
+ display: inline-flex;
1088
+ align-items: center;
1089
+ justify-content: space-between;
1090
+ gap: var(--sft-space-2);
1091
+ width: 220px;
1092
+ height: 36px;
1093
+ padding: 0 var(--sft-space-4);
1094
+ border: 1px solid var(--sft-color-border);
1095
+ border-radius: var(--sft-radius-md);
1096
+ background: var(--sft-color-surface);
1097
+ color: var(--sft-color-text);
1098
+ font: inherit;
1099
+ font-size: var(--sft-font-size-sm);
1100
+ font-weight: var(--sft-font-weight-medium);
1101
+ cursor: pointer;
1102
+ }
1103
+
1104
+ .sft-cal-catfilter__trigger:hover {
1105
+ background: var(--sft-color-bg-hover);
1106
+ }
1107
+
1108
+ .sft-cal-catfilter__popover {
1109
+ position: absolute;
1110
+ top: calc(100% + 4px);
1111
+ right: 0;
1112
+ z-index: var(--sft-z-modal);
1113
+ width: 240px;
1114
+ padding: var(--sft-space-1);
1115
+ background: var(--sft-color-surface);
1116
+ border: 1px solid var(--sft-color-border);
1117
+ border-radius: var(--sft-radius-md);
1118
+ box-shadow: var(--sft-shadow-overlay);
1119
+ }
1120
+
1121
+ .sft-cal-catfilter__list {
1122
+ max-height: 320px;
1123
+ overflow-y: auto;
1124
+ }
1125
+
1126
+ /* ── month view ──────────────────────────────────────────── */
1127
+
1128
+ .sft-cal-month {
1129
+ flex: 1;
1130
+ min-height: 0;
1131
+ display: flex;
1132
+ flex-direction: column;
1133
+ border: 1px solid var(--sft-color-border);
1134
+ border-radius: var(--sft-radius-sm);
1135
+ overflow: hidden;
1136
+ }
1137
+
1138
+ .sft-cal-month__weekdays {
1139
+ display: grid;
1140
+ grid-template-columns: repeat(7, 1fr);
1141
+ border-bottom: 1px solid var(--sft-color-border);
1142
+ background: var(--sft-color-bg-subtle);
1143
+ flex: none;
1144
+ }
1145
+
1146
+ .sft-cal-month__weekday {
1147
+ padding: 2px 12px;
1148
+ text-align: right;
1149
+ font-size: var(--sft-font-size-sm);
1150
+ font-weight: var(--sft-font-weight-medium);
1151
+ color: var(--sft-color-text-secondary);
1152
+ border-right: 1px solid var(--sft-color-border);
1153
+ }
1154
+
1155
+ .sft-cal-month__weekday:last-child {
1156
+ border-right: none;
1157
+ }
1158
+
1159
+ .sft-cal-month__grid {
1160
+ display: grid;
1161
+ grid-template-columns: repeat(7, 1fr);
1162
+ flex: 1;
1163
+ min-height: 0;
1164
+ overflow: auto;
1165
+ }
1166
+
1167
+ .sft-cal-month__cell {
1168
+ position: relative;
1169
+ display: flex;
1170
+ flex-direction: column;
1171
+ min-height: 100px;
1172
+ user-select: none;
1173
+ background: var(--sft-color-bg);
1174
+ border-right: 1px solid var(--sft-color-border);
1175
+ border-bottom: 1px solid var(--sft-color-border);
1176
+ }
1177
+
1178
+ .sft-cal-month__cell[data-lastcol] {
1179
+ border-right: none;
1180
+ }
1181
+
1182
+ .sft-cal-month__cell[data-lastrow] {
1183
+ border-bottom: none;
1184
+ }
1185
+
1186
+ .sft-cal-month__cell[data-weekend] {
1187
+ background: var(--sft-color-bg-subtle);
1188
+ }
1189
+
1190
+ /* drag-to-move target day highlight — a plain outline, not a fill, so it
1191
+ never competes with the uniform-height item backgrounds inside the cell */
1192
+
1193
+ .sft-cal-month__cell[data-movetarget] {
1194
+ box-shadow: inset 0 0 0 2px var(--sft-cal-accent);
1195
+ }
1196
+
1197
+ .sft-cal-month__cell:focus-visible {
1198
+ outline: 2px solid var(--sft-cal-accent);
1199
+ outline-offset: -2px;
1200
+ }
1201
+
1202
+ .sft-cal-month__cellhead {
1203
+ display: flex;
1204
+ justify-content: flex-end;
1205
+ align-items: center;
1206
+ gap: 4px;
1207
+ flex: none;
1208
+ height: var(--sft-cal-event-h);
1209
+ margin: 2px 4px 1px 4px;
1210
+ }
1211
+
1212
+ .sft-cal-month__holiday {
1213
+ flex: 1;
1214
+ min-width: 0;
1215
+ overflow: hidden;
1216
+ text-overflow: ellipsis;
1217
+ white-space: nowrap;
1218
+ font-size: var(--sft-font-size-sm);
1219
+ color: var(--sft-cal-sun);
1220
+ }
1221
+
1222
+ .sft-cal-month__num {
1223
+ display: inline-flex;
1224
+ align-items: center;
1225
+ justify-content: center;
1226
+ width: 20px;
1227
+ height: 20px;
1228
+ font-size: var(--sft-font-size-md);
1229
+ color: var(--sft-color-text);
1230
+ }
1231
+
1232
+ .sft-cal-month__num--dim {
1233
+ color: var(--sft-color-text-muted);
1234
+ opacity: 0.6;
1235
+ }
1236
+
1237
+ .sft-cal-month__num--today {
1238
+ background: var(--sft-cal-accent);
1239
+ color: var(--sft-color-text-on-accent);
1240
+ border-radius: 50%;
1241
+ }
1242
+
1243
+ .sft-cal-month__events {
1244
+ flex: 1;
1245
+ position: relative;
1246
+ overflow: hidden;
1247
+ }
1248
+
1249
+ .sft-cal-month__bar {
1250
+ position: absolute;
1251
+ left: 0;
1252
+ right: 0;
1253
+ height: var(--sft-cal-event-h);
1254
+ display: flex;
1255
+ align-items: center;
1256
+ gap: 4px;
1257
+ cursor: pointer;
1258
+ overflow: hidden;
1259
+ transition: opacity var(--sft-duration-fast) var(--sft-ease);
1260
+ }
1261
+
1262
+ .sft-cal-month__bar:hover {
1263
+ opacity: 0.9;
1264
+ }
1265
+
1266
+ .sft-cal-month__bar[data-movable]:active,
1267
+ .sft-cal-month__chip[data-movable]:active {
1268
+ cursor: grabbing;
1269
+ }
1270
+
1271
+ .sft-cal-month__bar:focus-visible,
1272
+ .sft-cal-month__chip:focus-visible {
1273
+ outline: 2px solid var(--sft-cal-accent);
1274
+ outline-offset: -2px;
1275
+ }
1276
+
1277
+ /* left/right edges of a period bar's start/end day segment — drag to resize
1278
+ the date range, widened past the visual edge for an easier grab */
1279
+
1280
+ .sft-cal-month__bar-resize {
1281
+ position: absolute;
1282
+ top: 0;
1283
+ bottom: 0;
1284
+ width: 7px;
1285
+ cursor: col-resize;
1286
+ }
1287
+
1288
+ .sft-cal-month__bar-resize--left {
1289
+ left: -3px;
1290
+ }
1291
+
1292
+ .sft-cal-month__bar-resize--right {
1293
+ right: -3px;
1294
+ }
1295
+
1296
+ .sft-cal-month__bar-title {
1297
+ display: flex;
1298
+ align-items: center;
1299
+ gap: 4px;
1300
+ flex: 1;
1301
+ min-width: 0;
1302
+ font-size: var(--sft-font-size-md);
1303
+ overflow: hidden;
1304
+ text-overflow: ellipsis;
1305
+ white-space: nowrap;
1306
+ }
1307
+
1308
+ .sft-cal-month__chip {
1309
+ position: relative;
1310
+ display: flex;
1311
+ align-items: center;
1312
+ gap: 4px;
1313
+ height: var(--sft-cal-event-h);
1314
+ flex: none;
1315
+ padding: 0 8px 0 4px;
1316
+ border-radius: var(--sft-radius-sm);
1317
+ cursor: pointer;
1318
+ }
1319
+
1320
+ .sft-cal-month__chip:hover {
1321
+ background: var(--sft-color-bg-hover);
1322
+ }
1323
+
1324
+ .sft-cal-month__chip--preview {
1325
+ opacity: 0.5;
1326
+ }
1327
+
1328
+ .sft-cal-month__chip-bar {
1329
+ width: 4px;
1330
+ height: 14px;
1331
+ flex: none;
1332
+ border-radius: var(--sft-radius-full);
1333
+ }
1334
+
1335
+ .sft-cal-month__chip-title {
1336
+ flex: 1;
1337
+ min-width: 0;
1338
+ font-size: var(--sft-font-size-md);
1339
+ color: var(--sft-color-text);
1340
+ overflow: hidden;
1341
+ text-overflow: ellipsis;
1342
+ white-space: nowrap;
1343
+ }
1344
+
1345
+ .sft-cal-month__chip-icon {
1346
+ color: var(--sft-color-text-muted);
1347
+ flex: none;
1348
+ }
1349
+
1350
+ .sft-cal-month__chip-time {
1351
+ font-size: var(--sft-font-size-sm);
1352
+ color: var(--sft-color-text-muted);
1353
+ flex: none;
1354
+ }
1355
+
1356
+ .sft-cal-month__more {
1357
+ display: flex;
1358
+ align-items: center;
1359
+ flex: none;
1360
+ height: var(--sft-cal-event-h);
1361
+ padding: 0 4px;
1362
+ border: none;
1363
+ border-radius: var(--sft-radius-sm);
1364
+ background: transparent;
1365
+ color: var(--sft-cal-accent);
1366
+ font: inherit;
1367
+ font-size: var(--sft-font-size-md);
1368
+ font-weight: var(--sft-font-weight-medium);
1369
+ text-align: left;
1370
+ cursor: pointer;
1371
+ }
1372
+
1373
+ .sft-cal-month__more:hover {
1374
+ background: var(--sft-color-bg-hover);
1375
+ }
1376
+
1377
+ /* drag-to-create preview: mirrors the "+ new event" add button, spanning the
1378
+ dragged days as one growing bar */
1379
+
1380
+ .sft-cal-month__bar--drag {
1381
+ background: var(--sft-color-bg-subtle);
1382
+ color: var(--sft-color-text-muted);
1383
+ box-shadow: inset 0 0 0 1px var(--sft-color-border);
1384
+ pointer-events: none;
1385
+ }
1386
+
1387
+ .sft-cal-month__add {
1388
+ display: flex;
1389
+ align-items: center;
1390
+ gap: 4px;
1391
+ height: var(--sft-cal-event-h);
1392
+ margin: 1px 4px 0 4px;
1393
+ padding: 0 8px;
1394
+ border: none;
1395
+ border-radius: var(--sft-radius-sm);
1396
+ background: var(--sft-color-bg-subtle);
1397
+ color: var(--sft-color-text-muted);
1398
+ font: inherit;
1399
+ font-size: var(--sft-font-size-md);
1400
+ font-weight: var(--sft-font-weight-medium);
1401
+ cursor: pointer;
1402
+ opacity: 0;
1403
+ transition: opacity var(--sft-duration-fast) var(--sft-ease);
1404
+ }
1405
+
1406
+ .sft-cal-month__cell:hover .sft-cal-month__add {
1407
+ opacity: 1;
1408
+ }
1409
+
1410
+ /* ── time grid (week / day) ──────────────────────────────── */
1411
+
1412
+ .sft-cal-timegrid {
1413
+ display: grid;
1414
+ flex: 1;
1415
+ min-height: 0;
1416
+ border: 1px solid var(--sft-color-border);
1417
+ border-radius: var(--sft-radius-sm);
1418
+ overflow: hidden;
1419
+ grid-template-rows: auto 1fr;
1420
+ }
1421
+
1422
+ .sft-cal-timegrid--week {
1423
+ grid-template-columns: 64px repeat(7, 1fr);
1424
+ }
1425
+
1426
+ .sft-cal-timegrid--day {
1427
+ grid-template-columns: 64px 1fr;
1428
+ }
1429
+
1430
+ .sft-cal-timegrid__corner {
1431
+ border-bottom: 1px solid var(--sft-color-border);
1432
+ border-right: 1px solid var(--sft-color-border);
1433
+ background: var(--sft-color-bg-subtle);
1434
+ }
1435
+
1436
+ .sft-cal-timegrid__colhead {
1437
+ padding: 2px 8px;
1438
+ text-align: center;
1439
+ background: var(--sft-color-bg-subtle);
1440
+ border-bottom: 1px solid var(--sft-color-border);
1441
+ border-right: 1px solid var(--sft-color-border);
1442
+ }
1443
+
1444
+ .sft-cal-timegrid__colhead:last-child {
1445
+ border-right: none;
1446
+ }
1447
+
1448
+ /* cross-day drag target — a plain outline, matching the month view's
1449
+ [data-movetarget] cell highlight */
1450
+
1451
+ .sft-cal-timegrid__colhead[data-movetarget] {
1452
+ box-shadow: inset 0 0 0 2px var(--sft-cal-accent);
1453
+ }
1454
+
1455
+ .sft-cal-timegrid__daylabel {
1456
+ font-size: var(--sft-font-size-md);
1457
+ color: var(--sft-color-text-secondary);
1458
+ }
1459
+
1460
+ .sft-cal-timegrid__daylabel[data-today] {
1461
+ color: var(--sft-cal-accent);
1462
+ font-weight: var(--sft-font-weight-medium);
1463
+ }
1464
+
1465
+ .sft-cal-timegrid__hours {
1466
+ position: relative;
1467
+ border-right: 1px solid var(--sft-color-border);
1468
+ background: var(--sft-color-bg-subtle);
1469
+ overflow: hidden;
1470
+ }
1471
+
1472
+ .sft-cal-timegrid__hour {
1473
+ height: calc(100% / 24);
1474
+ padding: 2px 8px;
1475
+ box-sizing: border-box;
1476
+ border-bottom: 1px solid var(--sft-color-border);
1477
+ }
1478
+
1479
+ .sft-cal-timegrid__hour:last-child {
1480
+ border-bottom: none;
1481
+ }
1482
+
1483
+ .sft-cal-timegrid__hourlabel {
1484
+ font-size: var(--sft-font-size-xs);
1485
+ color: var(--sft-color-text-muted);
1486
+ }
1487
+
1488
+ .sft-cal-timegrid__col {
1489
+ position: relative;
1490
+ border-right: 1px solid var(--sft-color-border);
1491
+ overflow: hidden;
1492
+ }
1493
+
1494
+ .sft-cal-timegrid__col:last-child {
1495
+ border-right: none;
1496
+ }
1497
+
1498
+ .sft-cal-timegrid__slot {
1499
+ display: block;
1500
+ width: 100%;
1501
+ height: calc(100% / 24);
1502
+ border: none;
1503
+ border-bottom: 1px solid var(--sft-color-border);
1504
+ background: transparent;
1505
+ cursor: pointer;
1506
+ padding: 0;
1507
+ }
1508
+
1509
+ .sft-cal-timegrid__slot:hover {
1510
+ background: var(--sft-color-bg-subtle);
1511
+ }
1512
+
1513
+ .sft-cal-timeevent {
1514
+ position: absolute;
1515
+ border-radius: 4px;
1516
+ padding: 2px 6px;
1517
+ box-sizing: border-box;
1518
+ min-height: 20px;
1519
+ overflow: hidden;
1520
+ cursor: pointer;
1521
+ display: flex;
1522
+ align-items: center;
1523
+ transition: opacity var(--sft-duration-fast) var(--sft-ease);
1524
+ }
1525
+
1526
+ .sft-cal-timeevent:hover {
1527
+ opacity: 0.85;
1528
+ }
1529
+
1530
+ .sft-cal-timeevent[data-editing] {
1531
+ opacity: 0.5;
1532
+ }
1533
+
1534
+ .sft-cal-timeevent:focus-visible {
1535
+ outline: 2px solid var(--sft-cal-accent);
1536
+ outline-offset: 1px;
1537
+ }
1538
+
1539
+ .sft-cal-timeevent__label {
1540
+ display: flex;
1541
+ align-items: center;
1542
+ gap: 6px;
1543
+ min-width: 0;
1544
+ font-size: var(--sft-font-size-md);
1545
+ font-weight: var(--sft-font-weight-medium);
1546
+ }
1547
+
1548
+ .sft-cal-timeevent__title {
1549
+ overflow: hidden;
1550
+ text-overflow: ellipsis;
1551
+ white-space: nowrap;
1552
+ }
1553
+
1554
+ .sft-cal-timeevent[data-movable] {
1555
+ cursor: grab;
1556
+ /* week/day move+resize track via column geometry (works under touch); claim
1557
+ the drag gesture on the chip so a touch on it drags instead of scrolling */
1558
+ touch-action: none;
1559
+ }
1560
+
1561
+ .sft-cal-timeevent[data-movable]:active {
1562
+ cursor: grabbing;
1563
+ }
1564
+
1565
+ /* top/bottom resize handles — thin strips that widen the hit target past the
1566
+ 1-2px visual edge, shown only on non-recurring (movable) events */
1567
+
1568
+ .sft-cal-timeevent__resize {
1569
+ position: absolute;
1570
+ left: 0;
1571
+ right: 0;
1572
+ height: 6px;
1573
+ cursor: row-resize;
1574
+ touch-action: none;
1575
+ }
1576
+
1577
+ .sft-cal-timeevent__resize--top {
1578
+ top: -3px;
1579
+ }
1580
+
1581
+ .sft-cal-timeevent__resize--bottom {
1582
+ bottom: -3px;
1583
+ }
1584
+
1585
+ /* coarse pointers (touch/pen) need bigger targets than the 6px resize strips */
1586
+
1587
+ @media (pointer: coarse) {
1588
+ .sft-cal-timeevent__resize {
1589
+ height: 14px;
1590
+ }
1591
+ .sft-cal-timeevent__resize--top {
1592
+ top: -7px;
1593
+ }
1594
+ .sft-cal-timeevent__resize--bottom {
1595
+ bottom: -7px;
1596
+ }
1597
+ }
1598
+
1599
+ /* drag-to-create draft bar: mirrors the month view's "+ new event" ghost —
1600
+ plain outline, not a category color, since no category is chosen yet */
1601
+
1602
+ .sft-cal-timeevent--draft {
1603
+ background: var(--sft-color-bg-subtle);
1604
+ color: var(--sft-color-text-muted);
1605
+ box-shadow: inset 0 0 0 1px var(--sft-color-border);
1606
+ pointer-events: none;
1607
+ }
1608
+
1609
+ .sft-cal-timeevent--draft .sft-cal-timeevent__title {
1610
+ color: var(--sft-color-text-muted);
1611
+ }
1612
+
1613
+ /* ── year view ───────────────────────────────────────────── */
1614
+
1615
+ .sft-cal-year {
1616
+ flex: 1;
1617
+ min-height: 0;
1618
+ overflow: auto;
1619
+ }
1620
+
1621
+ .sft-cal-year__grid {
1622
+ display: grid;
1623
+ grid-template-columns: repeat(4, 1fr);
1624
+ gap: var(--sft-space-2);
1625
+ }
1626
+
1627
+ .sft-cal-year__cell {
1628
+ border: 1px solid var(--sft-color-border);
1629
+ border-radius: var(--sft-radius-sm);
1630
+ padding: var(--sft-space-2) var(--sft-space-3);
1631
+ }
1632
+
1633
+ .sft-cal-mini {
1634
+ display: flex;
1635
+ flex-direction: column;
1636
+ gap: 4px;
1637
+ }
1638
+
1639
+ .sft-cal-mini__head {
1640
+ display: flex;
1641
+ align-items: center;
1642
+ justify-content: space-between;
1643
+ padding: 0 var(--sft-space-2);
1644
+ }
1645
+
1646
+ .sft-cal-mini__title {
1647
+ margin: 0;
1648
+ font-size: var(--sft-font-size-lg);
1649
+ font-weight: var(--sft-font-weight-bold);
1650
+ }
1651
+
1652
+ .sft-cal-mini__count {
1653
+ font-size: var(--sft-font-size-xs);
1654
+ color: var(--sft-color-text-muted);
1655
+ }
1656
+
1657
+ .sft-cal-mini__weekdays,
1658
+ .sft-cal-mini__grid {
1659
+ display: grid;
1660
+ grid-template-columns: repeat(7, 1fr);
1661
+ gap: 1px;
1662
+ }
1663
+
1664
+ .sft-cal-mini__weekday {
1665
+ height: 20px;
1666
+ display: flex;
1667
+ align-items: center;
1668
+ justify-content: center;
1669
+ font-size: var(--sft-font-size-xs);
1670
+ font-weight: var(--sft-font-weight-medium);
1671
+ color: var(--sft-color-text-muted);
1672
+ }
1673
+
1674
+ .sft-cal-mini__day {
1675
+ position: relative;
1676
+ height: 34px;
1677
+ display: flex;
1678
+ flex-direction: column;
1679
+ align-items: center;
1680
+ padding-top: 2px;
1681
+ border: none;
1682
+ border-radius: var(--sft-radius-sm);
1683
+ background: transparent;
1684
+ color: var(--sft-color-text);
1685
+ font: inherit;
1686
+ font-size: var(--sft-font-size-sm);
1687
+ cursor: pointer;
1688
+ }
1689
+
1690
+ .sft-cal-mini__day:hover:not([data-empty]) {
1691
+ background: var(--sft-color-bg-subtle);
1692
+ }
1693
+
1694
+ .sft-cal-mini__day[data-empty] {
1695
+ visibility: hidden;
1696
+ cursor: default;
1697
+ }
1698
+
1699
+ .sft-cal-mini__day[data-today] {
1700
+ background: color-mix(in srgb, var(--sft-cal-accent) 16%, transparent);
1701
+ color: var(--sft-cal-accent);
1702
+ font-weight: var(--sft-font-weight-medium);
1703
+ }
1704
+
1705
+ .sft-cal-mini__dots {
1706
+ display: flex;
1707
+ gap: 2px;
1708
+ margin-top: 2px;
1709
+ }
1710
+
1711
+ .sft-cal-mini__dot {
1712
+ width: 4px;
1713
+ height: 4px;
1714
+ border-radius: 50%;
1715
+ }
1716
+
1717
+ /* ── responsive ──────────────────────────────────────────── */
1718
+
1719
+ @media (max-width: 900px) {
1720
+ .sft-cal-year__grid {
1721
+ grid-template-columns: repeat(3, 1fr);
1722
+ }
1723
+ }
1724
+
1725
+ @media (max-width: 640px) {
1726
+ .sft-cal-year__grid {
1727
+ grid-template-columns: repeat(2, 1fr);
1728
+ }
1729
+ .sft-cal-catfilter__trigger {
1730
+ width: 160px;
1731
+ }
1732
+ }