@linked.cm/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.
Files changed (44) hide show
  1. package/LICENSE +12 -0
  2. package/README.md +48 -0
  3. package/THIRD_PARTY_NOTICES.md +12 -0
  4. package/lib/esm/Calendar.d.ts +57 -0
  5. package/lib/esm/Calendar.js +202 -0
  6. package/lib/esm/Calendar.js.map +1 -0
  7. package/lib/esm/Calendar.module.css +912 -0
  8. package/lib/esm/EventPopover.d.ts +17 -0
  9. package/lib/esm/EventPopover.js +104 -0
  10. package/lib/esm/EventPopover.js.map +1 -0
  11. package/lib/esm/ResourceGrid.d.ts +11 -0
  12. package/lib/esm/ResourceGrid.js +36 -0
  13. package/lib/esm/ResourceGrid.js.map +1 -0
  14. package/lib/esm/TimeGrid.d.ts +15 -0
  15. package/lib/esm/TimeGrid.js +276 -0
  16. package/lib/esm/TimeGrid.js.map +1 -0
  17. package/lib/esm/index.d.ts +10 -0
  18. package/lib/esm/index.js +12 -0
  19. package/lib/esm/index.js.map +1 -0
  20. package/lib/esm/package.d.ts +8 -0
  21. package/lib/esm/package.js +10 -0
  22. package/lib/esm/package.js.map +1 -0
  23. package/lib/esm/range.d.ts +3 -0
  24. package/lib/esm/range.js +22 -0
  25. package/lib/esm/range.js.map +1 -0
  26. package/lib/esm/recurrence.d.ts +14 -0
  27. package/lib/esm/recurrence.js +60 -0
  28. package/lib/esm/recurrence.js.map +1 -0
  29. package/lib/esm/refreshBus.d.ts +10 -0
  30. package/lib/esm/refreshBus.js +25 -0
  31. package/lib/esm/refreshBus.js.map +1 -0
  32. package/lib/esm/styles.d.ts +4 -0
  33. package/lib/esm/translations/en.json +49 -0
  34. package/lib/esm/translations.d.ts +56 -0
  35. package/lib/esm/translations.js +44 -0
  36. package/lib/esm/translations.js.map +1 -0
  37. package/lib/esm/types.d.ts +97 -0
  38. package/lib/esm/types.js +11 -0
  39. package/lib/esm/types.js.map +1 -0
  40. package/lib/esm/tz.d.ts +30 -0
  41. package/lib/esm/tz.js +78 -0
  42. package/lib/esm/tz.js.map +1 -0
  43. package/package.json +98 -0
  44. package/src/translations/en.json +49 -0
