@twentyfirstmedia/ui-core 0.1.1 → 0.2.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.
Files changed (84) hide show
  1. package/dist/Icon.d.ts +1 -1
  2. package/dist/components/admin.d.ts.map +1 -1
  3. package/dist/components/admin.js +2 -2
  4. package/dist/components/admin.js.map +1 -1
  5. package/dist/components/charts.js +4 -4
  6. package/dist/components/charts.js.map +1 -1
  7. package/dist/components/data-display.d.ts +2 -0
  8. package/dist/components/data-display.d.ts.map +1 -1
  9. package/dist/components/data-display.js +32 -8
  10. package/dist/components/data-display.js.map +1 -1
  11. package/dist/components/developer.d.ts.map +1 -1
  12. package/dist/components/developer.js +4 -2
  13. package/dist/components/developer.js.map +1 -1
  14. package/dist/components/feedback.d.ts +1 -1
  15. package/dist/components/feedback.d.ts.map +1 -1
  16. package/dist/components/feedback.js +9 -5
  17. package/dist/components/feedback.js.map +1 -1
  18. package/dist/components/forms.d.ts.map +1 -1
  19. package/dist/components/forms.js +3 -1
  20. package/dist/components/forms.js.map +1 -1
  21. package/dist/components/index.d.ts +1 -1
  22. package/dist/components/index.d.ts.map +1 -1
  23. package/dist/components/index.js +1 -1
  24. package/dist/components/index.js.map +1 -1
  25. package/dist/components/overlays.d.ts.map +1 -1
  26. package/dist/components/overlays.js +5 -4
  27. package/dist/components/overlays.js.map +1 -1
  28. package/dist/components/primitives.d.ts.map +1 -1
  29. package/dist/components/primitives.js +3 -1
  30. package/dist/components/primitives.js.map +1 -1
  31. package/dist/components/shell.d.ts +11 -1
  32. package/dist/components/shell.d.ts.map +1 -1
  33. package/dist/components/shell.js +41 -4
  34. package/dist/components/shell.js.map +1 -1
  35. package/dist/components/types.d.ts +54 -2
  36. package/dist/components/types.d.ts.map +1 -1
  37. package/dist/components/workspace.d.ts +2 -2
  38. package/dist/components/workspace.d.ts.map +1 -1
  39. package/dist/components/workspace.js +9 -3
  40. package/dist/components/workspace.js.map +1 -1
  41. package/dist/cx.d.ts +7 -2
  42. package/dist/cx.d.ts.map +1 -1
  43. package/dist/cx.js +25 -3
  44. package/dist/cx.js.map +1 -1
  45. package/dist/index.d.ts +3 -1
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +2 -0
  48. package/dist/index.js.map +1 -1
  49. package/dist/motion.d.ts +13 -0
  50. package/dist/motion.d.ts.map +1 -0
  51. package/dist/motion.js +44 -0
  52. package/dist/motion.js.map +1 -0
  53. package/dist/presence.d.ts +18 -0
  54. package/dist/presence.d.ts.map +1 -0
  55. package/dist/presence.js +49 -0
  56. package/dist/presence.js.map +1 -0
  57. package/dist/provider.d.ts +22 -0
  58. package/dist/provider.d.ts.map +1 -1
  59. package/dist/provider.js +18 -4
  60. package/dist/provider.js.map +1 -1
  61. package/dist/themes.css +1821 -102
  62. package/dist/toast-store.d.ts +2 -0
  63. package/dist/toast-store.d.ts.map +1 -1
  64. package/dist/toast-store.js +28 -1
  65. package/dist/toast-store.js.map +1 -1
  66. package/package.json +1 -1
  67. package/src/components/admin.tsx +7 -3
  68. package/src/components/charts.tsx +4 -4
  69. package/src/components/data-display.tsx +48 -8
  70. package/src/components/developer.tsx +4 -2
  71. package/src/components/feedback.tsx +9 -4
  72. package/src/components/forms.tsx +4 -1
  73. package/src/components/index.ts +1 -1
  74. package/src/components/overlays.tsx +15 -5
  75. package/src/components/primitives.tsx +4 -1
  76. package/src/components/shell.tsx +103 -4
  77. package/src/components/types.ts +54 -2
  78. package/src/components/workspace.tsx +8 -1
  79. package/src/cx.ts +22 -5
  80. package/src/index.ts +3 -0
  81. package/src/motion.ts +48 -0
  82. package/src/presence.ts +58 -0
  83. package/src/provider.tsx +44 -5
  84. package/src/toast-store.ts +28 -1
package/dist/themes.css CHANGED
@@ -125,6 +125,10 @@
125
125
  --dur-enter: 520ms;
126
126
  --dur-slow: 900ms;
127
127
  --stagger-step: 55ms;
128
+ --dur-exit: 160ms;
129
+ --motion-time: 1;
130
+ --motion-travel: 1;
131
+ --motion-blur: 0px;
128
132
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
129
133
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
130
134
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
@@ -331,6 +335,20 @@
331
335
  --on-frame-danger: #f2a8a0;
332
336
  --scrim: rgba(10, 10, 10, 0.32);
333
337
  --scrim-strong: rgba(10, 10, 10, 0.38);
338
+ --glass: color-mix(in srgb, var(--card) 72%, transparent);
339
+ --glass-strong: color-mix(in srgb, var(--card) 86%, transparent);
340
+ --glass-control: color-mix(in srgb, var(--card) 62%, transparent);
341
+ --glass-well: color-mix(in srgb, var(--foreground) 6%, transparent);
342
+ --glass-hover: color-mix(in srgb, var(--foreground) 8%, transparent);
343
+ --glass-border: rgba(255, 255, 255, 0.6);
344
+ --glass-highlight: rgba(255, 255, 255, 0.95);
345
+ --glass-sheen: rgba(255, 255, 255, 0.5);
346
+ --ambient-base: var(--background);
347
+ --ambient-1: color-mix(in oklab, var(--sky) 72%, var(--sky-ink));
348
+ --ambient-2: color-mix(in oklab, var(--mint) 72%, var(--mint-ink));
349
+ --ambient-3: color-mix(in oklab, var(--lilac) 72%, var(--lilac-ink));
350
+ --ambient-4: color-mix(in oklab, var(--butter) 72%, var(--butter-ink));
351
+ --ambient-scrim: rgba(255, 255, 255, 0.28);
334
352
  --bg-000: var(--canvas);
335
353
  --bg-100: var(--surface);
336
354
  --bg-200: var(--surface-sunken);
@@ -388,6 +406,7 @@
388
406
  --shadow-lift: 0 2px 4px rgba(20,20,20,0.06), 0 14px 32px rgba(20,20,20,0.10);
389
407
  --shadow-float: 0 16px 40px rgba(0,0,0,0.22);
390
408
  --shadow-overlay: var(--shadow-float);
409
+ --shadow-glass: 0 1px 2px rgba(20, 20, 40, 0.06), 0 12px 40px rgba(20, 20, 40, 0.14);
391
410
  --button-radius: var(--radius-pill);
392
411
  --field-radius: var(--radius-pill);
393
412
  --badge-radius: var(--radius-pill);
@@ -397,6 +416,8 @@
397
416
  --panel-shadow: var(--shadow-card);
398
417
  --panel-pad: var(--space-6);
399
418
  --panel-gap: var(--space-4);
419
+ --glass-filter: blur(24px) saturate(180%) brightness(1.05);
420
+ --glass-tint: 62%;
400
421
  color-scheme: light;
401
422
  }
402
423
  @media (prefers-color-scheme: dark) {
@@ -462,6 +483,20 @@
462
483
  --on-frame-danger: #f2a8a0;
463
484
  --scrim: rgba(10, 10, 10, 0.32);
464
485
  --scrim-strong: rgba(10, 10, 10, 0.38);
486
+ --glass: color-mix(in srgb, var(--card) 70%, transparent);
487
+ --glass-strong: color-mix(in srgb, var(--card) 86%, transparent);
488
+ --glass-control: color-mix(in srgb, var(--foreground) 10%, transparent);
489
+ --glass-well: color-mix(in srgb, var(--foreground) 6%, transparent);
490
+ --glass-hover: color-mix(in srgb, var(--foreground) 12%, transparent);
491
+ --glass-border: rgba(255, 255, 255, 0.1);
492
+ --glass-highlight: rgba(255, 255, 255, 0.18);
493
+ --glass-sheen: rgba(255, 255, 255, 0.05);
494
+ --ambient-base: var(--background);
495
+ --ambient-1: var(--sky);
496
+ --ambient-2: var(--mint);
497
+ --ambient-3: var(--lilac);
498
+ --ambient-4: var(--butter);
499
+ --ambient-scrim: rgba(10, 10, 10, 0.45);
465
500
  --bg-000: var(--canvas);
466
501
  --bg-100: var(--surface);
467
502
  --bg-200: var(--surface-sunken);
@@ -519,6 +554,7 @@
519
554
  --shadow-lift: 0 2px 6px rgba(0,0,0,0.5), 0 14px 32px rgba(0,0,0,0.45);
520
555
  --shadow-float: 0 16px 40px rgba(0,0,0,0.6);
521
556
  --shadow-overlay: var(--shadow-float);
557
+ --shadow-glass: 0 1px 2px rgba(0, 0, 0, 0.3), 0 16px 48px rgba(0, 0, 0, 0.45);
522
558
  --button-radius: var(--radius-pill);
523
559
  --field-radius: var(--radius-pill);
524
560
  --badge-radius: var(--radius-pill);
@@ -528,6 +564,8 @@
528
564
  --panel-shadow: var(--shadow-card);
529
565
  --panel-pad: var(--space-6);
530
566
  --panel-gap: var(--space-4);
567
+ --glass-filter: blur(24px) saturate(160%) brightness(0.85);
568
+ --glass-tint: 62%;
531
569
  color-scheme: dark;
532
570
  }
533
571
  }
@@ -594,6 +632,20 @@
594
632
  --on-frame-danger: #f2a8a0;
595
633
  --scrim: rgba(10, 10, 10, 0.32);
596
634
  --scrim-strong: rgba(10, 10, 10, 0.38);
635
+ --glass: color-mix(in srgb, var(--card) 70%, transparent);
636
+ --glass-strong: color-mix(in srgb, var(--card) 86%, transparent);
637
+ --glass-control: color-mix(in srgb, var(--foreground) 10%, transparent);
638
+ --glass-well: color-mix(in srgb, var(--foreground) 6%, transparent);
639
+ --glass-hover: color-mix(in srgb, var(--foreground) 12%, transparent);
640
+ --glass-border: rgba(255, 255, 255, 0.1);
641
+ --glass-highlight: rgba(255, 255, 255, 0.18);
642
+ --glass-sheen: rgba(255, 255, 255, 0.05);
643
+ --ambient-base: var(--background);
644
+ --ambient-1: var(--sky);
645
+ --ambient-2: var(--mint);
646
+ --ambient-3: var(--lilac);
647
+ --ambient-4: var(--butter);
648
+ --ambient-scrim: rgba(10, 10, 10, 0.45);
597
649
  --bg-000: var(--canvas);
598
650
  --bg-100: var(--surface);
599
651
  --bg-200: var(--surface-sunken);
@@ -651,6 +703,7 @@
651
703
  --shadow-lift: 0 2px 6px rgba(0,0,0,0.5), 0 14px 32px rgba(0,0,0,0.45);
652
704
  --shadow-float: 0 16px 40px rgba(0,0,0,0.6);
653
705
  --shadow-overlay: var(--shadow-float);
706
+ --shadow-glass: 0 1px 2px rgba(0, 0, 0, 0.3), 0 16px 48px rgba(0, 0, 0, 0.45);
654
707
  --button-radius: var(--radius-pill);
655
708
  --field-radius: var(--radius-pill);
656
709
  --badge-radius: var(--radius-pill);
@@ -660,6 +713,8 @@
660
713
  --panel-shadow: var(--shadow-card);
661
714
  --panel-pad: var(--space-6);
662
715
  --panel-gap: var(--space-4);
716
+ --glass-filter: blur(24px) saturate(160%) brightness(0.85);
717
+ --glass-tint: 62%;
663
718
  color-scheme: dark;
664
719
  }
665
720
  }
@@ -726,6 +781,20 @@
726
781
  --on-frame-danger: #f2a8a0;
727
782
  --scrim: rgba(10, 10, 10, 0.32);
728
783
  --scrim-strong: rgba(10, 10, 10, 0.38);
784
+ --glass: color-mix(in srgb, var(--card) 72%, transparent);
785
+ --glass-strong: color-mix(in srgb, var(--card) 86%, transparent);
786
+ --glass-control: color-mix(in srgb, var(--card) 62%, transparent);
787
+ --glass-well: color-mix(in srgb, var(--foreground) 6%, transparent);
788
+ --glass-hover: color-mix(in srgb, var(--foreground) 8%, transparent);
789
+ --glass-border: rgba(255, 255, 255, 0.6);
790
+ --glass-highlight: rgba(255, 255, 255, 0.95);
791
+ --glass-sheen: rgba(255, 255, 255, 0.5);
792
+ --ambient-base: var(--background);
793
+ --ambient-1: color-mix(in oklab, var(--sky) 72%, var(--sky-ink));
794
+ --ambient-2: color-mix(in oklab, var(--mint) 72%, var(--mint-ink));
795
+ --ambient-3: color-mix(in oklab, var(--lilac) 72%, var(--lilac-ink));
796
+ --ambient-4: color-mix(in oklab, var(--butter) 72%, var(--butter-ink));
797
+ --ambient-scrim: rgba(255, 255, 255, 0.28);
729
798
  --bg-000: var(--canvas);
730
799
  --bg-100: var(--surface);
731
800
  --bg-200: var(--surface-sunken);
@@ -783,6 +852,7 @@
783
852
  --shadow-lift: 0 2px 4px rgba(20,20,20,0.06), 0 14px 32px rgba(20,20,20,0.10);
784
853
  --shadow-float: 0 16px 40px rgba(0,0,0,0.22);
785
854
  --shadow-overlay: var(--shadow-float);
855
+ --shadow-glass: 0 1px 2px rgba(20, 20, 40, 0.06), 0 12px 40px rgba(20, 20, 40, 0.14);
786
856
  --button-radius: var(--radius-pill);
787
857
  --field-radius: var(--radius-pill);
788
858
  --badge-radius: var(--radius-pill);
@@ -792,6 +862,8 @@
792
862
  --panel-shadow: var(--shadow-card);
793
863
  --panel-pad: var(--space-6);
794
864
  --panel-gap: var(--space-4);
865
+ --glass-filter: blur(24px) saturate(180%) brightness(1.05);
866
+ --glass-tint: 62%;
795
867
  color-scheme: light;
796
868
  }
797
869
  }
@@ -857,6 +929,20 @@
857
929
  --on-frame-danger: #f2a8a0;
858
930
  --scrim: rgba(10, 10, 10, 0.32);
859
931
  --scrim-strong: rgba(10, 10, 10, 0.38);
932
+ --glass: color-mix(in srgb, var(--card) 70%, transparent);
933
+ --glass-strong: color-mix(in srgb, var(--card) 86%, transparent);
934
+ --glass-control: color-mix(in srgb, var(--foreground) 10%, transparent);
935
+ --glass-well: color-mix(in srgb, var(--foreground) 6%, transparent);
936
+ --glass-hover: color-mix(in srgb, var(--foreground) 12%, transparent);
937
+ --glass-border: rgba(255, 255, 255, 0.1);
938
+ --glass-highlight: rgba(255, 255, 255, 0.18);
939
+ --glass-sheen: rgba(255, 255, 255, 0.05);
940
+ --ambient-base: var(--background);
941
+ --ambient-1: var(--sky);
942
+ --ambient-2: var(--mint);
943
+ --ambient-3: var(--lilac);
944
+ --ambient-4: var(--butter);
945
+ --ambient-scrim: rgba(10, 10, 10, 0.45);
860
946
  --bg-000: var(--canvas);
861
947
  --bg-100: var(--surface);
862
948
  --bg-200: var(--surface-sunken);
@@ -914,6 +1000,7 @@
914
1000
  --shadow-lift: 0 2px 6px rgba(0,0,0,0.5), 0 14px 32px rgba(0,0,0,0.45);
915
1001
  --shadow-float: 0 16px 40px rgba(0,0,0,0.6);
916
1002
  --shadow-overlay: var(--shadow-float);
1003
+ --shadow-glass: 0 1px 2px rgba(0, 0, 0, 0.3), 0 16px 48px rgba(0, 0, 0, 0.45);
917
1004
  --button-radius: var(--radius-pill);
918
1005
  --field-radius: var(--radius-pill);
919
1006
  --badge-radius: var(--radius-pill);
@@ -923,6 +1010,8 @@
923
1010
  --panel-shadow: var(--shadow-card);
924
1011
  --panel-pad: var(--space-6);
925
1012
  --panel-gap: var(--space-4);
1013
+ --glass-filter: blur(24px) saturate(160%) brightness(0.85);
1014
+ --glass-tint: 62%;
926
1015
  color-scheme: dark;
927
1016
  }
928
1017
  :where([data-kit="halo"][data-theme="light"], [data-kit="halo"] [data-theme="light"], [data-kit="halo"].light, [data-kit="halo"] .light) {
@@ -987,6 +1076,20 @@
987
1076
  --on-frame-danger: #f2a8a0;
988
1077
  --scrim: rgba(10, 10, 10, 0.32);
989
1078
  --scrim-strong: rgba(10, 10, 10, 0.38);
1079
+ --glass: color-mix(in srgb, var(--card) 72%, transparent);
1080
+ --glass-strong: color-mix(in srgb, var(--card) 86%, transparent);
1081
+ --glass-control: color-mix(in srgb, var(--card) 62%, transparent);
1082
+ --glass-well: color-mix(in srgb, var(--foreground) 6%, transparent);
1083
+ --glass-hover: color-mix(in srgb, var(--foreground) 8%, transparent);
1084
+ --glass-border: rgba(255, 255, 255, 0.6);
1085
+ --glass-highlight: rgba(255, 255, 255, 0.95);
1086
+ --glass-sheen: rgba(255, 255, 255, 0.5);
1087
+ --ambient-base: var(--background);
1088
+ --ambient-1: color-mix(in oklab, var(--sky) 72%, var(--sky-ink));
1089
+ --ambient-2: color-mix(in oklab, var(--mint) 72%, var(--mint-ink));
1090
+ --ambient-3: color-mix(in oklab, var(--lilac) 72%, var(--lilac-ink));
1091
+ --ambient-4: color-mix(in oklab, var(--butter) 72%, var(--butter-ink));
1092
+ --ambient-scrim: rgba(255, 255, 255, 0.28);
990
1093
  --bg-000: var(--canvas);
991
1094
  --bg-100: var(--surface);
992
1095
  --bg-200: var(--surface-sunken);
@@ -1044,6 +1147,7 @@
1044
1147
  --shadow-lift: 0 2px 4px rgba(20,20,20,0.06), 0 14px 32px rgba(20,20,20,0.10);
1045
1148
  --shadow-float: 0 16px 40px rgba(0,0,0,0.22);
1046
1149
  --shadow-overlay: var(--shadow-float);
1150
+ --shadow-glass: 0 1px 2px rgba(20, 20, 40, 0.06), 0 12px 40px rgba(20, 20, 40, 0.14);
1047
1151
  --button-radius: var(--radius-pill);
1048
1152
  --field-radius: var(--radius-pill);
1049
1153
  --badge-radius: var(--radius-pill);
@@ -1053,6 +1157,8 @@
1053
1157
  --panel-shadow: var(--shadow-card);
1054
1158
  --panel-pad: var(--space-6);
1055
1159
  --panel-gap: var(--space-4);
1160
+ --glass-filter: blur(24px) saturate(180%) brightness(1.05);
1161
+ --glass-tint: 62%;
1056
1162
  color-scheme: light;
1057
1163
  }
