@xenide-io/the-old-ui-theme 0.9.17 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/dist/{Chip-BzuNgJIa.d.mts → Chip-DKT-82Lf.d.mts} +5 -3
  2. package/dist/{Chip-BzuNgJIa.d.ts → Chip-DKT-82Lf.d.ts} +5 -3
  3. package/dist/{chunk-6SVJAU5K.mjs → chunk-LHE4ROON.mjs} +977 -521
  4. package/dist/index.d.mts +2 -2
  5. package/dist/index.d.ts +2 -2
  6. package/dist/index.js +138 -99
  7. package/dist/index.mjs +1 -1
  8. package/dist/suite.d.mts +23 -1
  9. package/dist/suite.d.ts +23 -1
  10. package/dist/suite.js +4250 -4041
  11. package/dist/suite.mjs +1008 -795
  12. package/dist/tailwind-preset.js +10 -1
  13. package/dist/tailwind-preset.mjs +10 -1
  14. package/dist/ui.d.mts +33 -4
  15. package/dist/ui.d.ts +33 -4
  16. package/dist/ui.js +1024 -566
  17. package/dist/ui.mjs +13 -1
  18. package/docs/macos-identity-audit.md +279 -0
  19. package/package.json +1 -1
  20. package/src/app/globals.css +334 -44
  21. package/src/components/ui/Accordion.tsx +4 -7
  22. package/src/components/ui/Avatar.tsx +5 -5
  23. package/src/components/ui/Calendar.tsx +7 -7
  24. package/src/components/ui/CodeBlock.tsx +3 -10
  25. package/src/components/ui/CollapsibleSection.tsx +4 -4
  26. package/src/components/ui/CommandPalette.tsx +7 -10
  27. package/src/components/ui/EmptyState.tsx +2 -2
  28. package/src/components/ui/Input.tsx +1 -1
  29. package/src/components/ui/Marketing.tsx +128 -0
  30. package/src/components/ui/MarketingIllustrations.tsx +287 -0
  31. package/src/components/ui/Panel.tsx +1 -1
  32. package/src/components/ui/SegmentedControl.tsx +59 -13
  33. package/src/components/ui/ShowcaseWrapper.tsx +3 -3
  34. package/src/components/ui/Table.tsx +18 -6
  35. package/src/components/ui/Typography.tsx +4 -4
  36. package/src/components/ui/avatar-stat.test.tsx +14 -1
  37. package/src/components/ui/index.ts +13 -12
  38. package/src/components/ui/interaction-primitives.test.tsx +12 -6
  39. package/src/components/ui/marketing.test.tsx +39 -0
  40. package/src/components/ui/table.test.tsx +20 -0
  41. package/src/styles/suite-skin.css +405 -40
  42. package/src/styles/themes.css +45 -45
  43. package/src/styles/typography.css +25 -1
  44. package/src/suite/components/ai-panel.tsx +17 -17
  45. package/src/suite/components/app-switcher.tsx +9 -9
  46. package/src/suite/components/suite-app-layout.tsx +7 -4
  47. package/src/suite/components/suite-bottom-nav.tsx +1 -1
  48. package/src/suite/components/suite-clients-projects-directory.tsx +6 -6
  49. package/src/suite/components/suite-entity-icon.tsx +3 -3
  50. package/src/suite/components/suite-integration-picker.tsx +7 -7
  51. package/src/suite/components/suite-integration-rules.tsx +5 -5
  52. package/src/suite/components/suite-layout.test.tsx +32 -3
  53. package/src/suite/components/suite-layout.tsx +4 -4
  54. package/src/suite/components/suite-mobile-drawer.tsx +2 -2
  55. package/src/suite/components/suite-mobile-header.tsx +1 -1
  56. package/src/suite/components/suite-notification-bell.tsx +4 -4
  57. package/src/suite/components/suite-notification-settings.tsx +171 -0
  58. package/src/suite/components/suite-palette-library.test.tsx +46 -0
  59. package/src/suite/components/suite-palette-library.tsx +82 -15
  60. package/src/suite/components/suite-settings-layout.tsx +2 -2
  61. package/src/suite/components/suite-settings-mobile-nav.tsx +5 -9
  62. package/src/suite/components/suite-sidebar.test.tsx +39 -0
  63. package/src/suite/components/suite-sidebar.tsx +41 -19
  64. package/src/suite/components/suite-skeleton.tsx +6 -6
  65. package/src/suite/components/suite-user-menu.tsx +2 -2
  66. package/src/suite/components/today-calibrating.tsx +3 -3
  67. package/src/suite/components/today-ui.tsx +12 -12
  68. package/src/suite/components/workspace-switcher.tsx +3 -3
  69. package/src/suite/index.ts +6 -0
  70. package/tailwind-preset.ts +9 -0
