@candor-ui/react 2.1.0 → 2.3.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 (57) hide show
  1. package/dist/adapters/use-ag-ui.d.ts +1 -1
  2. package/dist/adapters/use-candor-chat.d.ts +1 -1
  3. package/dist/adapters/use-claude-agent.d.ts +1 -1
  4. package/dist/blocks/copy-field.js +4 -1
  5. package/dist/blocks/degraded-panel.js +3 -1
  6. package/dist/blocks/locked.js +5 -1
  7. package/dist/blocks/status-dot.d.ts +14 -3
  8. package/dist/blocks/status-dot.js +17 -22
  9. package/dist/blocks/step-list.d.ts +2 -1
  10. package/dist/blocks/step-list.js +19 -27
  11. package/dist/blocks/streaming-text.js +3 -1
  12. package/dist/blocks/surface.d.ts +1 -1
  13. package/dist/chat/attachment-preview.js +5 -2
  14. package/dist/chat/card-registry.js +3 -1
  15. package/dist/chat/citation.js +2 -2
  16. package/dist/chat/composer.js +19 -53
  17. package/dist/chat/context-meter.js +4 -1
  18. package/dist/chat/entity-chip.js +1 -1
  19. package/dist/chat/folded-turns.js +3 -1
  20. package/dist/chat/message-actions.js +5 -2
  21. package/dist/chat/message.js +9 -5
  22. package/dist/chat/payload.js +1 -1
  23. package/dist/chat/permission-prompt.js +6 -1
  24. package/dist/chat/prompt-suggestions.js +4 -1
  25. package/dist/chat/reasoning.js +6 -1
  26. package/dist/chat/thread.js +19 -8
  27. package/dist/chat/tool-call.js +6 -2
  28. package/dist/index.d.ts +8 -0
  29. package/dist/index.js +8 -0
  30. package/dist/lib/motion.d.ts +451 -0
  31. package/dist/lib/motion.js +350 -0
  32. package/dist/styles.css +543 -44
  33. package/dist/ui/accordion.d.ts +23 -0
  34. package/dist/ui/accordion.js +45 -0
  35. package/dist/ui/alert.d.ts +20 -0
  36. package/dist/ui/alert.js +51 -0
  37. package/dist/ui/button.d.ts +1 -1
  38. package/dist/ui/button.js +5 -3
  39. package/dist/ui/checkbox.d.ts +14 -0
  40. package/dist/ui/checkbox.js +32 -0
  41. package/dist/ui/collapsible.d.ts +3 -2
  42. package/dist/ui/collapsible.js +6 -3
  43. package/dist/ui/label.d.ts +10 -0
  44. package/dist/ui/label.js +16 -0
  45. package/dist/ui/popover.d.ts +1 -1
  46. package/dist/ui/popover.js +4 -2
  47. package/dist/ui/progress.d.ts +29 -0
  48. package/dist/ui/progress.js +27 -0
  49. package/dist/ui/skeleton.d.ts +1 -1
  50. package/dist/ui/skeleton.js +5 -2
  51. package/dist/ui/slider.d.ts +28 -0
  52. package/dist/ui/slider.js +41 -0
  53. package/dist/ui/switch.d.ts +14 -0
  54. package/dist/ui/switch.js +23 -0
  55. package/dist/ui/tooltip.d.ts +1 -1
  56. package/dist/ui/tooltip.js +4 -2
  57. package/package.json +1 -1
package/dist/styles.css CHANGED
@@ -248,12 +248,16 @@
248
248
  * text and 15px body and label text, with a wider thread and sidebar. Both set the
249
249
  * same four tokens, so one overrides the other when nested.
250
250
  *
251
- * Motion: data-motion="none" | "subtle" | "expressive" on <html> (or any container).
252
- * Subtle is the default: a change that happened is shown settling (a collapse,
253
- * a drawn tick, a fade). None turns every animation and transition off, with or
254
- * without the OS setting. Expressive adds scale to pops and a shake to a locked
255
- * control that was pressed. Motion reports a state change and never invents one;
256
- * the OS's reduced-motion setting wins over all three.
251
+ * Motion: fourteen families (reveal, arrive, pop, mark, fill, value, move, overlay,
252
+ * press, tint, refuse, attention, live, clock), each with a level (0 off, 1 subtle,
253
+ * 2 expressive), a duration, an easing, an amplitude and a variant. A brand file sets
254
+ * --cd-motion-<family>-* for a family everywhere, or --cd-motion-<item>-<moment>-* for
255
+ * one moment; components put the chain on the moving element (lib/motion.ts) and add
256
+ * a family utility (cd-pop, cd-overlay…) only at the honest moment. The person
257
+ * outranks the brand: data-motion="subtle" | "expressive" | "calm" | "none" on <html>
258
+ * (or any container), and the OS's reduced-motion setting, which is the calm level
259
+ * (opacity and colour only, 150 ms at most, nothing loops). None is the hard off.
260
+ * Motion reports a state change and never invents one.
257
261
  */
258
262
  @custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
259
263
 
@@ -301,9 +305,6 @@
301
305
  --cd-dur-quick: 120ms;
302
306
  --cd-dur-base: 200ms;
303
307
  --cd-dur-slow: 360ms;
304
- /* What data-motion="expressive" turns on. Subtle pops only fade (a scale of 1) and never shakes. */
305
- --cd-pop-from: 1;
306
- --cd-motion-shake: none;
307
308
 
308
309
  /* The message column's width, and the app sidebar's. (Not --sidebar-width: shadcn's SidebarProvider sets that.) */
309
310
  --cd-thread-width: 48rem;
@@ -350,10 +351,108 @@
350
351
  }
351
352
  }
352
353
 