1058
1164
  :where([data-kit="halo"][data-density="compact"], [data-kit="halo"] [data-density="compact"]) {
@@ -1069,6 +1175,69 @@
1069
1175
  --density-font-size: 14px;
1070
1176
  --density-line-height: 20px;
1071
1177
  }
1178
+ :where([data-kit="halo"][data-motion="expressive"], [data-kit="halo"] [data-motion="expressive"]) {
1179
+ --dur-enter: 760ms;
1180
+ --dur-slow: 1300ms;
1181
+ --dur-exit: 220ms;
1182
+ --stagger-step: 90ms;
1183
+ --motion-time: 1.4;
1184
+ --motion-travel: 1.7;
1185
+ --motion-blur: 8px;
1186
+ }
1187
+ :where([data-kit="halo"][data-motion="off"], [data-kit="halo"] [data-motion="off"]) {
1188
+ --duration-fast: 0ms;
1189
+ --duration-base: 0ms;
1190
+ --dur-fast: 0ms;
1191
+ --dur-base: 0ms;
1192
+ --dur-enter: 0ms;
1193
+ --dur-slow: 0ms;
1194
+ --dur-exit: 0ms;
1195
+ --stagger-step: 0ms;
1196
+ --motion-time: 0;
1197
+ --motion-travel: 0;
1198
+ --motion-blur: 0px;
1199
+ }
1200
+ @media (prefers-reduced-motion: reduce) {
1201
+ :where([data-kit="halo"], [data-kit="halo"][data-motion], [data-kit="halo"] [data-motion], [data-kit="halo"][data-theme], [data-kit="halo"] [data-theme]) {
1202
+ --duration-fast: 0ms;
1203
+ --duration-base: 0ms;
1204
+ --dur-fast: 0ms;
1205
+ --dur-base: 0ms;
1206
+ --dur-enter: 0ms;
1207
+ --dur-slow: 0ms;
1208
+ --dur-exit: 0ms;
1209
+ --stagger-step: 0ms;
1210
+ --motion-time: 0;
1211
+ --motion-travel: 0;
1212
+ --motion-blur: 0px;
1213
+ }
1214
+ }
1215
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
1216
+ :where([data-kit="halo"], [data-kit="halo"][data-theme], [data-kit="halo"] [data-theme], [data-kit="halo"].dark, [data-kit="halo"] .dark, [data-kit="halo"].light, [data-kit="halo"] .light) {
1217
+ --glass: var(--glass-strong);
1218
+ }
1219
+ }
1220
+ @media (prefers-contrast: more) {
1221
+ :where([data-kit="halo"], [data-kit="halo"][data-theme], [data-kit="halo"] [data-theme], [data-kit="halo"].dark, [data-kit="halo"] .dark, [data-kit="halo"].light, [data-kit="halo"] .light) {
1222
+ --glass: var(--glass-strong);
1223
+ }
1224
+ }
1225
+ @media (prefers-reduced-transparency: reduce) {
1226
+ :where([data-kit="halo"], [data-kit="halo"][data-theme], [data-kit="halo"] [data-theme], [data-kit="halo"].dark, [data-kit="halo"] .dark, [data-kit="halo"].light, [data-kit="halo"] .light) {
1227
+ --glass: var(--card);
1228
+ --glass-strong: var(--popover);
1229
+ --glass-sheen: transparent;
1230
+ --glass-filter: none;
1231
+ }
1232
+ }
1233
+ @media (forced-colors: active) {
1234
+ :where([data-kit="halo"], [data-kit="halo"][data-theme], [data-kit="halo"] [data-theme], [data-kit="halo"].dark, [data-kit="halo"] .dark, [data-kit="halo"].light, [data-kit="halo"] .light) {
1235
+ --glass: var(--card);
1236
+ --glass-strong: var(--popover);
1237
+ --glass-sheen: transparent;
1238
+ --glass-filter: none;
1239
+ }
1240
+ }
1072
1241
 
1073
1242
  /* Generated by scripts/tokens.ts from tokens.json: Pro tokens, scoped to [data-kit="pro"]. Do not edit; run `pnpm tokens`. */
1074
1243
  :where([data-kit="pro"]) {
@@ -1099,6 +1268,10 @@
1099
1268
  --dur-enter: var(--duration-base);
1100
1269
  --dur-slow: var(--duration-base);
1101
1270
  --stagger-step: 0ms;
1271
+ --dur-exit: var(--duration-fast);
1272
+ --motion-time: 1;
1273
+ --motion-travel: 1;
1274
+ --motion-blur: 0px;
1102
1275
  --ease-out: var(--ease-standard);
1103
1276
  --ease-spring: var(--ease-standard);
1104
1277
  --ease-in-out: var(--ease-standard);
@@ -1305,6 +1478,20 @@
1305
1478
  --on-frame-danger: var(--danger);
1306
1479
  --scrim: rgba(0,0,0,0.62);
1307
1480
  --scrim-strong: var(--scrim);
1481
+ --glass: color-mix(in srgb, var(--card) 72%, transparent);
1482
+ --glass-strong: color-mix(in srgb, var(--card) 88%, transparent);
1483
+ --glass-control: color-mix(in srgb, var(--foreground) 7%, transparent);
1484
+ --glass-well: color-mix(in srgb, var(--foreground) 5%, transparent);
1485
+ --glass-hover: color-mix(in srgb, var(--foreground) 9%, transparent);
1486
+ --glass-border: color-mix(in srgb, var(--foreground) 14%, transparent);
1487
+ --glass-highlight: rgba(255, 255, 255, 0.07);
1488
+ --glass-sheen: transparent;
1489
+ --ambient-base: var(--background);
1490
+ --ambient-1: color-mix(in oklab, var(--chart-1) 30%, var(--background));
1491
+ --ambient-2: color-mix(in oklab, var(--chart-4) 26%, var(--background));
1492
+ --ambient-3: color-mix(in oklab, var(--chart-2) 22%, var(--background));
1493
+ --ambient-4: color-mix(in oklab, var(--foreground) 8%, var(--background));
1494
+ --ambient-scrim: rgba(9, 9, 11, 0.55);
1308
1495
  --bg-000: var(--background);
1309
1496
  --bg-100: var(--card);
1310
1497
  --bg-200: var(--muted);
@@ -1362,6 +1549,7 @@
1362
1549
  --shadow-lift: none;
1363
1550
  --shadow-float: 0 16px 40px rgba(0,0,0,0.55);
1364
1551
  --shadow-overlay: 0 16px 40px rgba(0,0,0,0.55);
1552
+ --shadow-glass: 0 12px 32px rgba(0, 0, 0, 0.5);
1365
1553
  --button-radius: var(--radius-1);
1366
1554
  --field-radius: var(--radius-1);
1367
1555
  --badge-radius: var(--radius-1);
@@ -1371,6 +1559,8 @@
1371
1559
  --panel-shadow: none;
1372
1560
  --panel-pad: var(--space-4);
1373
1561
  --panel-gap: 1px;
1562
+ --glass-filter: blur(16px) saturate(120%) brightness(0.8);
1563
+ --glass-tint: 40%;
1374
1564
  color-scheme: dark;
1375
1565
  }
1376
1566
  @media (prefers-color-scheme: dark) {
@@ -1436,6 +1626,20 @@
1436
1626
  --on-frame-danger: var(--danger);
1437
1627
  --scrim: rgba(0,0,0,0.62);
1438
1628
  --scrim-strong: var(--scrim);
1629
+ --glass: color-mix(in srgb, var(--card) 72%, transparent);
1630
+ --glass-strong: color-mix(in srgb, var(--card) 88%, transparent);
1631
+ --glass-control: color-mix(in srgb, var(--foreground) 7%, transparent);
1632
+ --glass-well: color-mix(in srgb, var(--foreground) 5%, transparent);
1633
+ --glass-hover: color-mix(in srgb, var(--foreground) 9%, transparent);
1634
+ --glass-border: color-mix(in srgb, var(--foreground) 14%, transparent);
1635
+ --glass-highlight: rgba(255, 255, 255, 0.07);
1636
+ --glass-sheen: transparent;
1637
+ --ambient-base: var(--background);
1638
+ --ambient-1: color-mix(in oklab, var(--chart-1) 30%, var(--background));
1639
+ --ambient-2: color-mix(in oklab, var(--chart-4) 26%, var(--background));
1640
+ --ambient-3: color-mix(in oklab, var(--chart-2) 22%, var(--background));
1641
+ --ambient-4: color-mix(in oklab, var(--foreground) 8%, var(--background));
1642
+ --ambient-scrim: rgba(9, 9, 11, 0.55);
1439
1643
  --bg-000: var(--background);
1440
1644
  --bg-100: var(--card);
1441
1645
  --bg-200: var(--muted);
@@ -1493,6 +1697,7 @@
1493
1697
  --shadow-lift: none;
1494
1698
  --shadow-float: 0 16px 40px rgba(0,0,0,0.55);
1495
1699
  --shadow-overlay: 0 16px 40px rgba(0,0,0,0.55);
1700
+ --shadow-glass: 0 12px 32px rgba(0, 0, 0, 0.5);
1496
1701
  --button-radius: var(--radius-1);
1497
1702
  --field-radius: var(--radius-1);
1498
1703
  --badge-radius: var(--radius-1);
@@ -1502,6 +1707,8 @@
1502
1707
  --panel-shadow: none;
1503
1708
  --panel-pad: var(--space-4);
1504
1709
  --panel-gap: 1px;
1710
+ --glass-filter: blur(16px) saturate(120%) brightness(0.8);
1711
+ --glass-tint: 40%;
1505
1712
  color-scheme: dark;
1506
1713
  }
1507
1714
  }
@@ -1568,6 +1775,20 @@
1568
1775
  --on-frame-danger: var(--danger);
1569
1776
  --scrim: rgba(17,17,20,0.36);
1570
1777
  --scrim-strong: var(--scrim);
1778
+ --glass: color-mix(in srgb, var(--card) 74%, transparent);
1779
+ --glass-strong: color-mix(in srgb, var(--card) 88%, transparent);
1780
+ --glass-control: color-mix(in srgb, var(--card) 55%, transparent);
1781
+ --glass-well: color-mix(in srgb, var(--foreground) 5%, transparent);
1782
+ --glass-hover: color-mix(in srgb, var(--foreground) 7%, transparent);
1783
+ --glass-border: color-mix(in srgb, var(--foreground) 12%, transparent);
1784
+ --glass-highlight: rgba(255, 255, 255, 0.7);
1785
+ --glass-sheen: transparent;
1786
+ --ambient-base: var(--background);
1787
+ --ambient-1: color-mix(in oklab, var(--chart-1) 22%, var(--background));
1788
+ --ambient-2: color-mix(in oklab, var(--chart-4) 18%, var(--background));
1789
+ --ambient-3: color-mix(in oklab, var(--chart-2) 16%, var(--background));
1790
+ --ambient-4: color-mix(in oklab, var(--foreground) 6%, var(--background));
1791
+ --ambient-scrim: rgba(246, 246, 247, 0.4);
1571
1792
  --bg-000: var(--background);
1572
1793
  --bg-100: var(--card);
1573
1794
  --bg-200: var(--muted);
@@ -1625,6 +1846,7 @@
1625
1846
  --shadow-lift: none;
1626
1847
  --shadow-float: 0 16px 40px rgba(17,17,20,0.12);
1627
1848
  --shadow-overlay: 0 16px 40px rgba(17,17,20,0.12);
1849
+ --shadow-glass: 0 8px 24px rgba(17, 17, 20, 0.1);
1628
1850
  --button-radius: var(--radius-1);
1629
1851
  --field-radius: var(--radius-1);
1630
1852
  --badge-radius: var(--radius-1);
@@ -1634,6 +1856,8 @@
1634
1856
  --panel-shadow: none;
1635
1857
  --panel-pad: var(--space-4);
1636
1858
  --panel-gap: 1px;
1859
+ --glass-filter: blur(16px) saturate(130%) brightness(1.04);
1860
+ --glass-tint: 40%;
1637
1861
  color-scheme: light;
1638
1862
  }
1639
1863
  }
@@ -1699,6 +1923,20 @@
1699
1923
  --on-frame-danger: var(--danger);
1700
1924
  --scrim: rgba(0,0,0,0.62);
1701
1925
  --scrim-strong: var(--scrim);
1926
+ --glass: color-mix(in srgb, var(--card) 72%, transparent);
1927
+ --glass-strong: color-mix(in srgb, var(--card) 88%, transparent);
1928
+ --glass-control: color-mix(in srgb, var(--foreground) 7%, transparent);
1929
+ --glass-well: color-mix(in srgb, var(--foreground) 5%, transparent);
1930
+ --glass-hover: color-mix(in srgb, var(--foreground) 9%, transparent);
1931
+ --glass-border: color-mix(in srgb, var(--foreground) 14%, transparent);
1932
+ --glass-highlight: rgba(255, 255, 255, 0.07);
1933
+ --glass-sheen: transparent;
1934
+ --ambient-base: var(--background);
1935
+ --ambient-1: color-mix(in oklab, var(--chart-1) 30%, var(--background));
1936
+ --ambient-2: color-mix(in oklab, var(--chart-4) 26%, var(--background));
1937
+ --ambient-3: color-mix(in oklab, var(--chart-2) 22%, var(--background));
1938
+ --ambient-4: color-mix(in oklab, var(--foreground) 8%, var(--background));
1939
+ --ambient-scrim: rgba(9, 9, 11, 0.55);
1702
1940
  --bg-000: var(--background);
1703
1941
  --bg-100: var(--card);
1704
1942
  --bg-200: var(--muted);
@@ -1756,6 +1994,7 @@
1756
1994
  --shadow-lift: none;
1757
1995
  --shadow-float: 0 16px 40px rgba(0,0,0,0.55);
1758
1996
  --shadow-overlay: 0 16px 40px rgba(0,0,0,0.55);
1997
+ --shadow-glass: 0 12px 32px rgba(0, 0, 0, 0.5);
1759
1998
  --button-radius: var(--radius-1);
1760
1999
  --field-radius: var(--radius-1);
1761
2000
  --badge-radius: var(--radius-1);
@@ -1765,6 +2004,8 @@
1765
2004
  --panel-shadow: none;
1766
2005
  --panel-pad: var(--space-4);
1767
2006
  --panel-gap: 1px;
2007
+ --glass-filter: blur(16px) saturate(120%) brightness(0.8);
2008
+ --glass-tint: 40%;
1768
2009
  color-scheme: dark;
1769
2010
  }
1770
2011
  :where([data-kit="pro"][data-theme="light"], [data-kit="pro"] [data-theme="light"], [data-kit="pro"].light, [data-kit="pro"] .light) {
@@ -1829,6 +2070,20 @@
1829
2070
  --on-frame-danger: var(--danger);
1830
2071
  --scrim: rgba(17,17,20,0.36);
1831
2072
  --scrim-strong: var(--scrim);
2073
+ --glass: color-mix(in srgb, var(--card) 74%, transparent);
2074
+ --glass-strong: color-mix(in srgb, var(--card) 88%, transparent);
2075
+ --glass-control: color-mix(in srgb, var(--card) 55%, transparent);
2076
+ --glass-well: color-mix(in srgb, var(--foreground) 5%, transparent);
2077
+ --glass-hover: color-mix(in srgb, var(--foreground) 7%, transparent);
2078
+ --glass-border: color-mix(in srgb, var(--foreground) 12%, transparent);
2079
+ --glass-highlight: rgba(255, 255, 255, 0.7);
2080
+ --glass-sheen: transparent;
2081
+ --ambient-base: var(--background);
2082
+ --ambient-1: color-mix(in oklab, var(--chart-1) 22%, var(--background));
2083
+ --ambient-2: color-mix(in oklab, var(--chart-4) 18%, var(--background));
2084
+ --ambient-3: color-mix(in oklab, var(--chart-2) 16%, var(--background));
2085
+ --ambient-4: color-mix(in oklab, var(--foreground) 6%, var(--background));
2086
+ --ambient-scrim: rgba(246, 246, 247, 0.4);
1832
2087
  --bg-000: var(--background);
1833
2088
  --bg-100: var(--card);
1834
2089
  --bg-200: var(--muted);
@@ -1886,6 +2141,7 @@
1886
2141
  --shadow-lift: none;
1887
2142
  --shadow-float: 0 16px 40px rgba(17,17,20,0.12);
1888
2143
  --shadow-overlay: 0 16px 40px rgba(17,17,20,0.12);
2144
+ --shadow-glass: 0 8px 24px rgba(17, 17, 20, 0.1);
1889
2145
  --button-radius: var(--radius-1);
1890
2146
  --field-radius: var(--radius-1);
1891
2147
  --badge-radius: var(--radius-1);
@@ -1895,6 +2151,8 @@
1895
2151
  --panel-shadow: none;
1896
2152
  --panel-pad: var(--space-4);
1897
2153
  --panel-gap: 1px;
2154
+ --glass-filter: blur(16px) saturate(130%) brightness(1.04);
2155
+ --glass-tint: 40%;
1898
2156
  color-scheme: light;
1899
2157
  }
1900
2158
  @media (pointer: coarse) {
@@ -1920,6 +2178,70 @@
1920
2178
  --density-font-size: 14px;
1921
2179
  --density-line-height: 20px;
1922
2180
  }