@@ -0,0 +1,912 @@
1
+ /* Calendar engine — token-themed (no hardcoded colors). Month grid + agenda. */
2
+ .cal {
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: var(--calendar-space-md, var(--box-gap));
6
+ }
7
+
8
+ /* One semantic event-card state model for every calendar projection. Consumers may override the named
9
+ calendar seams; otherwise both states are mathematical tints of the event color, which defaults to the
10
+ host's control accent. LINKED Button consumes the aliases so its primitive interaction contract remains
11
+ intact without replacing the calendar's domain presentation. */
12
+ .agItem,
13
+ .tgAllDayEvent,
14
+ .tgEvent,
15
+ .mBar,
16
+ .resourceEvent {
17
+ --button-primary-bg: var(
18
+ --calendar-event-surface-bg,
19
+ color-mix(in srgb, var(--c, var(--control-accent)) 12%, var(--box-bg))
20
+ );
21
+ --button-primary-bg-hover: var(
22
+ --calendar-event-surface-bg-hover,
23
+ color-mix(in srgb, var(--c, var(--control-accent)) 20%, var(--box-bg))
24
+ );
25
+ --button-primary-color: var(--text-primary);
26
+ --button-primary-color-hover: var(--text-primary);
27
+ }
28
+ .head {
29
+ display: flex;
30
+ align-items: center;
31
+ justify-content: space-between;
32
+ gap: var(--calendar-space-md, var(--box-gap));
33
+ flex-wrap: wrap;
34
+ }
35
+ .nav {
36
+ display: flex;
37
+ align-items: center;
38
+ gap: var(--calendar-space-sm, var(--list-item-gap));
39
+ }
40
+ .navBtn {
41
+ width: 32px;
42
+ height: 32px;
43
+ border-radius: var(--control-radius);
44
+ border: 1px solid var(--box-border);
45
+ background: var(--bg-panel);
46
+ color: var(--text-primary);
47
+ font-size: var(--calendar-large-text-size, var(--typography-large-size));
48
+ cursor: pointer;
49
+ display: inline-flex;
50
+ align-items: center;
51
+ justify-content: center;
52
+ }
53
+ .navBtn:hover {
54
+ background: var(--bg-hover);
55
+ }
56
+ .today {
57
+ height: 32px;
58
+ padding: 0 var(--calendar-space-md, var(--box-gap));
59
+ border-radius: var(--control-radius);
60
+ border: 1px solid var(--box-border);
61
+ background: var(--bg-panel);
62
+ color: var(--calendar-muted-text, var(--typography-auxiliary-color));
63
+ font-family: var(--calendar-control-font, var(--button-font-family));
64
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
65
+ cursor: pointer;
66
+ }
67
+ .today:hover {
68
+ background: var(--bg-hover);
69
+ color: var(--text-primary);
70
+ }
71
+ .title {
72
+ font-family: var(--heading-font-family);
73
+ font-size: var(--calendar-title-text-size, var(--heading-4-font-size));
74
+ color: var(--text-primary);
75
+ margin: 0 0 0 var(--calendar-space-sm, var(--list-item-gap));
76
+ }
77
+ .views {
78
+ display: flex;
79
+ gap: var(--calendar-space-2xs, var(--popover-gap));
80
+ padding: var(--calendar-space-2xs, var(--popover-gap));
81
+ border-radius: var(--radius-full);
82
+ background: var(--bg-panel);
83
+ border: 1px solid var(--box-border);
84
+ }
85
+ .viewBtn {
86
+ padding: var(--calendar-space-2xs, var(--popover-gap)) var(--calendar-space-md, var(--box-gap));
87
+ border-radius: var(--radius-full);
88
+ border: none;
89
+ background: transparent;
90
+ color: var(--calendar-muted-text, var(--typography-auxiliary-color));
91
+ font-family: var(--calendar-control-font, var(--button-font-family));
92
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
93
+ cursor: pointer;
94
+ }
95
+ .viewBtn[data-active] {
96
+ background: var(--control-accent);
97
+ color: var(--control-text-contrast);
98
+ }
99
+ .empty {
100
+ padding: 48px var(--calendar-space-lg, var(--section-gap));
101
+ text-align: center;
102
+ color: var(--text-auxiliary);
103
+ font-family: var(--typography-font-family);
104
+ font-size: var(--calendar-body-text-size, var(--typography-font-size));
105
+ }
106
+
107
+ /* ── month grid ── */
108
+ .grid {
109
+ display: grid;
110
+ /* minmax(0,1fr) → EVERY column is exactly equal; long event titles can't stretch a column */
111
+ grid-template-columns: repeat(7, minmax(0, 1fr));
112
+ gap: 1px;
113
+ background: var(--box-border);
114
+ border: 1px solid var(--box-border);
115
+ border-radius: var(--radius-box);
116
+ overflow: hidden;
117
+ }
118
+ .dow {
119
+ background: var(--calendar-surface-bg, var(--surface-bg));
120
+ padding: var(--calendar-space-xs, var(--control-gap));
121
+ text-align: center;
122
+ font-family: var(--calendar-control-font, var(--button-font-family));
123
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
124
+ letter-spacing: 0.08em;
125
+ text-transform: uppercase;
126
+ color: var(--text-auxiliary);
127
+ }
128
+ .cell {
129
+ background: var(--box-bg);
130
+ min-height: 104px;
131
+ min-width: 0; /* allow the column to stay 1fr; content clips instead of expanding it */
132
+ padding: var(--calendar-space-2xs, var(--popover-gap));
133
+ display: flex;
134
+ flex-direction: column;
135
+ gap: var(--calendar-space-2xs, var(--popover-gap));
136
+ }
137
+ .cell[data-out] {
138
+ background: var(--calendar-surface-bg, var(--surface-bg));
139
+ }
140
+ .cell[data-out] .date {
141
+ color: var(--text-auxiliary);
142
+ }
143
+ .date {
144
+ font-family: var(--typography-font-family);
145
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
146
+ color: var(--calendar-muted-text, var(--typography-auxiliary-color));
147
+ align-self: flex-end;
148
+ padding: 0 var(--calendar-space-2xs, var(--popover-gap));
149
+ }
150
+ .cell[data-today] .date {
151
+ background: var(--control-accent);
152
+ color: var(--control-text-contrast);
153
+ border-radius: var(--radius-full);
154
+ min-width: 20px;
155
+ text-align: center;
156
+ }
157
+ .chips {
158
+ display: flex;
159
+ flex-direction: column;
160
+ gap: 2px;
161
+ }
162
+ .chip {
163
+ display: flex;
164
+ align-items: center;
165
+ gap: var(--calendar-space-2xs, var(--popover-gap));
166
+ padding: 1px var(--calendar-space-2xs, var(--popover-gap));
167
+ border-radius: var(--list-item-radius);
168
+ border: none;
169
+ background: color-mix(in srgb, var(--c) 14%, transparent);
170
+ cursor: pointer;
171
+ text-align: left;
172
+ width: 100%;
173
+ }
174
+ .chip:hover {
175
+ background: color-mix(in srgb, var(--c) 24%, transparent);
176
+ }
177
+ .dot {
178
+ width: 6px;
179
+ height: 6px;
180
+ border-radius: var(--radius-full);
181
+ background: var(--c);
182
+ flex-shrink: 0;
183
+ }
184
+ .chipText {
185
+ font-family: var(--typography-font-family);
186
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
187
+ color: var(--text-primary);
188
+ white-space: nowrap;
189
+ overflow: hidden;
190
+ text-overflow: ellipsis;
191
+ }
192
+ .more {
193
+ font-family: var(--typography-font-family);
194
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
195
+ color: var(--text-auxiliary);
196
+ padding: 0 var(--calendar-space-2xs, var(--popover-gap));
197
+ }
198
+
199
+ /* phones: shorter cells, hide chip text (dots only) */
200
+ @media (max-width: 640px) {
201
+ .cell {
202
+ min-height: 64px;
203
+ }
204
+ .chipText,
205
+ .more {
206
+ display: none;
207
+ }
208
+ }
209
+
210
+ /* ── agenda ── */
211
+ .agenda {
212
+ display: flex;
213
+ flex-direction: column;
214
+ gap: var(--calendar-space-md, var(--box-gap));
215
+ }
216
+ .agDay {
217
+ display: grid;
218
+ grid-template-columns: 56px 1fr;
219
+ gap: var(--calendar-space-md, var(--box-gap));
220
+ }
221
+ .agDate {
222
+ text-align: center;
223
+ }
224
+ .agDow {
225
+ font-family: var(--calendar-control-font, var(--button-font-family));
226
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
227
+ text-transform: uppercase;
228
+ color: var(--text-auxiliary);
229
+ }
230
+ .agNum {
231
+ font-family: var(--heading-font-family);
232
+ font-size: var(--calendar-title-text-size, var(--heading-4-font-size));
233
+ color: var(--text-primary);
234
+ }
235
+ .agDate[data-today] .agNum {
236
+ color: var(--control-accent);
237
+ }
238
+ .agItems {
239
+ display: flex;
240
+ flex-direction: column;
241
+ gap: var(--calendar-space-2xs, var(--popover-gap));
242
+ }
243
+ .agItem {
244
+ display: flex;
245
+ align-items: center;
246
+ gap: var(--calendar-space-sm, var(--list-item-gap));
247
+ padding: var(--calendar-space-sm, var(--list-item-gap));
248
+ border-radius: var(--radius-box);
249
+ border: 1px solid var(--box-border);
250
+ background: var(--box-bg);
251
+ cursor: pointer;
252
+ text-align: left;
253
+ }
254
+ .agItem:hover {
255
+ border-color: color-mix(in srgb, var(--c, var(--control-accent)) 40%, var(--box-border));
256
+ }
257
+ .agBar {
258
+ width: 3px;
259
+ align-self: stretch;
260
+ border-radius: var(--radius-full);
261
+ flex-shrink: 0;
262
+ }
263
+ .agTime {
264
+ font-family: var(--calendar-control-font, var(--button-font-family));
265
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
266
+ color: var(--calendar-muted-text, var(--typography-auxiliary-color));
267
+ min-width: 64px;
268
+ }
269
+ .agTitle {
270
+ font-family: var(--heading-font-family);
271
+ font-size: var(--calendar-body-text-size, var(--typography-font-size));
272
+ color: var(--text-primary);
273
+ flex: 1;
274
+ }
275
+ .agLoc {
276
+ font-family: var(--typography-font-family);
277
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
278
+ color: var(--text-auxiliary);
279
+ }
280
+ .agCross {
281
+ display: block;
282
+ font-family: var(--typography-font-family);
283
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
284
+ color: var(--calendar-info, var(--link-color));
285
+ margin-top: 2px;
286
+ }
287
+
288
+ /* ── week / day time grid ── */
289
+ .tg {
290
+ display: flex;
291
+ flex-direction: column;
292
+ border: 1px solid var(--box-border);
293
+ border-radius: var(--radius-box);
294
+ overflow: hidden;
295
+ }
296
+ .tgHead {
297
+ display: flex;
298
+ border-bottom: 1px solid var(--box-border);
299
+ background: var(--calendar-surface-bg, var(--surface-bg));
300
+ }
301
+ .tgDayHead {
302
+ flex: 1;
303
+ min-width: 0;
304
+ display: flex;
305
+ align-items: baseline;
306
+ justify-content: center;
307
+ gap: var(--calendar-space-2xs, var(--popover-gap));
308
+ padding: var(--calendar-space-xs, var(--control-gap));
309
+ border-left: 1px solid var(--box-border);
310
+ }
311
+ .tgDow {
312
+ font-family: var(--calendar-control-font, var(--button-font-family));
313
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
314
+ text-transform: uppercase;
315
+ color: var(--text-auxiliary);
316
+ }
317
+ .tgNum {
318
+ font-family: var(--heading-font-family);
319
+ font-size: var(--calendar-body-text-size, var(--typography-font-size));
320
+ color: var(--text-primary);
321
+ }
322
+ .tgDayHead[data-today] .tgNum {
323
+ color: var(--control-accent);
324
+ }
325
+ .tgAllDay {
326
+ display: grid;
327
+ gap: 2px 0;
328
+ padding: var(--calendar-space-2xs, var(--popover-gap)) 0;
329
+ border-bottom: 1px solid var(--box-border);
330
+ background: var(--calendar-surface-bg, var(--surface-bg));
331
+ }
332
+ .tgAllDayLabel {
333
+ grid-column: 1;
334
+ grid-row: 1 / -1;
335
+ align-self: center;
336
+ padding-left: var(--calendar-space-xs, var(--control-gap));
337
+ font-family: var(--calendar-control-font, var(--button-font-family));
338
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
339
+ text-transform: uppercase;
340
+ color: var(--text-auxiliary);
341
+ }
342
+ .tgAllDayEvent {
343
+ display: block;
344
+ height: 20px;
345
+ margin: 0 2px;
346
+ padding: 0 var(--calendar-space-xs, var(--control-gap));
347
+ border: none;
348
+ border-radius: var(--list-item-radius);
349
+ box-shadow: inset 3px 0 0 var(--a, var(--c));
350
+ color: var(--text-primary);
351
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
352
+ line-height: 20px;
353
+ text-align: left;
354
+ white-space: nowrap;
355
+ overflow: hidden;
356
+ text-overflow: ellipsis;
357
+ cursor: pointer;
358
+ }
359
+ .tgBody {
360
+ display: flex;
361
+ align-items: flex-start; /* columns keep their true 24h height instead of stretching to the viewport */
362
+ position: relative;
363
+ max-height: 68vh;
364
+ overflow-y: auto;
365
+ }
366
+ .tgGutter {
367
+ width: 56px;
368
+ flex-shrink: 0;
369
+ }
370
+ .tgHour {
371
+ height: var(--hour-h);
372
+ position: relative;
373
+ }
374
+ .tgHourLabel {
375
+ position: absolute;
376
+ top: -7px;
377
+ right: var(--calendar-space-xs, var(--control-gap));
378
+ font-family: var(--calendar-control-font, var(--button-font-family));
379
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
380
+ color: var(--text-auxiliary);
381
+ }
382
+ .tgCols {
383
+ display: flex;
384
+ flex: 1;
385
+ min-width: 0;
386
+ position: relative;
387
+ height: calc(var(--hour-h) * 24); /* the columns area — grid-level pointer target for cross-day drag */
388
+ touch-action: pan-y; /* allow vertical scroll; long-press starts a move, a scroll cancels the press */
389
+ }
390
+ .tgCol {
391
+ flex: 1;
392
+ min-width: 0;
393
+ height: 100%;
394
+ position: relative;
395
+ border-left: 1px solid var(--box-border);
396
+ cursor: pointer;
397
+ }
398
+ .tgSlot {
399
+ height: var(--hour-h);
400
+ border-top: 1px solid color-mix(in srgb, var(--box-border) 60%, transparent);
401
+ }
402
+ .tgNow {
403
+ position: absolute;
404
+ left: 0;
405
+ right: 0;
406
+ height: 2px;
407
+ background: var(--calendar-danger, var(--color-error));
408
+ z-index: 3;
409
+ pointer-events: none;
410
+ }
411
+ .tgSel {
412
+ position: absolute;
413
+ left: 2px;
414
+ right: 2px;
415
+ background: color-mix(in srgb, var(--control-accent) 22%, transparent);
416
+ border: 1px dashed var(--control-accent);
417
+ border-radius: var(--list-item-radius);
418
+ z-index: 2;
419
+ pointer-events: none;
420
+ }
421
+ .tgEvent {
422
+ position: absolute;
423
+ z-index: 2;
424
+ overflow: hidden;
425
+ border: none;
426
+ border-radius: var(--list-item-radius);
427
+ box-shadow: inset 3px 0 0 var(--a, var(--c));
428
+ padding: 3px var(--calendar-space-xs, var(--control-gap));
429
+ text-align: left;
430
+ cursor: grab;
431
+ display: flex;
432
+ flex-direction: column;
433
+ gap: 1px;
434
+ }
435
+ /* organizer attention marker — a small dot on the card (warn = amber, danger = red) */
436
+ .alertDot,
437
+ .tgAlert {
438
+ flex-shrink: 0;
439
+ width: 7px;
440
+ height: 7px;
441
+ border-radius: var(--radius-full);
442
+ background: var(--calendar-warning, var(--notification-accent));
443
+ }
444
+ .alertDot {
445
+ display: inline-block;
446
+ margin-left: var(--calendar-space-2xs, var(--popover-gap));
447
+ }
448
+ .alertDot[data-tone='danger'],
449
+ .tgAlert[data-tone='danger'] {
450
+ background: var(--calendar-danger, var(--color-error));
451
+ }
452
+ .tgAlert {
453
+ position: absolute;
454
+ top: 4px;
455
+ right: 4px;
456
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--bg-panel) 70%, transparent);
457
+ }
458
+ .tgEvent[data-continues] {
459
+ border-bottom-left-radius: 0;
460
+ border-bottom-right-radius: 0;
461
+ border-bottom: 2px dashed color-mix(in srgb, var(--c) 60%, transparent); /* runs into the next day */
462
+ }
463
+ .tgEvent[data-dragging] {
464
+ cursor: grabbing;
465
+ opacity: 0.92;
466
+ box-shadow: var(--box-shadow), inset 3px 0 0 var(--a, var(--c));
467
+ z-index: 4;
468
+ }
469
+ /* resize grips — top edge changes the start, bottom edge changes the end */
470
+ .tgResize,
471
+ .tgResizeTop {
472
+ position: absolute;
473
+ left: 0;
474
+ right: 0;
475
+ height: 8px;
476
+ cursor: ns-resize;
477
+ }
478
+ .tgResize {
479
+ bottom: 0;
480
+ border-bottom-left-radius: var(--list-item-radius);
481
+ border-bottom-right-radius: var(--list-item-radius);
482
+ }
483
+ .tgResizeTop {
484
+ top: 0;
485
+ border-top-left-radius: var(--list-item-radius);
486
+ border-top-right-radius: var(--list-item-radius);
487
+ }
488
+ .tgEvent:hover .tgResize,
489
+ .tgEvent:hover .tgResizeTop {
490
+ background: color-mix(in srgb, var(--c) 45%, transparent);
491
+ }
492
+ /* ghost left where the event was, during a move + while awaiting confirmation */
493
+ .tgGhost {
494
+ position: absolute;
495
+ z-index: 1;
496
+ border: 1px dashed var(--c);
497
+ border-radius: var(--list-item-radius);
498
+ background: color-mix(in srgb, var(--c) 8%, transparent);
499
+ opacity: 0.7;
500
+ pointer-events: none;
501
+ }
502
+ /* confirm/cancel — a centered floating toast (not crammed into the column) until the move is committed */
503
+ .tgConfirm {
504
+ position: fixed;
505
+ left: 50%;
506
+ bottom: 28px;
507
+ transform: translateX(-50%);
508
+ z-index: 80;
509
+ display: flex;
510
+ align-items: center;
511
+ gap: var(--calendar-space-sm, var(--list-item-gap));
512
+ padding: var(--calendar-space-sm, var(--list-item-gap)) var(--calendar-space-md, var(--box-gap));
513
+ border-radius: var(--radius-full);
514
+ background: var(--calendar-popover-bg, var(--popover-bg));
515
+ border: 1px solid var(--control-accent);
516
+ box-shadow: var(--box-shadow);
517
+ white-space: nowrap;
518
+ }
519
+ .tgConfirmText {
520
+ font-family: var(--typography-font-family);
521
+ font-size: var(--calendar-body-text-size, var(--typography-font-size));
522
+ color: var(--text-primary);
523
+ white-space: nowrap;
524
+ }
525
+ .tgConfirmYes,
526
+ .tgConfirmNo {
527
+ font-family: var(--calendar-control-font, var(--button-font-family));
528
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
529
+ border-radius: var(--radius-full);
530
+ padding: var(--calendar-space-2xs, var(--popover-gap)) var(--calendar-space-md, var(--box-gap));
531
+ cursor: pointer;
532
+ border: 1px solid var(--box-border);
533
+ }
534
+ .tgConfirmYes {
535
+ background: var(--control-accent);
536
+ color: var(--control-text-contrast);
537
+ border-color: transparent;
538
+ }
539
+ .tgConfirmNo {
540
+ background: transparent;
541
+ color: var(--calendar-muted-text, var(--typography-auxiliary-color));
542
+ }
543
+ .tgEvTime {
544
+ font-family: var(--calendar-control-font, var(--button-font-family));
545
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
546
+ color: var(--calendar-muted-text, var(--typography-auxiliary-color));
547
+ }
548
+ .tgEvTitle {
549
+ font-family: var(--typography-font-family);
550
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
551
+ color: var(--text-primary);
552
+ white-space: nowrap;
553
+ overflow: hidden;
554
+ text-overflow: ellipsis;
555
+ }
556
+
557
+ /* ── quick-action popover (single click) ── */
558
+ .popBackdrop {
559
+ position: fixed;
560
+ inset: 0;
561
+ z-index: 70;
562
+ }
563
+ .pop {
564
+ position: fixed;
565
+ z-index: 71;
566
+ background: var(--calendar-popover-bg, var(--popover-bg));
567
+ border: 1px solid var(--box-border);
568
+ border-radius: var(--radius-box);
569
+ box-shadow: var(--box-shadow);
570
+ padding: var(--calendar-space-md, var(--box-gap));
571
+ display: flex;
572
+ flex-direction: column;
573
+ gap: var(--calendar-space-sm, var(--list-item-gap));
574
+ }
575
+ .popHead {
576
+ display: flex;
577
+ align-items: center;
578
+ gap: var(--calendar-space-sm, var(--list-item-gap));
579
+ }
580
+ .popDot {
581
+ width: 8px;
582
+ height: 8px;
583
+ border-radius: var(--radius-full);
584
+ flex-shrink: 0;
585
+ }
586
+ .popTitle {
587
+ flex: 1;
588
+ min-width: 0;
589
+ font-family: var(--heading-font-family);
590
+ font-size: var(--calendar-body-text-size, var(--typography-font-size));
591
+ color: var(--text-primary);
592
+ }
593
+ .popClose {
594
+ flex-shrink: 0;
595
+ }
596
+ .popMeta {
597
+ font-family: var(--typography-font-family);
598
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
599
+ color: var(--calendar-muted-text, var(--typography-auxiliary-color));
600
+ display: flex;
601
+ flex-direction: column;
602
+ gap: 2px;
603
+ }
604
+ .popExtra {
605
+ padding-top: var(--calendar-space-2xs, var(--popover-gap));
606
+ margin-top: var(--calendar-space-2xs, var(--popover-gap));
607
+ border-top: 1px solid var(--box-border);
608
+ }
609
+ .popTimeRow {
610
+ display: flex;
611
+ align-items: center;
612
+ justify-content: space-between;
613
+ gap: var(--calendar-space-xs, var(--control-gap));
614
+ }
615
+ .popEditBtn {
616
+ font-family: var(--calendar-control-font, var(--button-font-family));
617
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
618
+ text-transform: uppercase;
619
+ color: var(--control-accent);
620
+ background: none;
621
+ border: none;
622
+ padding: 0;
623
+ cursor: pointer;
624
+ }
625
+ .popEdit {
626
+ display: flex;
627
+ flex-direction: column;
628
+ gap: var(--calendar-space-2xs, var(--popover-gap));
629
+ }
630
+ .popField {
631
+ display: flex;
632
+ align-items: center;
633
+ justify-content: space-between;
634
+ gap: var(--calendar-space-xs, var(--control-gap));
635
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
636
+ color: var(--text-auxiliary);
637
+ }
638
+ .popInput {
639
+ font-family: var(--typography-font-family);
640
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
641
+ color: var(--text-primary);
642
+ background: var(--bg-panel);
643
+ border: 1px solid var(--box-border);
644
+ border-radius: var(--field-radius);
645
+ padding: var(--calendar-space-2xs, var(--popover-gap)) var(--calendar-space-2xs, var(--popover-gap));
646
+ }
647
+ .popEditRow {
648
+ display: flex;
649
+ gap: var(--calendar-space-xs, var(--control-gap));
650
+ margin-top: var(--calendar-space-2xs, var(--popover-gap));
651
+ }
652
+ .popSave,
653
+ .popEditCancel {
654
+ font-family: var(--calendar-control-font, var(--button-font-family));
655
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
656
+ line-height: 1.2;
657
+ border-radius: var(--radius-full);
658
+ padding: var(--calendar-space-xs, var(--control-gap)) var(--calendar-space-md, var(--box-gap));
659
+ cursor: pointer;
660
+ }
661
+ .popSave {
662
+ color: var(--control-text-contrast);
663
+ background: var(--control-accent);
664
+ border: none;
665
+ }
666
+ .popEditCancel {
667
+ color: var(--calendar-muted-text, var(--typography-auxiliary-color));
668
+ background: var(--bg-panel);
669
+ border: 1px solid var(--box-border);
670
+ }
671
+ .popCross {
672
+ color: var(--calendar-info, var(--link-color));
673
+ }
674
+ .popLoc {
675
+ color: var(--text-auxiliary);
676
+ }
677
+ .popActions {
678
+ display: flex;
679
+ flex-wrap: wrap;
680
+ gap: var(--calendar-space-2xs, var(--popover-gap));
681
+ }
682
+ .popAction {
683
+ font-family: var(--calendar-control-font, var(--button-font-family));
684
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
685
+ color: var(--text-primary);
686
+ text-decoration: none;
687
+ background: var(--bg-panel);
688
+ border: 1px solid var(--box-border);
689
+ border-radius: var(--radius-full);
690
+ padding: var(--calendar-space-2xs, var(--popover-gap)) var(--calendar-space-sm, var(--list-item-gap));
691
+ cursor: pointer;
692
+ }
693
+ .popAction:hover {
694
+ background: var(--bg-hover);
695
+ }
696
+ .popExpand {
697
+ font-family: var(--calendar-control-font, var(--button-font-family));
698
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
699
+ color: var(--control-text-contrast);
700
+ background: var(--control-accent);
701
+ border: none;
702
+ border-radius: var(--radius-full);
703
+ padding: var(--calendar-space-2xs, var(--popover-gap)) var(--calendar-space-sm, var(--list-item-gap));
704
+ cursor: pointer;
705
+ align-self: flex-start;
706
+ }
707
+
708
+ /* ── Month view (spanning bars) — multi-day events span their days, single-day events occupy one column.
709
+ Each week is a 7-col grid of cells with an absolutely-positioned bar overlay above. ── */
710
+ .month {
711
+ --m-date-h: 22px;
712
+ --m-bar-h: 18px;
713
+ border: 1px solid var(--box-border);
714
+ border-radius: var(--radius-box);
715
+ overflow: hidden;
716
+ }
717
+ .dowRow {
718
+ display: grid;
719
+ grid-template-columns: repeat(7, minmax(0, 1fr));
720
+ border-bottom: 1px solid var(--box-border);
721
+ }
722
+ .mWeek {
723
+ position: relative;
724
+ display: grid;
725
+ grid-template-columns: repeat(7, minmax(0, 1fr));
726
+ /* room for the date row + the lane cap of bars */
727
+ min-height: calc(var(--m-date-h) + 4 * (var(--m-bar-h) + 2px) + var(--calendar-space-sm, var(--list-item-gap)));
728
+ border-bottom: 1px solid var(--box-border);
729
+ }
730
+ .mWeek:last-child {
731
+ border-bottom: none;
732
+ }
733
+ .mCell {
734
+ --button-primary-bg: var(--calendar-day-surface-bg, var(--box-bg));
735
+ --button-primary-bg-hover: var(--calendar-day-surface-bg-hover, var(--bg-hover));
736
+ --button-primary-color: var(--text-primary);
737
+ --button-primary-color-hover: var(--text-primary);
738
+ position: relative;
739
+ min-width: 0;
740
+ border-right: 1px solid var(--box-border);
741
+ padding: var(--calendar-space-2xs, var(--popover-gap));
742
+ cursor: pointer;
743
+ display: flex;
744
+ flex-direction: column;
745
+ }
746
+ .mCell:last-child {
747
+ border-right: none;
748
+ }
749
+ .mCell[data-out] {
750
+ --button-primary-bg: var(--calendar-surface-bg, var(--surface-bg));
751
+ }
752
+ .mCell[data-out] .mDate {
753
+ color: var(--text-auxiliary);
754
+ }
755
+ .mDate {
756
+ align-self: flex-end;
757
+ font-family: var(--typography-font-family);
758
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
759
+ color: var(--calendar-muted-text, var(--typography-auxiliary-color));
760
+ padding: 0 2px;
761
+ height: calc(var(--m-date-h) - 4px);
762
+ }
763
+ .mCell[data-today] .mDate {
764
+ background: var(--control-accent);
765
+ color: var(--control-text-contrast);
766
+ border-radius: var(--radius-full);
767
+ min-width: 20px;
768
+ text-align: center;
769
+ }
770
+ .mMore {
771
+ margin-top: auto;
772
+ font-family: var(--typography-font-family);
773
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
774
+ color: var(--text-auxiliary);
775
+ padding: 0 2px;
776
+ }
777
+ /* bar overlay — sits above the cells; empty space lets clicks fall through to open the day */
778
+ .mBars {
779
+ position: absolute;
780
+ inset: 0;
781
+ pointer-events: none;
782
+ }
783
+ .mBar {
784
+ position: absolute;
785
+ height: var(--m-bar-h);
786
+ display: flex;
787
+ align-items: center;
788
+ gap: var(--calendar-space-2xs, var(--popover-gap));
789
+ padding: 0 var(--calendar-space-xs, var(--control-gap));
790
+ border: none;
791
+ border-radius: var(--list-item-radius);
792
+ cursor: pointer;
793
+ pointer-events: auto;
794
+ text-align: left;
795
+ overflow: hidden;
796
+ }
797
+ .mBar[data-multi] {
798
+ --button-primary-bg: var(
799
+ --calendar-event-multiday-surface-bg,
800
+ color-mix(in srgb, var(--c, var(--control-accent)) 18%, var(--box-bg))
801
+ );
802
+ }
803
+ .mBar:hover,
804
+ .mBar:focus-visible {
805
+ outline: none;
806
+ }
807
+ .mDot {
808
+ flex-shrink: 0;
809
+ width: 6px;
810
+ height: 6px;
811
+ border-radius: var(--radius-full);
812
+ background: var(--a, var(--c));
813
+ }
814
+ .mBarText {
815
+ font-family: var(--typography-font-family);
816
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
817
+ color: var(--text-primary);
818
+ white-space: nowrap;
819
+ overflow: hidden;
820
+ text-overflow: ellipsis;
821
+ }
822
+
823
+ /* Resource view — host-projected people, rooms, equipment, or roles. Resource identity remains opaque to
824
+ the engine; one event may appear in several columns without duplicating its canonical graph resource. */
825
+ .resourceGrid {
826
+ display: grid;
827
+ grid-auto-flow: column;
828
+ grid-auto-columns: minmax(220px, 1fr);
829
+ gap: var(--calendar-space-sm, var(--list-item-gap));
830
+ overflow-x: auto;
831
+ padding-bottom: var(--calendar-space-xs, var(--control-gap));
832
+ scrollbar-gutter: stable;
833
+ }
834
+ .resourceColumn {
835
+ min-width: 0;
836
+ min-height: 240px;
837
+ display: flex;
838
+ flex-direction: column;
839
+ gap: var(--calendar-space-xs, var(--control-gap));
840
+ padding: var(--calendar-space-sm, var(--list-item-gap));
841
+ border: 1px solid var(--box-border);
842
+ border-top: 3px solid var(--resource-color);
843
+ border-radius: var(--box-radius);
844
+ background: var(--calendar-surface-bg, var(--surface-bg));
845
+ }
846
+ .resourceHeading {
847
+ margin: 0;
848
+ font-family: var(--heading-font-family);
849
+ font-size: var(--calendar-body-text-size, var(--typography-font-size));
850
+ color: var(--heading-color);
851
+ }
852
+ .resourceEvents {
853
+ display: flex;
854
+ flex-direction: column;
855
+ gap: var(--calendar-space-xs, var(--control-gap));
856
+ }
857
+ .resourceEvent {
858
+ width: 100%;
859
+ min-width: 0;
860
+ display: flex;
861
+ align-items: stretch;
862
+ gap: var(--calendar-space-xs, var(--control-gap));
863
+ padding: var(--calendar-space-xs, var(--control-gap));
864
+ text-align: left;
865
+ border: 1px solid var(--box-border);
866
+ border-radius: var(--list-item-radius);
867
+ color: var(--text-primary);
868
+ }
869
+ .resourceEventAccent {
870
+ width: 3px;
871
+ flex: 0 0 3px;
872
+ border-radius: var(--radius-full);
873
+ background: var(--a, var(--resource-color));
874
+ }
875
+ .resourceEventBody {
876
+ min-width: 0;
877
+ display: flex;
878
+ flex: 1;
879
+ flex-direction: column;
880
+ gap: var(--calendar-space-2xs, var(--popover-gap));
881
+ }
882
+ .resourceEventTime,
883
+ .resourceEventLocation,
884
+ .resourceColumnEmpty {
885
+ font-family: var(--typography-font-family);
886
+ font-size: var(--calendar-compact-text-size, var(--typography-small-size));
887
+ color: var(--calendar-muted-text, var(--typography-auxiliary-color));
888
+ }
889
+ .resourceEventTitle {
890
+ overflow: hidden;
891
+ font-family: var(--typography-font-family);
892
+ font-size: var(--calendar-small-text-size, var(--typography-small-size));
893
+ color: var(--text-primary);
894
+ text-overflow: ellipsis;
895
+ }
896
+ .resourceColumnEmpty {
897
+ padding: var(--calendar-space-sm, var(--list-item-gap));
898
+ text-align: center;
899
+ }
900
+
901
+ /* phones: the floating NavBar pill owns the bottom band — lift the reschedule confirm above it */
902
+ @media (max-width: 767px) {
903
+ .resourceGrid {
904
+ grid-auto-flow: row;
905
+ grid-auto-columns: unset;
906
+ grid-template-columns: minmax(0, 1fr);
907
+ overflow-x: visible;
908
+ }
909
+ .tgConfirm {
910
+ bottom: calc(var(--calendar-space-md, var(--box-gap)) + env(safe-area-inset-bottom, 0px) + var(--calendar-mobile-navigation-clearance, 0px));
911
+ }
912
+ }