353
- /* The motion presets. Subtle needs no attribute; expressive adds scale and a shake; none is below, after the keyframes. */
354
+ /*
355
+ * The motion layer's numbers. --cd-motion-preset is the level every family defaults to, --cd-motion-cap the highest
356
+ * level allowed where it's read, --cd-motion-speed multiplies every duration but the clock's and the attention ring's
357
+ * (which WCAG 2.2.2 caps at five seconds). They're registered so a
358
+ * data-motion container anywhere in the tree changes them for what's inside.
359
+ */
360
+ @property --cd-motion-preset { syntax: "<number>"; inherits: true; initial-value: 1; }
361
+ @property --cd-motion-cap { syntax: "<number>"; inherits: true; initial-value: 2; }
362
+ @property --cd-motion-speed { syntax: "<number>"; inherits: true; initial-value: 1; }
363
+
364
+ /*
365
+ * A moment's chain (lib/motion.ts puts it in the moving element's style): its level, duration, easing, amplitude and
366
+ * variant, each falling back to the family's token, then the default. Registered as not inherited, so a child never
367
+ * plays with its parent's moment. Not for brand files: set --cd-motion-* instead.
368
+ */
369
+ @property --cd-m-reveal { syntax: "*"; inherits: false; }
370
+ @property --cd-m-reveal-dur { syntax: "*"; inherits: false; }
371
+ @property --cd-m-reveal-ease { syntax: "*"; inherits: false; }
372
+ @property --cd-m-reveal-variant { syntax: "*"; inherits: false; }
373
+ @property --cd-m-arrive { syntax: "*"; inherits: false; }
374
+ @property --cd-m-arrive-dur { syntax: "*"; inherits: false; }
375
+ @property --cd-m-arrive-ease { syntax: "*"; inherits: false; }
376
+ @property --cd-m-arrive-amp { syntax: "*"; inherits: false; }
377
+ @property --cd-m-arrive-variant { syntax: "*"; inherits: false; }
378
+ @property --cd-m-pop { syntax: "*"; inherits: false; }
379
+ @property --cd-m-pop-dur { syntax: "*"; inherits: false; }
380
+ @property --cd-m-pop-out-dur { syntax: "*"; inherits: false; }
381
+ @property --cd-m-pop-ease { syntax: "*"; inherits: false; }
382
+ @property --cd-m-pop-amp { syntax: "*"; inherits: false; }
383
+ @property --cd-m-pop-variant { syntax: "*"; inherits: false; }
384
+ @property --cd-m-mark { syntax: "*"; inherits: false; }
385
+ @property --cd-m-mark-dur { syntax: "*"; inherits: false; }
386
+ @property --cd-m-mark-ease { syntax: "*"; inherits: false; }
387
+ @property --cd-m-mark-variant { syntax: "*"; inherits: false; }
388
+ @property --cd-m-fill { syntax: "*"; inherits: false; }
389
+ @property --cd-m-fill-dur { syntax: "*"; inherits: false; }
390
+ @property --cd-m-fill-ease { syntax: "*"; inherits: false; }
391
+ @property --cd-m-value { syntax: "*"; inherits: false; }
392
+ @property --cd-m-value-dur { syntax: "*"; inherits: false; }
393
+ @property --cd-m-value-ease { syntax: "*"; inherits: false; }
394
+ @property --cd-m-value-amp { syntax: "*"; inherits: false; }
395
+ @property --cd-m-value-variant { syntax: "*"; inherits: false; }
396
+ @property --cd-m-move { syntax: "*"; inherits: false; }
397
+ @property --cd-m-move-dur { syntax: "*"; inherits: false; }
398
+ @property --cd-m-move-ease { syntax: "*"; inherits: false; }
399
+ @property --cd-m-overlay { syntax: "*"; inherits: false; }
400
+ @property --cd-m-overlay-dur { syntax: "*"; inherits: false; }
401
+ @property --cd-m-overlay-out-dur { syntax: "*"; inherits: false; }
402
+ @property --cd-m-overlay-ease { syntax: "*"; inherits: false; }
403
+ @property --cd-m-overlay-amp { syntax: "*"; inherits: false; }
404
+ @property --cd-m-overlay-variant { syntax: "*"; inherits: false; }
405
+ @property --cd-m-press { syntax: "*"; inherits: false; }
406
+ @property --cd-m-press-dur { syntax: "*"; inherits: false; }
407
+ @property --cd-m-press-ease { syntax: "*"; inherits: false; }
408
+ @property --cd-m-press-amp { syntax: "*"; inherits: false; }
409
+ @property --cd-m-tint { syntax: "*"; inherits: false; }
410
+ @property --cd-m-tint-dur { syntax: "*"; inherits: false; }
411
+ @property --cd-m-tint-ease { syntax: "*"; inherits: false; }
412
+ @property --cd-m-refuse { syntax: "*"; inherits: false; }
413
+ @property --cd-m-refuse-dur { syntax: "*"; inherits: false; }
414
+ @property --cd-m-refuse-ease { syntax: "*"; inherits: false; }
415
+ @property --cd-m-refuse-amp { syntax: "*"; inherits: false; }
416
+ @property --cd-m-attention { syntax: "*"; inherits: false; }
417
+ @property --cd-m-attention-dur { syntax: "*"; inherits: false; }
418
+ @property --cd-m-attention-ease { syntax: "*"; inherits: false; }
419
+ @property --cd-m-attention-amp { syntax: "*"; inherits: false; }
420
+ @property --cd-m-live { syntax: "*"; inherits: false; }
421
+ @property --cd-m-live-dur { syntax: "*"; inherits: false; }
422
+ @property --cd-m-live-ease { syntax: "*"; inherits: false; }
423
+ @property --cd-m-clock { syntax: "*"; inherits: false; }
424
+
425
+ /*
426
+ * The person's setting, which outranks the brand. No attribute: the brand's levels, up to expressive. Subtle caps every
427
+ * family at 1; expressive raises the ones the brand didn't set; calm is the reduced-motion level by choice; none is the
428
+ * hard off (its rules are in the base layer, below the keyframes). Under the OS setting the cap is 1 and the calm forms
429
+ * apply whatever the attribute says, except none.
430
+ */
431
+ [data-motion="subtle"] { --cd-motion-preset: 1; --cd-motion-cap: 1; }
354
432
  [data-motion="expressive"] {
355
- --cd-pop-from: 0.85;
356
- --cd-motion-shake: shake var(--cd-dur-slow) var(--cd-ease) both;
433
+ --cd-motion-preset: 2;
434
+ --cd-motion-cap: 2;
435
+ /* 2.2's expressive values, for apps that use the animate-pop-in and animate-shake utilities directly. */
436
+ --cd-pop-from-preset: 0.85;
437
+ --cd-motion-shake-preset: shake var(--cd-dur-slow) var(--cd-ease) both;
438
+ }
439
+ [data-motion="calm"] { --cd-motion-cap: 1; }
440
+ [data-motion="none"] { --cd-motion-preset: 0; --cd-motion-cap: 0; }
441
+ @media (prefers-reduced-motion: reduce) {
442
+ :root, [data-motion]:not([data-motion="none"]) { --cd-motion-cap: 1; }
443
+ }
444
+
445
+ /*
446
+ * The calm level, as a variant the family utilities use: the OS's reduced-motion setting, or inside data-motion="calm".
447
+ * (The ancestor form, so it also works on ::before and ::after.)
448
+ */
449
+ @custom-variant calm {
450
+ @media (prefers-reduced-motion: reduce) {
451
+ @slot;
452
+ }
453
+ :where([data-motion="calm"]) & {
454
+ @slot;
455
+ }
357
456
  }