2181
+ :where([data-kit="pro"][data-motion="expressive"], [data-kit="pro"] [data-motion="expressive"]) {
2182
+ --dur-enter: 360ms;
2183
+ --dur-slow: 560ms;
2184
+ --dur-exit: 140ms;
2185
+ --stagger-step: 45ms;
2186
+ --motion-time: 1;
2187
+ --motion-travel: 0.8;
2188
+ --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
2189
+ --motion-blur: 0px;
2190
+ }
2191
+ :where([data-kit="pro"][data-motion="off"], [data-kit="pro"] [data-motion="off"]) {
2192
+ --duration-fast: 0ms;
2193
+ --duration-base: 0ms;
2194
+ --dur-fast: 0ms;
2195
+ --dur-base: 0ms;
2196
+ --dur-enter: 0ms;
2197
+ --dur-slow: 0ms;
2198
+ --dur-exit: 0ms;
2199
+ --stagger-step: 0ms;
2200
+ --motion-time: 0;
2201
+ --motion-travel: 0;
2202
+ --motion-blur: 0px;
2203
+ }
2204
+ @media (prefers-reduced-motion: reduce) {
2205
+ :where([data-kit="pro"], [data-kit="pro"][data-motion], [data-kit="pro"] [data-motion], [data-kit="pro"][data-theme], [data-kit="pro"] [data-theme]) {
2206
+ --duration-fast: 0ms;
2207
+ --duration-base: 0ms;
2208
+ --dur-fast: 0ms;
2209
+ --dur-base: 0ms;
2210
+ --dur-enter: 0ms;
2211
+ --dur-slow: 0ms;
2212
+ --dur-exit: 0ms;
2213
+ --stagger-step: 0ms;
2214
+ --motion-time: 0;
2215
+ --motion-travel: 0;
2216
+ --motion-blur: 0px;
2217
+ }
2218
+ }
2219
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
2220
+ :where([data-kit="pro"], [data-kit="pro"][data-theme], [data-kit="pro"] [data-theme], [data-kit="pro"].dark, [data-kit="pro"] .dark, [data-kit="pro"].light, [data-kit="pro"] .light) {
2221
+ --glass: var(--glass-strong);
2222
+ }
2223
+ }
2224
+ @media (prefers-contrast: more) {
2225
+ :where([data-kit="pro"], [data-kit="pro"][data-theme], [data-kit="pro"] [data-theme], [data-kit="pro"].dark, [data-kit="pro"] .dark, [data-kit="pro"].light, [data-kit="pro"] .light) {
2226
+ --glass: var(--glass-strong);
2227
+ }
2228
+ }
2229
+ @media (prefers-reduced-transparency: reduce) {
2230
+ :where([data-kit="pro"], [data-kit="pro"][data-theme], [data-kit="pro"] [data-theme], [data-kit="pro"].dark, [data-kit="pro"] .dark, [data-kit="pro"].light, [data-kit="pro"] .light) {
2231
+ --glass: var(--card);
2232
+ --glass-strong: var(--popover);
2233
+ --glass-sheen: transparent;
2234
+ --glass-filter: none;
2235
+ }
2236
+ }
2237
+ @media (forced-colors: active) {
2238
+ :where([data-kit="pro"], [data-kit="pro"][data-theme], [data-kit="pro"] [data-theme], [data-kit="pro"].dark, [data-kit="pro"] .dark, [data-kit="pro"].light, [data-kit="pro"] .light) {
2239
+ --glass: var(--card);
2240
+ --glass-strong: var(--popover);
2241
+ --glass-sheen: transparent;
2242
+ --glass-filter: none;
2243
+ }
2244
+ }
1923
2245
 
1924
2246
  /* 01-foundation.css */
1925
2247
  /* Halo components, ported from reference/halo/source/halo.css (ha- → tf-). Every value comes from the tokens. */
@@ -2465,18 +2787,23 @@
2465
2787
  box-shadow: none;
2466
2788
  }
2467
2789
  :where([data-kit="halo"]) .tf-bg-sky {
2790
+ --tint: var(--sky);
2468
2791
  background: var(--sky);
2469
2792
  }
2470
2793
  :where([data-kit="halo"]) .tf-bg-mint {
2794
+ --tint: var(--mint);
2471
2795
  background: var(--mint);
2472
2796
  }
2473
2797
  :where([data-kit="halo"]) .tf-bg-lilac {
2798
+ --tint: var(--lilac);
2474
2799
  background: var(--lilac);
2475
2800
  }
2476
2801
  :where([data-kit="halo"]) .tf-bg-butter {
2802
+ --tint: var(--butter);
2477
2803
  background: var(--butter);
2478
2804
  }
2479
2805
  :where([data-kit="halo"]) .tf-bg-blush {
2806
+ --tint: var(--blush);
2480
2807
  background: var(--blush);
2481
2808
  }
2482
2809
  :where([data-kit="halo"]) .tf-bg-surface {
@@ -2898,7 +3225,7 @@
2898
3225
  @keyframes tf-halo-rise {
2899
3226
  from {
2900
3227
  opacity: 0;
2901
- transform: translateY(14px) scale(0.985);
3228
+ transform: translateY(calc(14px * var(--motion-travel))) scale(0.985);
2902
3229
  }
2903
3230
  to {
2904
3231
  opacity: 1;
@@ -2916,7 +3243,7 @@
2916
3243
  @keyframes tf-halo-drop {
2917
3244
  from {
2918
3245
  opacity: 0;
2919
- transform: translateY(-10px);
3246
+ transform: translateY(calc(-10px * var(--motion-travel)));
2920
3247
  }
2921
3248
  to {
2922
3249
  opacity: 1;
@@ -2926,7 +3253,7 @@
2926
3253
  @keyframes tf-halo-slide-in {
2927
3254
  from {
2928
3255
  opacity: 0;
2929
- transform: translateX(24px);
3256
+ transform: translateX(calc(24px * var(--motion-travel)));
2930
3257
  }
2931
3258
  to {
2932
3259
  opacity: 1;
@@ -2936,7 +3263,8 @@
2936
3263
  @keyframes tf-halo-slide-up {
2937
3264
  from {
2938
3265
  opacity: 0;
2939
- transform: translate(0, 28px) scale(0.9);
3266
+ transform: translate(calc(0px * var(--motion-travel)), calc(28px * var(--motion-travel)))
3267
+ scale(0.9);
2940
3268
  }
2941
3269
  to {
2942
3270
  opacity: 1;
@@ -2995,47 +3323,60 @@
2995
3323
  }
2996
3324
 
2997
3325
  :where([data-kit="halo"]) .tf-in {
3326
+ --enter-delay: var(--d, 0ms);
2998
3327
  animation: tf-halo-rise var(--dur-enter) var(--ease-out) both;
2999
- animation-delay: var(--d, 0ms);
3328
+ animation-delay: var(--enter-delay);
3000
3329
  }
3001
3330
  :where([data-kit="halo"]) .tf-stagger > * {
3002
3331
  animation: tf-halo-rise var(--dur-enter) var(--ease-out) both;
3003
3332
  }
3004
3333
  :where([data-kit="halo"]) .tf-stagger > :nth-child(1) {
3005
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 0);
3334
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 0);
3335
+ animation-delay: var(--enter-delay);
3006
3336
  }
3007
3337
  :where([data-kit="halo"]) .tf-stagger > :nth-child(2) {
3008
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 1);
3338
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 1);
3339
+ animation-delay: var(--enter-delay);
3009
3340
  }
3010
3341
  :where([data-kit="halo"]) .tf-stagger > :nth-child(3) {
3011
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 2);
3342
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 2);
3343
+ animation-delay: var(--enter-delay);
3012
3344
  }
3013
3345
  :where([data-kit="halo"]) .tf-stagger > :nth-child(4) {
3014
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 3);
3346
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 3);
3347
+ animation-delay: var(--enter-delay);
3015
3348
  }
3016
3349
  :where([data-kit="halo"]) .tf-stagger > :nth-child(5) {
3017
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 4);
3350
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 4);
3351
+ animation-delay: var(--enter-delay);
3018
3352
  }
3019
3353
  :where([data-kit="halo"]) .tf-stagger > :nth-child(6) {
3020
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 5);
3354
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 5);
3355
+ animation-delay: var(--enter-delay);
3021
3356
  }
3022
3357
  :where([data-kit="halo"]) .tf-stagger > :nth-child(7) {
3023
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 6);
3358
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 6);
3359
+ animation-delay: var(--enter-delay);
3024
3360
  }
3025
3361
  :where([data-kit="halo"]) .tf-stagger > :nth-child(8) {
3026
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 7);
3362
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 7);
3363
+ animation-delay: var(--enter-delay);
3027
3364
  }
3028
3365
  :where([data-kit="halo"]) .tf-stagger > :nth-child(9) {
3029
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 8);
3366
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 8);
3367
+ animation-delay: var(--enter-delay);
3030
3368
  }
3031
3369
  :where([data-kit="halo"]) .tf-stagger > :nth-child(10) {
3032
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 9);
3370
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 9);
3371
+ animation-delay: var(--enter-delay);
3033
3372
  }
3034
3373
  :where([data-kit="halo"]) .tf-stagger > :nth-child(11) {
3035
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 10);
3374
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 10);
3375
+ animation-delay: var(--enter-delay);
3036
3376
  }
3037
3377
  :where([data-kit="halo"]) .tf-stagger > :nth-child(n + 12) {
3038
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 11);
3378
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 11);
3379
+ animation-delay: var(--enter-delay);
3039
3380
  }
3040
3381
  :where([data-kit="halo"]) .tf-topbar {
3041
3382
  animation: tf-halo-drop var(--dur-enter) var(--ease-out) both;
@@ -3045,32 +3386,32 @@
3045
3386
  }
3046
3387
  :where([data-kit="halo"]) .tf-panel.tf-side {
3047
3388
  animation: tf-halo-slide-in var(--dur-enter) var(--ease-out) both;
3048
- animation-delay: 160ms;
3389
+ animation-delay: calc(160ms * var(--motion-time));
3049
3390
  }
3050
3391
  :where([data-kit="halo"]) .tf-dock {
3051
3392
  animation: tf-halo-slide-up var(--dur-enter) var(--ease-spring) both;
3052
- animation-delay: 420ms;
3393
+ animation-delay: calc(420ms * var(--motion-time));
3053
3394
  }
3054
3395
  :where([data-kit="halo"]) .tf-dock .tf-dock-btn {
3055
3396
  animation: tf-halo-pop var(--dur-base) var(--ease-spring) both;
3056
3397
  }
3057
3398
  :where([data-kit="halo"]) .tf-dock .tf-dock-btn:nth-child(1) {
3058
- animation-delay: 520ms;
3399
+ animation-delay: calc(520ms * var(--motion-time));
3059
3400
  }
3060
3401
  :where([data-kit="halo"]) .tf-dock .tf-dock-btn:nth-child(2) {
3061
- animation-delay: 570ms;
3402
+ animation-delay: calc(570ms * var(--motion-time));
3062
3403
  }
3063
3404
  :where([data-kit="halo"]) .tf-dock .tf-dock-btn:nth-child(3) {
3064
- animation-delay: 620ms;
3405
+ animation-delay: calc(620ms * var(--motion-time));
3065
3406
  }
3066
3407
  :where([data-kit="halo"]) .tf-dock .tf-dock-btn:nth-child(4) {
3067
- animation-delay: 670ms;
3408
+ animation-delay: calc(670ms * var(--motion-time));
3068
3409
  }
3069
3410
  :where([data-kit="halo"]) .tf-dock .tf-dock-btn:nth-child(5) {
3070
- animation-delay: 720ms;
3411
+ animation-delay: calc(720ms * var(--motion-time));
3071
3412
  }
3072
3413
  :where([data-kit="halo"]) .tf-dock .tf-dock-btn:nth-child(n + 6) {
3073
- animation-delay: 770ms;
3414
+ animation-delay: calc(770ms * var(--motion-time));
3074
3415
  }
3075
3416
  :where([data-kit="halo"]) .tf-rail-btn {
3076
3417
  animation: tf-halo-pop var(--dur-base) var(--ease-spring) both;
@@ -3107,7 +3448,7 @@
3107
3448
  :where([data-kit="halo"]) .tf-progress > span {
3108
3449
  transform-origin: left;
3109
3450
  animation: tf-halo-grow-x var(--dur-slow) var(--ease-out) both;
3110
- animation-delay: 200ms;
3451
+ animation-delay: calc(var(--enter-delay, 0ms) + calc(200ms * var(--motion-time)));
3111
3452
  }
3112
3453
 
3113
3454
  /* Sliding tab indicator */
@@ -3186,6 +3527,7 @@
3186
3527
  transform-box: fill-box;
3187
3528
  transform-origin: bottom;
3188
3529
  animation: tf-halo-grow-y var(--dur-slow) var(--ease-out) both;
3530
+ animation-delay: var(--enter-delay, 0ms);
3189
3531
  }
3190
3532
  :where([data-kit="halo"]) .tf-bar-ink {
3191
3533
  fill: var(--primary);
@@ -3213,7 +3555,7 @@
3213
3555
  stroke-dasharray: 1;
3214
3556
  stroke-dashoffset: 1;
3215
3557
  animation: tf-halo-draw var(--dur-slow) var(--ease-out) forwards;
3216
- animation-delay: 150ms;
3558
+ animation-delay: calc(var(--enter-delay, 0ms) + calc(150ms * var(--motion-time)));
3217
3559
  }
3218
3560
  :where([data-kit="halo"]) .tf-line-ink {
3219
3561
  stroke: var(--primary);
@@ -3236,7 +3578,7 @@
3236
3578
  :where([data-kit="halo"]) .tf-area {
3237
3579
  opacity: 0;
3238
3580
  animation: tf-halo-fade var(--dur-slow) var(--ease-out) forwards;
3239
- animation-delay: 500ms;
3581
+ animation-delay: calc(var(--enter-delay, 0ms) + calc(500ms * var(--motion-time)));
3240
3582
  }
3241
3583
  :where([data-kit="halo"]) .tf-area-sky {
3242
3584
  fill: var(--sky);
@@ -3257,7 +3599,7 @@
3257
3599
  fill: var(--surface);
3258
3600
  stroke-width: 2.5;
3259
3601
  animation: tf-halo-pop var(--dur-base) var(--ease-spring) both;
3260
- animation-delay: 900ms;
3602
+ animation-delay: calc(var(--enter-delay, 0ms) + calc(900ms * var(--motion-time)));
3261
3603
  transform-box: fill-box;
3262
3604
  transform-origin: center;
3263
3605
  }
@@ -3686,6 +4028,22 @@
3686
4028
  }
3687
4029
  }
3688
4030
 
4031
+ /* the same for an app that turns motion off: data-motion="off" */
4032
+ :where([data-kit="halo"])[data-motion="off"] *,
4033
+ :where([data-kit="halo"]) [data-motion="off"] *,
4034
+ :where([data-kit="halo"])[data-motion="off"] *::before,
4035
+ :where([data-kit="halo"]) [data-motion="off"] *::before,
4036
+ :where([data-kit="halo"])[data-motion="off"] *::after,
4037
+ :where([data-kit="halo"]) [data-motion="off"] *::after {
4038
+ animation-duration: 1ms !important;
4039
+ animation-delay: 0ms !important;
4040
+ animation-iteration-count: 1 !important;
4041
+ transition-duration: 1ms !important;
4042
+ }
4043
+ :where([data-kit="halo"])[data-motion="off"] .tf-line, :where([data-kit="halo"]) [data-motion="off"] .tf-line {
4044
+ stroke-dashoffset: 0;
4045
+ }
4046
+
3689
4047
  /* ───────── Refinements ───────── */
