@nomideusz/svelte-calendar 1.3.0 → 1.4.1

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.
@@ -10,7 +10,7 @@ import EventContent from "../shared/EventContent.svelte";
10
10
  import { createClock } from "../../core/clock.svelte.js";
11
11
  import { sod, addDaysMs, isAllDay } from "../../core/time.js";
12
12
  import { startOfWeek as sowFn } from "../../core/time.js";
13
- import { fmtTime as _fmtTime, fmtWeekRange, weekdayShort } from "../../core/locale.js";
13
+ import { fmtTime as _fmtTime, fmtDayNum, fmtWeekRange, weekdayShort } from "../../core/locale.js";
14
14
  import { dateLong } from "../shared/format.js";
15
15
  import { createSwipe } from "./swipe.js";
16
16
  let { mondayStart = true, locale, height = null, events = [], style = "", focusDate, oneventclick, selectedEventId = null } = $props();
@@ -53,7 +53,8 @@ const dayCells = $derived.by(() => {
53
53
  const jsDay = d.getDay();
54
54
  const isoDay = jsDay === 0 ? 7 : jsDay;
55
55
  if (hideSet.has(isoDay)) continue;
56
- const isToday = ms === todayMs;
56
+ // A dateless weekly template (showDates=false) has no today to mark.
57
+ const isToday = showDates && ms === todayMs;
57
58
  const isPast = equalDays ? false : ms < todayMs;
58
59
  const isWeekend = jsDay === 0 || jsDay === 6;
59
60
  const isDisabled = disabledSet.has(ms);
@@ -99,7 +100,9 @@ function evTimeLabel(ev) {
99
100
  /** Visible time on a day row: the start, or "until 01:00" on the day an
100
101
  * overnight event runs into. */
101
102
  function evRowTime(ev, dayMs) {
102
- if (inAllDayStrip(ev)) return L.allDay;
103
+ // A multi-day band says "All day" once, on its first row this week;
104
+ // every row's aria-label still says it.
105
+ if (inAllDayStrip(ev)) return dayCells.find((c) => c.events.includes(ev))?.ms === dayMs ? L.allDay : "";
103
106
  if (ev.start.getTime() < dayMs) return `${L.until} ${fmtTime(ev.end)}`;
104
107
  return fmtTime(ev.start);
105
108
  }
@@ -204,7 +207,7 @@ function handleDayKeydown(e, dayMs) {
204
207
  <div class="mw-date">
205
208
  <span class="mw-day-name" class:mw-day-name--today={cell.isToday}>{cell.dayName}</span>
206
209
  {#if showDates}
207
- <span class="mw-day-num" class:mw-day-num--today={cell.isToday}>{cell.dayNum}</span>
210
+ <span class="mw-day-num" class:mw-day-num--today={cell.isToday}>{fmtDayNum(cell.ms, locale)}</span>
208
211
  {/if}
209
212
  </div>
210
213
 
@@ -224,11 +227,11 @@ function handleDayKeydown(e, dayMs) {
224
227
  class:mw-ev--tentative={ev.status === 'tentative'}
225
228
  class:mw-ev--full={ev.status === 'full'}
226
229
  class:mw-ev--limited={ev.status === 'limited'}
227
- style:--ev-color={ev.color ?? 'var(--dt-accent)'}
230
+ style:--ev-color={ev.color ?? (inAllDayStrip(ev) ? 'var(--dt-accent)' : 'var(--dt-event, var(--dt-accent))')}
228
231
  onclick={(e) => { e.stopPropagation(); oneventclick?.(ev); }}
229
232
  onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.stopPropagation(); oneventclick?.(ev); } }}
230
233
  onpointerenter={() => oneventhover?.(ev)}
231
- aria-label="{ev.title}{statusText(ev)}, {evTimeLabel(ev)}"
234
+ aria-label="{ev.title}{statusText(ev)}, {dateLong(cell.ms, locale)}, {evTimeLabel(ev)}"
232
235
  >
233
236
  <span class="mw-ev-stripe"></span>
234
237
  <div class="mw-ev-body">
@@ -244,6 +247,7 @@ function handleDayKeydown(e, dayMs) {
244
247
  type="button"
245
248
  class="mw-ev-more"
246
249
  aria-expanded={expandedDays.has(cell.ms)}
250
+ aria-label="{expandedDays.has(cell.ms) ? L.showLess : L.nMore(cell.totalCount - MAX_EVENTS)}, {dateLong(cell.ms, locale)}"
247
251
  onclick={() => toggleExpand(cell.ms)}
248
252
  >
249
253
  {expandedDays.has(cell.ms) ? L.showLess : L.nMore(cell.totalCount - MAX_EVENTS)}
@@ -268,7 +272,7 @@ function handleDayKeydown(e, dayMs) {
268
272
  user-select: none;
269
273
  font-variant-numeric: tabular-nums;
270
274
  overflow: hidden;
271
- background: var(--dt-bg, #fff);
275
+ background: var(--dt-bg, #efebe9);
272
276
  -webkit-tap-highlight-color: transparent;
273
277
  touch-action: pan-y pinch-zoom;
274
278
  }
@@ -282,7 +286,7 @@ function handleDayKeydown(e, dayMs) {
282
286
  overscroll-behavior: contain;
283
287
  -webkit-overflow-scrolling: touch;
284
288
  scrollbar-width: thin;
285
- scrollbar-color: var(--dt-scrollbar, rgba(0, 0, 0, 0.1)) transparent;
289
+ scrollbar-color: var(--dt-scrollbar, rgba(15, 15, 15, 0.1)) transparent;
286
290
  }
287
291
  .mw--auto .mw-list { overflow-y: visible; }
288
292
  .mw-list--animate {
@@ -308,34 +312,34 @@ function handleDayKeydown(e, dayMs) {
308
312
  text-align: left;
309
313
  width: 100%;
310
314
  -webkit-tap-highlight-color: transparent;
311
- border-bottom: 1px solid var(--dt-border, rgba(0, 0, 0, 0.08));
315
+ border-bottom: 1px solid var(--dt-border, rgba(15, 15, 15, 0.08));
312
316
  min-height: 56px;
313
317
  }
314
318
  .mw-row:last-child {
315
319
  border-bottom: none;
316
320
  }
317
321
  .mw-row:has(.mw-row-target:active) {
318
- background: var(--dt-hover, rgba(0, 0, 0, 0.04));
322
+ background: var(--dt-hover, rgba(15, 15, 15, 0.04));
319
323
  }
320
324
  .mw-row--today {
321
- background: color-mix(in srgb, var(--dt-accent, #2563eb) 4%, transparent);
325
+ background: color-mix(in srgb, var(--dt-accent, #1d4fd7) 4%, transparent);
322
326
  }
323
327
  /* Token-based dim (not subtree opacity) so past rows stay legible/tappable */
324
328
  .mw-row--past {
325
- background: color-mix(in srgb, var(--dt-text, rgba(0, 0, 0, 0.87)) 3%, transparent);
329
+ background: color-mix(in srgb, var(--dt-text, rgba(15, 15, 15, 0.87)) 3%, transparent);
326
330
  }
327
331
  .mw-row--past :global(.mw-ev-title),
328
332
  .mw-row--past :global(.mw-ev-time),
329
333
  .mw-row--past .mw-day-num {
330
- color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
334
+ color: var(--dt-text-2, rgba(15, 15, 15, 0.54));
331
335
  }
332
336
  .mw-row--disabled {
333
337
  background-image: repeating-linear-gradient(
334
338
  135deg,
335
339
  transparent,
336
340
  transparent 6px,
337
- color-mix(in srgb, var(--dt-text, rgba(0, 0, 0, 0.87)) 4%, transparent) 6px,
338
- color-mix(in srgb, var(--dt-text, rgba(0, 0, 0, 0.87)) 4%, transparent) 12px
341
+ color-mix(in srgb, var(--dt-text, rgba(15, 15, 15, 0.87)) 4%, transparent) 6px,
342
+ color-mix(in srgb, var(--dt-text, rgba(15, 15, 15, 0.87)) 4%, transparent) 12px
339
343
  );
340
344
  }
341
345
  .mw-row-target {
@@ -353,7 +357,7 @@ function handleDayKeydown(e, dayMs) {
353
357
  }
354
358
  .mw-row-target:focus-visible {
355
359
  outline: none;
356
- box-shadow: inset 0 0 0 2px var(--dt-accent, #2563eb);
360
+ box-shadow: inset 0 0 0 2px var(--dt-text, #0f0f0f);
357
361
  }
358
362
 
359
363
  /* ─── Date column ────────────────────────────────── */
@@ -373,10 +377,10 @@ function handleDayKeydown(e, dayMs) {
373
377
  font: 500 12px/1 var(--dt-sans, system-ui, sans-serif);
374
378
  letter-spacing: 0.08em;
375
379
  text-transform: uppercase;
376
- color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
380
+ color: var(--dt-text-2, rgba(15, 15, 15, 0.54));
377
381
  }
378
382
  .mw-day-name--today {
379
- color: var(--dt-accent, #2563eb);
383
+ color: var(--dt-accent, #1d4fd7);
380
384
  }
381
385
 
382
386
  /* The date is the typography: large and regular, narrowed like the planner's */
@@ -385,10 +389,10 @@ function handleDayKeydown(e, dayMs) {
385
389
  font-stretch: 90%;
386
390
  font-variant-numeric: tabular-nums;
387
391
  letter-spacing: -0.02em;
388
- color: var(--dt-text, rgba(0, 0, 0, 0.87));
392
+ color: var(--dt-text, rgba(15, 15, 15, 0.87));
389
393
  }
390
394
  .mw-day-num--today {
391
- color: var(--dt-accent, #2563eb);
395
+ color: var(--dt-accent, #1d4fd7);
392
396
  }
393
397
 
394
398
  /* ─── Events column ──────────────────────────────── */
@@ -407,7 +411,7 @@ function handleDayKeydown(e, dayMs) {
407
411
 
408
412
  .mw-empty {
409
413
  font: 400 13px/1 var(--dt-sans, system-ui, sans-serif);
410
- color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
414
+ color: var(--dt-text-2, rgba(15, 15, 15, 0.54));
411
415
  }
412
416
 
413
417
  /* ─── Event chip ─────────────────────────────────── */
@@ -423,20 +427,20 @@ function handleDayKeydown(e, dayMs) {
423
427
  transition: background 120ms;
424
428
  -webkit-tap-highlight-color: transparent;
425
429
  border: none;
426
- border-bottom: 1px solid var(--dt-border, rgba(0, 0, 0, 0.3));
430
+ border-bottom: 1px solid var(--dt-border, rgba(15, 15, 15, 0.3));
427
431
  text-align: left;
428
432
  padding: 0;
429
433
  pointer-events: auto;
430
434
  }
431
435
  .mw-ev:hover,
432
436
  .mw-ev:active {
433
- background: var(--dt-hover, rgba(0, 0, 0, 0.04));
437
+ background: var(--dt-hover, rgba(15, 15, 15, 0.04));
434
438
  }
435
439
  .mw-ev--selected {
436
440
  box-shadow: inset 0 0 0 1px var(--ev-color);
437
441
  }
438
442
  .mw-ev--current {
439
- background: var(--dt-accent-dim, rgba(37, 99, 235, 0.12));
443
+ background: var(--dt-accent-dim, rgba(29, 79, 215, 0.12));
440
444
  }
441
445
  /* All day: a solid band on the event colour, no tint. */
442
446
  .mw-ev--allday {
@@ -460,14 +464,14 @@ function handleDayKeydown(e, dayMs) {
460
464
  limited one is set in grey with a dashed bar — never a bare opacity. */
461
465
  .mw-ev--cancelled .mw-ev-title {
462
466
  text-decoration: line-through;
463
- color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
467
+ color: var(--dt-text-2, rgba(15, 15, 15, 0.54));
464
468
  }
465
469
  .mw-ev--cancelled .mw-ev-stripe {
466
470
  opacity: 0.45; /* decorative bar only */
467
471
  }
468
472
  .mw-ev--tentative .mw-ev-title,
469
473
  .mw-ev--full .mw-ev-title {
470
- color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
474
+ color: var(--dt-text-2, rgba(15, 15, 15, 0.54));
471
475
  }
472
476
  .mw-ev--tentative .mw-ev-stripe,
473
477
  .mw-ev--limited .mw-ev-stripe {
@@ -500,7 +504,7 @@ function handleDayKeydown(e, dayMs) {
500
504
 
501
505
  .mw-ev-title {
502
506
  font: 500 15px/1.25 var(--dt-sans, system-ui, sans-serif);
503
- color: var(--dt-text, rgba(0, 0, 0, 0.87));
507
+ color: var(--dt-text, rgba(15, 15, 15, 0.87));
504
508
  white-space: nowrap;
505
509
  overflow: hidden;
506
510
  text-overflow: ellipsis;
@@ -511,14 +515,14 @@ function handleDayKeydown(e, dayMs) {
511
515
  .mw-ev-time {
512
516
  font: 400 14px/1 var(--dt-sans, system-ui, sans-serif);
513
517
  font-variant-numeric: tabular-nums;
514
- color: var(--dt-text, rgba(0, 0, 0, 0.87));
518
+ color: var(--dt-text, rgba(15, 15, 15, 0.87));
515
519
  white-space: nowrap;
516
520
  flex-shrink: 0;
517
521
  }
518
522
 
519
523
  .mw-ev-more {
520
524
  font: 400 12.5px/1 var(--dt-sans, system-ui, sans-serif);
521
- color: var(--dt-text-2, rgba(0, 0, 0, 0.54));
525
+ color: var(--dt-text-2, rgba(15, 15, 15, 0.54));
522
526
  padding: 2px 4px;
523
527
  min-height: 32px;
524
528
  border: none;
@@ -530,25 +534,21 @@ function handleDayKeydown(e, dayMs) {
530
534
  pointer-events: auto;
531
535
  -webkit-tap-highlight-color: transparent;
532
536
  }
533
- /* Hit-slop: 44px effective touch target */
534
- .mw-ev-more::before {
535
- content: '';
536
- position: absolute;
537
- left: 0;
538
- right: 0;
539
- top: 50%;
540
- transform: translateY(-50%);
541
- height: 44px;
537
+ @media (pointer: coarse) {
538
+ .mw-ev-more {
539
+ min-height: 44px;
540
+ min-width: 44px;
541
+ }
542
542
  }
543
543
  .mw-ev-more:focus-visible {
544
544
  outline: none;
545
- box-shadow: 0 0 0 2px var(--dt-accent, #2563eb);
545
+ box-shadow: 0 0 0 2px var(--dt-text, #0f0f0f);
546
546
  }
547
547
 
548
548
  /* ─── Chevron ────────────────────────────────────── */
549
549
  .mw-chevron {
550
550
  flex-shrink: 0;
551
- color: var(--dt-text-3, rgba(0, 0, 0, 0.38));
551
+ color: var(--dt-text-3, rgba(15, 15, 15, 0.38));
552
552
  position: relative;
553
553
  z-index: 1;
554
554
  pointer-events: none;
@@ -557,6 +557,6 @@ function handleDayKeydown(e, dayMs) {
557
557
  /* ─── Focus ──────────────────────────────────────── */
558
558
  .mw-ev:focus-visible {
559
559
  outline: none;
560
- box-shadow: 0 0 0 2px var(--dt-accent, #2563eb);
560
+ box-shadow: 0 0 0 2px var(--dt-accent, #1d4fd7);
561
561
  }
562
562
  </style>
@@ -9,7 +9,8 @@
9
9
  <script lang="ts">import { useCalendarContext } from "../shared/context.svelte.js";
10
10
  import { createClock } from "../../core/clock.svelte.js";
11
11
  import { DAY_MS, sod, addDaysMs, isAllDay } from "../../core/time.js";
12
- import { fmtTime, weekdayShort } from "../../core/locale.js";
12
+ import { fmtTime, fmtDayNum, weekdayShort } from "../../core/locale.js";
13
+ import { dateLong } from "../shared/format.js";
13
14
  let { events = [], style = "", height = null, locale, focusDate, oneventclick, selectedEventId = null } = $props();
14
15
  const ctx = useCalendarContext();
15
16
  const L = $derived(ctx.labels);
@@ -139,11 +140,18 @@ function cellKeydown(e, cell) {
139
140
  case " ":
140
141
  if (!cell.isDisabled) {
141
142
  e.preventDefault();
142
- ondayclick?.(cell.date);
143
+ activateCell(cell);
143
144
  }
144
145
  break;
145
146
  }
146
147
  }
148
+ /** The cell's own action: drill into the day; on phones (dots, no
149
+ * ondayclick) the whole cell opens its overflow instead of a tiny "+N". */
150
+ function activateCell(cell) {
151
+ if (cell.isDisabled) return;
152
+ if (ondayclick) ondayclick(cell.date);
153
+ else if (dotsMode && cell.overflow > 0) expandedMs = expandedMs === cell.ms ? null : cell.ms;
154
+ }
147
155
  function overflowClick(e, cell) {
148
156
  e.stopPropagation();
149
157
  if (ondayclick) ondayclick(cell.date);
@@ -236,18 +244,25 @@ function chipTime(e) {
236
244
  aria-current={cell.isToday ? 'date' : undefined}
237
245
  data-ms={cell.ms}
238
246
  tabindex={isFocusable(cell) ? (cell.ms === rovingMs ? 0 : -1) : undefined}
239
- onclick={() => {
240
- if (!cell.isDisabled) ondayclick?.(cell.date);
241
- }}
247
+ onclick={() => activateCell(cell)}
242
248
  onfocusin={() => (focusMs = cell.ms)}
243
249
  onkeydown={(e) => cellKeydown(e, cell)}
244
250
  >
245
251
  <span class="mg-daynum" class:mg-daynum--today={cell.isToday}>
246
- {cell.dayNum}
252
+ {fmtDayNum(cell.ms, locale)}
247
253
  </span>
248
- <div class="mg-chips">
254
+ <!-- Phones: dots are a picture of the day; the cell (its label counts
255
+ the events) is the one tap and tab target. -->
256
+ <div class="mg-chips" aria-hidden={dotsMode || undefined}>
249
257
  {#each expandedMs === cell.ms ? cell.all : cell.chips as ev (ev.id + cell.ms)}
250
- {#if eventSnippet}
258
+ {#if dotsMode}
259
+ <span
260
+ class="mg-chip"
261
+ class:mg-chip--selected={ev.id === selectedEventId}
262
+ class:mg-chip--cancelled={ev.status === 'cancelled'}
263
+ style:--mg-chip-color={ev.color ?? (isAllDay(ev) ? 'var(--dt-accent)' : 'var(--dt-event, var(--dt-accent))')}
264
+ ><span class="mg-chip-dot"></span></span>
265
+ {:else if eventSnippet}
251
266
  <button
252
267
  type="button"
253
268
  class="mg-chip mg-chip--custom"
@@ -266,9 +281,9 @@ function chipTime(e) {
266
281
  class="mg-chip"
267
282
  class:mg-chip--selected={ev.id === selectedEventId}
268
283
  class:mg-chip--cancelled={ev.status === 'cancelled'}
269
- style:--mg-chip-color={ev.color ?? 'var(--dt-accent)'}
284
+ style:--mg-chip-color={ev.color ?? (isAllDay(ev) ? 'var(--dt-accent)' : 'var(--dt-event, var(--dt-accent))')}
270
285
  title={ev.title}
271
- aria-label="{ev.title}{chipTime(ev) ? `, ${chipTime(ev)}` : ''}"
286
+ aria-label="{ev.title}, {dateLong(cell.ms, locale)}{chipTime(ev) ? `, ${chipTime(ev)}` : ''}"
272
287
  onclick={(e) => {
273
288
  e.stopPropagation();
274
289
  oneventclick?.(ev, e.currentTarget.getBoundingClientRect());
@@ -281,15 +296,19 @@ function chipTime(e) {
281
296
  </button>
282
297
  {/if}
283
298
  {/each}
284
- {#if cell.overflow > 0 && expandedMs !== cell.ms}
299
+ {#if dotsMode}
300
+ {#if cell.overflow > 0 && expandedMs !== cell.ms}
301
+ <span class="mg-more">+{cell.overflow}</span>
302
+ {/if}
303
+ {:else if cell.overflow > 0 && expandedMs !== cell.ms}
285
304
  <button
286
305
  type="button"
287
306
  class="mg-more"
288
307
  aria-expanded={ondayclick ? undefined : false}
289
- aria-label={L.nMore(cell.overflow)}
308
+ aria-label="{L.nMore(cell.overflow)}, {dateLong(cell.ms, locale)}"
290
309
  onclick={(e) => overflowClick(e, cell)}
291
310
  >
292
- {dotsMode ? `+${cell.overflow}` : L.nMore(cell.overflow)}
311
+ {L.nMore(cell.overflow)}
293
312
  </button>
294
313
  {:else if expandedMs === cell.ms}
295
314
  <button
@@ -338,7 +357,7 @@ function chipTime(e) {
338
357
  font-variant-numeric: tabular-nums;
339
358
  text-transform: uppercase;
340
359
  letter-spacing: 0.08em;
341
- color: var(--dt-text-2, rgba(0, 0, 0, 0.66));
360
+ color: var(--dt-text-2, rgba(15, 15, 15, 0.66));
342
361
  }
343
362
 
344
363
  .mg-body {
@@ -372,7 +391,7 @@ function chipTime(e) {
372
391
  border-right: none;
373
392
  }
374
393
  .mg-cell--weekend {
375
- background: var(--dt-weekend-bg, rgba(0, 0, 0, 0.02));
394
+ background: var(--dt-weekend-bg, rgba(15, 15, 15, 0.02));
376
395
  }
377
396
  /* Dim only the day number for adjacent-month cells — their events stay
378
397
  legible. text-2, not text-3: a 22px numeral still needs 4.5:1. */
@@ -380,7 +399,7 @@ function chipTime(e) {
380
399
  background: var(--dt-surface, transparent);
381
400
  }
382
401
  .mg-cell--out .mg-daynum {
383
- color: var(--dt-text-2, rgba(0, 0, 0, 0.66));
402
+ color: var(--dt-text-2, rgba(15, 15, 15, 0.66));
384
403
  }
385
404
  .mg-cell--today {
386
405
  background: var(--dt-today-bg);
@@ -396,10 +415,10 @@ function chipTime(e) {
396
415
  cursor: pointer;
397
416
  }
398
417
  .mg-cell--clickable:hover {
399
- background: var(--dt-hover, rgba(0, 0, 0, 0.04));
418
+ background: var(--dt-hover, rgba(15, 15, 15, 0.04));
400
419
  }
401
420
  .mg-cell:focus-visible {
402
- outline: 2px solid var(--dt-accent, #2563eb);
421
+ outline: 2px solid var(--dt-text, #0f0f0f);
403
422
  outline-offset: -2px;
404
423
  }
405
424
 
@@ -446,10 +465,10 @@ function chipTime(e) {
446
465
  text-align: left;
447
466
  }
448
467
  .mg-chip:hover {
449
- background: var(--dt-hover, rgba(0, 0, 0, 0.04));
468
+ background: var(--dt-hover, rgba(15, 15, 15, 0.04));
450
469
  }
451
470
  .mg-chip:focus-visible {
452
- box-shadow: 0 0 0 2px var(--dt-accent, #2563eb);
471
+ box-shadow: 0 0 0 2px var(--dt-accent, #1d4fd7);
453
472
  outline: none;
454
473
  }
455
474
  .mg-chip--selected {
@@ -493,11 +512,11 @@ function chipTime(e) {
493
512
  cursor: pointer;
494
513
  }
495
514
  .mg-more:hover {
496
- background: var(--dt-hover, rgba(0, 0, 0, 0.04));
515
+ background: var(--dt-hover, rgba(15, 15, 15, 0.04));
497
516
  color: var(--dt-text);
498
517
  }
499
518
  .mg-more:focus-visible {
500
- box-shadow: 0 0 0 2px var(--dt-accent, #2563eb);
519
+ box-shadow: 0 0 0 2px var(--dt-text, #0f0f0f);
501
520
  outline: none;
502
521
  }
503
522
 
@@ -518,13 +537,20 @@ function chipTime(e) {
518
537
  /* ── Dots mode (mobile) ─────────────────────────────
519
538
  Cells are too narrow for text chips, so events render as colored
520
539
  dots in a wrapping row. The cell itself stays the tap target
521
- (day drill-down); dots keep their title/aria-label for a11y. */
540
+ (day drill-down) and its label counts the events; dots are aria-hidden. */
522
541
  .mg--dots .mg-chips {
523
542
  flex-direction: row;
524
543
  flex-wrap: wrap;
525
544
  align-items: center;
526
545
  gap: 3px;
527
546
  }
547
+ /* The cell is the target: at least a 44px tap, dots never take the hit. */
548
+ .mg--dots .mg-cell {
549
+ min-height: 44px;
550
+ }
551
+ .mg--dots .mg-chips {
552
+ pointer-events: none;
553
+ }
528
554
  .mg--dots .mg-chip {
529
555
  padding: 3px;
530
556
  min-height: 0;