358
457
 
359
458
  @theme inline {
@@ -458,28 +557,26 @@
458
557
  --ease-inout: var(--cd-ease-inout);
459
558
  --ease-spring: var(--cd-ease-spring);
460
559
 
461
- --animate-shimmer: shimmer 2.2s linear infinite;
462
- --animate-pulse-dot: pulse-dot 1.6s var(--cd-ease) infinite;
463
- --animate-rise-in: rise-in 240ms var(--cd-ease) both;
464
- --animate-caret: caret 1s steps(2, start) infinite;
465
-
466
560
  /*
467
- * Motion that reports a change. Tailwind has no --duration-* namespace, so use the tokens directly:
468
- * duration-(--cd-dur-base). A collapse follows Radix's measured height; a pop is a fade (and a scale under
469
- * expressive); tick-draw draws a mark whose path has pathLength="1"; fill grows a bar from --cd-fill-from; shake is
470
- * none unless expressive; attention is one ring pulse, attention-wait three slow ones (then still: WCAG 2.2.2 wants moving content to stop).
561
+ * 2.2's animation utilities, kept for apps that use them in their own screens. Candor's components use the motion
562
+ * families below (cd-pop, cd-reveal…), which a brand file and data-motion reach moment by moment; these read only the
563
+ * family's duration. attention-wait is three pulses of 1.6 s (4.8 s in all, then still: WCAG 2.2.2 wants moving
564
+ * content to stop).
471
565
  */
472
- --animate-collapse-down: collapse-down var(--cd-dur-base) var(--cd-ease);
473
- --animate-collapse-up: collapse-up var(--cd-dur-base) var(--cd-ease);
474
- --animate-pop-in: pop-in var(--cd-dur-base) var(--cd-ease) both;
475
- --animate-pop-out: pop-out var(--cd-dur-quick) var(--cd-ease) both;
476
- --animate-tick-draw: tick-draw var(--cd-dur-slow) var(--cd-ease) both;
477
- --animate-fill: fill var(--cd-dur-slow) var(--cd-ease) both;
478
- --animate-shake: var(--cd-motion-shake);
479
- --animate-attention: attention 900ms var(--cd-ease) 1;
480
- --animate-attention-wait: attention 2.4s var(--cd-ease) 3;
481
- /* A prompt that was clicked around instead of answered: one attention ring, and a shake when expressive. */
482
- --animate-nudge: var(--cd-motion-shake), attention 900ms var(--cd-ease) 1;
566
+ --animate-shimmer: shimmer 2.2s linear infinite;
567
+ --animate-pulse-dot: pulse-dot var(--cd-motion-live-dur, 1.6s) var(--cd-ease) infinite;
568
+ --animate-rise-in: rise-in var(--cd-motion-arrive-dur, 240ms) var(--cd-ease) both;
569
+ --animate-caret: caret 1s steps(2, start) infinite;
570
+ --animate-collapse-down: collapse-down var(--cd-motion-reveal-dur, var(--cd-dur-base)) var(--cd-ease);
571
+ --animate-collapse-up: collapse-up var(--cd-motion-reveal-dur, var(--cd-dur-base)) var(--cd-ease);
572
+ --animate-pop-in: pop-in var(--cd-motion-pop-dur, var(--cd-dur-base)) var(--cd-ease) both;
573
+ --animate-pop-out: pop-out var(--cd-motion-pop-out-dur, var(--cd-dur-quick)) var(--cd-ease) both;
574
+ --animate-tick-draw: tick-draw var(--cd-motion-mark-dur, var(--cd-dur-slow)) var(--cd-ease) both;
575
+ --animate-fill: fill var(--cd-motion-fill-dur, var(--cd-dur-slow)) var(--cd-ease) both;
576
+ --animate-shake: var(--cd-motion-shake, var(--cd-motion-shake-preset, none));
577
+ --animate-attention: attention var(--cd-motion-attention-dur, 900ms) var(--cd-ease) 1;
578
+ --animate-attention-wait: attention 1.6s var(--cd-ease) 3;
579
+ --animate-nudge: var(--cd-motion-shake, var(--cd-motion-shake-preset, none)), attention var(--cd-motion-attention-dur, 900ms) var(--cd-ease) 1;
483
580
  }
484
581
 
485
582
  @keyframes shimmer {
@@ -508,12 +605,12 @@
508
605
  }
509
606
  /* Something added or removed: a fade, and a scale from --cd-pop-from (1 unless expressive). */
510
607
  @keyframes pop-in {
511
- from { opacity: 0; transform: scale(var(--cd-pop-from)); }
608
+ from { opacity: 0; transform: scale(var(--cd-pop-from, var(--cd-pop-from-preset, 1))); }
512
609
  to { opacity: 1; transform: none; }
513
610
  }
514
611
  @keyframes pop-out {
515
612
  from { opacity: 1; transform: none; }
516
- to { opacity: 0; transform: scale(var(--cd-pop-from)); }
613
+ to { opacity: 0; transform: scale(var(--cd-pop-from, var(--cd-pop-from-preset, 1))); }
517
614
  }
518
615
  /* A tick or cross drawn along its path; the path has pathLength="1" and stroke-dasharray 1. */