3690
4048
  :where([data-kit="halo"]) .tf-nav-label {
3691
4049
  white-space: nowrap;
@@ -3717,7 +4075,7 @@
3717
4075
  :where([data-kit="halo"]) .tf-area {
3718
4076
  opacity: 0;
3719
4077
  animation: tf-halo-area-in var(--dur-slow) var(--ease-out) forwards;
3720
- animation-delay: 500ms;
4078
+ animation-delay: calc(var(--enter-delay, 0ms) + calc(500ms * var(--motion-time)));
3721
4079
  }
3722
4080
  @keyframes tf-halo-area-in {
3723
4081
  to {
@@ -4279,7 +4637,7 @@
4279
4637
  }
4280
4638
  @keyframes tf-halo-drawer-in {
4281
4639
  from {
4282
- transform: translateX(40px);
4640
+ transform: translateX(calc(40px * var(--motion-travel)));
4283
4641
  opacity: 0;
4284
4642
  }
4285
4643
  to {
@@ -5153,7 +5511,7 @@
5153
5511
  box-shadow:
5154
5512
  var(--shadow-float),
5155
5513
  0 0 0 1px var(--line);
5156
- animation: tf-pop var(--dur-base) var(--ease-spring) both;
5514
+ animation: tf-halo-pop var(--dur-base) var(--ease-spring) both;
5157
5515
  transform-origin: top left;
5158
5516
  }
5159
5517
  :where([data-kit="halo"]) .tf-popover.tf-pop-end {
@@ -6153,7 +6511,7 @@
6153
6511
  color: var(--on-frame);
6154
6512
  box-shadow: var(--shadow-float);
6155
6513
  font: 600 13px/18px var(--font-sans);
6156
- animation: tf-slide-up var(--dur-base) var(--ease-spring) both;
6514
+ animation: tf-halo-slide-up var(--dur-base) var(--ease-spring) both;
6157
6515
  margin-bottom: 8px;
6158
6516
  }
6159
6517
  :where([data-kit="halo"]) .tf-bulkbar > b {
@@ -6253,7 +6611,8 @@
6253
6611
  :where([data-kit="halo"]) .tf-seg-bar {
6254
6612
  transform-box: fill-box;
6255
6613
  transform-origin: bottom;
6256
- animation: tf-grow-y var(--dur-slow) var(--ease-out) both;
6614
+ animation: tf-halo-grow-y var(--dur-slow) var(--ease-out) both;
6615
+ animation-delay: var(--enter-delay, 0ms);
6257
6616
  transition: opacity var(--dur-fast);
6258
6617
  }
6259
6618
  :where([data-kit="halo"]) .tf-chart g.dim .tf-seg-bar {
@@ -6299,7 +6658,7 @@
6299
6658
  :where([data-kit="halo"]) .tf-area2 {
6300
6659
  opacity: 0;
6301
6660
  animation: tf-halo-area2-in var(--dur-slow) var(--ease-out) forwards;
6302
- animation-delay: 400ms;
6661
+ animation-delay: calc(var(--enter-delay, 0ms) + calc(400ms * var(--motion-time)));
6303
6662
  }
6304
6663
  @keyframes tf-halo-area2-in {
6305
6664
  to {
@@ -6361,7 +6720,7 @@
6361
6720
  height: 20px;
6362
6721
  border-radius: 4px;
6363
6722
  background: var(--surface-sunken);
6364
- animation: tf-fade var(--dur-base) var(--ease-out) both;
6723
+ animation: tf-halo-fade var(--dur-base) var(--ease-out) both;
6365
6724
  transition: box-shadow var(--dur-fast);
6366
6725
  }
6367
6726
  :where([data-kit="halo"]) .tf-heat-cell.l1 {
@@ -6536,6 +6895,23 @@
6536
6895
  display: none;
6537
6896
  }
6538
6897
  }
6898
+ /* the same for an app that turns motion off: data-motion="off" */
6899
+ :where([data-kit="halo"])[data-motion="off"] .tf-seg-bar,
6900
+ :where([data-kit="halo"]) [data-motion="off"] .tf-seg-bar,
6901
+ :where([data-kit="halo"])[data-motion="off"] .tf-area2,
6902
+ :where([data-kit="halo"]) [data-motion="off"] .tf-area2,
6903
+ :where([data-kit="halo"])[data-motion="off"] .tf-heat-cell,
6904
+ :where([data-kit="halo"]) [data-motion="off"] .tf-heat-cell,
6905
+ :where([data-kit="halo"])[data-motion="off"] .tf-tooltip,
6906
+ :where([data-kit="halo"]) [data-motion="off"] .tf-tooltip,
6907
+ :where([data-kit="halo"])[data-motion="off"] .tf-popover,
6908
+ :where([data-kit="halo"]) [data-motion="off"] .tf-popover {
6909
+ animation: none !important;
6910
+ opacity: 1;
6911
+ }
6912
+ :where([data-kit="halo"])[data-motion="off"] .tf-toast-timer, :where([data-kit="halo"]) [data-motion="off"] .tf-toast-timer {
6913
+ display: none;
6914
+ }
6539
6915
  @media (max-width: 640px) {
6540
6916
  :where([data-kit="halo"]) .tf-dp {
6541
6917
  flex-direction: column;
@@ -6697,7 +7073,7 @@
6697
7073
  gap: 12px;
6698
7074
  align-items: flex-start;
6699
7075
  min-width: 0;
6700
- animation: tf-rise var(--dur-base) var(--ease-out) both;
7076
+ animation: tf-halo-rise var(--dur-base) var(--ease-out) both;
6701
7077
  }
6702
7078
  :where([data-kit="halo"]) .tf-msg.me {
6703
7079
  flex-direction: row-reverse;
@@ -6913,7 +7289,7 @@
6913
7289
  border-radius: 50%;
6914
7290
  background: var(--mint-ink);
6915
7291
  box-shadow: 0 0 0 2px var(--surface);
6916
- animation: tf-pulse 1.8s ease-out infinite;
7292
+ animation: tf-halo-pulse 1.8s ease-out infinite;
6917
7293
  }
6918
7294
 
6919
7295
  /* Tool calls, reasoning, approvals */
@@ -7060,7 +7436,7 @@
7060
7436
  :where([data-kit="halo"]) .tf-reason.live .tf-reason-head {
7061
7437
  background: linear-gradient(90deg, var(--surface-sunken), var(--line), var(--surface-sunken));
7062
7438
  background-size: 200% 100%;
7063
- animation: tf-shimmer 1.6s linear infinite;
7439
+ animation: tf-halo-shimmer 1.6s linear infinite;
7064
7440
  }
7065
7441
  :where([data-kit="halo"]) .tf-reason-head:focus-visible {
7066
7442
  outline: 2px solid var(--focus);
@@ -7438,7 +7814,7 @@
7438
7814
  }
7439
7815
  :where([data-kit="halo"]) .tf-trace-row.is-running .tf-trace-bar i {
7440
7816
  background: var(--sky-ink);
7441
- animation: tf-pulse 1.4s ease-in-out infinite;
7817
+ animation: tf-halo-pulse 1.4s ease-in-out infinite;
7442
7818
  }
7443
7819
  :where([data-kit="halo"]) .tf-trace-bar em {
7444
7820
  position: absolute;
@@ -8304,6 +8680,19 @@
8304
8680
  animation: none !important;
8305
8681
  }
8306
8682
  }
8683
+ /* the same for an app that turns motion off: data-motion="off" */
8684
+ :where([data-kit="halo"])[data-motion="off"] .tf-msg,
8685
+ :where([data-kit="halo"]) [data-motion="off"] .tf-msg,
8686
+ :where([data-kit="halo"])[data-motion="off"] .tf-caret,
8687
+ :where([data-kit="halo"]) [data-motion="off"] .tf-caret,
8688
+ :where([data-kit="halo"])[data-motion="off"] .tf-typing i,
8689
+ :where([data-kit="halo"]) [data-motion="off"] .tf-typing i,
8690
+ :where([data-kit="halo"])[data-motion="off"] .tf-spin,
8691
+ :where([data-kit="halo"]) [data-motion="off"] .tf-spin,
8692
+ :where([data-kit="halo"])[data-motion="off"] .tf-reason.live .tf-reason-head,
8693
+ :where([data-kit="halo"]) [data-motion="off"] .tf-reason.live .tf-reason-head {
8694
+ animation: none !important;
8695
+ }
8307
8696
 
8308
8697
  /* 04-status-agents-operations.css */
8309
8698
  /* ════════ Kit 4: status shapes, approvals A–D, foundations, agent & operations ════════ */
@@ -8320,7 +8709,7 @@
8320
8709
  border-radius: 50%;
8321
8710
  }
8322
8711
  :where([data-kit="halo"]) .tf-shape-pulse {
8323
- animation: tf-pulse 1.8s ease-out infinite;
8712
+ animation: tf-halo-pulse 1.8s ease-out infinite;
8324
8713
  }
8325
8714
  :where([data-kit="halo"]) .tf-shape-diamond {
8326
8715
  width: 7px;
@@ -8701,7 +9090,7 @@
8701
9090
  border-radius: 50%;
8702
9091
  border: 2px solid var(--line-strong);
8703
9092
  border-top-color: var(--ink);
8704
- animation: tf-spin 0.8s linear infinite;
9093
+ animation: tf-halo-spin 0.8s linear infinite;
8705
9094
  flex: none;
8706
9095
  }
8707
9096
  :where([data-kit="halo"]) .tf-spinner.lg {
@@ -9877,7 +10266,7 @@
9877
10266
  }
9878
10267
  :where([data-kit="halo"]) .tf-stage.st-running::after {
9879
10268
  background: var(--info);
9880
- animation: tf-pulse 1.4s ease-in-out infinite;
10269
+ animation: tf-halo-pulse 1.4s ease-in-out infinite;
9881
10270
  }
9882
10271
  :where([data-kit="halo"]) .tf-stage.st-danger::after {
9883
10272
  background: var(--danger);
@@ -10474,6 +10863,17 @@
10474
10863
  animation: none !important;
10475
10864
  }
10476
10865
  }
10866
+ /* the same for an app that turns motion off: data-motion="off" */
10867
+ :where([data-kit="halo"])[data-motion="off"] .tf-shape-pulse,
10868
+ :where([data-kit="halo"]) [data-motion="off"] .tf-shape-pulse,
10869
+ :where([data-kit="halo"])[data-motion="off"] .tf-voice-wave i,
10870
+ :where([data-kit="halo"]) [data-motion="off"] .tf-voice-wave i,
10871
+ :where([data-kit="halo"])[data-motion="off"] .tf-stage.st-running::after,
10872
+ :where([data-kit="halo"]) [data-motion="off"] .tf-stage.st-running::after,
10873
+ :where([data-kit="halo"])[data-motion="off"] .tf-log-line.fresh,
10874
+ :where([data-kit="halo"]) [data-motion="off"] .tf-log-line.fresh {
10875
+ animation: none !important;
10876
+ }
10477
10877
  :where([data-kit="halo"]) .tf-approval-mail {
10478
10878
  padding: 12px 16px;
10479
10879
  border-radius: var(--radius-md);
@@ -10828,7 +11228,7 @@
10828
11228
  @keyframes tf-halo-fresh {
10829
11229
  0% {
10830
11230
  background: var(--surface-sunken);
10831
- transform: translateY(-4px);
11231
+ transform: translateY(calc(-4px * var(--motion-travel)));
10832
11232
  opacity: 0;
10833
11233
  }
10834
11234
  15% {
@@ -12557,7 +12957,7 @@
12557
12957
  background: var(--surface);
12558
12958
  box-shadow: var(--shadow-float);
12559
12959
  overflow: hidden;
12560
- animation: tf-pop var(--dur-base) var(--ease-spring) both;
12960
+ animation: tf-halo-pop var(--dur-base) var(--ease-spring) both;
12561
12961
  transform-origin: bottom right;
12562
12962
  }
12563
12963
  :where([data-kit="halo"]) .tf-launch-head {
@@ -12732,6 +13132,17 @@
12732
13132
  animation: none;
12733
13133
  }
12734
13134
  }
13135
+ /* the same for an app that turns motion off: data-motion="off" */
13136
+ :where([data-kit="halo"])[data-motion="off"] .tf-live-dot,
13137
+ :where([data-kit="halo"]) [data-motion="off"] .tf-live-dot,
13138
+ :where([data-kit="halo"])[data-motion="off"] .tf-map-bubble.pulse::after,
13139
+ :where([data-kit="halo"]) [data-motion="off"] .tf-map-bubble.pulse::after,
13140
+ :where([data-kit="halo"])[data-motion="off"] .tf-map-pin.pulse::after,
13141
+ :where([data-kit="halo"]) [data-motion="off"] .tf-map-pin.pulse::after,
13142
+ :where([data-kit="halo"])[data-motion="off"] .tf-livefeed-row.fresh,
13143
+ :where([data-kit="halo"]) [data-motion="off"] .tf-livefeed-row.fresh {
13144
+ animation: none;
13145
+ }
12735
13146
  :where([data-kit="halo"]) .tf-map-world {
12736
13147
  position: absolute;
12737
13148
  inset: 0;
@@ -12848,7 +13259,7 @@
12848
13259
  padding: 0 20px 20px;
12849
13260
  font: 500 14px/22px var(--font-sans);
12850
13261
  color: var(--ink-muted);
12851
- animation: tf-fade var(--dur-base) var(--ease-out) both;
13262
+ animation: tf-halo-fade var(--dur-base) var(--ease-out) both;
12852
13263
  }
12853
13264
  :where([data-kit="halo"]) .tf-accordion.flush {
12854
13265
  gap: 0;
@@ -12981,6 +13392,8 @@
12981
13392
  }
12982
13393
  :where([data-kit="halo"]) .tf-togglegroup {
12983
13394
  display: inline-flex;
13395
+ flex-wrap: wrap;
13396
+ width: fit-content;
12984
13397
  align-items: center;
12985
13398
  gap: 4px;
12986
13399
  padding: 4px;
@@ -13103,7 +13516,7 @@
13103
13516
  box-shadow:
13104
13517
  var(--shadow-float),
13105
13518
  0 0 0 1px var(--line);
13106
- animation: tf-fade var(--dur-base) var(--ease-out) both;
13519
+ animation: tf-halo-fade var(--dur-base) var(--ease-out) both;
13107
13520
  }
13108
13521
  :where([data-kit="halo"]) .tf-hovercard.tf-hc-top {
13109
13522
  top: auto;
@@ -13428,7 +13841,7 @@
13428
13841
  box-shadow:
13429
13842
  var(--shadow-float),
13430
13843
  0 0 0 1px var(--line);
13431
- animation: tf-drop var(--dur-base) var(--ease-out) both;
13844
+ animation: tf-halo-drop var(--dur-base) var(--ease-out) both;
13432
13845
  }
13433
13846
  :where([data-kit="halo"]) .tf-navmenu-panel.with-feature {
13434
13847
  grid-template-columns: 200px minmax(0, 1fr);
@@ -13643,19 +14056,19 @@
13643
14056
  @keyframes tf-halo-sheet-left {
13644
14057
  from {
13645
14058
  opacity: 0;
13646
- transform: translateX(-24px);
14059
+ transform: translateX(calc(-24px * var(--motion-travel)));
13647
14060
  }
13648
14061
  }
13649
14062
  @keyframes tf-halo-sheet-top {
13650
14063
  from {
13651
14064
  opacity: 0;
13652
- transform: translateY(-24px);
14065
+ transform: translateY(calc(-24px * var(--motion-travel)));
13653
14066
  }
13654
14067
  }
13655
14068
  @keyframes tf-halo-sheet-bottom {
13656
14069
  from {
13657
14070
  opacity: 0;
13658
- transform: translateY(24px);
14071
+ transform: translateY(calc(24px * var(--motion-travel)));
13659
14072
  }
13660
14073
  }
13661
14074
 
@@ -14383,6 +14796,612 @@
14383
14796
  box-sizing: border-box;
14384
14797
  }
14385
14798
 
14799
+ /* 08-glass.css */
14800
+ /* Glass: translucent surfaces for UI that floats over content (maps, 3D scenes, video, photos).
14801
+ *
14802
+ * A glass surface shows a blurred, colour-lifted view of what is behind it, with a light edge on
14803
+ * top. What sits on it reads the glass tokens too (inputs, chips, tab tracks, hover highlights,
14804
+ * nested cards), so the surface stays one piece of glass instead of opaque blocks on glass.
14805
+ *
14806
+ * - `.tf-glass` (the `surface="glass"` prop) makes one surface glass.
14807
+ * - `[data-surface="glass"]` (`<UIProvider surface="glass">`) makes every top-level surface and
14808
+ * every floating layer inside it glass. Surfaces nested in a surface stay clear instead of
14809
+ * stacking glass on glass; `.tf-solid` (`surface="solid"`) opts one surface out.
14810
+ *
14811
+ * Floating layers (menus, popovers, dialogs, drawers) use the stronger `--glass-strong` fill: they
14812
+ * carry more text. The fills are opaque enough for 4.5:1 body text over any backdrop; reduced
14813
+ * transparency, high contrast and forced colours fall back to solid surfaces.
14814
+ */
14815
+
14816
+ /* the surface itself */
14817
+ :where([data-kit="halo"]) .tf-glass:not(.tf-solid),
14818
+ :where([data-kit="halo"])[data-surface="glass"]
14819
+ :is(
14820
+ .tf-panel,
14821
+ .tf-card,
14822
+ .tf-stat,
14823
+ .tf-dock,
14824
+ .tf-sidebar,
14825
+ .tf-map-legend,
14826
+ .tf-map-ctl,
14827
+ .tf-map-pop
14828
+ ):not(
14829
+ :is(
14830
+ .tf-panel,
14831
+ .tf-card,
14832
+ .tf-stat,
14833
+ .tf-dock,
14834
+ .tf-sidebar,
14835
+ .tf-popover,
14836
+ .tf-menu,
14837
+ .tf-hovercard,
14838
+ .tf-selectmenu-list,
14839
+ .tf-navmenu-panel,
14840
+ .tf-palette,
14841
+ .tf-modal,
14842
+ .tf-drawer,
14843
+ .tf-glass
14844
+ )
14845
+ *
14846
+ ):not(.tf-solid),
14847
+ :where([data-kit="halo"]) [data-surface="glass"]
14848
+ :is(
14849
+ .tf-panel,
14850
+ .tf-card,
14851
+ .tf-stat,
14852
+ .tf-dock,
14853
+ .tf-sidebar,
14854
+ .tf-map-legend,
14855
+ .tf-map-ctl,
14856
+ .tf-map-pop
14857
+ ):not(
14858
+ :is(
14859
+ .tf-panel,
14860
+ .tf-card,
14861
+ .tf-stat,
14862
+ .tf-dock,
14863
+ .tf-sidebar,
14864
+ .tf-popover,
14865
+ .tf-menu,
14866
+ .tf-hovercard,
14867
+ .tf-selectmenu-list,
14868
+ .tf-navmenu-panel,
14869
+ .tf-palette,
14870
+ .tf-modal,
14871
+ .tf-drawer,
14872
+ .tf-glass
14873
+ )
14874
+ *
14875
+ ):not(.tf-solid),
14876
+ :where([data-kit="halo"])[data-surface="glass"]
14877
+ :is(
14878
+ .tf-popover,
14879
+ .tf-menu:not(.tf-menu-static),
14880
+ .tf-hovercard,
14881
+ .tf-selectmenu-list,
14882
+ .tf-navmenu-panel,
14883
+ .tf-palette,
14884
+ .tf-modal,
14885
+ .tf-drawer
14886
+ ):not(.tf-solid),
14887
+ :where([data-kit="halo"]) [data-surface="glass"]
14888
+ :is(
14889
+ .tf-popover,
14890
+ .tf-menu:not(.tf-menu-static),
14891
+ .tf-hovercard,
14892
+ .tf-selectmenu-list,
14893
+ .tf-navmenu-panel,
14894
+ .tf-palette,
14895
+ .tf-modal,
14896
+ .tf-drawer
14897
+ ):not(.tf-solid) {
14898
+ --glass-fill: var(--glass);
14899
+ background:
14900
+ linear-gradient(to bottom, var(--glass-sheen), transparent 56px) border-box,
14901
+ linear-gradient(var(--glass-tinted), var(--glass-tinted)) border-box,
14902
+ var(--glass-fill);
14903
+ --glass-tinted: color-mix(in srgb, var(--tint, transparent) var(--glass-tint), transparent);
14904
+ -webkit-backdrop-filter: var(--glass-filter);
14905
+ backdrop-filter: var(--glass-filter);
14906
+ border-color: var(--glass-border);
14907
+ box-shadow:
14908
+ inset 0 1px 0 0 var(--glass-highlight),
14909
+ inset 0 0 0 1px var(--glass-border),
14910
+ var(--shadow-glass);
14911
+ color: var(--foreground);
14912
+ /* what sits on the glass */
14913
+ --surface: var(--glass-control);
14914
+ --secondary: var(--glass-control);
14915
+ --bg-100: var(--glass-control);
14916
+ --surface-sunken: var(--glass-well);
14917
+ --muted: var(--glass-well);
14918
+ --canvas: var(--glass-well);
14919
+ --bg-200: var(--glass-well);
14920
+ --accent: var(--glass-hover);
14921
+ --bg-300: var(--glass-hover);
14922
+ /* the faintest text steps up one shade: glass gives up some contrast to what is behind */
14923
+ --ink-subtle: var(--muted-foreground);
14924
+ --fg-300: var(--muted-foreground);
14925
+ }
14926
+
14927
+ /* floating layers carry more text: a stronger fill */
14928
+ :where([data-kit="halo"]) :is(
14929
+ .tf-popover,
14930
+ .tf-menu,
14931
+ .tf-hovercard,
14932
+ .tf-selectmenu-list,
14933
+ .tf-navmenu-panel,
14934
+ .tf-palette,
14935
+ .tf-modal,
14936
+ .tf-drawer
14937
+ ).tf-glass,
14938
+ :where([data-kit="halo"])[data-surface="glass"]
14939
+ :is(
14940
+ .tf-popover,
14941
+ .tf-menu:not(.tf-menu-static),
14942
+ .tf-hovercard,
14943
+ .tf-selectmenu-list,
14944
+ .tf-navmenu-panel,
14945
+ .tf-palette,
14946
+ .tf-modal,
14947
+ .tf-drawer
14948
+ ):not(.tf-solid),
14949
+ :where([data-kit="halo"]) [data-surface="glass"]
14950
+ :is(
14951
+ .tf-popover,
14952
+ .tf-menu:not(.tf-menu-static),
14953
+ .tf-hovercard,
14954
+ .tf-selectmenu-list,
14955
+ .tf-navmenu-panel,
14956
+ .tf-palette,
14957
+ .tf-modal,
14958
+ .tf-drawer
14959
+ ):not(.tf-solid) {
14960
+ --glass-fill: var(--glass-strong);
14961
+ }
14962
+
14963
+ /* Controls floating on their own (not on a surface) become small glass pills: a search field or
14964
+ zoom buttons over a map */
14965
+ :where([data-kit="halo"])[data-surface="glass"]
14966
+ :is(
14967
+ .tf-search,
14968
+ .tf-seg,
14969
+ .tf-btngroup,
14970
+ .tf-iconbtn-soft,
14971
+ .tf-iconbtn-outline,
14972
+ .tf-btn-secondary,
14973
+ .tf-chip:not([aria-pressed="true"])
14974
+ ):not(
14975
+ :is(
14976
+ .tf-panel,
14977
+ .tf-card,
14978
+ .tf-dock,
14979
+ .tf-popover,
14980
+ .tf-menu,
14981
+ .tf-hovercard,
14982
+ .tf-selectmenu-list,
14983
+ .tf-navmenu-panel,
14984
+ .tf-palette,
14985
+ .tf-modal,
14986
+ .tf-drawer,
14987
+ .tf-glass,
14988
+ .tf-btngroup,
14989
+ .tf-map-ctl,
14990
+ .tf-topbar
14991
+ )
14992
+ *
14993
+ ):not(.tf-solid),
14994
+ :where([data-kit="halo"]) [data-surface="glass"]
14995
+ :is(
14996
+ .tf-search,
14997
+ .tf-seg,
14998
+ .tf-btngroup,
14999
+ .tf-iconbtn-soft,
15000
+ .tf-iconbtn-outline,
15001
+ .tf-btn-secondary,
15002
+ .tf-chip:not([aria-pressed="true"])
15003
+ ):not(
15004
+ :is(
15005
+ .tf-panel,
15006
+ .tf-card,
15007
+ .tf-dock,
15008
+ .tf-popover,
15009
+ .tf-menu,
15010
+ .tf-hovercard,
15011
+ .tf-selectmenu-list,
15012
+ .tf-navmenu-panel,
15013
+ .tf-palette,
15014
+ .tf-modal,
15015
+ .tf-drawer,
15016
+ .tf-glass,
15017
+ .tf-btngroup,
15018
+ .tf-map-ctl,
15019
+ .tf-topbar
15020
+ )
15021
+ *
15022
+ ):not(.tf-solid) {
15023
+ background:
15024
+ linear-gradient(to bottom, var(--glass-sheen), transparent) border-box,
15025
+ var(--glass);
15026
+ -webkit-backdrop-filter: var(--glass-filter);
15027
+ backdrop-filter: var(--glass-filter);
15028
+ box-shadow:
15029
+ inset 0 1px 0 0 var(--glass-highlight),
15030
+ inset 0 0 0 1px var(--glass-border),
15031
+ var(--shadow-glass);
15032
+ color: var(--foreground);
15033
+ --surface: var(--glass-control);
15034
+ --secondary: var(--glass-control);
15035
+ --surface-sunken: var(--glass-well);
15036
+ --bg-200: var(--glass-well);
15037
+ --accent: var(--glass-hover);
15038
+ --bg-300: var(--glass-hover);
15039
+ }
15040
+ :where([data-kit="halo"])[data-surface="glass"]
15041
+ :is(.tf-iconbtn-soft, .tf-iconbtn-outline, .tf-btn-secondary, .tf-chip):not(
15042
+ :is(.tf-panel, .tf-card, .tf-dock, .tf-popover, .tf-menu, .tf-modal, .tf-drawer, .tf-glass) *
15043
+ ):not(.tf-solid):not([aria-pressed="true"]):hover, :where([data-kit="halo"]) [data-surface="glass"]
15044
+ :is(.tf-iconbtn-soft, .tf-iconbtn-outline, .tf-btn-secondary, .tf-chip):not(
15045
+ :is(.tf-panel, .tf-card, .tf-dock, .tf-popover, .tf-menu, .tf-modal, .tf-drawer, .tf-glass) *
15046
+ ):not(.tf-solid):not([aria-pressed="true"]):hover {
15047
+ background:
15048
+ linear-gradient(var(--glass-hover), var(--glass-hover)) border-box,
15049
+ var(--glass);
15050
+ }
15051
+
15052
+ /* AppShell on glass: the same layout as the solid shell, the frame turned to glass. Top bar and
15053
+ rail sit on it without a fill of their own, the sheet clears so the backdrop shows through,
15054
+ and everything drawn on the frame (nav, user, rail) reads the glass colours */
15055
+ :where([data-kit="halo"])[data-surface="glass"] .tf-shell, :where([data-kit="halo"]) [data-surface="glass"] .tf-shell {
15056
+ background:
15057
+ linear-gradient(to bottom, var(--glass-sheen), transparent 56px) border-box,
15058
+ var(--glass);
15059
+ -webkit-backdrop-filter: var(--glass-filter);
15060
+ backdrop-filter: var(--glass-filter);
15061
+ box-shadow:
15062
+ inset 0 1px 0 0 var(--glass-highlight),
15063
+ inset 0 0 0 1px var(--glass-border),
15064
+ var(--shadow-glass);
15065
+ --frame: var(--glass);
15066
+ --frame-hover: var(--glass-hover);
15067
+ --frame-active: var(--glass-hover);
15068
+ --frame-strong: var(--glass-control);
15069
+ --on-frame: var(--foreground);
15070
+ --on-frame-muted: var(--muted-foreground);
15071
+ }
15072
+ :where([data-kit="halo"])[data-surface="glass"] .tf-shell .tf-sheet, :where([data-kit="halo"]) [data-surface="glass"] .tf-shell .tf-sheet {
15073
+ background: transparent;
15074
+ }
15075
+ :where([data-kit="halo"])[data-surface="glass"] .tf-shell .tf-topbar, :where([data-kit="halo"]) [data-surface="glass"] .tf-shell .tf-topbar {
15076
+ background: transparent;
15077
+ }
15078
+
15079
+ /* switch knobs stay solid on glass */
15080
+ :where([data-kit="halo"]) .tf-glass .tf-switch::after,
15081
+ :where([data-kit="halo"])[data-surface="glass"] .tf-switch::after,
15082
+ :where([data-kit="halo"]) [data-surface="glass"] .tf-switch::after {
15083
+ background: var(--card);
15084
+ }
15085
+
15086
+ /* Reduced transparency, more contrast, forced colours and browsers without backdrop blur switch
15087
+ the glass tokens themselves (see tokens.css). Forced colours drop shadows, so glass keeps an
15088
+ edge there. */
15089
+ @media (forced-colors: active) {
15090
+ :where([data-kit="halo"]) .tf-glass,
15091
+ :where([data-kit="halo"])[data-surface="glass"]
15092
+ :is(
15093
+ .tf-panel,
15094
+ .tf-card,
15095
+ .tf-stat,
15096
+ .tf-dock,
15097
+ .tf-sidebar,
15098
+ .tf-map-legend,
15099
+ .tf-map-ctl,
15100
+ .tf-map-pop
15101
+ ),
15102
+ :where([data-kit="halo"]) [data-surface="glass"]
15103
+ :is(
15104
+ .tf-panel,
15105
+ .tf-card,
15106
+ .tf-stat,
15107
+ .tf-dock,
15108
+ .tf-sidebar,
15109
+ .tf-map-legend,
15110
+ .tf-map-ctl,
15111
+ .tf-map-pop
15112
+ ) {
15113
+ outline: 1px solid CanvasText;
15114
+ outline-offset: -1px;
15115
+ }
15116
+ }
15117
+
15118
+ /* FloatingLayout: UI along the edges of a full-bleed background */
15119
+ :where([data-kit="halo"]) .tf-floating {
15120
+ position: relative;
15121
+ overflow: hidden;
15122
+ isolation: isolate;
15123
+ border-radius: var(--radius-lg);
15124
+ background: var(--surface-sunken);
15125
+ container: tf-floating / inline-size;
15126
+ }
15127
+ :where([data-kit="halo"]) .tf-floating-bg {
15128
+ position: absolute;
15129
+ inset: 0;
15130
+ }
15131
+ :where([data-kit="halo"]) .tf-floating-bg > * {
15132
+ width: 100%;
15133
+ height: 100%;
15134
+ }
15135
+ :where([data-kit="halo"]) .tf-floating-ui {
15136
+ position: absolute;
15137
+ inset: 0;
15138
+ z-index: 1;
15139
+ display: grid;
15140
+ grid-template-columns: minmax(0, 320px) minmax(0, 1fr) minmax(0, 340px);
15141
+ grid-template-rows: auto minmax(0, 1fr) auto;
15142
+ grid-template-areas:
15143
+ "top top top"
15144
+ "start . end"
15145
+ "bottom bottom bottom";
15146
+ gap: var(--space-4);
15147
+ padding: var(--space-4);
15148
+ overflow-y: auto;
15149
+ /* the background stays usable between the slots */
15150
+ pointer-events: none;
15151
+ }
15152
+ :where([data-kit="halo"]) .tf-floating-ui > * {
15153
+ pointer-events: auto;
15154
+ min-width: 0;
15155
+ }
15156
+ :where([data-kit="halo"]) .tf-floating-top {
15157
+ grid-area: top;
15158
+ display: flex;
15159
+ flex-wrap: wrap;
15160
+ align-items: center;
15161
+ gap: var(--space-2);
15162
+ }
15163
+ :where([data-kit="halo"]) .tf-floating-start {
15164
+ grid-area: start;
15165
+ align-self: start;
15166
+ }
15167
+ :where([data-kit="halo"]) .tf-floating-end {
15168
+ grid-area: end;
15169
+ align-self: start;
15170
+ }
15171
+ :where([data-kit="halo"]) .tf-floating-bottom {
15172
+ grid-area: bottom;
15173
+ justify-self: center;
15174
+ }
15175
+ :where([data-kit="halo"]) .tf-floating-ui > :is(.tf-floating-top, .tf-floating-bottom) {
15176
+ pointer-events: none;
15177
+ }
15178
+ :where([data-kit="halo"]) .tf-floating-ui > :is(.tf-floating-top, .tf-floating-bottom) > * {
15179
+ pointer-events: auto;
15180
+ }
15181
+ @container tf-floating (max-width: 720px) {
15182
+ /* on a phone the layout grows with its slots and the background fills behind them */
15183
+ :where([data-kit="halo"]) .tf-floating-ui {
15184
+ position: relative;
15185
+ min-height: inherit;
15186
+ overflow: visible;
15187
+ grid-template-columns: minmax(0, 1fr);
15188
+ grid-template-rows: auto auto minmax(120px, 1fr) auto auto;
15189
+ grid-template-areas:
15190
+ "top"
15191
+ "start"
15192
+ "."
15193
+ "end"
15194
+ "bottom";
15195
+ gap: var(--space-3);
15196
+ padding: var(--space-3);
15197
+ }
15198
+ }
15199
+
15200
+ /* 09-motion.css */
15201
+ /* Motion: leaving layers, reveal on scroll, page transitions, the expressive level.
15202
+ *
15203
+ * Levels come from `data-motion` (tokens.css): "standard", "expressive" (longer, staggered page
15204
+ * entrances, more travel) and "off". The reader's reduced-motion setting always means off. Only
15205
+ * transform, opacity and (expressive Halo) a short blur move; everything else stays put.
15206
+ */
15207
+
15208
+ /* ── Leaving: layers animate out for --dur-exit, then unmount (usePresence) ── */
15209
+ @keyframes tf-halo-out {
15210
+ to {
15211
+ opacity: 0;
15212
+ translate: 0 calc(6px * var(--motion-travel));
15213
+ scale: 0.98;
15214
+ }
15215
+ }
15216
+ @keyframes tf-halo-out-fade {
15217
+ to {
15218
+ opacity: 0;
15219
+ }
15220
+ }
15221
+ @keyframes tf-halo-out-right {
15222
+ to {
15223
+ opacity: 0;
15224
+ translate: calc(40px * var(--motion-travel)) 0;
15225
+ }
15226
+ }
15227
+ @keyframes tf-halo-out-left {
15228
+ to {
15229
+ opacity: 0;
15230
+ translate: calc(-40px * var(--motion-travel)) 0;
15231
+ }
15232
+ }
15233
+ @keyframes tf-halo-out-up {
15234
+ to {
15235
+ opacity: 0;
15236
+ translate: 0 calc(-40px * var(--motion-travel));
15237
+ }
15238
+ }
15239
+ @keyframes tf-halo-out-down {
15240
+ to {
15241
+ opacity: 0;
15242
+ translate: 0 calc(16px * var(--motion-travel));
15243
+ }
15244
+ }
15245
+ :where([data-kit="halo"])[data-closing], :where([data-kit="halo"]) [data-closing] {
15246
+ pointer-events: none;
15247
+ }
15248
+ :where([data-kit="halo"]) .tf-popover[data-closing],
15249
+ :where([data-kit="halo"]) .tf-hovercard[data-closing],
15250
+ :where([data-kit="halo"]) .tf-modal-wrap[data-closing] .tf-modal,
15251
+ :where([data-kit="halo"]) .tf-overlay[data-closing] :is(.tf-modal, .tf-confirm),
15252
+ :where([data-kit="halo"]) .tf-palette-wrap[data-closing] .tf-palette {
15253
+ animation: tf-halo-out var(--dur-exit) var(--ease-in-out) forwards;
15254
+ }
15255
+ :where([data-kit="halo"]) .tf-tooltip[data-closing],
15256
+ :where([data-kit="halo"]) .tf-modal-wrap[data-closing] .tf-backdrop,
15257
+ :where([data-kit="halo"]) .tf-overlay[data-closing] .tf-backdrop,
15258
+ :where([data-kit="halo"]) .tf-palette-wrap[data-closing],
15259
+ :where([data-kit="halo"]) .tf-drawer-wrap[data-closing] {
15260
+ animation: tf-halo-out-fade var(--dur-exit) var(--ease-in-out) forwards;
15261
+ }
15262
+ :where([data-kit="halo"]) .tf-drawer-wrap[data-closing] .tf-drawer {
15263
+ animation: tf-halo-out-right var(--dur-exit) var(--ease-in-out) forwards;
15264
+ }
15265
+ :where([data-kit="halo"]) .tf-drawer-wrap[data-closing] .tf-drawer.side-left {
15266
+ animation-name: tf-halo-out-left;
15267
+ }
15268
+ :where([data-kit="halo"]) .tf-drawer-wrap[data-closing] .tf-drawer.side-top {
15269
+ animation-name: tf-halo-out-up;
15270
+ }
15271
+ :where([data-kit="halo"]) .tf-drawer-wrap[data-closing] .tf-drawer.side-bottom,
15272
+ :where([data-kit="halo"]) .tf-toast[data-closing] {
15273
+ animation: tf-halo-out-down var(--dur-exit) var(--ease-in-out) forwards;
15274
+ }
15275
+
15276
+ /* ── Reveal: a Stagger below the fold waits until it scrolls into view ── */
15277
+ :where([data-kit="halo"]) .tf-stagger[data-reveal="waiting"] > *,
15278
+ :where([data-kit="halo"]) .tf-stagger[data-reveal="waiting"] > * * {
15279
+ animation-play-state: paused;
15280
+ }
15281
+
15282
+ /* ── Page transitions (startViewTransition, Next.js and React view transitions) ── */
15283
+ @keyframes tf-halo-vt-out {
15284
+ to {
15285
+ opacity: 0;
15286
+ translate: 0 calc(-6px * var(--motion-travel));
15287
+ }
15288
+ }
15289
+ @keyframes tf-halo-vt-in {
15290
+ from {
15291
+ opacity: 0;
15292
+ translate: 0 calc(10px * var(--motion-travel));
15293
+ }
15294
+ }
15295
+ :where([data-kit="halo"])::view-transition-old(root) {
15296
+ animation: tf-halo-vt-out var(--dur-base) var(--ease-in-out) both;
15297
+ }
15298
+ :where([data-kit="halo"])::view-transition-new(root) {
15299
+ animation: tf-halo-vt-in var(--dur-enter) var(--ease-out) both;
15300
+ }
15301
+
15302
+ /* ── Expressive: things come into focus as they rise (Halo; Pro keeps a blur of 0) ── */
15303
+ @keyframes tf-halo-focus-in {
15304
+ from {
15305
+ filter: blur(var(--motion-blur));
15306
+ }
15307
+ to {
15308
+ filter: none;
15309
+ }
15310
+ }
15311
+ :where([data-kit="halo"])[data-motion="expressive"] :is(.tf-stagger > *, .tf-in), :where([data-kit="halo"]) [data-motion="expressive"] :is(.tf-stagger > *, .tf-in) {
15312
+ animation-name: tf-halo-rise, tf-halo-focus-in;
15313
+ }
15314
+ :where([data-kit="halo"])[data-motion="expressive"] .tf-topbar, :where([data-kit="halo"]) [data-motion="expressive"] .tf-topbar {
15315
+ animation-name: tf-halo-drop, tf-halo-focus-in;
15316
+ }
15317
+
15318
+ /* 10-ambient.css */
15319
+ /* Ambient: a calm, living background for glass UI. Soft colour fields from the kit (pastels in
15320
+ * Halo, a faint aurora in Pro) drift slowly; a photo or video can take their place under a scrim.
15321
+ * The drift only moves (transform), stops with motion off and pauses off screen.
15322
+ */
15323
+ :where([data-kit="halo"]) :where(:has(> .tf-ambient:not(.fixed))) {
15324
+ position: relative;
15325
+ isolation: isolate;
15326
+ }
15327
+ :where([data-kit="halo"]) .tf-ambient {
15328
+ position: absolute;
15329
+ inset: 0;
15330
+ z-index: -1;
15331
+ overflow: hidden;
15332
+ background: var(--ambient-base);
15333
+ pointer-events: none;
15334
+ }
15335
+ :where([data-kit="halo"]) .tf-ambient.fixed {
15336
+ position: fixed;
15337
+ }
15338
+ :where([data-kit="halo"]) .tf-ambient-field {
15339
+ position: absolute;
15340
+ width: 75%;
15341
+ aspect-ratio: 1;
15342
+ border-radius: 50%;
15343
+ background: radial-gradient(closest-side, var(--field), transparent);
15344
+ animation: tf-halo-ambient-drift 34s var(--ease-in-out) infinite alternate;
15345
+ }
15346
+ :where([data-kit="halo"]) .tf-ambient-field:nth-child(1) {
15347
+ top: -30%;
15348
+ left: -15%;
15349
+ }
15350
+ :where([data-kit="halo"]) .tf-ambient-field:nth-child(2) {
15351
+ top: -10%;
15352
+ right: -25%;
15353
+ animation-duration: 41s;
15354
+ animation-direction: alternate-reverse;
15355
+ }
15356
+ :where([data-kit="halo"]) .tf-ambient-field:nth-child(3) {
15357
+ bottom: -35%;
15358
+ left: 10%;
15359
+ animation-duration: 47s;
15360
+ }
15361
+ :where([data-kit="halo"]) .tf-ambient-field:nth-child(4) {
15362
+ bottom: -25%;
15363
+ right: -10%;
15364
+ animation-duration: 38s;
15365
+ animation-direction: alternate-reverse;
15366
+ }
15367
+ :where([data-kit="halo"]) .tf-ambient-field:nth-child(n + 5) {
15368
+ top: 20%;
15369
+ left: 30%;
15370
+ width: 55%;
15371
+ animation-duration: 52s;
15372
+ }
15373
+ @keyframes tf-halo-ambient-drift {
15374
+ to {
15375
+ translate: 12% 9%;
15376
+ scale: 1.15;
15377
+ }
15378
+ }
15379
+ :where([data-kit="halo"]) .tf-ambient.still .tf-ambient-field,
15380
+ :where([data-kit="halo"]) .tf-ambient[data-paused] .tf-ambient-field {
15381
+ animation-play-state: paused;
15382
+ }
15383
+ :where([data-kit="halo"]) .tf-ambient-media {
15384
+ position: absolute;
15385
+ inset: 0;
15386
+ width: 100%;
15387
+ height: 100%;
15388
+ object-fit: cover;
15389
+ }
15390
+ :where([data-kit="halo"]) .tf-ambient.media::after {
15391
+ content: "";
15392
+ position: absolute;
15393
+ inset: 0;
15394
+ background: var(--ambient-scrim);
15395
+ }
15396
+ @media (prefers-reduced-motion: reduce) {
15397
+ :where([data-kit="halo"]) .tf-ambient-field {
15398
+ animation: none;
15399
+ }
15400
+ }
15401
+ :where([data-kit="halo"])[data-motion="off"] .tf-ambient-field, :where([data-kit="halo"]) [data-motion="off"] .tf-ambient-field {
15402
+ animation: none;
15403
+ }
15404
+
14386
15405
  /* 01-foundation.css */
14387
15406
  /* Generated by scripts/pro-css.ts from packages/halo/css. Do not edit; the Pro look lives in 90-pro-look.css. */
14388
15407
  /* Halo components, ported from reference/halo/source/halo.css (ha- → tf-). Every value comes from the tokens. */
@@ -14928,18 +15947,23 @@
14928
15947
  box-shadow: none;
14929
15948
  }
14930
15949
  :where([data-kit="pro"]) .tf-bg-sky {
15950
+ --tint: var(--sky);
14931
15951
  background: var(--sky);
14932
15952
  }
14933
15953
  :where([data-kit="pro"]) .tf-bg-mint {
15954
+ --tint: var(--mint);
14934
15955
  background: var(--mint);
14935
15956
  }
14936
15957
  :where([data-kit="pro"]) .tf-bg-lilac {
15958
+ --tint: var(--lilac);
14937
15959
  background: var(--lilac);
14938
15960
  }
14939
15961
  :where([data-kit="pro"]) .tf-bg-butter {
15962
+ --tint: var(--butter);
14940
15963
  background: var(--butter);
14941
15964
  }
14942
15965
  :where([data-kit="pro"]) .tf-bg-blush {
15966
+ --tint: var(--blush);
14943
15967
  background: var(--blush);
14944
15968
  }
14945
15969
  :where([data-kit="pro"]) .tf-bg-surface {
@@ -15361,7 +16385,7 @@
15361
16385
  @keyframes tf-pro-rise {
15362
16386
  from {
15363
16387
  opacity: 0;
15364
- transform: translateY(14px) scale(0.985);
16388
+ transform: translateY(calc(14px * var(--motion-travel))) scale(0.985);
15365
16389
  }
15366
16390
  to {
15367
16391
  opacity: 1;
@@ -15379,7 +16403,7 @@
15379
16403
  @keyframes tf-pro-drop {
15380
16404
  from {
15381
16405
  opacity: 0;
15382
- transform: translateY(-10px);
16406
+ transform: translateY(calc(-10px * var(--motion-travel)));
15383
16407
  }
15384
16408
  to {
15385
16409
  opacity: 1;
@@ -15389,7 +16413,7 @@
15389
16413
  @keyframes tf-pro-slide-in {
15390
16414
  from {
15391
16415
  opacity: 0;
15392
- transform: translateX(24px);
16416
+ transform: translateX(calc(24px * var(--motion-travel)));
15393
16417
  }
15394
16418
  to {
15395
16419
  opacity: 1;
@@ -15399,7 +16423,8 @@
15399
16423
  @keyframes tf-pro-slide-up {
15400
16424
  from {
15401
16425
  opacity: 0;
15402
- transform: translate(0, 28px) scale(0.9);
16426
+ transform: translate(calc(0px * var(--motion-travel)), calc(28px * var(--motion-travel)))
16427
+ scale(0.9);
15403
16428
  }
15404
16429
  to {
15405
16430
  opacity: 1;
@@ -15458,47 +16483,60 @@
15458
16483
  }
15459
16484
 
15460
16485
  :where([data-kit="pro"]) .tf-in {
16486
+ --enter-delay: var(--d, 0ms);
15461
16487
  animation: tf-pro-rise var(--dur-enter) var(--ease-out) both;
15462
- animation-delay: var(--d, 0ms);
16488
+ animation-delay: var(--enter-delay);
15463
16489
  }
15464
16490
  :where([data-kit="pro"]) .tf-stagger > * {
15465
16491
  animation: tf-pro-rise var(--dur-enter) var(--ease-out) both;
15466
16492
  }
15467
16493
  :where([data-kit="pro"]) .tf-stagger > :nth-child(1) {
15468
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 0);
16494
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 0);
16495
+ animation-delay: var(--enter-delay);
15469
16496
  }
15470
16497
  :where([data-kit="pro"]) .tf-stagger > :nth-child(2) {
15471
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 1);
16498
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 1);
16499
+ animation-delay: var(--enter-delay);
15472
16500
  }
15473
16501
  :where([data-kit="pro"]) .tf-stagger > :nth-child(3) {
15474
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 2);
16502
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 2);
16503
+ animation-delay: var(--enter-delay);
15475
16504
  }
15476
16505
  :where([data-kit="pro"]) .tf-stagger > :nth-child(4) {
15477
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 3);
16506
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 3);
16507
+ animation-delay: var(--enter-delay);
15478
16508
  }
15479
16509
  :where([data-kit="pro"]) .tf-stagger > :nth-child(5) {
15480
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 4);
16510
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 4);
16511
+ animation-delay: var(--enter-delay);
15481
16512
  }
15482
16513
  :where([data-kit="pro"]) .tf-stagger > :nth-child(6) {
15483
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 5);
16514
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 5);
16515
+ animation-delay: var(--enter-delay);
15484
16516
  }