@@ -44,7 +44,7 @@
44
44
  --ph-chrome-inset-solid-bottom: inset 0 -1px 0 hsl(0deg 0% 0% / 0.14);
45
45
  --ph-radius-app: 0.375rem;
46
46
  --ph-radius-control: var(--ph-radius-app);
47
- --ph-radius-surface: 0.5rem;
47
+ --ph-radius-surface: 0.625rem;
48
48
  --ph-radius-overlay: 0.75rem;
49
49
  --ph-border-control: color-mix(in oklab, var(--ph-border) 68%, var(--ph-border-strong));
50
50
  /** Tailwind `ph.brand` maps to `--ph-accent`; plain CSS controls used only this name, so it must exist. */
@@ -77,8 +77,10 @@
77
77
  --ph-danger-bg: color-mix(in oklab, var(--ph-danger) 12%, var(--ph-surface));
78
78
  --ph-danger-border: color-mix(in oklab, var(--ph-danger) 45%, var(--ph-border));
79
79
  --ph-danger-text: color-mix(in oklab, var(--ph-danger) 76%, var(--ph-text-primary));
80
- --ph-shadow-raised: 0 1px 2px hsl(0deg 0% 0% / 0.08), 0 3px 8px hsl(0deg 0% 0% / 0.06);
81
- --ph-shadow-floating: 0 18px 48px hsl(0deg 0% 0% / 0.22), 0 2px 8px hsl(0deg 0% 0% / 0.12);
80
+ --ph-shadow-raised: 0 1px 2px hsl(0deg 0% 0% / 0.08), 0 4px 12px hsl(0deg 0% 0% / 0.06);
81
+ --ph-shadow-floating: 0 18px 48px hsl(0deg 0% 0% / 0.2), 0 2px 8px hsl(0deg 0% 0% / 0.1);
82
+ --ph-shadow-control: 0 1px 2px hsl(0deg 0% 0% / 0.1), inset 0 1px 0 hsl(0deg 0% 100% / 0.38);
83
+ --ph-focus-halo: 0 0 0 3px color-mix(in oklab, var(--ph-focus-ring) 30%, transparent);
82
84
  --ph-motion-fast: 120ms;
83
85
  --ph-motion-standard: 180ms;
84
86
  }