519
616
  @keyframes tick-draw {
@@ -560,27 +657,424 @@
560
657
  [data-slot="payload"][data-syntax="highlight"] :is([data-token="property"], [data-token="tag"], [data-token="type"]) { color: var(--warning-text); }
561
658
 
562
659
  /*
563
- * data-motion="none": nothing moves, with or without the OS setting. An element leaving with a pop-out (data-leaving)
564
- * is simply gone. The reduced-motion block below comes last and stays authoritative for every preset.
660
+ * ---------------------------------------------------------------- The motion families
661
+ *
662
+ * One utility (or an in and out pair) per family. A component adds it only at the honest moment, and puts the
663
+ * moment's chain from lib/motion.ts in the same element's style; with no chain, the family's tokens apply. Every
664
+ * value is worked out here, on the element that moves, so the nearest data-motion and the brand's tokens apply:
665
+ *
666
+ * level = min(moment ?? family ?? preset, cap)
667
+ * time = duration × speed × min(level, 1) (level 0: the end state at once; events still fire)
668
+ * amount = amplitude × (subtle share + (1 − share) × clamp(0, level − 1, 1))
669
+ *
670
+ * Each has a calm form (@variant calm: the OS's reduced-motion setting or data-motion="calm"): opacity and colour only,
671
+ * 150 ms at most, nothing loops. Defaults here must equal lib/motion.ts's; `npm run check:motion` compares them.
565
672
  */
566
- [data-motion="none"], [data-motion="none"] *, [data-motion="none"] *::before, [data-motion="none"] *::after {
567
- animation: none !important;
568
- transition: none !important;
569
- scroll-behavior: auto !important;
673
+
674
+ /* reveal: content opened or closed to its measured size (Radix's), or faded with the size snapping. */
675
+ @utility cd-reveal {
676
+ --cd-reveal-l: min(var(--cd-m-reveal, var(--cd-motion-reveal, var(--cd-motion-preset))), var(--cd-motion-cap));
677
+ --cd-reveal-t: calc(var(--cd-m-reveal-dur, var(--cd-motion-reveal-dur, 200ms)) * var(--cd-motion-speed) * min(var(--cd-reveal-l), 1));
678
+ --cd-size: var(--radix-collapsible-content-height, var(--radix-accordion-content-height, auto));
679
+ animation: var(--cd-m-reveal-variant, var(--cd-motion-reveal-variant, cd-size)) var(--cd-reveal-t) var(--cd-m-reveal-ease, var(--cd-motion-reveal-ease, var(--cd-ease)));
680
+ @variant calm {
681
+ animation-name: none !important;
682
+ }
683
+ }
684
+ @utility cd-reveal-out {
685
+ --cd-reveal-l: min(var(--cd-m-reveal, var(--cd-motion-reveal, var(--cd-motion-preset))), var(--cd-motion-cap));
686
+ --cd-reveal-t: calc(var(--cd-m-reveal-dur, var(--cd-motion-reveal-dur, 200ms)) * var(--cd-motion-speed) * min(var(--cd-reveal-l), 1));
687
+ --cd-size: var(--radix-collapsible-content-height, var(--radix-accordion-content-height, auto));
688
+ animation: var(--cd-m-reveal-variant, var(--cd-motion-reveal-variant, cd-size)) var(--cd-reveal-t) var(--cd-m-reveal-ease, var(--cd-motion-reveal-ease, var(--cd-ease))) reverse both;
689
+ @variant calm {
690
+ animation-name: none !important;
691
+ }
692
+ }
693
+ /* A disclosure's chevron turning with its content. */
694
+ @utility cd-reveal-turn {
695
+ --cd-reveal-l: min(var(--cd-m-reveal, var(--cd-motion-reveal, var(--cd-motion-preset))), var(--cd-motion-cap));
696
+ --cd-reveal-t: calc(var(--cd-m-reveal-dur, var(--cd-motion-reveal-dur, 200ms)) * var(--cd-motion-speed) * min(var(--cd-reveal-l), 1));
697
+ transition-property: transform, rotate;
698
+ transition-duration: var(--cd-reveal-t);
699
+ transition-timing-function: var(--cd-m-reveal-ease, var(--cd-motion-reveal-ease, var(--cd-ease)));
700
+ @variant calm {
701
+ transition-property: none !important;
702
+ }
703
+ }
704
+
705
+ /* arrive: something new after the first draw rises in (or fades, or pops). */
706
+ @utility cd-arrive {
707
+ --cd-arrive-l: min(var(--cd-m-arrive, var(--cd-motion-arrive, var(--cd-motion-preset))), var(--cd-motion-cap));
708
+ --cd-arrive-t: calc(var(--cd-m-arrive-dur, var(--cd-motion-arrive-dur, 240ms)) * var(--cd-motion-speed) * min(var(--cd-arrive-l), 1));
709
+ --cd-arrive-f: calc(0.5 + 0.5 * clamp(0, var(--cd-arrive-l) - 1, 1));
710
+ --cd-from-y: calc(var(--cd-m-arrive-amp, var(--cd-motion-arrive-distance, 8px)) * var(--cd-arrive-f));
711
+ --cd-from-scale: calc(1 - 0.04 * var(--cd-arrive-f));
712
+ animation: var(--cd-m-arrive-variant, var(--cd-motion-arrive-variant, cd-rise)) var(--cd-arrive-t) var(--cd-m-arrive-ease, var(--cd-motion-arrive-ease, var(--cd-ease))) both;
713
+ @variant calm {
714
+ animation-name: cd-fade !important;
715
+ animation-duration: min(var(--cd-arrive-t), 150ms) !important;
716
+ }
717
+ }
718
+
719
+ /* pop: added, removed, or a small mark appearing. A fade, with a scale from the amplitude at expressive. */
720
+ @utility cd-pop {
721
+ --cd-pop-l: min(var(--cd-m-pop, var(--cd-motion-pop, var(--cd-motion-preset))), var(--cd-motion-cap));
722
+ --cd-pop-t: calc(var(--cd-m-pop-dur, var(--cd-motion-pop-dur, 200ms)) * var(--cd-motion-speed) * min(var(--cd-pop-l), 1));
723
+ /* A 2.2 brand's --cd-pop-from still wins. */
724
+ --cd-from-scale: var(--cd-pop-from, calc(1 - (1 - var(--cd-m-pop-amp, var(--cd-motion-pop-scale, 0.85))) * clamp(0, var(--cd-pop-l) - 1, 1)));
725
+ animation: var(--cd-m-pop-variant, var(--cd-motion-pop-variant, cd-scale)) var(--cd-pop-t) var(--cd-m-pop-ease, var(--cd-motion-pop-ease, var(--cd-ease))) both;
726
+ @variant calm {
727
+ animation-name: cd-fade !important;
728
+ animation-duration: min(var(--cd-pop-t), 150ms) !important;
729
+ }
730
+ }
731
+ @utility cd-pop-out {
732
+ --cd-pop-l: min(var(--cd-m-pop, var(--cd-motion-pop, var(--cd-motion-preset))), var(--cd-motion-cap));
733
+ --cd-pop-t: calc(var(--cd-m-pop-out-dur, var(--cd-motion-pop-out-dur, 120ms)) * var(--cd-motion-speed) * min(var(--cd-pop-l), 1));
734
+ --cd-from-scale: var(--cd-pop-from, calc(1 - (1 - var(--cd-m-pop-amp, var(--cd-motion-pop-scale, 0.85))) * clamp(0, var(--cd-pop-l) - 1, 1)));
735
+ animation: var(--cd-m-pop-variant, var(--cd-motion-pop-variant, cd-scale)) var(--cd-pop-t) var(--cd-m-pop-ease, var(--cd-motion-pop-ease, var(--cd-ease))) reverse both;
736
+ @variant calm {
737
+ animation-name: cd-fade !important;
738
+ animation-duration: min(var(--cd-pop-t), 150ms) !important;
739
+ }
740
+ }
741
+
742
+ /*
743
+ * mark: a tick or cross drawn when a result settles. Put it on each path (pathLength="1"); set --cd-mark-step to 1 on a
744
+ * second stroke to draw it after the first.
745
+ */
746
+ @utility cd-mark {
747
+ --cd-mark-l: min(var(--cd-m-mark, var(--cd-motion-mark, var(--cd-motion-preset))), var(--cd-motion-cap));
748
+ --cd-mark-t: calc(var(--cd-m-mark-dur, var(--cd-motion-mark-dur, 360ms)) * var(--cd-motion-speed) * min(var(--cd-mark-l), 1));
749
+ --cd-from-scale: 0.6;
750
+ --cd-from-y: -4px;
751
+ stroke-dasharray: 1;
752
+ transform-box: fill-box;
753
+ transform-origin: center;
754
+ animation: var(--cd-m-mark-variant, var(--cd-motion-mark-variant, cd-draw)) var(--cd-mark-t) var(--cd-m-mark-ease, var(--cd-motion-mark-ease, var(--cd-ease))) both;
755
+ animation-delay: calc(var(--cd-mark-step, 0) * var(--cd-mark-t) / 3);
756
+ @variant calm {
757
+ animation-name: cd-fade !important;
758
+ animation-duration: min(var(--cd-mark-t), 150ms) !important;
759
+ animation-delay: 0s !important;
760
+ }
761
+ }
762
+
763
+ /* fill: a bar or ring moving between measured values (a transition on its width, dash or scale). */
764
+ @utility cd-fill {
765
+ --cd-fill-l: min(var(--cd-m-fill, var(--cd-motion-fill, var(--cd-motion-preset))), var(--cd-motion-cap));
766
+ --cd-fill-t: calc(var(--cd-m-fill-dur, var(--cd-motion-fill-dur, 360ms)) * var(--cd-motion-speed) * min(var(--cd-fill-l), 1));
767
+ transition-property: width, inline-size, height, block-size, scale, stroke-dasharray, stroke-dashoffset, stroke, background-color;
768
+ transition-duration: var(--cd-fill-t);
769
+ transition-timing-function: var(--cd-m-fill-ease, var(--cd-motion-fill-ease, var(--cd-ease)));
770
+ @variant calm {
771
+ transition-property: stroke, background-color !important;
772
+ transition-duration: min(var(--cd-fill-t), 150ms) !important;
773
+ }
774
+ }
775
+ /* A bar that grows into place from --cd-fill-from (along its width; "1 0" for height), when a step it reports finishes. */
776
+ @utility cd-fill-grow {
777
+ --cd-fill-l: min(var(--cd-m-fill, var(--cd-motion-fill, var(--cd-motion-preset))), var(--cd-motion-cap));
778
+ --cd-fill-t: calc(var(--cd-m-fill-dur, var(--cd-motion-fill-dur, 360ms)) * var(--cd-motion-speed) * min(var(--cd-fill-l), 1));
779
+ animation: cd-grow var(--cd-fill-t) var(--cd-m-fill-ease, var(--cd-motion-fill-ease, var(--cd-ease))) both;
780
+ @variant calm {
781
+ animation-name: none !important;
782
+ }
783
+ }
784
+
785
+ /* value: a number or word changed in place, crossfaded (and slid by the distance at expressive). Key the element on the value. */
786
+ @utility cd-value {
787
+ --cd-value-l: min(var(--cd-m-value, var(--cd-motion-value, var(--cd-motion-preset))), var(--cd-motion-cap));
788
+ --cd-value-t: calc(var(--cd-m-value-dur, var(--cd-motion-value-dur, 120ms)) * var(--cd-motion-speed) * min(var(--cd-value-l), 1));
789
+ --cd-from-y: calc(var(--cd-m-value-amp, var(--cd-motion-value-distance, 2px)) * clamp(0, var(--cd-value-l) - 1, 1));
790
+ animation: var(--cd-m-value-variant, var(--cd-motion-value-variant, cd-fade)) var(--cd-value-t) var(--cd-m-value-ease, var(--cd-motion-value-ease, var(--cd-ease))) both;
791
+ @variant calm {
792
+ animation-name: cd-fade !important;
793
+ animation-duration: min(var(--cd-value-t), 150ms) !important;
794
+ }
795
+ }
796
+
797
+ /* move: a thing changed place (a transition on its position). */
798
+ @utility cd-move {
799
+ --cd-move-l: min(var(--cd-m-move, var(--cd-motion-move, var(--cd-motion-preset))), var(--cd-motion-cap));
800
+ --cd-move-t: calc(var(--cd-m-move-dur, var(--cd-motion-move-dur, 200ms)) * var(--cd-motion-speed) * min(var(--cd-move-l), 1));
801
+ transition-property: transform, translate, inset-inline-start, inset-inline-end, inset-block-start, left, right, top, width;
802
+ transition-duration: var(--cd-move-t);
803
+ transition-timing-function: var(--cd-m-move-ease, var(--cd-motion-move-ease, var(--cd-ease)));
804
+ @variant calm {
805
+ transition-property: none !important;
806
+ }
807
+ }
808
+
809
+ /*
810
+ * overlay: a dialog, sheet, popover, menu or tooltip opening (cd-overlay) or closing (cd-overlay-out), from the
811
+ * trigger's origin (set transform-origin) and nudged from its side (Radix's data-side, or --cd-side-x/-y of -1, 0 or 1).
812
+ * A sheet sets --cd-overlay-distance to how far it travels. cd-scrim is the backdrop behind a dialog or sheet: always a fade.
813
+ */
814
+ @utility cd-overlay {
815
+ --cd-overlay-l: min(var(--cd-m-overlay, var(--cd-motion-overlay, var(--cd-motion-preset))), var(--cd-motion-cap));
816
+ --cd-overlay-t: calc(var(--cd-m-overlay-dur, var(--cd-motion-overlay-dur, 150ms)) * var(--cd-motion-speed) * min(var(--cd-overlay-l), 1));
817
+ --cd-from-scale: var(--cd-m-overlay-amp, var(--cd-motion-overlay-scale, 0.95));
818
+ --cd-nudge-x: calc(var(--cd-side-x, 0) * 0.5rem);
819
+ --cd-nudge-y: calc(var(--cd-side-y, 0) * 0.5rem);
820
+ --cd-from-x: calc(var(--cd-side-x, 0) * var(--cd-overlay-distance, 0.5rem));
821
+ --cd-from-y: calc(var(--cd-side-y, 0) * var(--cd-overlay-distance, 0.5rem));
822
+ animation: var(--cd-m-overlay-variant, var(--cd-motion-overlay-variant, cd-scale)) var(--cd-overlay-t) var(--cd-m-overlay-ease, var(--cd-motion-overlay-ease, var(--cd-ease))) both;
823
+ &[data-side="bottom"] { --cd-side-y: -1; }
824
+ &[data-side="top"] { --cd-side-y: 1; }
825
+ &[data-side="left"] { --cd-side-x: 1; }
826
+ &[data-side="right"] { --cd-side-x: -1; }
827
+ @variant calm {
828
+ animation-name: cd-fade !important;
829
+ animation-duration: min(var(--cd-overlay-t), 150ms) !important;
830
+ }
831
+ }
832
+ @utility cd-overlay-out {
833
+ --cd-overlay-l: min(var(--cd-m-overlay, var(--cd-motion-overlay, var(--cd-motion-preset))), var(--cd-motion-cap));
834
+ --cd-overlay-t: calc(var(--cd-m-overlay-out-dur, var(--cd-motion-overlay-out-dur, 150ms)) * var(--cd-motion-speed) * min(var(--cd-overlay-l), 1));
835
+ --cd-from-scale: var(--cd-m-overlay-amp, var(--cd-motion-overlay-scale, 0.95));
836
+ /* Leaving isn't nudged; a sheet still slides back to its edge. */
837
+ --cd-nudge-x: 0;
838
+ --cd-nudge-y: 0;
839
+ --cd-from-x: calc(var(--cd-side-x, 0) * var(--cd-overlay-distance, 0.5rem));
840
+ --cd-from-y: calc(var(--cd-side-y, 0) * var(--cd-overlay-distance, 0.5rem));
841
+ animation: var(--cd-m-overlay-variant, var(--cd-motion-overlay-variant, cd-scale)) var(--cd-overlay-t) var(--cd-m-overlay-ease, var(--cd-motion-overlay-ease, var(--cd-ease))) reverse both;
842
+ @variant calm {
843
+ animation-name: cd-fade !important;
844
+ animation-duration: min(var(--cd-overlay-t), 150ms) !important;
845
+ }
846
+ }
847
+ @utility cd-scrim {
848
+ --cd-overlay-l: min(var(--cd-m-overlay, var(--cd-motion-overlay, var(--cd-motion-preset))), var(--cd-motion-cap));
849
+ --cd-overlay-t: calc(var(--cd-m-overlay-dur, var(--cd-motion-overlay-dur, 150ms)) * var(--cd-motion-speed) * min(var(--cd-overlay-l), 1));
850
+ animation: cd-fade var(--cd-overlay-t) var(--cd-m-overlay-ease, var(--cd-motion-overlay-ease, var(--cd-ease))) both;
851
+ @variant calm {
852
+ animation-duration: min(var(--cd-overlay-t), 150ms) !important;
853
+ }
854
+ }
855
+ @utility cd-scrim-out {
856
+ --cd-overlay-l: min(var(--cd-m-overlay, var(--cd-motion-overlay, var(--cd-motion-preset))), var(--cd-motion-cap));
857
+ --cd-overlay-t: calc(var(--cd-m-overlay-out-dur, var(--cd-motion-overlay-out-dur, 150ms)) * var(--cd-motion-speed) * min(var(--cd-overlay-l), 1));
858
+ animation: cd-fade var(--cd-overlay-t) var(--cd-m-overlay-ease, var(--cd-motion-overlay-ease, var(--cd-ease))) reverse both;
859
+ @variant calm {
860
+ animation-duration: min(var(--cd-overlay-t), 150ms) !important;
861
+ }
570
862
  }
571
- [data-motion="none"] [data-leaving] {
572
- display: none !important;
863
+
864
+ /*
865
+ * tint and press share one transition, so either utility (or both) on an element gives colours, opacity, shadows and
866
+ * filters the tint family's timing and the press scale the press family's. cd-press also scales the element while it
867
+ * is pressed.
868
+ */
869
+ @utility cd-tint {
870
+ --cd-tint-l: min(var(--cd-m-tint, var(--cd-motion-tint, var(--cd-motion-preset))), var(--cd-motion-cap));
871
+ --cd-tint-t: calc(var(--cd-m-tint-dur, var(--cd-motion-tint-dur, 150ms)) * var(--cd-motion-speed) * min(var(--cd-tint-l), 1));
872
+ --cd-tint-e: var(--cd-m-tint-ease, var(--cd-motion-tint-ease, var(--cd-ease)));
873
+ --cd-press-l: min(var(--cd-m-press, var(--cd-motion-press, var(--cd-motion-preset))), var(--cd-motion-cap));
874
+ --cd-press-t: calc(var(--cd-m-press-dur, var(--cd-motion-press-dur, 150ms)) * var(--cd-motion-speed) * min(var(--cd-press-l), 1));
875
+ --cd-press-e: var(--cd-m-press-ease, var(--cd-motion-press-ease, var(--cd-ease)));
876
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, opacity, box-shadow, filter, scale;
877
+ transition-duration: var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-press-t);
878
+ transition-timing-function: var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-press-e);
879
+ @variant calm {
880
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, opacity !important;
881
+ transition-duration: min(var(--cd-tint-t), 150ms) !important;
882
+ transition-timing-function: var(--cd-tint-e) !important;
883
+ }
884
+ }
885
+ @utility cd-press {
886
+ --cd-tint-l: min(var(--cd-m-tint, var(--cd-motion-tint, var(--cd-motion-preset))), var(--cd-motion-cap));
887
+ --cd-tint-t: calc(var(--cd-m-tint-dur, var(--cd-motion-tint-dur, 150ms)) * var(--cd-motion-speed) * min(var(--cd-tint-l), 1));
888
+ --cd-tint-e: var(--cd-m-tint-ease, var(--cd-motion-tint-ease, var(--cd-ease)));
889
+ --cd-press-l: min(var(--cd-m-press, var(--cd-motion-press, var(--cd-motion-preset))), var(--cd-motion-cap));
890
+ --cd-press-t: calc(var(--cd-m-press-dur, var(--cd-motion-press-dur, 150ms)) * var(--cd-motion-speed) * min(var(--cd-press-l), 1));
891
+ --cd-press-e: var(--cd-m-press-ease, var(--cd-motion-press-ease, var(--cd-ease)));
892
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, opacity, box-shadow, filter, scale;
893
+ transition-duration: var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-tint-t), var(--cd-press-t);
894
+ transition-timing-function: var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-tint-e), var(--cd-press-e);
895
+ /* :where keeps it below an item's own active:scale-100 (a link, a locked control). */
896
+ &:where(:active) {
897
+ scale: calc(1 - (1 - var(--cd-m-press-amp, var(--cd-motion-press-scale, 0.96))) * (0.5 + 0.5 * clamp(0, var(--cd-press-l) - 1, 1)) * min(var(--cd-press-l), 1));
898
+ }
899
+ @variant calm {
900
+ transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, opacity !important;
901
+ transition-duration: min(var(--cd-tint-t), 150ms) !important;
902
+ transition-timing-function: var(--cd-tint-e) !important;
903
+ &:where(:active) {
904
+ scale: none !important;
905
+ }
906
+ }
907
+ }
908
+
909
+ /* refuse: a locked control was pressed. The reason is shown in words (a tint); at expressive the control shakes. */
910
+ @utility cd-refuse {
911
+ --cd-refuse-l: min(var(--cd-m-refuse, var(--cd-motion-refuse, var(--cd-motion-preset))), var(--cd-motion-cap));
912
+ --cd-refuse-t: calc(var(--cd-m-refuse-dur, var(--cd-motion-refuse-dur, 360ms)) * var(--cd-motion-speed) * min(var(--cd-refuse-l), 1));
913
+ --cd-shake: calc(var(--cd-m-refuse-amp, var(--cd-motion-refuse-distance, 3px)) * clamp(0, var(--cd-refuse-l) - 1, 1));
914
+ /* A 2.2 brand's --cd-motion-shake still wins. */
915
+ animation: var(--cd-motion-shake, cd-shake var(--cd-refuse-t) var(--cd-m-refuse-ease, var(--cd-motion-refuse-ease, var(--cd-ease))) both);
916
+ @variant calm {
917
+ animation-name: none !important;
918
+ }
919
+ }
920
+
921
+ /* attention: something new waits on the person. A ring that grows and fades, --cd-motion-…-count times. */
922
+ @utility cd-attention {
923
+ --cd-attention-l: min(var(--cd-m-attention, var(--cd-motion-attention, var(--cd-motion-preset))), var(--cd-motion-cap));
924
+ /* Not scaled by the speed token: count × duration must stay under five seconds (WCAG 2.2.2). */
925
+ --cd-attention-t: calc(var(--cd-m-attention-dur, var(--cd-motion-attention-dur, 900ms)) * min(var(--cd-attention-l), 1));
926
+ animation: cd-ring var(--cd-attention-t) var(--cd-m-attention-ease, var(--cd-motion-attention-ease, var(--cd-ease))) var(--cd-m-attention-amp, var(--cd-motion-attention-count, 1));
927
+ @variant calm {
928
+ animation-name: cd-ring-calm !important;
929
+ animation-duration: min(var(--cd-attention-t), 150ms) !important;
930
+ animation-iteration-count: 1 !important;
931
+ }
932
+ }
933
+ /* A prompt that was clicked around instead of answered: refuse's shake (expressive only) and one attention ring. */
934
+ @utility cd-nudge {
935
+ --cd-refuse-l: min(var(--cd-m-refuse, var(--cd-motion-refuse, var(--cd-motion-preset))), var(--cd-motion-cap));
936
+ --cd-refuse-t: calc(var(--cd-m-refuse-dur, var(--cd-motion-refuse-dur, 360ms)) * var(--cd-motion-speed) * min(var(--cd-refuse-l), 1));
937
+ --cd-shake: calc(var(--cd-m-refuse-amp, var(--cd-motion-refuse-distance, 3px)) * clamp(0, var(--cd-refuse-l) - 1, 1));
938
+ --cd-attention-l: min(var(--cd-m-attention, var(--cd-motion-attention, var(--cd-motion-preset))), var(--cd-motion-cap));
939
+ --cd-attention-t: calc(var(--cd-m-attention-dur, var(--cd-motion-attention-dur, 900ms)) * var(--cd-motion-speed) * min(var(--cd-attention-l), 1));
940
+ animation:
941
+ var(--cd-motion-shake, cd-shake var(--cd-refuse-t) var(--cd-m-refuse-ease, var(--cd-motion-refuse-ease, var(--cd-ease))) both),
942
+ cd-ring var(--cd-attention-t) var(--cd-m-attention-ease, var(--cd-motion-attention-ease, var(--cd-ease))) 1;
943
+ @variant calm {
944
+ animation: cd-ring-calm min(var(--cd-attention-t), 150ms) var(--cd-ease) 1 !important;
945
+ }
946
+ }
947
+
948
+ /*
949
+ * live: work that is being heard from. Each indicator has its own drawing and period; all of them are still at level 0
950
+ * and under calm, so keep the word beside them ("Running", "Sending…").
951
+ */
952
+ @utility cd-live-dot {
953
+ --cd-live-l: min(var(--cd-m-live, var(--cd-motion-live, var(--cd-motion-preset))), var(--cd-motion-cap));
954
+ animation: cd-pulse-dot calc(var(--cd-m-live-dur, var(--cd-motion-live-dur, 1600ms)) * var(--cd-motion-speed) * min(var(--cd-live-l), 1)) var(--cd-m-live-ease, var(--cd-motion-live-ease, var(--cd-ease))) infinite;
955
+ @variant calm {
956
+ animation: none !important;
957
+ }
958
+ }
959
+ @utility cd-live-pulse {
960
+ --cd-live-l: min(var(--cd-m-live, var(--cd-motion-live, var(--cd-motion-preset))), var(--cd-motion-cap));
961
+ animation: cd-pulse calc(var(--cd-m-live-dur, var(--cd-motion-live-dur, 2000ms)) * var(--cd-motion-speed) * min(var(--cd-live-l), 1)) var(--cd-m-live-ease, var(--cd-motion-live-ease, var(--cd-ease-inout))) infinite;
962
+ @variant calm {
963
+ animation: none !important;
964
+ }
965
+ }
966
+ @utility cd-live-spin {
967
+ --cd-live-l: min(var(--cd-m-live, var(--cd-motion-live, var(--cd-motion-preset))), var(--cd-motion-cap));
968
+ animation: cd-spin calc(var(--cd-m-live-dur, var(--cd-motion-live-dur, 1000ms)) * var(--cd-motion-speed) * min(var(--cd-live-l), 1)) linear infinite;
969
+ @variant calm {
970
+ animation: none !important;
971
+ }
972
+ }
973
+ @utility cd-live-caret {
974
+ --cd-live-l: min(var(--cd-m-live, var(--cd-motion-live, var(--cd-motion-preset))), var(--cd-motion-cap));
975
+ animation: cd-caret calc(var(--cd-m-live-dur, var(--cd-motion-live-dur, 1000ms)) * var(--cd-motion-speed) * min(var(--cd-live-l), 1)) steps(2, start) infinite;
976
+ @variant calm {
977
+ animation: none !important;
978
+ }
573
979
  }