15485
16517
  :where([data-kit="pro"]) .tf-stagger > :nth-child(7) {
15486
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 6);
16518
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 6);
16519
+ animation-delay: var(--enter-delay);
15487
16520
  }
15488
16521
  :where([data-kit="pro"]) .tf-stagger > :nth-child(8) {
15489
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 7);
16522
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 7);
16523
+ animation-delay: var(--enter-delay);
15490
16524
  }
15491
16525
  :where([data-kit="pro"]) .tf-stagger > :nth-child(9) {
15492
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 8);
16526
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 8);
16527
+ animation-delay: var(--enter-delay);
15493
16528
  }
15494
16529
  :where([data-kit="pro"]) .tf-stagger > :nth-child(10) {
15495
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 9);
16530
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 9);
16531
+ animation-delay: var(--enter-delay);
15496
16532
  }
15497
16533
  :where([data-kit="pro"]) .tf-stagger > :nth-child(11) {
15498
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 10);
16534
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 10);
16535
+ animation-delay: var(--enter-delay);
15499
16536
  }
15500
16537
  :where([data-kit="pro"]) .tf-stagger > :nth-child(n + 12) {
15501
- animation-delay: calc(var(--base, 0ms) + var(--stagger-step) * 11);
16538
+ --enter-delay: calc(var(--base, 0ms) + var(--stagger-step) * 11);
16539
+ animation-delay: var(--enter-delay);
15502
16540
  }
