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