574
980
 
981
+ @keyframes cd-fade {
982
+ from { opacity: 0; }
983
+ }
984
+ @keyframes cd-rise {
985
+ from { opacity: 0; transform: translateY(var(--cd-from-y, 4px)); }
986
+ }
987
+ @keyframes cd-pop {
988
+ from { opacity: 0; transform: scale(var(--cd-from-scale, 1)); }
989
+ }
990
+ @keyframes cd-scale {
991
+ from { opacity: 0; transform: translate(var(--cd-nudge-x, 0), var(--cd-nudge-y, 0)) scale(var(--cd-from-scale, 1)); }
992
+ }
993
+ @keyframes cd-slide {
994
+ from { opacity: 0; transform: translate(var(--cd-from-x, 0), var(--cd-from-y, 0)); }
995
+ }
996
+ @keyframes cd-drop {
997
+ from { opacity: 0; transform: translateY(var(--cd-from-y, -4px)); }
998
+ }
999
+ /* Overflow is hidden only while it moves. */
1000
+ @keyframes cd-size {
1001
+ from { height: 0; overflow: hidden; }
1002
+ to { height: var(--cd-size, auto); overflow: hidden; }
1003
+ }
1004
+ /* Along a path with pathLength="1" and stroke-dasharray 1. */
1005
+ @keyframes cd-draw {
1006
+ from { stroke-dashoffset: 1; }
1007
+ to { stroke-dashoffset: 0; }
1008
+ }
1009
+ @keyframes cd-grow {
1010
+ from { scale: var(--cd-fill-from, 0 1); }
1011
+ }
1012
+ @keyframes cd-shake {
1013
+ 0%, 100% { transform: none; }
1014
+ 20%, 60% { transform: translateX(calc(-1 * var(--cd-shake, 0px))); }
1015
+ 40%, 80% { transform: translateX(var(--cd-shake, 0px)); }
1016
+ }
1017
+ /* In --cd-attention-color (the text colour unless set). */
1018
+ @keyframes cd-ring {
1019
+ 0%, 100% { outline: 0 solid color-mix(in oklab, var(--cd-attention-color, currentColor) 45%, transparent); }
1020
+ 60% { outline: 6px solid transparent; }
1021
+ }
1022
+ /* The calm ring: a fixed width whose colour fades. */
1023
+ @keyframes cd-ring-calm {
1024
+ from { outline: 3px solid color-mix(in oklab, var(--cd-attention-color, currentColor) 45%, transparent); }
1025
+ to { outline: 3px solid transparent; }
1026
+ }
1027
+ @keyframes cd-pulse-dot {
1028
+ 0%, 100% { box-shadow: 0 0 0 0 color-mix(in oklab, currentColor 45%, transparent); }
1029
+ 70% { box-shadow: 0 0 0 5px transparent; }
1030
+ }
1031
+ @keyframes cd-pulse {
1032
+ 50% { opacity: 0.5; }
1033
+ }
1034
+ @keyframes cd-spin {
1035
+ to { transform: rotate(360deg); }
1036
+ }
1037
+ @keyframes cd-caret {
1038
+ to { visibility: hidden; }
1039
+ }
1040
+
1041
+ /*
1042
+ * data-motion="none", the hard off: nothing animates or transitions, under any setting, and an element leaving with an
1043
+ * out moment (data-leaving) is simply gone. In the base layer with !important, which beats every later layer's
1044
+ * !important (the calm forms) and the unlayered one below.
1045
+ */
1046
+ @layer base {
1047
+ [data-motion="none"], [data-motion="none"] *, [data-motion="none"] *::before, [data-motion="none"] *::after {
1048
+ animation: none !important;
1049
+ transition: none !important;
1050
+ scroll-behavior: auto !important;
1051
+ }
1052
+ [data-motion="none"] [data-leaving] {
1053
+ display: none !important;
1054
+ }
1055
+ }
1056
+
1057
+ /*
1058
+ * The calm level for everything outside the families (an app's own keyframes, a third-party widget): its animations
1059
+ * end at once, nothing loops, only opacity and colour transition, scrolling is instant. Unlayered !important is the
1060
+ * weakest important, so the families' own calm forms win over it.
1061
+ */
575
1062
  @media (prefers-reduced-motion: reduce) {
576
1063
  *, *::before, *::after {
577
1064
  animation-duration: 0.001ms !important;
578
1065
  animation-delay: 0s !important;
579
1066
  animation-iteration-count: 1 !important;
580
- transition-duration: 0.001ms !important;
1067
+ transition-property: opacity, color, background-color, border-color, outline-color, text-decoration-color, fill, stroke !important;
581
1068
  scroll-behavior: auto !important;
582
1069
  }
583
1070
  }