15503
16541
  :where([data-kit="pro"]) .tf-topbar {
15504
16542
  animation: tf-pro-drop var(--dur-enter) var(--ease-out) both;
@@ -15508,32 +16546,32 @@
15508
16546
  }
15509
16547
  :where([data-kit="pro"]) .tf-panel.tf-side {
15510
16548
  animation: tf-pro-slide-in var(--dur-enter) var(--ease-out) both;
15511
- animation-delay: 160ms;
16549
+ animation-delay: calc(160ms * var(--motion-time));
15512
16550
  }
15513
16551
  :where([data-kit="pro"]) .tf-dock {
15514
16552
  animation: tf-pro-slide-up var(--dur-enter) var(--ease-spring) both;
15515
- animation-delay: 420ms;
16553
+ animation-delay: calc(420ms * var(--motion-time));
15516
16554
  }
15517
16555
  :where([data-kit="pro"]) .tf-dock .tf-dock-btn {
15518
16556
  animation: tf-pro-pop var(--dur-base) var(--ease-spring) both;
15519
16557
  }
15520
16558
  :where([data-kit="pro"]) .tf-dock .tf-dock-btn:nth-child(1) {
15521
- animation-delay: 520ms;
16559
+ animation-delay: calc(520ms * var(--motion-time));
15522
16560
  }
15523
16561
  :where([data-kit="pro"]) .tf-dock .tf-dock-btn:nth-child(2) {
15524
- animation-delay: 570ms;
16562
+ animation-delay: calc(570ms * var(--motion-time));
15525
16563
  }
15526
16564
  :where([data-kit="pro"]) .tf-dock .tf-dock-btn:nth-child(3) {
15527
- animation-delay: 620ms;
16565
+ animation-delay: calc(620ms * var(--motion-time));
15528
16566
  }
15529
16567
  :where([data-kit="pro"]) .tf-dock .tf-dock-btn:nth-child(4) {
15530
- animation-delay: 670ms;
16568
+ animation-delay: calc(670ms * var(--motion-time));
15531
16569
  }
15532
16570
  :where([data-kit="pro"]) .tf-dock .tf-dock-btn:nth-child(5) {
15533
- animation-delay: 720ms;
16571
+ animation-delay: calc(720ms * var(--motion-time));
15534
16572
  }
15535
16573
  :where([data-kit="pro"]) .tf-dock .tf-dock-btn:nth-child(n + 6) {
15536
- animation-delay: 770ms;
16574
+ animation-delay: calc(770ms * var(--motion-time));
15537
16575
  }
15538
16576
  :where([data-kit="pro"]) .tf-rail-btn {
15539
16577
  animation: tf-pro-pop var(--dur-base) var(--ease-spring) both;
@@ -15570,7 +16608,7 @@
15570
16608
  :where([data-kit="pro"]) .tf-progress > span {
15571
16609
  transform-origin: left;
15572
16610
  animation: tf-pro-grow-x var(--dur-slow) var(--ease-out) both;
15573
- animation-delay: 200ms;
16611
+ animation-delay: calc(var(--enter-delay, 0ms) + calc(200ms * var(--motion-time)));
15574
16612
  }
15575
16613
 
15576
16614
  /* Sliding tab indicator */
@@ -15649,6 +16687,7 @@
15649
16687
  transform-box: fill-box;
15650
16688
  transform-origin: bottom;
15651
16689
  animation: tf-pro-grow-y var(--dur-slow) var(--ease-out) both;
16690
+ animation-delay: var(--enter-delay, 0ms);
15652
16691
  }
15653
16692
  :where([data-kit="pro"]) .tf-bar-ink {
15654
16693
  fill: var(--primary);
@@ -15676,7 +16715,7 @@
15676
16715
  stroke-dasharray: 1;
15677
16716
  stroke-dashoffset: 1;
15678
16717
  animation: tf-pro-draw var(--dur-slow) var(--ease-out) forwards;
15679
- animation-delay: 150ms;
16718
+ animation-delay: calc(var(--enter-delay, 0ms) + calc(150ms * var(--motion-time)));
15680
16719
  }
15681
16720
  :where([data-kit="pro"]) .tf-line-ink {
15682
16721
  stroke: var(--primary);
@@ -15699,7 +16738,7 @@
15699
16738
  :where([data-kit="pro"]) .tf-area {
15700
16739
  opacity: 0;
15701
16740
  animation: tf-pro-fade var(--dur-slow) var(--ease-out) forwards;
15702
- animation-delay: 500ms;
16741
+ animation-delay: calc(var(--enter-delay, 0ms) + calc(500ms * var(--motion-time)));
15703
16742
  }
15704
16743
  :where([data-kit="pro"]) .tf-area-sky {
15705
16744
  fill: var(--sky);
@@ -15720,7 +16759,7 @@
15720
16759
  fill: var(--surface);
15721
16760
  stroke-width: 2.5;
15722
16761
  animation: tf-pro-pop var(--dur-base) var(--ease-spring) both;
15723
- animation-delay: 900ms;
16762
+ animation-delay: calc(var(--enter-delay, 0ms) + calc(900ms * var(--motion-time)));
15724
16763
  transform-box: fill-box;
15725
16764
  transform-origin: center;
15726
16765
  }
@@ -16149,6 +17188,22 @@
16149
17188
  }
16150
17189
  }
16151
17190
 
17191
+ /* the same for an app that turns motion off: data-motion="off" */
17192
+ :where([data-kit="pro"])[data-motion="off"] *,
17193
+ :where([data-kit="pro"]) [data-motion="off"] *,
17194
+ :where([data-kit="pro"])[data-motion="off"] *::before,
17195
+ :where([data-kit="pro"]) [data-motion="off"] *::before,
17196
+ :where([data-kit="pro"])[data-motion="off"] *::after,
17197
+ :where([data-kit="pro"]) [data-motion="off"] *::after {
17198
+ animation-duration: 1ms !important;
17199
+ animation-delay: 0ms !important;
17200
+ animation-iteration-count: 1 !important;
17201
+ transition-duration: 1ms !important;
17202
+ }
17203
+ :where([data-kit="pro"])[data-motion="off"] .tf-line, :where([data-kit="pro"]) [data-motion="off"] .tf-line {
17204
+ stroke-dashoffset: 0;
17205
+ }
17206
+
16152
17207
  /* ───────── Refinements ───────── */