@@ -104,21 +106,28 @@ html {
104
106
 
105
107
  body {
106
108
  @apply bg-ph-canvas text-ph-ink antialiased;
107
- font-size: 15px;
108
- line-height: 1.5;
109
+ font-family: var(--ph-font-sans-stack);
110
+ font-size: var(--ph-type-body);
111
+ line-height: var(--ph-leading-body);
109
112
  }
110
113
 
111
114
  @layer components {
115
+ .ph-page-title {
116
+ font-size: var(--ph-type-page);
117
+ line-height: var(--ph-leading-title);
118
+ letter-spacing: -0.025em;
119
+ text-wrap: balance;
120
+ }
112
121
  /**
113
122
  * PostHog LemonButton — from frontend/src/lib/lemon-ui/LemonButton/LemonButton.scss
114
123
  */
115
124
  .ph-btn {
116
- --ph-btn-control-size: 2.3125rem;
125
+ --ph-btn-control-size: 2.5rem;
117
126
  @apply inline-flex shrink-0 cursor-pointer items-center justify-center gap-2 whitespace-nowrap font-medium;
118
127
  border-radius: var(--ph-radius-control);
119
- min-height: 2.3125rem;
128
+ min-height: var(--ph-btn-control-size);
120
129
  padding: 0.25rem 0.875rem;
121
- font-size: 0.875rem;
130
+ font-size: var(--ph-type-ui);
122
131
  line-height: 1.5rem;
123
132
  transition:
124
133
  transform var(--ph-motion-fast) ease,
@@ -131,27 +140,27 @@ body {
131
140
  }
132
141
 
133
142
  .ph-btn:focus-visible {
134
- outline: 3px solid color-mix(in oklab, var(--ph-focus-ring) 38%, transparent);
135
- outline-offset: 2px;
143
+ outline: none;
144
+ box-shadow: var(--ph-focus-halo);
136
145
  }
137
146
 
138
147
  .ph-btn-sm {
139
- --ph-btn-control-size: 2.0625rem;
140
- min-height: 2.0625rem;
148
+ --ph-btn-control-size: 2.125rem;
149
+ min-height: var(--ph-btn-control-size);
141
150
  padding: 0.25rem 0.625rem;
142
- font-size: 0.8125rem;
151
+ font-size: var(--ph-type-meta);
143
152
  }
144
153
 
145
154
  .ph-btn-xs {
146
- --ph-btn-control-size: 1.625rem;
147
- min-height: 1.625rem;
155
+ --ph-btn-control-size: 1.75rem;
156
+ min-height: var(--ph-btn-control-size);
148
157
  padding: 0.125rem 0.5rem;
149
- font-size: 0.6875rem;
158
+ font-size: var(--ph-type-overline);
150
159
  }
151
160
 
152
161
  .ph-btn-lg {
153
- --ph-btn-control-size: 3.0625rem;
154
- min-height: 3.0625rem;
162
+ --ph-btn-control-size: 3rem;
163
+ min-height: var(--ph-btn-control-size);
155
164
  padding: 0.375rem 1.25rem;
156
165
  font-size: 1rem;
157
166
  }
@@ -305,7 +314,7 @@ body {
305
314
  justify-content: center;
306
315
  gap: inherit;
307
316
  width: 100%;
308
- min-height: 2.3125rem;
317
+ min-height: var(--ph-btn-control-size);
309
318
  padding:
310
319
  calc(0.25rem - var(--ph-btn-chrome-depth) * 0.5) 0.875rem
311
320
  calc(0.25rem + var(--ph-btn-chrome-depth) * 0.5);
@@ -336,25 +345,25 @@ body {
336
345
 
337
346
  .ph-btn-sm.ph-btn-raised .ph-btn-chrome,
338
347
  .ph-btn-sm:is(.ph-btn-primary, .ph-btn-secondary, .ph-btn-signal, .ph-btn-accent, .ph-btn-neutral, .ph-btn-info, .ph-btn-success, .ph-btn-warning, .ph-btn-danger):not(:has(.ph-btn-chrome)) {
339
- min-height: 2.0625rem;
348
+ min-height: var(--ph-btn-control-size);
340
349
  padding:
341
350
  calc(0.25rem - var(--ph-btn-chrome-depth) * 0.5) 0.625rem
342
351
  calc(0.25rem + var(--ph-btn-chrome-depth) * 0.5);
343
- font-size: 0.8125rem;
352
+ font-size: var(--ph-type-meta);
344
353
  }
345
354
 
346
355
  .ph-btn-xs.ph-btn-raised .ph-btn-chrome,
347
356
  .ph-btn-xs:is(.ph-btn-primary, .ph-btn-secondary, .ph-btn-signal, .ph-btn-accent, .ph-btn-neutral, .ph-btn-info, .ph-btn-success, .ph-btn-warning, .ph-btn-danger):not(:has(.ph-btn-chrome)) {
348
- min-height: 1.625rem;
357
+ min-height: var(--ph-btn-control-size);
349
358
  padding:
350
359
  calc(0.125rem - var(--ph-btn-chrome-depth) * 0.5) 0.5rem
351
360
  calc(0.125rem + var(--ph-btn-chrome-depth) * 0.5);
352
- font-size: 0.6875rem;
361
+ font-size: var(--ph-type-overline);
353
362
  }
354
363
 
355
364
  .ph-btn-lg.ph-btn-raised .ph-btn-chrome,
356
365
  .ph-btn-lg:is(.ph-btn-primary, .ph-btn-secondary, .ph-btn-signal, .ph-btn-accent, .ph-btn-neutral, .ph-btn-info, .ph-btn-success, .ph-btn-warning, .ph-btn-danger):not(:has(.ph-btn-chrome)) {
357
- min-height: 3.0625rem;
366
+ min-height: var(--ph-btn-control-size);
358
367
  padding:
359
368
  calc(0.375rem - var(--ph-btn-chrome-depth) * 0.5) 1.25rem
360
369
  calc(0.375rem + var(--ph-btn-chrome-depth) * 0.5);
@@ -539,6 +548,7 @@ body {
539
548
  background: var(--ph-btn-face);
540
549
  border: var(--ph-btn-border-width) solid var(--ph-btn-border);
541
550
  border-radius: var(--ph-radius-control);
551
+ box-shadow: var(--ph-chrome-inset-solid-top);
542
552
  transform: translateY(var(--ph-btn-face-offset));
543
553
  transition:
544
554
  border-color var(--ph-motion-fast) ease,
@@ -585,9 +595,7 @@ body {
585
595
  @apply border bg-ph-muted p-6;
586
596
  border-radius: var(--ph-radius-surface);
587
597
  border-color: var(--ph-border-control);
588
- box-shadow:
589
- var(--ph-chrome-inset-face-top),
590
- var(--ph-shadow-elevation-3000);
598
+ box-shadow: var(--ph-chrome-inset-face-top);
591
599
  }
592
600
 
593
601
  .ph-card {
@@ -692,7 +700,8 @@ body {
692
700
  background: var(--ph-surface-raised);
693
701
  border-radius: var(--ph-radius-control);
694
702
  border: 1px solid var(--ph-border-control);
695
- min-height: 2.3125rem;
703
+ min-height: 2.5rem;
704
+ font-size: var(--ph-type-ui);
696
705
  line-height: 1.5rem;
697
706
  font-family: inherit;
698
707
  box-shadow:
@@ -705,7 +714,7 @@ body {
705
714
  .ph-textarea:focus-visible {
706
715
  outline: none;
707
716
  box-shadow:
708
- 0 0 0 3px color-mix(in oklab, var(--ph-focus-ring) 24%, transparent),
717
+ var(--ph-focus-halo),
709
718
  var(--ph-chrome-inset-face-top),
710
719
  var(--ph-chrome-inset-face-bottom);
711
720
  border-color: color-mix(in oklab, var(--ph-focus-ring) 58%, var(--ph-border));
@@ -715,6 +724,22 @@ body {
715
724
  @apply ph-input-base;
716
725
  }
717
726
 
727
+ .ph-field-icon-button {
728
+ @apply absolute inset-y-0 right-0 flex w-10 items-center justify-center text-ph-mutedtext disabled:opacity-40;
729
+ border-radius: 0 var(--ph-radius-control) var(--ph-radius-control) 0;
730
+ transition: color var(--ph-motion-fast) ease;
731
+ }
732
+
733
+ .ph-field-icon-button:hover:not(:disabled) {
734
+ color: var(--ph-text-primary);
735
+ }
736
+
737
+ .ph-field-icon-button:focus-visible {
738
+ z-index: 1;
739
+ outline: none;
740
+ box-shadow: var(--ph-focus-halo);
741
+ }
742
+
718
743
  .ph-input-error:focus-visible,
719
744
  .ph-select.ph-input-error:focus-visible,
720
745
  .ph-textarea.ph-input-error:focus-visible {
@@ -737,7 +762,7 @@ body {
737
762
  .ph-input-sm {
738
763
  min-height: 1.875rem;
739
764
  padding-block: 0.125rem;
740
- font-size: 0.8125rem;
765
+ font-size: var(--ph-type-meta);
741
766
  }
742
767
 
743
768
  .ph-input-lg {
@@ -792,7 +817,7 @@ body {
792
817
  .ph-search-group__submit .ph-btn-chrome {
793
818
  box-sizing: border-box;
794
819
  height: 100%;
795
- min-height: 2.3125rem;
820
+ min-height: 2.5rem;
796
821
  padding-left: 0.75rem;
797
822
  padding-right: 0.75rem;
798
823
  }
@@ -824,6 +849,13 @@ body {
824
849
  min-height: 6rem;
825
850
  }
826
851
 
852
+ @media (pointer: coarse) {
853
+ .ph-input,
854
+ .ph-select {
855
+ min-height: 2.75rem;
856
+ }
857
+ }
858
+
827
859
  .ph-checkbox,
828
860
  .ph-radio {
829
861
  @apply shrink-0 cursor-pointer appearance-none transition;
@@ -865,7 +897,7 @@ body {
865
897
  .ph-toggle:focus-visible {
866
898
  outline: none;
867
899
  box-shadow:
868
- 0 0 0 3px color-mix(in oklab, var(--ph-accent) 18%, transparent),
900
+ var(--ph-focus-halo),
869
901
  var(--ph-chrome-inset-face-top),
870
902
  var(--ph-chrome-inset-face-bottom);
871
903
  }
@@ -953,18 +985,24 @@ body {
953
985
  /* LemonTable.scss — sticky-header border Simulation + row rhythm */
954
986
  .ph-table-wrap {
955
987
  @apply overflow-x-auto bg-ph-surface;
956
- border-radius: var(--ph-radius-app);
988
+ border-radius: var(--ph-radius-surface);
957
989
  border: 1px solid var(--ph-border);
958
- box-shadow: var(--ph-shadow-elevation-3000);
990
+ box-shadow: none;
991
+ }
992
+
993
+ .ph-table-wrap:focus-visible {
994
+ outline: none;
995
+ border-color: color-mix(in oklab, var(--ph-focus-ring) 58%, var(--ph-border));
996
+ box-shadow: var(--ph-focus-halo);
959
997
  }
960
998
 
961
999
  .ph-table {
962
1000
  @apply w-full border-collapse text-left;
963
- font-size: 13px;
1001
+ font-size: var(--ph-type-small);
964
1002
  }
965
1003
 
966
1004
  .ph-table thead {
967
- background: var(--ph-surface);
1005
+ background: var(--ph-surface-inset);
968
1006
  color: var(--ph-text-tertiary);
969
1007
  }
970
1008
 
@@ -972,8 +1010,8 @@ body {
972
1010
  @apply whitespace-nowrap px-2 py-2;
973
1011
  padding-left: 1rem;
974
1012
  padding-right: 1rem;
975
- font-size: 0.75rem;
976
- font-weight: 700;
1013
+ font-size: var(--ph-type-meta);
1014
+ font-weight: 600;
977
1015
  text-transform: uppercase;
978
1016
  letter-spacing: 0.03125rem;
979
1017
  box-shadow: inset 0 -1px var(--ph-border);
@@ -985,6 +1023,7 @@ body {
985
1023
  padding-right: 1rem;
986
1024
  vertical-align: middle;
987
1025
  color: var(--ph-text-secondary);
1026
+ padding-block: 0.625rem;
988
1027
  }
989
1028
 
990
1029
  .ph-table tbody tr + tr td {
@@ -1020,7 +1059,151 @@ body {
1020
1059
  }
1021
1060
 
1022
1061
  .ph-table-compact .ph-table td {
1023
- @apply py-1 text-[12px];
1062
+ @apply py-1.5;
1063
+ font-size: var(--ph-type-meta);
1064
+ }
1065
+
1066
+ .ph-table td.ph-table-empty {
1067
+ @apply py-8 text-center text-sm text-ph-mutedtext;
1068
+ }
1069
+
1070
+ .ph-table--ribbon tbody td.ph-table-empty::before {
1071
+ content: none;
1072
+ }
1073
+
1074
+ .ph-avatar {
1075
+ box-shadow: var(--ph-chrome-inset-solid-top);
1076
+ }
1077
+
1078
+ .ph-empty-state {
1079
+ @apply flex flex-col items-center justify-center border border-dashed px-8 py-16 text-center;
1080
+ border-color: var(--ph-border-subtle);
1081
+ border-radius: var(--ph-radius-surface);
1082
+ background: var(--ph-surface-inset);
1083
+ }
1084
+
1085
+ .ph-empty-state__icon {
1086
+ @apply mb-4 flex h-14 w-14 items-center justify-center rounded-full text-ph-mutedtext;
1087
+ background: var(--ph-surface-raised);
1088
+ box-shadow: var(--ph-chrome-inset-solid-top);
1089
+ }
1090
+
1091
+ .ph-accordion {
1092
+ @apply overflow-hidden border bg-ph-surface;
1093
+ border-color: var(--ph-border-subtle);
1094
+ border-radius: var(--ph-radius-surface);
1095
+ }
1096
+
1097
+ .ph-accordion__item + .ph-accordion__item {
1098
+ border-top: 1px solid var(--ph-border-subtle);
1099
+ }
1100
+
1101
+ .ph-accordion__trigger,
1102
+ .ph-collapsible-trigger {
1103
+ @apply flex w-full items-center justify-between px-5 py-4 text-left;
1104
+ color: var(--ph-text-primary);
1105
+ transition: background-color var(--ph-motion-fast) ease;
1106
+ }
1107
+
1108
+ .ph-accordion__trigger:hover,
1109
+ .ph-collapsible-trigger:hover {
1110
+ background: var(--ph-surface-hover);
1111
+ }
1112
+
1113
+ .ph-accordion__trigger:focus-visible {
1114
+ outline: 3px solid color-mix(in oklab, var(--ph-focus-ring) 30%, transparent);
1115
+ outline-offset: -3px;
1116
+ }
1117
+
1118
+ .ph-collapsible-trigger {
1119
+ border: 1px solid var(--ph-border-subtle);
1120
+ border-radius: var(--ph-radius-surface);
1121
+ background: var(--ph-surface-inset);
1122
+ }
1123
+
1124
+ .ph-collapsible-trigger:focus-visible,
1125
+ .ph-showcase-toggle:focus-visible {
1126
+ outline: none;
1127
+ box-shadow: var(--ph-focus-halo);
1128
+ }
1129
+
1130
+ .ph-calendar {
1131
+ border: 1px solid var(--ph-border-control);
1132
+ border-radius: var(--ph-radius-overlay);
1133
+ background: color-mix(in oklab, var(--ph-surface-overlay) 94%, transparent);
1134
+ -webkit-backdrop-filter: blur(24px) saturate(1.2);
1135
+ backdrop-filter: blur(24px) saturate(1.2);
1136
+ box-shadow:
1137
+ var(--ph-chrome-inset-face-top),
1138
+ var(--ph-shadow-floating);
1139
+ }
1140
+
1141
+ .ph-calendar__nav {
1142
+ @apply flex h-9 w-9 items-center justify-center text-ph-subtle;
1143
+ border-radius: var(--ph-radius-control);
1144
+ transition:
1145
+ color var(--ph-motion-fast) ease,
1146
+ background-color var(--ph-motion-fast) ease;
1147
+ }
1148
+
1149
+ .ph-calendar__nav:hover {
1150
+ color: var(--ph-text-primary);
1151
+ background: var(--ph-surface-hover);
1152
+ }
1153
+
1154
+ .ph-calendar__nav:focus-visible,
1155
+ .ph-calendar__day:focus-visible {
1156
+ z-index: 1;
1157
+ outline: none;
1158
+ box-shadow: var(--ph-focus-halo);
1159
+ }
1160
+
1161
+ .ph-calendar__day {
1162
+ @apply flex h-full w-full items-center justify-center text-sm text-ph-ink;
1163
+ border-radius: var(--ph-radius-control);
1164
+ transition:
1165
+ color var(--ph-motion-fast) ease,
1166
+ background-color var(--ph-motion-fast) ease,
1167
+ box-shadow var(--ph-motion-fast) ease;
1168
+ }
1169
+
1170
+ .ph-calendar__day:hover {
1171
+ background: var(--ph-surface-hover);
1172
+ }
1173
+
1174
+ .ph-calendar__day--selected {
1175
+ color: var(--ph-on-accent);
1176
+ background: var(--ph-brand);
1177
+ box-shadow: var(--ph-shadow-control);
1178
+ font-weight: 600;
1179
+ }
1180
+
1181
+ .ph-calendar__day--today:not(.ph-calendar__day--selected) {
1182
+ color: var(--ph-selected-text);
1183
+ background: var(--ph-selected-bg);
1184
+ box-shadow: inset 0 0 0 1px var(--ph-selected-border);
1185
+ font-weight: 600;
1186
+ }
1187
+
1188
+ .ph-code-block {
1189
+ @apply overflow-hidden border border-ph-border bg-[#1a1a2e];
1190
+ border-radius: var(--ph-radius-surface);
1191
+ }
1192
+
1193
+ .ph-code-block__copy {
1194
+ @apply text-xs text-white/60;
1195
+ border-radius: var(--ph-radius-control);
1196
+ transition: color var(--ph-motion-fast) ease;
1197
+ }
1198
+
1199
+ .ph-code-block__copy:hover {
1200
+ @apply text-white;
1201
+ }
1202
+
1203
+ .ph-code-block__copy:focus-visible {
1204
+ outline: none;
1205
+ color: white;
1206
+ box-shadow: 0 0 0 3px color-mix(in oklab, var(--ph-focus-ring) 55%, transparent);
1024
1207
  }
1025
1208
 
1026
1209
  /* Breadcrumbs */
@@ -1393,7 +1576,9 @@ body {
1393
1576
  overflow:hidden + border-radius, especially at the bottom-right action. */
1394
1577
  overflow: visible;
1395
1578
  overscroll-behavior: contain;
1396
- background: var(--ph-surface-overlay);
1579
+ background: color-mix(in oklab, var(--ph-surface-overlay) 94%, transparent);
1580
+ -webkit-backdrop-filter: blur(24px) saturate(1.2);
1581
+ backdrop-filter: blur(24px) saturate(1.2);
1397
1582
  border-radius: var(--ph-radius-overlay);
1398
1583
  border: 1px solid var(--ph-border-control);
1399
1584
  box-shadow: var(--ph-shadow-floating);
@@ -1432,6 +1617,55 @@ body {
1432
1617
  }
1433
1618
  }
1434
1619
 
1620
+ /* Command palette shares the floating overlay material with menus and modals. */
1621
+ .ph-command-palette__overlay {
1622
+ @apply fixed inset-0 z-50 bg-black/45 backdrop-blur-sm;
1623
+ animation: ph-modal-overlay-in var(--ph-motion-standard) ease-out;
1624
+ }
1625
+
1626
+ .ph-command-palette {
1627
+ @apply fixed left-1/2 top-[20vh] z-50 w-[calc(100%-1rem)] max-w-xl -translate-x-1/2 overflow-hidden;
1628
+ max-height: min(32rem, calc(100dvh - 2rem));
1629
+ border: 1px solid var(--ph-border-control);
1630
+ border-radius: var(--ph-radius-overlay);
1631
+ background: color-mix(in oklab, var(--ph-surface-overlay) 94%, transparent);
1632
+ -webkit-backdrop-filter: blur(24px) saturate(1.2);
1633
+ backdrop-filter: blur(24px) saturate(1.2);
1634
+ box-shadow:
1635
+ var(--ph-chrome-inset-face-top),
1636
+ var(--ph-shadow-floating);
1637
+ animation: ph-command-palette-in var(--ph-motion-standard) cubic-bezier(0.22, 1, 0.36, 1);
1638
+ }
1639
+
1640
+ .ph-command-palette__search {
1641
+ @apply flex items-center gap-3 px-4 py-3;
1642
+ border-bottom: 1px solid var(--ph-border-subtle);
1643
+ background: var(--ph-surface-inset);
1644
+ }
1645
+
1646
+ .ph-command-palette__option {
1647
+ @apply mx-1 flex min-h-9 cursor-pointer items-center gap-3 px-3 py-2 text-left text-sm;
1648
+ width: calc(100% - 0.5rem);
1649
+ border-radius: var(--ph-radius-control);
1650
+ transition:
1651
+ color var(--ph-motion-fast) ease,
1652
+ background-color var(--ph-motion-fast) ease,
1653
+ box-shadow var(--ph-motion-fast) ease;
1654
+ }
1655
+
1656
+ .ph-command-palette__option--selected {
1657
+ color: var(--ph-selected-text);
1658
+ background: var(--ph-selected-bg);
1659
+ box-shadow: inset 0 0 0 1px var(--ph-selected-border);
1660
+ }
1661
+
1662
+ @keyframes ph-command-palette-in {
1663
+ from {
1664
+ opacity: 0;
1665
+ transform: translate(-50%, 0.5rem) scale(0.98);
1666
+ }
1667
+ }
1668
+
1435
1669
  @media (max-width: 40rem) {
1436
1670
  .ph-modal-panel {
1437
1671
  width: calc(100% - 1rem);
@@ -1452,8 +1686,8 @@ body {
1452
1686
  }
1453
1687
 
1454
1688
  .ph-dropdown-trigger:focus-visible {
1455
- outline: 3px solid color-mix(in oklab, var(--ph-focus-ring) 38%, transparent);
1456
- outline-offset: 2px;
1689
+ outline: none;
1690
+ box-shadow: var(--ph-focus-halo);
1457
1691
  }
1458
1692
 
1459
1693
  .ph-dropdown-trigger:disabled {
@@ -1465,11 +1699,14 @@ body {
1465
1699
  }
1466
1700
 
1467
1701
  .ph-dropdown-panel {
1468
- @apply z-50 min-w-[12rem] overflow-y-auto bg-ph-surface p-1;
1702
+ @apply z-50 min-w-[12rem] overflow-y-auto p-1;
1469
1703
  max-width: min(22rem, calc(100vw - 1rem));
1470
1704
  max-height: var(--radix-dropdown-menu-content-available-height);
1471
1705
  border-radius: var(--ph-radius-overlay);
1472
1706
  border: 1px solid var(--ph-border-control);
1707
+ background: color-mix(in oklab, var(--ph-surface-overlay) 94%, transparent);
1708
+ -webkit-backdrop-filter: blur(24px) saturate(1.2);
1709
+ backdrop-filter: blur(24px) saturate(1.2);
1473
1710
  box-shadow:
1474
1711
  var(--ph-chrome-inset-face-top),
1475
1712
  var(--ph-shadow-floating);
@@ -1513,6 +1750,12 @@ body {
1513
1750
  background: var(--ph-surface-hover);
1514
1751
  }
1515
1752
 
1753
+ .ph-dropdown-item:focus-visible {
1754
+ color: var(--ph-selected-text);
1755
+ background: var(--ph-selected-bg);
1756
+ box-shadow: inset 0 0 0 1px var(--ph-selected-border);
1757
+ }
1758
+
1516
1759
  .ph-dropdown-item[data-disabled] {
1517
1760
  @apply pointer-events-none opacity-50;
1518
1761
  }
@@ -1857,6 +2100,52 @@ body {
1857
2100
  }
1858
2101
  }
1859
2102
 
2103
+ /* Segmented control — inset track with one raised selected face. */
2104
+ .ph-segmented-control {
2105
+ display: inline-flex;
2106
+ gap: 2px;
2107
+ padding: 3px;
2108
+ border: 1px solid var(--ph-border-subtle);
2109
+ border-radius: calc(var(--ph-radius-control) + 0.1875rem);
2110
+ background: var(--ph-surface-inset);
2111
+ box-shadow: inset 0 1px 2px hsl(0deg 0% 0% / 0.08);
2112
+ }
2113
+
2114
+ .ph-segmented-control__item {
2115
+ @apply relative flex min-h-11 items-center gap-1.5 px-3.5 py-1.5 text-sm font-medium sm:min-h-9;
2116
+ border: 1px solid transparent;
2117
+ border-radius: var(--ph-radius-control);
2118
+ color: var(--ph-text-secondary);
2119
+ transition:
2120
+ color var(--ph-motion-fast) ease,
2121
+ background-color var(--ph-motion-fast) ease,
2122
+ border-color var(--ph-motion-fast) ease,
2123
+ box-shadow var(--ph-motion-fast) ease,
2124
+ transform 80ms ease-out;
2125
+ }
2126
+
2127
+ .ph-segmented-control__item:hover:not([aria-checked="true"]) {
2128
+ color: var(--ph-text-primary);
2129
+ background: var(--ph-surface-hover);
2130
+ }
2131
+
2132
+ .ph-segmented-control__item[aria-checked="true"] {
2133
+ color: var(--ph-text-primary);
2134
+ border-color: var(--ph-border-subtle);
2135
+ background: var(--ph-surface-raised);
2136
+ box-shadow: var(--ph-shadow-control);
2137
+ }
2138
+
2139
+ .ph-segmented-control__item:active {
2140
+ transform: scale(0.98);
2141
+ }
2142
+
2143
+ .ph-segmented-control__item:focus-visible {
2144
+ z-index: 1;
2145
+ outline: none;
2146
+ box-shadow: var(--ph-focus-halo);
2147
+ }
2148
+
1860
2149
  /* Tabs */
1861
2150
  .ph-tabs-row {
1862
2151
  @apply flex flex-wrap gap-1 rounded-lg bg-ph-muted p-1 border border-ph-border;
@@ -1881,7 +2170,8 @@ body {
1881
2170
  }
1882
2171
 
1883
2172
  .ph-progress-bar {
1884
- @apply h-full rounded-full transition-all duration-300;
2173
+ @apply h-full rounded-full duration-300;
2174
+ transition-property: width;
1885
2175
  }
1886
2176
 
1887
2177
  /* Accessible, collision-aware tooltip overlay. */
@@ -43,22 +43,19 @@ export function Accordion({
43
43
 
44
44
  return (
45
45
  <div
46
- className={cn(
47
- "divide-y divide-ph-border rounded-xl border border-ph-border bg-ph-surface",
48
- className,
49
- )}
46
+ className={cn("ph-accordion", className)}
50
47
  >
51
48
  {items.map((item) => {
52
49
  const isOpen = openItems.has(item.id);
53
50
  const contentId = `accordion-${idPrefix}-${item.id}-content`;
54
51
  return (
55
- <div key={item.id} className="first:rounded-t-xl last:rounded-b-xl">
52
+ <div key={item.id} className="ph-accordion__item">
56
53
  <button
57
54
  type="button"
58
55
  onClick={() => toggleItem(item.id)}
59
56
  aria-expanded={isOpen}
60
57
  aria-controls={contentId}
61
- className="flex w-full items-center justify-between px-5 py-4 text-left transition hover:bg-ph-muted"
58
+ className="ph-accordion__trigger"
62
59
  >
63
60
  <span className="font-semibold text-ph-ink">{item.title}</span>
64
61
  <IconChevronDown
@@ -75,7 +72,7 @@ export function Accordion({
75
72
  if (node) node.toggleAttribute("inert", !isOpen);
76
73
  }}
77
74
  className={cn(
78
- "grid transition-all duration-200",
75
+ "grid transition-[grid-template-rows] duration-200",
79
76
  isOpen ? "grid-rows-[1fr]" : "grid-rows-[0fr]",
80
77
  )}
81
78
  >
@@ -1,4 +1,4 @@
1
- import type { ComponentPropsWithoutRef, ReactNode } from "react";
1
+ import { Children, type ComponentPropsWithoutRef, type ReactNode } from "react";
2
2
  import { cn } from "@/lib/cn";
3
3
 
4
4
  export type AvatarSize = "xs" | "sm" | "md" | "lg" | "xl";
@@ -38,7 +38,7 @@ export function Avatar({
38
38
  label,
39
39
  icon,
40
40
  size = "md",
41
- color = "bg-ph-brand text-white",
41
+ color = "bg-ph-brand text-[var(--ph-on-accent)]",
42
42
  status,
43
43
  badge,
44
44
  className,
@@ -48,7 +48,7 @@ export function Avatar({
48
48
  <div className={cn("relative inline-flex shrink-0", className)} {...props}>
49
49
  <div
50
50
  className={cn(
51
- "flex items-center justify-center rounded-full border border-ph-border font-bold shadow-ph",
51
+ "ph-avatar flex items-center justify-center rounded-full border border-ph-border font-bold",
52
52
  sizeMap[size],
53
53
  color,
54
54
  )}
@@ -66,7 +66,7 @@ export function Avatar({
66
66
  />
67
67
  )}
68
68
  {badge && (
69
- <span className="absolute -bottom-1 -right-1 flex min-w-[22px] items-center justify-center rounded-full bg-ph-brand px-1.5 py-px text-[10px] font-bold text-white">
69
+ <span className="absolute -bottom-1 -right-1 flex min-w-[22px] items-center justify-center rounded-full bg-ph-brand px-1.5 py-px text-[10px] font-bold text-[var(--ph-on-accent)]">
70
70
  {badge}
71
71
  </span>
72
72
  )}
@@ -80,7 +80,7 @@ export interface AvatarGroupProps extends ComponentPropsWithoutRef<"div"> {
80
80
  }
81
81
 
82
82
  export function AvatarGroup({ children, max, className, ...props }: AvatarGroupProps) {
83
- const items = Array.isArray(children) ? children : [children];
83
+ const items = Children.toArray(children);
84
84
  const visible = max ? items.slice(0, max) : items;
85
85
  const remaining = max ? items.length - max : 0;
86
86