1071
+ [data-motion="calm"], [data-motion="calm"] *, [data-motion="calm"] *::before, [data-motion="calm"] *::after {
1072
+ animation-duration: 0.001ms !important;
1073
+ animation-delay: 0s !important;
1074
+ animation-iteration-count: 1 !important;
1075
+ transition-property: opacity, color, background-color, border-color, outline-color, text-decoration-color, fill, stroke !important;
1076
+ scroll-behavior: auto !important;
1077
+ }
584
1078
 
585
1079
  @layer base {
586
1080
  * {
@@ -597,11 +1091,16 @@
597
1091
  }
598
1092
  }
599
1093
 
1094
+ /* Text that is still arriving: a live indicator, so it's still at level 0 and under calm (the words stay readable). */
600
1095
  @utility shimmer-text {
1096
+ --cd-live-l: min(var(--cd-m-live, var(--cd-motion-live, var(--cd-motion-preset))), var(--cd-motion-cap));
601
1097
  background: linear-gradient(90deg, var(--muted-foreground) 0%, var(--muted-foreground) 40%, var(--foreground) 50%, var(--muted-foreground) 60%, var(--muted-foreground) 100%);
602
1098
  background-size: 200% 100%;
603
1099
  -webkit-background-clip: text;
604
1100
  background-clip: text;
605
1101
  color: transparent;
606
- animation: var(--animate-shimmer);
1102
+ animation: shimmer calc(var(--cd-m-live-dur, var(--cd-motion-live-dur, 2200ms)) * var(--cd-motion-speed) * min(var(--cd-live-l), 1)) linear infinite;
1103
+ @variant calm {
1104
+ animation: none !important;
1105
+ }
607
1106
  }