16153
17208
  :where([data-kit="pro"]) .tf-nav-label {
16154
17209
  white-space: nowrap;
@@ -16180,7 +17235,7 @@
16180
17235
  :where([data-kit="pro"]) .tf-area {
16181
17236
  opacity: 0;
16182
17237
  animation: tf-pro-area-in var(--dur-slow) var(--ease-out) forwards;
16183
- animation-delay: 500ms;
17238
+ animation-delay: calc(var(--enter-delay, 0ms) + calc(500ms * var(--motion-time)));
16184
17239
  }
16185
17240
  @keyframes tf-pro-area-in {
16186
17241
  to {
@@ -16742,7 +17797,7 @@
16742
17797
  }
16743
17798
  @keyframes tf-pro-drawer-in {
16744
17799
  from {
16745
- transform: translateX(40px);
17800
+ transform: translateX(calc(40px * var(--motion-travel)));
16746
17801
  opacity: 0;
16747
17802
  }
16748
17803
  to {
@@ -17617,7 +18672,7 @@
17617
18672
  box-shadow:
17618
18673
  var(--shadow-float), 0 0 0 var(--line-width) var(--line),
17619
18674
  0 0 0 1px var(--line);
17620
- animation: tf-pop var(--dur-base) var(--ease-spring) both;
18675
+ animation: tf-pro-pop var(--dur-base) var(--ease-spring) both;
17621
18676
  transform-origin: top left;
17622
18677
  }
17623
18678
  :where([data-kit="pro"]) .tf-popover.tf-pop-end {
@@ -18617,7 +19672,7 @@
18617
19672
  color: var(--on-frame);
18618
19673
  box-shadow: var(--shadow-float), 0 0 0 var(--line-width) var(--line);
18619
19674
  font: 500 13px/18px var(--font-sans);
18620
- animation: tf-slide-up var(--dur-base) var(--ease-spring) both;
19675
+ animation: tf-pro-slide-up var(--dur-base) var(--ease-spring) both;
18621
19676
  margin-bottom: 8px;
18622
19677
  }
18623
19678
  :where([data-kit="pro"]) .tf-bulkbar > b {
@@ -18717,7 +19772,8 @@
18717
19772
  :where([data-kit="pro"]) .tf-seg-bar {
18718
19773
  transform-box: fill-box;
18719
19774
  transform-origin: bottom;
18720
- animation: tf-grow-y var(--dur-slow) var(--ease-out) both;
19775
+ animation: tf-pro-grow-y var(--dur-slow) var(--ease-out) both;
19776
+ animation-delay: var(--enter-delay, 0ms);
18721
19777
  transition: opacity var(--dur-fast);
18722
19778
  }
18723
19779
  :where([data-kit="pro"]) .tf-chart g.dim .tf-seg-bar {
@@ -18763,7 +19819,7 @@
18763
19819
  :where([data-kit="pro"]) .tf-area2 {
18764
19820
  opacity: 0;
18765
19821
  animation: tf-pro-area2-in var(--dur-slow) var(--ease-out) forwards;
18766
- animation-delay: 400ms;
19822
+ animation-delay: calc(var(--enter-delay, 0ms) + calc(400ms * var(--motion-time)));
18767
19823
  }
18768
19824
  @keyframes tf-pro-area2-in {
18769
19825
  to {
@@ -18825,7 +19881,7 @@
18825
19881
  height: 20px;
18826
19882
  border-radius: var(--radius-1);
18827
19883
  background: var(--surface-sunken);
18828
- animation: tf-fade var(--dur-base) var(--ease-out) both;
19884
+ animation: tf-pro-fade var(--dur-base) var(--ease-out) both;
18829
19885
  transition: box-shadow var(--dur-fast);
18830
19886
  }
18831
19887
  :where([data-kit="pro"]) .tf-heat-cell.l1 {
@@ -19000,6 +20056,23 @@
19000
20056
  display: none;
19001
20057
  }
19002
20058
  }
20059
+ /* the same for an app that turns motion off: data-motion="off" */
20060
+ :where([data-kit="pro"])[data-motion="off"] .tf-seg-bar,
20061
+ :where([data-kit="pro"]) [data-motion="off"] .tf-seg-bar,
20062
+ :where([data-kit="pro"])[data-motion="off"] .tf-area2,
20063
+ :where([data-kit="pro"]) [data-motion="off"] .tf-area2,
20064
+ :where([data-kit="pro"])[data-motion="off"] .tf-heat-cell,
20065
+ :where([data-kit="pro"]) [data-motion="off"] .tf-heat-cell,
20066
+ :where([data-kit="pro"])[data-motion="off"] .tf-tooltip,
20067
+ :where([data-kit="pro"]) [data-motion="off"] .tf-tooltip,
20068
+ :where([data-kit="pro"])[data-motion="off"] .tf-popover,
20069
+ :where([data-kit="pro"]) [data-motion="off"] .tf-popover {
20070
+ animation: none !important;
20071
+ opacity: 1;
20072
+ }
20073
+ :where([data-kit="pro"])[data-motion="off"] .tf-toast-timer, :where([data-kit="pro"]) [data-motion="off"] .tf-toast-timer {
20074
+ display: none;
20075
+ }
19003
20076
  @media (max-width: 640px) {
19004
20077
  :where([data-kit="pro"]) .tf-dp {
19005
20078
  flex-direction: column;
@@ -19162,7 +20235,7 @@
19162
20235
  gap: 12px;
19163
20236
  align-items: flex-start;
19164
20237
  min-width: 0;
19165
- animation: tf-rise var(--dur-base) var(--ease-out) both;
20238
+ animation: tf-pro-rise var(--dur-base) var(--ease-out) both;
19166
20239
  }
19167
20240
  :where([data-kit="pro"]) .tf-msg.me {
19168
20241
  flex-direction: row-reverse;
@@ -19378,7 +20451,7 @@
19378
20451
  border-radius: var(--radius-full);
19379
20452
  background: var(--mint-ink);
19380
20453
  box-shadow: 0 0 0 2px var(--surface);
19381
- animation: tf-pulse 1.8s ease-out infinite;
20454
+ animation: tf-pro-pulse 1.8s ease-out infinite;
19382
20455
  }
19383
20456
 
19384
20457
  /* Tool calls, reasoning, approvals */
@@ -19525,7 +20598,7 @@
19525
20598
  :where([data-kit="pro"]) .tf-reason.live .tf-reason-head {
19526
20599
  background: linear-gradient(90deg, var(--surface-sunken), var(--line), var(--surface-sunken));
19527
20600
  background-size: 200% 100%;
19528
- animation: tf-shimmer 1.6s linear infinite;
20601
+ animation: tf-pro-shimmer 1.6s linear infinite;
19529
20602
  }
19530
20603
  :where([data-kit="pro"]) .tf-reason-head:focus-visible {
19531
20604
  outline: 2px solid var(--focus);
@@ -19903,7 +20976,7 @@
19903
20976
  }
19904
20977
  :where([data-kit="pro"]) .tf-trace-row.is-running .tf-trace-bar i {
19905
20978
  background: var(--sky-ink);
19906
- animation: tf-pulse 1.4s ease-in-out infinite;
20979
+ animation: tf-pro-pulse 1.4s ease-in-out infinite;
19907
20980
  }
19908
20981
  :where([data-kit="pro"]) .tf-trace-bar em {
19909
20982
  position: absolute;
@@ -20769,6 +21842,19 @@
20769
21842
  animation: none !important;
20770
21843
  }
20771
21844
  }
21845
+ /* the same for an app that turns motion off: data-motion="off" */
21846
+ :where([data-kit="pro"])[data-motion="off"] .tf-msg,
21847
+ :where([data-kit="pro"]) [data-motion="off"] .tf-msg,
21848
+ :where([data-kit="pro"])[data-motion="off"] .tf-caret,
21849
+ :where([data-kit="pro"]) [data-motion="off"] .tf-caret,
21850
+ :where([data-kit="pro"])[data-motion="off"] .tf-typing i,
21851
+ :where([data-kit="pro"]) [data-motion="off"] .tf-typing i,
21852
+ :where([data-kit="pro"])[data-motion="off"] .tf-spin,
21853
+ :where([data-kit="pro"]) [data-motion="off"] .tf-spin,
21854
+ :where([data-kit="pro"])[data-motion="off"] .tf-reason.live .tf-reason-head,
21855
+ :where([data-kit="pro"]) [data-motion="off"] .tf-reason.live .tf-reason-head {
21856
+ animation: none !important;
21857
+ }
20772
21858
 
20773
21859
  /* 04-status-agents-operations.css */
20774
21860
  /* Generated by scripts/pro-css.ts from packages/halo/css. Do not edit; the Pro look lives in 90-pro-look.css. */
@@ -20786,7 +21872,7 @@
20786
21872
  border-radius: var(--radius-full);
20787
21873
  }
20788
21874
  :where([data-kit="pro"]) .tf-shape-pulse {
20789
- animation: tf-pulse 1.8s ease-out infinite;
21875
+ animation: tf-pro-pulse 1.8s ease-out infinite;
20790
21876
  }
20791
21877
  :where([data-kit="pro"]) .tf-shape-diamond {
20792
21878
  width: 7px;
@@ -21167,7 +22253,7 @@
21167
22253
  border-radius: var(--radius-full);
21168
22254
  border: 2px solid var(--line-strong);
21169
22255
  border-top-color: var(--ink);
21170
- animation: tf-spin 0.8s linear infinite;
22256
+ animation: tf-pro-spin 0.8s linear infinite;
21171
22257
  flex: none;
21172
22258
  }
21173
22259
  :where([data-kit="pro"]) .tf-spinner.lg {
@@ -22343,7 +23429,7 @@
22343
23429
  }
22344
23430
  :where([data-kit="pro"]) .tf-stage.st-running::after {
22345
23431
  background: var(--info);
22346
- animation: tf-pulse 1.4s ease-in-out infinite;
23432
+ animation: tf-pro-pulse 1.4s ease-in-out infinite;
22347
23433
  }
22348
23434
  :where([data-kit="pro"]) .tf-stage.st-danger::after {
22349
23435
  background: var(--danger);
@@ -22940,6 +24026,17 @@
22940
24026
  animation: none !important;
22941
24027
  }
22942
24028
  }
24029
+ /* the same for an app that turns motion off: data-motion="off" */
24030
+ :where([data-kit="pro"])[data-motion="off"] .tf-shape-pulse,
24031
+ :where([data-kit="pro"]) [data-motion="off"] .tf-shape-pulse,
24032
+ :where([data-kit="pro"])[data-motion="off"] .tf-voice-wave i,
24033
+ :where([data-kit="pro"]) [data-motion="off"] .tf-voice-wave i,
24034
+ :where([data-kit="pro"])[data-motion="off"] .tf-stage.st-running::after,
24035
+ :where([data-kit="pro"]) [data-motion="off"] .tf-stage.st-running::after,
24036
+ :where([data-kit="pro"])[data-motion="off"] .tf-log-line.fresh,
24037
+ :where([data-kit="pro"]) [data-motion="off"] .tf-log-line.fresh {
24038
+ animation: none !important;
24039
+ }
22943
24040
  :where([data-kit="pro"]) .tf-approval-mail {
22944
24041
  padding: 12px 16px;
22945
24042
  border-radius: var(--radius-md);
@@ -23295,7 +24392,7 @@
23295
24392
  @keyframes tf-pro-fresh {
23296
24393
  0% {
23297
24394
  background: var(--surface-sunken);
23298
- transform: translateY(-4px);
24395
+ transform: translateY(calc(-4px * var(--motion-travel)));
23299
24396
  opacity: 0;
23300
24397
  }
23301
24398
  15% {
@@ -25024,7 +26121,7 @@
25024
26121
  background: var(--surface);
25025
26122
  box-shadow: var(--shadow-float), 0 0 0 var(--line-width) var(--line);
25026
26123
  overflow: hidden;
25027
- animation: tf-pop var(--dur-base) var(--ease-spring) both;
26124
+ animation: tf-pro-pop var(--dur-base) var(--ease-spring) both;
25028
26125
  transform-origin: bottom right;
25029
26126
  }
25030
26127
  :where([data-kit="pro"]) .tf-launch-head {
@@ -25199,6 +26296,17 @@
25199
26296
  animation: none;
25200
26297
  }
25201
26298
  }
26299
+ /* the same for an app that turns motion off: data-motion="off" */
26300
+ :where([data-kit="pro"])[data-motion="off"] .tf-live-dot,
26301
+ :where([data-kit="pro"]) [data-motion="off"] .tf-live-dot,
26302
+ :where([data-kit="pro"])[data-motion="off"] .tf-map-bubble.pulse::after,
26303
+ :where([data-kit="pro"]) [data-motion="off"] .tf-map-bubble.pulse::after,
26304
+ :where([data-kit="pro"])[data-motion="off"] .tf-map-pin.pulse::after,
26305
+ :where([data-kit="pro"]) [data-motion="off"] .tf-map-pin.pulse::after,
26306
+ :where([data-kit="pro"])[data-motion="off"] .tf-livefeed-row.fresh,
26307
+ :where([data-kit="pro"]) [data-motion="off"] .tf-livefeed-row.fresh {
26308
+ animation: none;
26309
+ }
25202
26310
  :where([data-kit="pro"]) .tf-map-world {
25203
26311
  position: absolute;
25204
26312
  inset: 0;
@@ -25316,7 +26424,7 @@
25316
26424
  padding: 0 20px 20px;
25317
26425
  font: 500 14px/20px var(--font-sans);
25318
26426
  color: var(--ink-muted);
25319
- animation: tf-fade var(--dur-base) var(--ease-out) both;
26427
+ animation: tf-pro-fade var(--dur-base) var(--ease-out) both;
25320
26428
  }
25321
26429
  :where([data-kit="pro"]) .tf-accordion.flush {
25322
26430
  gap: 0;
@@ -25449,6 +26557,8 @@
25449
26557
  }
25450
26558
  :where([data-kit="pro"]) .tf-togglegroup {
25451
26559
  display: inline-flex;
26560
+ flex-wrap: wrap;
26561
+ width: fit-content;
25452
26562
  align-items: center;
25453
26563
  gap: 4px;
25454
26564
  padding: 4px;
@@ -25571,7 +26681,7 @@
25571
26681
  box-shadow:
25572
26682
  var(--shadow-float), 0 0 0 var(--line-width) var(--line),
25573
26683
  0 0 0 1px var(--line);
25574
- animation: tf-fade var(--dur-base) var(--ease-out) both;
26684
+ animation: tf-pro-fade var(--dur-base) var(--ease-out) both;
25575
26685
  }
25576
26686
  :where([data-kit="pro"]) .tf-hovercard.tf-hc-top {
25577
26687
  top: auto;
@@ -25896,7 +27006,7 @@
25896
27006
  box-shadow:
25897
27007
  var(--shadow-float), 0 0 0 var(--line-width) var(--line),
25898
27008
  0 0 0 1px var(--line);
25899
- animation: tf-drop var(--dur-base) var(--ease-out) both;
27009
+ animation: tf-pro-drop var(--dur-base) var(--ease-out) both;
25900
27010
  }
25901
27011
  :where([data-kit="pro"]) .tf-navmenu-panel.with-feature {
25902
27012
  grid-template-columns: 200px minmax(0, 1fr);
@@ -26111,19 +27221,19 @@
26111
27221
  @keyframes tf-pro-sheet-left {
26112
27222
  from {
26113
27223
  opacity: 0;
26114
- transform: translateX(-24px);
27224
+ transform: translateX(calc(-24px * var(--motion-travel)));
26115
27225
  }
26116
27226
  }
26117
27227
  @keyframes tf-pro-sheet-top {
26118
27228
  from {
26119
27229
  opacity: 0;
26120
- transform: translateY(-24px);
27230
+ transform: translateY(calc(-24px * var(--motion-travel)));
26121
27231
  }
26122
27232
  }
26123
27233
  @keyframes tf-pro-sheet-bottom {
26124
27234
  from {
26125
27235
  opacity: 0;
26126
- transform: translateY(24px);
27236
+ transform: translateY(calc(24px * var(--motion-travel)));
26127
27237
  }
26128
27238
  }
26129
27239
 
@@ -26853,6 +27963,615 @@
26853
27963
  box-sizing: border-box;
26854
27964
  }
26855
27965
 
27966
+ /* 08-glass.css */
27967
+ /* Generated by scripts/pro-css.ts from packages/halo/css. Do not edit; the Pro look lives in 90-pro-look.css. */
27968
+ /* Glass: translucent surfaces for UI that floats over content (maps, 3D scenes, video, photos).
27969
+ *
27970
+ * A glass surface shows a blurred, colour-lifted view of what is behind it, with a light edge on
27971
+ * top. What sits on it reads the glass tokens too (inputs, chips, tab tracks, hover highlights,
27972
+ * nested cards), so the surface stays one piece of glass instead of opaque blocks on glass.
27973
+ *
27974
+ * - `.tf-glass` (the `surface="glass"` prop) makes one surface glass.
27975
+ * - `[data-surface="glass"]` (`<UIProvider surface="glass">`) makes every top-level surface and
27976
+ * every floating layer inside it glass. Surfaces nested in a surface stay clear instead of
27977
+ * stacking glass on glass; `.tf-solid` (`surface="solid"`) opts one surface out.
27978
+ *
27979
+ * Floating layers (menus, popovers, dialogs, drawers) use the stronger `--glass-strong` fill: they
27980
+ * carry more text. The fills are opaque enough for 4.5:1 body text over any backdrop; reduced
27981
+ * transparency, high contrast and forced colours fall back to solid surfaces.
27982
+ */
27983
+
27984
+ /* the surface itself */
27985
+ :where([data-kit="pro"]) .tf-glass:not(.tf-solid),
27986
+ :where([data-kit="pro"])[data-surface="glass"]
27987
+ :is(
27988
+ .tf-panel,
27989
+ .tf-card,
27990
+ .tf-stat,
27991
+ .tf-dock,
27992
+ .tf-sidebar,
27993
+ .tf-map-legend,
27994
+ .tf-map-ctl,
27995
+ .tf-map-pop
27996
+ ):not(
27997
+ :is(
27998
+ .tf-panel,
27999
+ .tf-card,
28000
+ .tf-stat,
28001
+ .tf-dock,
28002
+ .tf-sidebar,
28003
+ .tf-popover,
28004
+ .tf-menu,
28005
+ .tf-hovercard,
28006
+ .tf-selectmenu-list,
28007
+ .tf-navmenu-panel,
28008
+ .tf-palette,
28009
+ .tf-modal,
28010
+ .tf-drawer,
28011
+ .tf-glass
28012
+ )
28013
+ *
28014
+ ):not(.tf-solid),
28015
+ :where([data-kit="pro"]) [data-surface="glass"]
28016
+ :is(
28017
+ .tf-panel,
28018
+ .tf-card,
28019
+ .tf-stat,
28020
+ .tf-dock,
28021
+ .tf-sidebar,
28022
+ .tf-map-legend,
28023
+ .tf-map-ctl,
28024
+ .tf-map-pop
28025
+ ):not(
28026
+ :is(
28027
+ .tf-panel,
28028
+ .tf-card,
28029
+ .tf-stat,
28030
+ .tf-dock,
28031
+ .tf-sidebar,
28032
+ .tf-popover,
28033
+ .tf-menu,
28034
+ .tf-hovercard,
28035
+ .tf-selectmenu-list,
28036
+ .tf-navmenu-panel,
28037
+ .tf-palette,
28038
+ .tf-modal,
28039
+ .tf-drawer,
28040
+ .tf-glass
28041
+ )
28042
+ *
28043
+ ):not(.tf-solid),
28044
+ :where([data-kit="pro"])[data-surface="glass"]
28045
+ :is(
28046
+ .tf-popover,
28047
+ .tf-menu:not(.tf-menu-static),
28048
+ .tf-hovercard,
28049
+ .tf-selectmenu-list,
28050
+ .tf-navmenu-panel,
28051
+ .tf-palette,
28052
+ .tf-modal,
28053
+ .tf-drawer
28054
+ ):not(.tf-solid),
28055
+ :where([data-kit="pro"]) [data-surface="glass"]
28056
+ :is(
28057
+ .tf-popover,
28058
+ .tf-menu:not(.tf-menu-static),
28059
+ .tf-hovercard,
28060
+ .tf-selectmenu-list,
28061
+ .tf-navmenu-panel,
28062
+ .tf-palette,
28063
+ .tf-modal,
28064
+ .tf-drawer
28065
+ ):not(.tf-solid) {
28066
+ --glass-fill: var(--glass);
28067
+ background:
28068
+ linear-gradient(to bottom, var(--glass-sheen), transparent 56px) border-box,
28069
+ linear-gradient(var(--glass-tinted), var(--glass-tinted)) border-box,
28070
+ var(--glass-fill);
28071
+ --glass-tinted: color-mix(in srgb, var(--tint, transparent) var(--glass-tint), transparent);
28072
+ -webkit-backdrop-filter: var(--glass-filter);
28073
+ backdrop-filter: var(--glass-filter);
28074
+ border-color: var(--glass-border);
28075
+ box-shadow:
28076
+ inset 0 1px 0 0 var(--glass-highlight),
28077
+ inset 0 0 0 1px var(--glass-border),
28078
+ var(--shadow-glass);
28079
+ color: var(--foreground);
28080
+ /* what sits on the glass */
28081
+ --surface: var(--glass-control);
28082
+ --secondary: var(--glass-control);
28083
+ --bg-100: var(--glass-control);
28084
+ --surface-sunken: var(--glass-well);
28085
+ --muted: var(--glass-well);
28086
+ --canvas: var(--glass-well);
28087
+ --bg-200: var(--glass-well);
28088
+ --accent: var(--glass-hover);
28089
+ --bg-300: var(--glass-hover);
28090
+ /* the faintest text steps up one shade: glass gives up some contrast to what is behind */
28091
+ --ink-subtle: var(--muted-foreground);
28092
+ --fg-300: var(--muted-foreground);
28093
+ }
28094
+
28095
+ /* floating layers carry more text: a stronger fill */
28096
+ :where([data-kit="pro"]) :is(
28097
+ .tf-popover,
28098
+ .tf-menu,
28099
+ .tf-hovercard,
28100
+ .tf-selectmenu-list,
28101
+ .tf-navmenu-panel,
28102
+ .tf-palette,
28103
+ .tf-modal,
28104
+ .tf-drawer
28105
+ ).tf-glass,
28106
+ :where([data-kit="pro"])[data-surface="glass"]
28107
+ :is(
28108
+ .tf-popover,
28109
+ .tf-menu:not(.tf-menu-static),
28110
+ .tf-hovercard,
28111
+ .tf-selectmenu-list,
28112
+ .tf-navmenu-panel,
28113
+ .tf-palette,
28114
+ .tf-modal,
28115
+ .tf-drawer
28116
+ ):not(.tf-solid),
28117
+ :where([data-kit="pro"]) [data-surface="glass"]
28118
+ :is(
28119
+ .tf-popover,
28120
+ .tf-menu:not(.tf-menu-static),
28121
+ .tf-hovercard,
28122
+ .tf-selectmenu-list,
28123
+ .tf-navmenu-panel,
28124
+ .tf-palette,
28125
+ .tf-modal,
28126
+ .tf-drawer
28127
+ ):not(.tf-solid) {
28128
+ --glass-fill: var(--glass-strong);
28129
+ }
28130
+
28131
+ /* Controls floating on their own (not on a surface) become small glass pills: a search field or
28132
+ zoom buttons over a map */
28133
+ :where([data-kit="pro"])[data-surface="glass"]
28134
+ :is(
28135
+ .tf-search,
28136
+ .tf-seg,
28137
+ .tf-btngroup,
28138
+ .tf-iconbtn-soft,
28139
+ .tf-iconbtn-outline,
28140
+ .tf-btn-secondary,
28141
+ .tf-chip:not([aria-pressed="true"])
28142
+ ):not(
28143
+ :is(
28144
+ .tf-panel,
28145
+ .tf-card,
28146
+ .tf-dock,
28147
+ .tf-popover,
28148
+ .tf-menu,
28149
+ .tf-hovercard,
28150
+ .tf-selectmenu-list,
28151
+ .tf-navmenu-panel,
28152
+ .tf-palette,
28153
+ .tf-modal,
28154
+ .tf-drawer,
28155
+ .tf-glass,
28156
+ .tf-btngroup,
28157
+ .tf-map-ctl,
28158
+ .tf-topbar
28159
+ )
28160
+ *
28161
+ ):not(.tf-solid),
28162
+ :where([data-kit="pro"]) [data-surface="glass"]
28163
+ :is(
28164
+ .tf-search,
28165
+ .tf-seg,
28166
+ .tf-btngroup,
28167
+ .tf-iconbtn-soft,
28168
+ .tf-iconbtn-outline,
28169
+ .tf-btn-secondary,
28170
+ .tf-chip:not([aria-pressed="true"])
28171
+ ):not(
28172
+ :is(
28173
+ .tf-panel,
28174
+ .tf-card,
28175
+ .tf-dock,
28176
+ .tf-popover,
28177
+ .tf-menu,
28178
+ .tf-hovercard,
28179
+ .tf-selectmenu-list,
28180
+ .tf-navmenu-panel,
28181
+ .tf-palette,
28182
+ .tf-modal,
28183
+ .tf-drawer,
28184
+ .tf-glass,
28185
+ .tf-btngroup,
28186
+ .tf-map-ctl,
28187
+ .tf-topbar
28188
+ )
28189
+ *
28190
+ ):not(.tf-solid) {
28191
+ background:
28192
+ linear-gradient(to bottom, var(--glass-sheen), transparent) border-box,
28193
+ var(--glass);
28194
+ -webkit-backdrop-filter: var(--glass-filter);
28195
+ backdrop-filter: var(--glass-filter);
28196
+ box-shadow:
28197
+ inset 0 1px 0 0 var(--glass-highlight),
28198
+ inset 0 0 0 1px var(--glass-border),
28199
+ var(--shadow-glass);
28200
+ color: var(--foreground);
28201
+ --surface: var(--glass-control);
28202
+ --secondary: var(--glass-control);
28203
+ --surface-sunken: var(--glass-well);
28204
+ --bg-200: var(--glass-well);
28205
+ --accent: var(--glass-hover);
28206
+ --bg-300: var(--glass-hover);
28207
+ }
28208
+ :where([data-kit="pro"])[data-surface="glass"]
28209
+ :is(.tf-iconbtn-soft, .tf-iconbtn-outline, .tf-btn-secondary, .tf-chip):not(
28210
+ :is(.tf-panel, .tf-card, .tf-dock, .tf-popover, .tf-menu, .tf-modal, .tf-drawer, .tf-glass) *
28211
+ ):not(.tf-solid):not([aria-pressed="true"]):hover, :where([data-kit="pro"]) [data-surface="glass"]
28212
+ :is(.tf-iconbtn-soft, .tf-iconbtn-outline, .tf-btn-secondary, .tf-chip):not(
28213
+ :is(.tf-panel, .tf-card, .tf-dock, .tf-popover, .tf-menu, .tf-modal, .tf-drawer, .tf-glass) *
28214
+ ):not(.tf-solid):not([aria-pressed="true"]):hover {
28215
+ background:
28216
+ linear-gradient(var(--glass-hover), var(--glass-hover)) border-box,
28217
+ var(--glass);
28218
+ }
28219
+
28220
+ /* AppShell on glass: the same layout as the solid shell, the frame turned to glass. Top bar and
28221
+ rail sit on it without a fill of their own, the sheet clears so the backdrop shows through,
28222
+ and everything drawn on the frame (nav, user, rail) reads the glass colours */
28223
+ :where([data-kit="pro"])[data-surface="glass"] .tf-shell, :where([data-kit="pro"]) [data-surface="glass"] .tf-shell {
28224
+ background:
28225
+ linear-gradient(to bottom, var(--glass-sheen), transparent 56px) border-box,
28226
+ var(--glass);
28227
+ -webkit-backdrop-filter: var(--glass-filter);
28228
+ backdrop-filter: var(--glass-filter);
28229
+ box-shadow:
28230
+ inset 0 1px 0 0 var(--glass-highlight),
28231
+ inset 0 0 0 1px var(--glass-border),
28232
+ var(--shadow-glass);
28233
+ --frame: var(--glass);
28234
+ --frame-hover: var(--glass-hover);
28235
+ --frame-active: var(--glass-hover);
28236
+ --frame-strong: var(--glass-control);
28237
+ --on-frame: var(--foreground);
28238
+ --on-frame-muted: var(--muted-foreground);
28239
+ }
28240
+ :where([data-kit="pro"])[data-surface="glass"] .tf-shell .tf-sheet, :where([data-kit="pro"]) [data-surface="glass"] .tf-shell .tf-sheet {
28241
+ background: transparent;
28242
+ }
28243
+ :where([data-kit="pro"])[data-surface="glass"] .tf-shell .tf-topbar, :where([data-kit="pro"]) [data-surface="glass"] .tf-shell .tf-topbar {
28244
+ background: transparent;
28245
+ }
28246
+
28247
+ /* switch knobs stay solid on glass */
28248
+ :where([data-kit="pro"]) .tf-glass .tf-switch::after,
28249
+ :where([data-kit="pro"])[data-surface="glass"] .tf-switch::after,
28250
+ :where([data-kit="pro"]) [data-surface="glass"] .tf-switch::after {
28251
+ background: var(--card);
28252
+ }
28253
+
28254
+ /* Reduced transparency, more contrast, forced colours and browsers without backdrop blur switch
28255
+ the glass tokens themselves (see tokens.css). Forced colours drop shadows, so glass keeps an
28256
+ edge there. */
28257
+ @media (forced-colors: active) {
28258
+ :where([data-kit="pro"]) .tf-glass,
28259
+ :where([data-kit="pro"])[data-surface="glass"]
28260
+ :is(
28261
+ .tf-panel,
28262
+ .tf-card,
28263
+ .tf-stat,
28264
+ .tf-dock,
28265
+ .tf-sidebar,
28266
+ .tf-map-legend,
28267
+ .tf-map-ctl,
28268
+ .tf-map-pop
28269
+ ),
28270
+ :where([data-kit="pro"]) [data-surface="glass"]
28271
+ :is(
28272
+ .tf-panel,
28273
+ .tf-card,
28274
+ .tf-stat,
28275
+ .tf-dock,
28276
+ .tf-sidebar,
28277
+ .tf-map-legend,
28278
+ .tf-map-ctl,
28279
+ .tf-map-pop
28280
+ ) {
28281
+ outline: 1px solid CanvasText;
28282
+ outline-offset: -1px;
28283
+ }
28284
+ }
28285
+
28286
+ /* FloatingLayout: UI along the edges of a full-bleed background */
28287
+ :where([data-kit="pro"]) .tf-floating {
28288
+ position: relative;
28289
+ overflow: hidden;
28290
+ isolation: isolate;
28291
+ border-radius: var(--radius-lg);
28292
+ background: var(--surface-sunken);
28293
+ container: tf-floating / inline-size;
28294
+ }
28295
+ :where([data-kit="pro"]) .tf-floating-bg {
28296
+ position: absolute;
28297
+ inset: 0;
28298
+ }
28299
+ :where([data-kit="pro"]) .tf-floating-bg > * {
28300
+ width: 100%;
28301
+ height: 100%;
28302
+ }
28303
+ :where([data-kit="pro"]) .tf-floating-ui {
28304
+ position: absolute;
28305
+ inset: 0;
28306
+ z-index: 1;
28307
+ display: grid;
28308
+ grid-template-columns: minmax(0, 320px) minmax(0, 1fr) minmax(0, 340px);
28309
+ grid-template-rows: auto minmax(0, 1fr) auto;
28310
+ grid-template-areas:
28311
+ "top top top"
28312
+ "start . end"
28313
+ "bottom bottom bottom";
28314
+ gap: var(--space-4);
28315
+ padding: var(--space-4);
28316
+ overflow-y: auto;
28317
+ /* the background stays usable between the slots */
28318
+ pointer-events: none;
28319
+ }
28320
+ :where([data-kit="pro"]) .tf-floating-ui > * {
28321
+ pointer-events: auto;
28322
+ min-width: 0;
28323
+ }
28324
+ :where([data-kit="pro"]) .tf-floating-top {
28325
+ grid-area: top;
28326
+ display: flex;
28327
+ flex-wrap: wrap;
28328
+ align-items: center;
28329
+ gap: var(--space-2);
28330
+ }
28331
+ :where([data-kit="pro"]) .tf-floating-start {
28332
+ grid-area: start;
28333
+ align-self: start;
28334
+ }
28335
+ :where([data-kit="pro"]) .tf-floating-end {
28336
+ grid-area: end;
28337
+ align-self: start;
28338
+ }
28339
+ :where([data-kit="pro"]) .tf-floating-bottom {
28340
+ grid-area: bottom;
28341
+ justify-self: center;
28342
+ }
28343
+ :where([data-kit="pro"]) .tf-floating-ui > :is(.tf-floating-top, .tf-floating-bottom) {
28344
+ pointer-events: none;
28345
+ }
28346
+ :where([data-kit="pro"]) .tf-floating-ui > :is(.tf-floating-top, .tf-floating-bottom) > * {
28347
+ pointer-events: auto;
28348
+ }
28349
+ @container tf-floating (max-width: 720px) {
28350
+ /* on a phone the layout grows with its slots and the background fills behind them */
28351
+ :where([data-kit="pro"]) .tf-floating-ui {
28352
+ position: relative;
28353
+ min-height: inherit;
28354
+ overflow: visible;
28355
+ grid-template-columns: minmax(0, 1fr);
28356
+ grid-template-rows: auto auto minmax(120px, 1fr) auto auto;
28357
+ grid-template-areas:
28358
+ "top"
28359
+ "start"
28360
+ "."
28361
+ "end"
28362
+ "bottom";
28363
+ gap: var(--space-3);
28364
+ padding: var(--space-3);
28365
+ }
28366
+ }
28367
+
28368
+ /* 09-motion.css */
28369
+ /* Generated by scripts/pro-css.ts from packages/halo/css. Do not edit; the Pro look lives in 90-pro-look.css. */
28370
+ /* Motion: leaving layers, reveal on scroll, page transitions, the expressive level.
28371
+ *
28372
+ * Levels come from `data-motion` (tokens.css): "standard", "expressive" (longer, staggered page
28373
+ * entrances, more travel) and "off". The reader's reduced-motion setting always means off. Only
28374
+ * transform, opacity and (expressive Halo) a short blur move; everything else stays put.
28375
+ */
28376
+
28377
+ /* ── Leaving: layers animate out for --dur-exit, then unmount (usePresence) ── */
28378
+ @keyframes tf-pro-out {
28379
+ to {
28380
+ opacity: 0;
28381
+ translate: 0 calc(6px * var(--motion-travel));
28382
+ scale: 0.98;
28383
+ }
28384
+ }
28385
+ @keyframes tf-pro-out-fade {
28386
+ to {
28387
+ opacity: 0;
28388
+ }
28389
+ }
28390
+ @keyframes tf-pro-out-right {
28391
+ to {
28392
+ opacity: 0;
28393
+ translate: calc(40px * var(--motion-travel)) 0;
28394
+ }
28395
+ }
28396
+ @keyframes tf-pro-out-left {
28397
+ to {
28398
+ opacity: 0;
28399
+ translate: calc(-40px * var(--motion-travel)) 0;
28400
+ }
28401
+ }
28402
+ @keyframes tf-pro-out-up {
28403
+ to {
28404
+ opacity: 0;
28405
+ translate: 0 calc(-40px * var(--motion-travel));
28406
+ }
28407
+ }
28408
+ @keyframes tf-pro-out-down {
28409
+ to {
28410
+ opacity: 0;
28411
+ translate: 0 calc(16px * var(--motion-travel));
28412
+ }
28413
+ }
28414
+ :where([data-kit="pro"])[data-closing], :where([data-kit="pro"]) [data-closing] {
28415
+ pointer-events: none;
28416
+ }
28417
+ :where([data-kit="pro"]) .tf-popover[data-closing],
28418
+ :where([data-kit="pro"]) .tf-hovercard[data-closing],
28419
+ :where([data-kit="pro"]) .tf-modal-wrap[data-closing] .tf-modal,
28420
+ :where([data-kit="pro"]) .tf-overlay[data-closing] :is(.tf-modal, .tf-confirm),
28421
+ :where([data-kit="pro"]) .tf-palette-wrap[data-closing] .tf-palette {
28422
+ animation: tf-pro-out var(--dur-exit) var(--ease-in-out) forwards;
28423
+ }
28424
+ :where([data-kit="pro"]) .tf-tooltip[data-closing],
28425
+ :where([data-kit="pro"]) .tf-modal-wrap[data-closing] .tf-backdrop,
28426
+ :where([data-kit="pro"]) .tf-overlay[data-closing] .tf-backdrop,
28427
+ :where([data-kit="pro"]) .tf-palette-wrap[data-closing],
28428
+ :where([data-kit="pro"]) .tf-drawer-wrap[data-closing] {
28429
+ animation: tf-pro-out-fade var(--dur-exit) var(--ease-in-out) forwards;
28430
+ }
28431
+ :where([data-kit="pro"]) .tf-drawer-wrap[data-closing] .tf-drawer {
28432
+ animation: tf-pro-out-right var(--dur-exit) var(--ease-in-out) forwards;
28433
+ }
28434
+ :where([data-kit="pro"]) .tf-drawer-wrap[data-closing] .tf-drawer.side-left {
28435
+ animation-name: tf-pro-out-left;
28436
+ }
28437
+ :where([data-kit="pro"]) .tf-drawer-wrap[data-closing] .tf-drawer.side-top {
28438
+ animation-name: tf-pro-out-up;
28439
+ }
28440
+ :where([data-kit="pro"]) .tf-drawer-wrap[data-closing] .tf-drawer.side-bottom,
28441
+ :where([data-kit="pro"]) .tf-toast[data-closing] {
28442
+ animation: tf-pro-out-down var(--dur-exit) var(--ease-in-out) forwards;
28443
+ }
28444
+
28445
+ /* ── Reveal: a Stagger below the fold waits until it scrolls into view ── */
28446
+ :where([data-kit="pro"]) .tf-stagger[data-reveal="waiting"] > *,
28447
+ :where([data-kit="pro"]) .tf-stagger[data-reveal="waiting"] > * * {
28448
+ animation-play-state: paused;
28449
+ }
28450
+
28451
+ /* ── Page transitions (startViewTransition, Next.js and React view transitions) ── */
28452
+ @keyframes tf-pro-vt-out {
28453
+ to {
28454
+ opacity: 0;
28455
+ translate: 0 calc(-6px * var(--motion-travel));
28456
+ }
28457
+ }
28458
+ @keyframes tf-pro-vt-in {
28459
+ from {
28460
+ opacity: 0;
28461
+ translate: 0 calc(10px * var(--motion-travel));
28462
+ }
28463
+ }
28464
+ :where([data-kit="pro"])::view-transition-old(root) {
28465
+ animation: tf-pro-vt-out var(--dur-base) var(--ease-in-out) both;
28466
+ }
28467
+ :where([data-kit="pro"])::view-transition-new(root) {
28468
+ animation: tf-pro-vt-in var(--dur-enter) var(--ease-out) both;
28469
+ }
28470
+
28471
+ /* ── Expressive: things come into focus as they rise (Halo; Pro keeps a blur of 0) ── */
28472
+ @keyframes tf-pro-focus-in {
28473
+ from {
28474
+ filter: blur(var(--motion-blur));
28475
+ }
28476
+ to {
28477
+ filter: none;
28478
+ }
28479
+ }
28480
+ :where([data-kit="pro"])[data-motion="expressive"] :is(.tf-stagger > *, .tf-in), :where([data-kit="pro"]) [data-motion="expressive"] :is(.tf-stagger > *, .tf-in) {
28481
+ animation-name: tf-pro-rise, tf-pro-focus-in;
28482
+ }
28483
+ :where([data-kit="pro"])[data-motion="expressive"] .tf-topbar, :where([data-kit="pro"]) [data-motion="expressive"] .tf-topbar {
28484
+ animation-name: tf-pro-drop, tf-pro-focus-in;
28485
+ }
28486
+
28487
+ /* 10-ambient.css */
28488
+ /* Generated by scripts/pro-css.ts from packages/halo/css. Do not edit; the Pro look lives in 90-pro-look.css. */
28489
+ /* Ambient: a calm, living background for glass UI. Soft colour fields from the kit (pastels in
28490
+ * Halo, a faint aurora in Pro) drift slowly; a photo or video can take their place under a scrim.
28491
+ * The drift only moves (transform), stops with motion off and pauses off screen.
28492
+ */
28493
+ :where([data-kit="pro"]) :where(:has(> .tf-ambient:not(.fixed))) {
28494
+ position: relative;
28495
+ isolation: isolate;
28496
+ }
28497
+ :where([data-kit="pro"]) .tf-ambient {
28498
+ position: absolute;
28499
+ inset: 0;
28500
+ z-index: -1;
28501
+ overflow: hidden;
28502
+ background: var(--ambient-base);
28503
+ pointer-events: none;
28504
+ }
28505
+ :where([data-kit="pro"]) .tf-ambient.fixed {
28506
+ position: fixed;
28507
+ }
28508
+ :where([data-kit="pro"]) .tf-ambient-field {
28509
+ position: absolute;
28510
+ width: 75%;
28511
+ aspect-ratio: 1;
28512
+ border-radius: var(--radius-1);
28513
+ background: radial-gradient(closest-side, var(--field), transparent);
28514
+ animation: tf-pro-ambient-drift 34s var(--ease-in-out) infinite alternate;
28515
+ }
28516
+ :where([data-kit="pro"]) .tf-ambient-field:nth-child(1) {
28517
+ top: -30%;
28518
+ left: -15%;
28519
+ }
28520
+ :where([data-kit="pro"]) .tf-ambient-field:nth-child(2) {
28521
+ top: -10%;
28522
+ right: -25%;
28523
+ animation-duration: 41s;
28524
+ animation-direction: alternate-reverse;
28525
+ }
28526
+ :where([data-kit="pro"]) .tf-ambient-field:nth-child(3) {
28527
+ bottom: -35%;
28528
+ left: 10%;
28529
+ animation-duration: 47s;
28530
+ }
28531
+ :where([data-kit="pro"]) .tf-ambient-field:nth-child(4) {
28532
+ bottom: -25%;
28533
+ right: -10%;
28534
+ animation-duration: 38s;
28535
+ animation-direction: alternate-reverse;
28536
+ }
28537
+ :where([data-kit="pro"]) .tf-ambient-field:nth-child(n + 5) {
28538
+ top: 20%;
28539
+ left: 30%;
28540
+ width: 55%;
28541
+ animation-duration: 52s;
28542
+ }
28543
+ @keyframes tf-pro-ambient-drift {
28544
+ to {
28545
+ translate: 12% 9%;
28546
+ scale: 1.15;
28547
+ }
28548
+ }
28549
+ :where([data-kit="pro"]) .tf-ambient.still .tf-ambient-field,
28550
+ :where([data-kit="pro"]) .tf-ambient[data-paused] .tf-ambient-field {
28551
+ animation-play-state: paused;
28552
+ }
28553
+ :where([data-kit="pro"]) .tf-ambient-media {
28554
+ position: absolute;
28555
+ inset: 0;
28556
+ width: 100%;
28557
+ height: 100%;
28558
+ object-fit: cover;
28559
+ }
28560
+ :where([data-kit="pro"]) .tf-ambient.media::after {
28561
+ content: "";
28562
+ position: absolute;
28563
+ inset: 0;
28564
+ background: var(--ambient-scrim);
28565
+ }
28566
+ @media (prefers-reduced-motion: reduce) {
28567
+ :where([data-kit="pro"]) .tf-ambient-field {
28568
+ animation: none;
28569
+ }
28570
+ }
28571
+ :where([data-kit="pro"])[data-motion="off"] .tf-ambient-field, :where([data-kit="pro"]) [data-motion="off"] .tf-ambient-field {
28572
+ animation: none;
28573
+ }
28574
+
26856
28575
  /* 90-pro-look.css */
26857
28576
  /* Pro look ("Clean Dark Pro", reference/pro): monochrome surfaces on a visible 1px hairline grid,
26858
28577
  square corners (2px on controls), Geist and Geist Mono, colour only for state, dense by default.