@open-mercato/ui 0.5.1-develop.2856.35de414092 → 0.5.1-develop.2874.77704bccbd

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 (246) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +204 -121
  3. package/dist/backend/AppShell.js +25 -28
  4. package/dist/backend/AppShell.js.map +2 -2
  5. package/dist/backend/ContextHelp.js +1 -1
  6. package/dist/backend/ContextHelp.js.map +1 -1
  7. package/dist/backend/CrudForm.js +12 -15
  8. package/dist/backend/CrudForm.js.map +2 -2
  9. package/dist/backend/DataTable.js +9 -10
  10. package/dist/backend/DataTable.js.map +2 -2
  11. package/dist/backend/FilterBar.js +6 -8
  12. package/dist/backend/FilterBar.js.map +2 -2
  13. package/dist/backend/FilterOverlay.js +10 -10
  14. package/dist/backend/FilterOverlay.js.map +2 -2
  15. package/dist/backend/FlashMessages.js +1 -1
  16. package/dist/backend/FlashMessages.js.map +2 -2
  17. package/dist/backend/JsonBuilder.js +6 -6
  18. package/dist/backend/JsonBuilder.js.map +1 -1
  19. package/dist/backend/NextStepCallout.js +1 -1
  20. package/dist/backend/NextStepCallout.js.map +1 -1
  21. package/dist/backend/PerspectiveSidebar.js +2 -2
  22. package/dist/backend/PerspectiveSidebar.js.map +2 -2
  23. package/dist/backend/ProfileDropdown.js +1 -1
  24. package/dist/backend/ProfileDropdown.js.map +1 -1
  25. package/dist/backend/RowActions.js +1 -1
  26. package/dist/backend/RowActions.js.map +1 -1
  27. package/dist/backend/UserMenu.js +2 -2
  28. package/dist/backend/UserMenu.js.map +1 -1
  29. package/dist/backend/WebhookSetupGuide.js +11 -11
  30. package/dist/backend/WebhookSetupGuide.js.map +2 -2
  31. package/dist/backend/charts/KpiCard.js +3 -3
  32. package/dist/backend/charts/KpiCard.js.map +1 -1
  33. package/dist/backend/columns/ColumnChooserPanel.js +1 -1
  34. package/dist/backend/columns/ColumnChooserPanel.js.map +2 -2
  35. package/dist/backend/custom-fields/FieldDefinitionsEditor.js +3 -3
  36. package/dist/backend/custom-fields/FieldDefinitionsEditor.js.map +2 -2
  37. package/dist/backend/dashboard/DashboardScreen.js +1 -1
  38. package/dist/backend/dashboard/DashboardScreen.js.map +1 -1
  39. package/dist/backend/date-range/DateRangeSelect.js +1 -1
  40. package/dist/backend/date-range/DateRangeSelect.js.map +1 -1
  41. package/dist/backend/date-range/InlineDateRangeSelect.js +1 -1
  42. package/dist/backend/date-range/InlineDateRangeSelect.js.map +1 -1
  43. package/dist/backend/detail/AccessDeniedMessage.js +1 -1
  44. package/dist/backend/detail/AccessDeniedMessage.js.map +1 -1
  45. package/dist/backend/detail/ActivitiesSection.js +5 -5
  46. package/dist/backend/detail/ActivitiesSection.js.map +1 -1
  47. package/dist/backend/detail/AddressEditor.js +3 -3
  48. package/dist/backend/detail/AddressEditor.js.map +2 -2
  49. package/dist/backend/detail/AddressTiles.js +3 -3
  50. package/dist/backend/detail/AddressTiles.js.map +2 -2
  51. package/dist/backend/detail/AttachmentMetadataDialog.js +1 -1
  52. package/dist/backend/detail/AttachmentMetadataDialog.js.map +1 -1
  53. package/dist/backend/detail/CustomDataSection.js +1 -1
  54. package/dist/backend/detail/CustomDataSection.js.map +1 -1
  55. package/dist/backend/detail/InlineEditors.js +5 -5
  56. package/dist/backend/detail/InlineEditors.js.map +1 -1
  57. package/dist/backend/detail/NotesSection.js +6 -6
  58. package/dist/backend/detail/NotesSection.js.map +1 -1
  59. package/dist/backend/detail/TagsSection.js +1 -1
  60. package/dist/backend/detail/TagsSection.js.map +1 -1
  61. package/dist/backend/devtools/UmesDevToolsPanel.js +6 -6
  62. package/dist/backend/devtools/UmesDevToolsPanel.js.map +2 -2
  63. package/dist/backend/devtools/components/ConflictWarnings.js +3 -3
  64. package/dist/backend/devtools/components/ConflictWarnings.js.map +2 -2
  65. package/dist/backend/devtools/components/EnricherTiming.js +2 -2
  66. package/dist/backend/devtools/components/EnricherTiming.js.map +2 -2
  67. package/dist/backend/devtools/components/EventFlow.js +5 -5
  68. package/dist/backend/devtools/components/EventFlow.js.map +2 -2
  69. package/dist/backend/devtools/components/ExtensionPointList.js +3 -3
  70. package/dist/backend/devtools/components/ExtensionPointList.js.map +2 -2
  71. package/dist/backend/devtools/components/InterceptorActivity.js +6 -6
  72. package/dist/backend/devtools/components/InterceptorActivity.js.map +2 -2
  73. package/dist/backend/forms/ActionsDropdown.js +1 -1
  74. package/dist/backend/forms/ActionsDropdown.js.map +1 -1
  75. package/dist/backend/forms/FormActionButtons.js +2 -3
  76. package/dist/backend/forms/FormActionButtons.js.map +2 -2
  77. package/dist/backend/indexes/PartialIndexBanner.js +8 -8
  78. package/dist/backend/indexes/PartialIndexBanner.js.map +2 -2
  79. package/dist/backend/inputs/ComboboxInput.js +1 -1
  80. package/dist/backend/inputs/ComboboxInput.js.map +2 -2
  81. package/dist/backend/inputs/DatePicker.js +3 -3
  82. package/dist/backend/inputs/DatePicker.js.map +1 -1
  83. package/dist/backend/inputs/DateTimePicker.js +3 -3
  84. package/dist/backend/inputs/DateTimePicker.js.map +1 -1
  85. package/dist/backend/inputs/EventSelect.js +1 -1
  86. package/dist/backend/inputs/EventSelect.js.map +2 -2
  87. package/dist/backend/inputs/LookupSelect.js +1 -1
  88. package/dist/backend/inputs/LookupSelect.js.map +1 -1
  89. package/dist/backend/inputs/SwitchableMarkdownInput.js +1 -1
  90. package/dist/backend/inputs/SwitchableMarkdownInput.js.map +1 -1
  91. package/dist/backend/inputs/TagsInput.js +2 -2
  92. package/dist/backend/inputs/TagsInput.js.map +2 -2
  93. package/dist/backend/inputs/TimeInput.js +1 -1
  94. package/dist/backend/inputs/TimeInput.js.map +1 -1
  95. package/dist/backend/inputs/TimePicker.js +3 -3
  96. package/dist/backend/inputs/TimePicker.js.map +1 -1
  97. package/dist/backend/messages/MessageObjectDetail.js +1 -1
  98. package/dist/backend/messages/MessageObjectDetail.js.map +1 -1
  99. package/dist/backend/messages/MessageObjectPreview.js +1 -1
  100. package/dist/backend/messages/MessageObjectPreview.js.map +1 -1
  101. package/dist/backend/messages/message-compose-form-groups.js +3 -3
  102. package/dist/backend/messages/message-compose-form-groups.js.map +1 -1
  103. package/dist/backend/notifications/NotificationCountBadge.js +1 -1
  104. package/dist/backend/notifications/NotificationCountBadge.js.map +2 -2
  105. package/dist/backend/notifications/NotificationPanel.js +3 -3
  106. package/dist/backend/notifications/NotificationPanel.js.map +1 -1
  107. package/dist/backend/progress/ProgressTopBar.js +4 -4
  108. package/dist/backend/progress/ProgressTopBar.js.map +2 -2
  109. package/dist/backend/schedule/ScheduleAgenda.js +1 -1
  110. package/dist/backend/schedule/ScheduleAgenda.js.map +2 -2
  111. package/dist/backend/schedule/ScheduleCalendar.js +1 -1
  112. package/dist/backend/schedule/ScheduleCalendar.js.map +1 -1
  113. package/dist/backend/schedule/ScheduleGrid.js +1 -1
  114. package/dist/backend/schedule/ScheduleGrid.js.map +2 -2
  115. package/dist/backend/version-history/VersionHistoryPanel.js +4 -4
  116. package/dist/backend/version-history/VersionHistoryPanel.js.map +2 -2
  117. package/dist/frontend/AuthFooter.js +1 -1
  118. package/dist/frontend/AuthFooter.js.map +1 -1
  119. package/dist/frontend/LanguageSwitcher.js +1 -1
  120. package/dist/frontend/LanguageSwitcher.js.map +1 -1
  121. package/dist/frontend/Layout.js +2 -2
  122. package/dist/frontend/Layout.js.map +1 -1
  123. package/dist/index.js +5 -0
  124. package/dist/index.js.map +2 -2
  125. package/dist/portal/PortalShell.js +15 -15
  126. package/dist/portal/PortalShell.js.map +2 -2
  127. package/dist/portal/components/PortalCard.js +2 -2
  128. package/dist/portal/components/PortalCard.js.map +2 -2
  129. package/dist/portal/components/PortalNotificationPanel.js +18 -18
  130. package/dist/portal/components/PortalNotificationPanel.js.map +2 -2
  131. package/dist/portal/components/PortalPageHeader.js +1 -1
  132. package/dist/portal/components/PortalPageHeader.js.map +2 -2
  133. package/dist/primitives/avatar.js +11 -1
  134. package/dist/primitives/avatar.js.map +2 -2
  135. package/dist/primitives/badge.js +1 -1
  136. package/dist/primitives/badge.js.map +1 -1
  137. package/dist/primitives/button.js +9 -5
  138. package/dist/primitives/button.js.map +2 -2
  139. package/dist/primitives/calendar.js +1 -1
  140. package/dist/primitives/calendar.js.map +1 -1
  141. package/dist/primitives/checkbox-field.js +63 -0
  142. package/dist/primitives/checkbox-field.js.map +7 -0
  143. package/dist/primitives/checkbox.js +31 -17
  144. package/dist/primitives/checkbox.js.map +2 -2
  145. package/dist/primitives/dialog.js +4 -4
  146. package/dist/primitives/dialog.js.map +1 -1
  147. package/dist/primitives/fancy-button.js +72 -0
  148. package/dist/primitives/fancy-button.js.map +7 -0
  149. package/dist/primitives/icon-button.js +20 -4
  150. package/dist/primitives/icon-button.js.map +2 -2
  151. package/dist/primitives/kbd.js +27 -0
  152. package/dist/primitives/kbd.js.map +7 -0
  153. package/dist/primitives/link-button.js +56 -0
  154. package/dist/primitives/link-button.js.map +7 -0
  155. package/dist/primitives/popover.js +1 -1
  156. package/dist/primitives/popover.js.map +1 -1
  157. package/dist/primitives/social-button.js +61 -0
  158. package/dist/primitives/social-button.js.map +7 -0
  159. package/dist/primitives/tabs.js +1 -1
  160. package/dist/primitives/tabs.js.map +1 -1
  161. package/dist/primitives/tag.js +45 -0
  162. package/dist/primitives/tag.js.map +7 -0
  163. package/dist/primitives/tooltip.js +1 -1
  164. package/dist/primitives/tooltip.js.map +1 -1
  165. package/package.json +3 -3
  166. package/src/backend/AppShell.tsx +25 -28
  167. package/src/backend/ContextHelp.tsx +1 -1
  168. package/src/backend/CrudForm.tsx +12 -15
  169. package/src/backend/DataTable.tsx +9 -10
  170. package/src/backend/FilterBar.tsx +6 -5
  171. package/src/backend/FilterOverlay.tsx +10 -10
  172. package/src/backend/FlashMessages.tsx +1 -1
  173. package/src/backend/JsonBuilder.tsx +6 -6
  174. package/src/backend/NextStepCallout.tsx +1 -1
  175. package/src/backend/PerspectiveSidebar.tsx +2 -2
  176. package/src/backend/ProfileDropdown.tsx +1 -1
  177. package/src/backend/RowActions.tsx +1 -1
  178. package/src/backend/UserMenu.tsx +2 -2
  179. package/src/backend/WebhookSetupGuide.tsx +11 -11
  180. package/src/backend/charts/KpiCard.tsx +3 -3
  181. package/src/backend/columns/ColumnChooserPanel.tsx +1 -1
  182. package/src/backend/custom-fields/FieldDefinitionsEditor.tsx +3 -3
  183. package/src/backend/dashboard/DashboardScreen.tsx +1 -1
  184. package/src/backend/date-range/DateRangeSelect.tsx +1 -1
  185. package/src/backend/date-range/InlineDateRangeSelect.tsx +1 -1
  186. package/src/backend/detail/AccessDeniedMessage.tsx +1 -1
  187. package/src/backend/detail/ActivitiesSection.tsx +5 -5
  188. package/src/backend/detail/AddressEditor.tsx +3 -3
  189. package/src/backend/detail/AddressTiles.tsx +3 -3
  190. package/src/backend/detail/AttachmentMetadataDialog.tsx +1 -1
  191. package/src/backend/detail/CustomDataSection.tsx +1 -1
  192. package/src/backend/detail/InlineEditors.tsx +5 -5
  193. package/src/backend/detail/NotesSection.tsx +6 -6
  194. package/src/backend/detail/TagsSection.tsx +1 -1
  195. package/src/backend/devtools/UmesDevToolsPanel.tsx +6 -6
  196. package/src/backend/devtools/components/ConflictWarnings.tsx +4 -4
  197. package/src/backend/devtools/components/EnricherTiming.tsx +2 -2
  198. package/src/backend/devtools/components/EventFlow.tsx +5 -5
  199. package/src/backend/devtools/components/ExtensionPointList.tsx +3 -3
  200. package/src/backend/devtools/components/InterceptorActivity.tsx +6 -6
  201. package/src/backend/forms/ActionsDropdown.tsx +1 -1
  202. package/src/backend/forms/FormActionButtons.tsx +4 -5
  203. package/src/backend/indexes/PartialIndexBanner.tsx +8 -8
  204. package/src/backend/inputs/ComboboxInput.tsx +1 -1
  205. package/src/backend/inputs/DatePicker.tsx +3 -3
  206. package/src/backend/inputs/DateTimePicker.tsx +3 -3
  207. package/src/backend/inputs/EventSelect.tsx +1 -1
  208. package/src/backend/inputs/LookupSelect.tsx +1 -1
  209. package/src/backend/inputs/SwitchableMarkdownInput.tsx +1 -1
  210. package/src/backend/inputs/TagsInput.tsx +2 -2
  211. package/src/backend/inputs/TimeInput.tsx +1 -1
  212. package/src/backend/inputs/TimePicker.tsx +3 -3
  213. package/src/backend/messages/MessageObjectDetail.tsx +1 -1
  214. package/src/backend/messages/MessageObjectPreview.tsx +1 -1
  215. package/src/backend/messages/message-compose-form-groups.tsx +3 -3
  216. package/src/backend/notifications/NotificationCountBadge.tsx +1 -1
  217. package/src/backend/notifications/NotificationPanel.tsx +3 -3
  218. package/src/backend/progress/ProgressTopBar.tsx +4 -4
  219. package/src/backend/schedule/ScheduleAgenda.tsx +1 -1
  220. package/src/backend/schedule/ScheduleCalendar.tsx +1 -1
  221. package/src/backend/schedule/ScheduleGrid.tsx +1 -1
  222. package/src/backend/version-history/VersionHistoryPanel.tsx +4 -4
  223. package/src/frontend/AuthFooter.tsx +1 -1
  224. package/src/frontend/LanguageSwitcher.tsx +1 -1
  225. package/src/frontend/Layout.tsx +2 -2
  226. package/src/index.ts +6 -1
  227. package/src/portal/PortalShell.tsx +15 -15
  228. package/src/portal/components/PortalCard.tsx +2 -2
  229. package/src/portal/components/PortalNotificationPanel.tsx +18 -18
  230. package/src/portal/components/PortalPageHeader.tsx +1 -1
  231. package/src/primitives/avatar.tsx +22 -0
  232. package/src/primitives/badge.tsx +1 -1
  233. package/src/primitives/button.tsx +12 -5
  234. package/src/primitives/calendar.tsx +1 -1
  235. package/src/primitives/checkbox-field.tsx +85 -0
  236. package/src/primitives/checkbox.tsx +44 -18
  237. package/src/primitives/dialog.tsx +4 -4
  238. package/src/primitives/fancy-button.tsx +89 -0
  239. package/src/primitives/icon-button.tsx +19 -2
  240. package/src/primitives/kbd.tsx +38 -0
  241. package/src/primitives/link-button.tsx +55 -0
  242. package/src/primitives/popover.tsx +1 -1
  243. package/src/primitives/social-button.tsx +80 -0
  244. package/src/primitives/tabs.tsx +1 -1
  245. package/src/primitives/tag.tsx +66 -0
  246. package/src/primitives/tooltip.tsx +1 -1
@@ -6,6 +6,7 @@ import Image from 'next/image'
6
6
  import { ChevronUp, ChevronDown } from 'lucide-react'
7
7
  import { Button } from '../primitives/button'
8
8
  import { IconButton } from '../primitives/icon-button'
9
+ import { Checkbox } from '../primitives/checkbox'
9
10
  import { Separator } from '../primitives/separator'
10
11
  import { FlashMessages } from './FlashMessages'
11
12
  import { QueryProvider } from '../theme/QueryProvider'
@@ -753,7 +754,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
753
754
 
754
755
  const asideWidth = effectiveCollapsed ? '72px' : expandedSidebarWidth
755
756
  // Use min-h-svh so the border extends with tall content; no overflow so sticky bottom works
756
- const asideClassesBase = `border-r bg-background/60 py-4 min-h-svh`;
757
+ const asideClassesBase = `border-r bg-background/80 py-4 min-h-svh`;
757
758
 
758
759
  // Persist collapse state to localStorage and cookie
759
760
  React.useEffect(() => {
@@ -932,18 +933,18 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
932
933
  ) : null}
933
934
  <div className="flex flex-1 flex-col gap-3 pr-1">
934
935
  <div className="space-y-3">
935
- <div className="h-8 rounded bg-muted/60" />
936
+ <div className="h-8 rounded bg-muted/50" />
936
937
  <div className="space-y-2 pl-1">
937
938
  <div className="h-8 rounded bg-muted/50" />
938
- <div className="h-8 rounded bg-muted/40" />
939
- <div className="h-8 rounded bg-muted/40" />
939
+ <div className="h-8 rounded bg-muted/50" />
940
+ <div className="h-8 rounded bg-muted/50" />
940
941
  </div>
941
942
  </div>
942
943
  <div className="space-y-3">
943
- <div className="h-8 rounded bg-muted/60" />
944
+ <div className="h-8 rounded bg-muted/50" />
944
945
  <div className="space-y-2 pl-1">
945
- <div className="h-8 rounded bg-muted/40" />
946
- <div className="h-8 rounded bg-muted/40" />
946
+ <div className="h-8 rounded bg-muted/50" />
947
+ <div className="h-8 rounded bg-muted/50" />
947
948
  </div>
948
949
  </div>
949
950
  </div>
@@ -1015,11 +1016,9 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
1015
1016
  >
1016
1017
  <span className="text-xs font-medium text-muted-foreground">{placeholder}</span>
1017
1018
  <div className="flex items-center gap-2">
1018
- <input
1019
- type="checkbox"
1020
- className="h-4 w-4 accent-foreground"
1019
+ <Checkbox
1021
1020
  checked={!hidden}
1022
- onChange={(event) => setItemHidden(itemKey, !event.target.checked)}
1021
+ onCheckedChange={(next) => setItemHidden(itemKey, next !== true)}
1023
1022
  disabled={savingPreferences}
1024
1023
  aria-label={t('appShell.sidebarCustomizationShowItem')}
1025
1024
  title={t('appShell.sidebarCustomizationShowItem')}
@@ -1029,7 +1028,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
1029
1028
  onChange={(event) => setItemLabel(itemKey, event.target.value)}
1030
1029
  placeholder={placeholder}
1031
1030
  disabled={savingPreferences}
1032
- className="h-8 flex-1 rounded border bg-background px-2 text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-60"
1031
+ className="h-8 flex-1 rounded border bg-background px-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50"
1033
1032
  />
1034
1033
  </div>
1035
1034
  {baseItem.children && baseItem.children.length > 0 ? (
@@ -1044,7 +1043,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
1044
1043
 
1045
1044
  const customizationEditor = customizing ? (
1046
1045
  customDraft ? (
1047
- <div className="flex flex-col gap-3 rounded border border-dashed bg-muted/20 p-3">
1046
+ <div className="flex flex-col gap-3 rounded border border-dashed bg-muted/30 p-3">
1048
1047
  <div className="flex flex-wrap items-center justify-between gap-2">
1049
1048
  <div className="text-sm font-semibold">{t('appShell.sidebarCustomizationHeading')}</div>
1050
1049
  <div className="flex items-center gap-2">
@@ -1076,7 +1075,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
1076
1075
  </div>
1077
1076
  <p className="text-xs text-muted-foreground">{t('appShell.sidebarCustomizationHint', { locale: localeLabel })}</p>
1078
1077
  {canApplyToRoles ? (
1079
- <div className="flex flex-col gap-2 rounded border bg-background/70 p-3 shadow-sm">
1078
+ <div className="flex flex-col gap-2 rounded border bg-background/80 p-3 shadow-sm">
1080
1079
  <div>
1081
1080
  <div className="text-sm font-semibold">{t('appShell.sidebarApplyToRolesTitle')}</div>
1082
1081
  <p className="text-xs text-muted-foreground">{t('appShell.sidebarApplyToRolesDescription')}</p>
@@ -1087,12 +1086,10 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
1087
1086
  const checked = selectedRoleIds.includes(role.id)
1088
1087
  const willClear = role.hasPreference && !checked
1089
1088
  return (
1090
- <label key={role.id} className="flex items-center gap-2 rounded border bg-background px-2 py-1 text-sm shadow-sm">
1091
- <input
1092
- type="checkbox"
1093
- className="h-4 w-4 accent-foreground"
1089
+ <label key={role.id} className="flex items-center gap-2 rounded-md border bg-background px-2 py-1 text-sm shadow-sm cursor-pointer">
1090
+ <Checkbox
1094
1091
  checked={checked}
1095
- onChange={() => toggleRoleSelection(role.id)}
1092
+ onCheckedChange={() => toggleRoleSelection(role.id)}
1096
1093
  disabled={savingPreferences}
1097
1094
  />
1098
1095
  <span className="flex-1 truncate">{role.name}</span>
@@ -1128,7 +1125,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
1128
1125
  onChange={(event) => setGroupLabel(groupId, event.target.value)}
1129
1126
  placeholder={placeholder}
1130
1127
  disabled={savingPreferences}
1131
- className="mt-1 h-8 w-full rounded border bg-background px-2 text-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-ring disabled:opacity-60"
1128
+ className="mt-1 h-8 w-full rounded border bg-background px-2 text-sm shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50"
1132
1129
  />
1133
1130
  </div>
1134
1131
  <div className="flex items-center gap-1 self-start">
@@ -1163,7 +1160,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
1163
1160
  </div>
1164
1161
  </div>
1165
1162
  ) : (
1166
- <div className="rounded border border-dashed bg-muted/20 p-3 text-sm text-muted-foreground">
1163
+ <div className="rounded border border-dashed bg-muted/30 p-3 text-sm text-muted-foreground">
1167
1164
  {t('appShell.sidebarCustomizationLoading')}
1168
1165
  </div>
1169
1166
  )
@@ -1320,7 +1317,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
1320
1317
  })()
1321
1318
  )}
1322
1319
  </div>
1323
- <div className="sticky bottom-0 pt-4 border-t bg-background/60 backdrop-blur-sm pb-1">
1320
+ <div className="sticky bottom-0 pt-4 border-t bg-background/80 backdrop-blur-sm pb-1">
1324
1321
  {shouldRenderSidebarInjectionSpots ? (
1325
1322
  <InjectionSpot
1326
1323
  spotId={BACKEND_SIDEBAR_NAV_FOOTER_INJECTION_SPOT_ID}
@@ -1440,7 +1437,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
1440
1437
  <aside className={`${asideClassesBase} ${effectiveCollapsed ? 'px-2' : 'px-3'} hidden lg:block`} style={{ width: asideWidth }}>{renderSidebar(effectiveCollapsed)}</aside>
1441
1438
 
1442
1439
  <div className="flex min-h-svh flex-col min-w-0">
1443
- <header className="border-b bg-background/60 px-3 lg:px-4 py-2 lg:py-3 flex items-center justify-between gap-2">
1440
+ <header className="border-b bg-background/80 px-3 lg:px-4 py-2 lg:py-3 flex items-center justify-between gap-2">
1444
1441
  <div
1445
1442
  data-testid="backend-chrome-ready"
1446
1443
  data-ready={isChromeReady ? 'true' : 'false'}
@@ -1518,8 +1515,8 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
1518
1515
  )}
1519
1516
  </div>
1520
1517
  </header>
1521
- <ProgressTopBar t={t} className="sticky top-0 z-10" />
1522
- <main className="flex-1 p-4 lg:p-6">
1518
+ <ProgressTopBar t={t} className="sticky top-0 z-sticky" />
1519
+ <main className="flex-1 p-4 lg:p-6 mx-auto w-full max-w-screen-2xl">
1523
1520
  <InjectionSpot spotId={BACKEND_LAYOUT_TOP_INJECTION_SPOT_ID} context={injectionContext} />
1524
1521
  <FlashMessages />
1525
1522
  <PartialIndexBanner />
@@ -1534,7 +1531,7 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
1534
1531
  {children}
1535
1532
  <InjectionSpot spotId={BACKEND_LAYOUT_FOOTER_INJECTION_SPOT_ID} context={injectionContext} />
1536
1533
  </main>
1537
- <footer className="border-t bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/50 px-4 py-3 flex flex-wrap items-center justify-end gap-4">
1534
+ <footer className="border-t bg-background/80 backdrop-blur supports-[backdrop-filter]:bg-background/80 px-4 py-3 flex flex-wrap items-center justify-end gap-4">
1538
1535
  {version ? (
1539
1536
  <span className="text-xs text-muted-foreground">
1540
1537
  {t('appShell.version', { version })}
@@ -1553,8 +1550,8 @@ function AppShellBody({ productName, logo, email, groups, rightHeaderSlot, child
1553
1550
 
1554
1551
  {/* Mobile drawer */}
1555
1552
  {mobileOpen && (
1556
- <div className="lg:hidden fixed inset-0 z-50">
1557
- <div className="absolute inset-0 bg-black/40" onClick={() => setMobileOpen(false)} aria-hidden="true" />
1553
+ <div className="lg:hidden fixed inset-0 z-modal">
1554
+ <div className="absolute inset-0 bg-black/20" onClick={() => setMobileOpen(false)} aria-hidden="true" />
1558
1555
  <aside className="absolute left-0 top-0 flex h-full w-[260px] flex-col bg-background border-r overflow-hidden">
1559
1556
  <div className="shrink-0 p-3 pb-2 flex items-center justify-between border-b">
1560
1557
  <Link href="/backend" className="flex items-center gap-2 text-sm font-semibold" onClick={() => setMobileOpen(false)} aria-label={t('appShell.goToDashboard')}>
@@ -21,7 +21,7 @@ export function ContextHelp({ title, children, defaultOpen = false, bulb = true,
21
21
  <Button
22
22
  type="button"
23
23
  variant="ghost"
24
- className="w-full justify-start gap-2 px-4 py-3 text-left hover:bg-accent/40"
24
+ className="w-full justify-start gap-2 px-4 py-3 text-left hover:bg-accent/50"
25
25
  aria-expanded={open}
26
26
  onClick={() => setOpen(v => !v)}
27
27
  >
@@ -7,6 +7,7 @@ import { DndContext, closestCenter, PointerSensor, KeyboardSensor, useSensor, us
7
7
  import { SortableContext, verticalListSortingStrategy, useSortable, arrayMove } from '@dnd-kit/sortable'
8
8
  import { CSS } from '@dnd-kit/utilities'
9
9
  import { DataLoader } from '../primitives/DataLoader'
10
+ import { Checkbox } from '../primitives/checkbox'
10
11
  import { flash } from './FlashMessages'
11
12
  import dynamic from 'next/dynamic'
12
13
  import { FormHeader } from './forms/FormHeader'
@@ -1733,7 +1734,7 @@ export function CrudForm<TValues extends Record<string, unknown>>({
1733
1734
  const text = t('entities.customFields.empty')
1734
1735
  const action = t('entities.customFields.addFirst')
1735
1736
  return (
1736
- <div className="rounded-md border border-dashed border-muted-foreground/50 bg-muted/10 px-3 py-4 text-sm text-muted-foreground">
1737
+ <div className="rounded-md border border-dashed border-muted-foreground/50 bg-muted/30 px-3 py-4 text-sm text-muted-foreground">
1737
1738
  <span>{text} </span>
1738
1739
  {customFieldsManageHref ? (
1739
1740
  <Link href={customFieldsManageHref} className="font-medium text-primary hover:underline">
@@ -2773,7 +2774,7 @@ export function CrudForm<TValues extends Record<string, unknown>>({
2773
2774
  <div className="pointer-events-none select-none opacity-70">
2774
2775
  {children}
2775
2776
  </div>
2776
- <div className="absolute inset-0 z-10 flex items-start justify-center rounded-lg bg-background/60 p-4 backdrop-blur-[1px] sm:p-6">
2777
+ <div className="absolute inset-0 z-10 flex items-start justify-center rounded-lg bg-background/80 p-4 backdrop-blur-[1px] sm:p-6">
2777
2778
  {readOnlyOverlay ?? <div className="rounded-xl border border-border/70 bg-background/95 px-4 py-3 shadow-sm" />}
2778
2779
  </div>
2779
2780
  </div>
@@ -3558,7 +3559,7 @@ const HtmlRichTextEditor = React.memo(function HtmlRichTextEditor({ value = '',
3558
3559
  </div>
3559
3560
  <div
3560
3561
  ref={ref}
3561
- className="w-full px-2 py-2 min-h-[100px] sm:min-h-[160px] focus:outline-none prose prose-sm max-w-none"
3562
+ className="w-full px-2 py-2 min-h-[100px] sm:min-h-[160px] focus-visible:outline-none prose prose-sm max-w-none"
3562
3563
  contentEditable
3563
3564
  suppressContentEditableWarning
3564
3565
  onKeyDown={onKeyDown}
@@ -3725,7 +3726,7 @@ const ListboxMultiSelect = React.memo(function ListboxMultiSelect({
3725
3726
  className={`w-full justify-start rounded-none font-normal px-3 py-2 ${isSel ? 'bg-muted' : ''}`}
3726
3727
  >
3727
3728
  <span className="inline-flex items-center gap-2">
3728
- <input type="checkbox" className="size-4" readOnly checked={isSel} />
3729
+ <Checkbox checked={isSel} disabled tabIndex={-1} className="pointer-events-none" />
3729
3730
  <span>{opt.label}</span>
3730
3731
  </span>
3731
3732
  </Button>
@@ -3945,12 +3946,10 @@ const FieldControl = React.memo(function FieldControlImpl({
3945
3946
  />
3946
3947
  )}
3947
3948
  {field.type === 'checkbox' && (
3948
- <label className="inline-flex items-center gap-2">
3949
- <input
3950
- type="checkbox"
3951
- className="size-4"
3949
+ <label className="inline-flex items-center gap-2 cursor-pointer">
3950
+ <Checkbox
3952
3951
  checked={value === true}
3953
- onChange={(e) => setValue(field.id, e.target.checked)}
3952
+ onCheckedChange={(next) => setValue(field.id, next === true)}
3954
3953
  data-crud-focus-target=""
3955
3954
  disabled={disabled}
3956
3955
  />
@@ -3996,14 +3995,12 @@ const FieldControl = React.memo(function FieldControlImpl({
3996
3995
  : []
3997
3996
  const checked = arr.includes(opt.value)
3998
3997
  return (
3999
- <label key={opt.value} className="inline-flex items-center gap-2">
4000
- <input
4001
- type="checkbox"
4002
- className="size-4"
3998
+ <label key={opt.value} className="inline-flex items-center gap-2 cursor-pointer">
3999
+ <Checkbox
4003
4000
  checked={checked}
4004
- onChange={(e) => {
4001
+ onCheckedChange={(state) => {
4005
4002
  const next = new Set(arr)
4006
- if (e.target.checked) {
4003
+ if (state === true) {
4007
4004
  next.add(opt.value)
4008
4005
  } else {
4009
4006
  next.delete(opt.value)
@@ -3,7 +3,7 @@ import * as React from 'react'
3
3
  import { useRouter } from 'next/navigation'
4
4
  import { useReactTable, getCoreRowModel, getSortedRowModel, flexRender, type ColumnDef, type SortingState, type Column as TableColumn, type VisibilityState, type RowSelectionState } from '@tanstack/react-table'
5
5
  import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
6
- import { RefreshCw, Loader2, SlidersHorizontal, MoreHorizontal, Circle, Filter, ChevronDown, Check } from 'lucide-react'
6
+ import { RefreshCw, Loader2, SlidersHorizontal, MoreHorizontal, Circle, Filter, Columns3, ChevronUp, ChevronDown, ChevronsUpDown, Check } from 'lucide-react'
7
7
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '../primitives/table'
8
8
  import { Button } from '../primitives/button'
9
9
  import { Checkbox } from '../primitives/checkbox'
@@ -628,7 +628,6 @@ function ExportMenu({ config, sections }: { config: DataTableExportConfig; secti
628
628
  <Button
629
629
  ref={buttonRef}
630
630
  variant="outline"
631
- size="sm"
632
631
  type="button"
633
632
  onClick={() => {
634
633
  if (disabled) return
@@ -644,7 +643,7 @@ function ExportMenu({ config, sections }: { config: DataTableExportConfig; secti
644
643
  <div
645
644
  ref={menuRef}
646
645
  role="menu"
647
- className="absolute right-0 mt-2 w-60 rounded-md border bg-background py-2 shadow z-20"
646
+ className="absolute right-0 mt-2 w-60 rounded-md border bg-background py-2 shadow z-dropdown"
648
647
  >
649
648
  {sections.map((section, idx) => (
650
649
  <div key={section.key} className={idx > 0 ? 'mt-2 border-t pt-3' : ''}>
@@ -2135,7 +2134,6 @@ export function DataTable<T>({
2135
2134
  <Button
2136
2135
  key={action.id}
2137
2136
  type="button"
2138
- size="sm"
2139
2137
  variant="outline"
2140
2138
  title={label}
2141
2139
  aria-label={label}
@@ -2154,7 +2152,6 @@ export function DataTable<T>({
2154
2152
  <Button
2155
2153
  key={action.id}
2156
2154
  type="button"
2157
- size="sm"
2158
2155
  variant={action.destructive ? 'destructive' : 'outline'}
2159
2156
  onClick={() => void runPropBulkAction(action)}
2160
2157
  >
@@ -2308,7 +2305,7 @@ export function DataTable<T>({
2308
2305
  >
2309
2306
  <Filter className="h-4 w-4" />
2310
2307
  {advancedFilter.value.conditions.length > 0 ? (
2311
- <span className="absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-[10px] text-primary-foreground">
2308
+ <span className="absolute -top-1 -right-1 flex h-4 w-4 items-center justify-center rounded-full bg-primary text-overline text-primary-foreground">
2312
2309
  {advancedFilter.value.conditions.length}
2313
2310
  </span>
2314
2311
  ) : null}
@@ -2405,10 +2402,12 @@ export function DataTable<T>({
2405
2402
  >
2406
2403
  {flexRender(header.column.columnDef.header, header.getContext())}
2407
2404
  {sortable && header.column.getCanSort?.() ? (
2408
- <span className="ml-1 inline-flex flex-col text-[10px] leading-none gap-px">
2409
- <span className={header.column.getIsSorted() === 'asc' ? 'text-foreground' : 'text-muted-foreground/40'}>▲</span>
2410
- <span className={header.column.getIsSorted() === 'desc' ? 'text-foreground' : 'text-muted-foreground/40'}>▼</span>
2411
- </span>
2405
+ (() => {
2406
+ const sortState = header.column.getIsSorted()
2407
+ if (sortState === 'asc') return <ChevronUp className="ml-1 size-3.5 shrink-0 text-foreground" aria-hidden="true" />
2408
+ if (sortState === 'desc') return <ChevronDown className="ml-1 size-3.5 shrink-0 text-foreground" aria-hidden="true" />
2409
+ return <ChevronsUpDown className="ml-1 size-3.5 shrink-0 text-muted-foreground/50" aria-hidden="true" />
2410
+ })()
2412
2411
  ) : null}
2413
2412
  </Button>
2414
2413
  )
@@ -1,5 +1,6 @@
1
1
  "use client"
2
2
  import * as React from 'react'
3
+ import { ListFilter, Search } from 'lucide-react'
3
4
  import { Button } from '../primitives/button'
4
5
  import { FilterDef, FilterOverlay, FilterValues } from './FilterOverlay'
5
6
  import { useT } from '@open-mercato/shared/lib/i18n/context'
@@ -72,22 +73,22 @@ export function FilterBar({
72
73
 
73
74
  const containerClass = `flex flex-col ${layout === 'inline' ? 'gap-1 sm:gap-2' : 'gap-2'} w-full`
74
75
  const searchInput = onSearchChange ? (
75
- <div className={`relative w-full sm:w-auto sm:min-w-[180px] sm:max-w-[240px] ${searchAlign === 'right' ? 'sm:ml-auto' : ''}`}>
76
+ <div className={`relative w-full sm:w-72 lg:w-80 ${searchAlign === 'right' ? 'sm:ml-auto' : ''}`}>
76
77
  <input
77
78
  value={searchDraft}
78
79
  onChange={(e) => setSearchDraft(e.target.value)}
79
80
  placeholder={resolvedSearchPlaceholder}
80
- className="h-9 w-full rounded border pl-8 pr-2 text-sm"
81
+ className="h-9 w-full rounded-md border border-input bg-background pl-8 pr-2 text-sm shadow-xs outline-none transition-colors placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-2 focus-visible:ring-ring/50"
81
82
  suppressHydrationWarning
82
83
  />
83
- <span className="absolute left-2 top-1/2 -translate-y-1/2 text-muted-foreground">🔍</span>
84
+ <Search aria-hidden="true" className="absolute left-2 top-1/2 size-4 -translate-y-1/2 text-muted-foreground" />
84
85
  </div>
85
86
  ) : null
86
87
  const controls = (
87
88
  <div className={`flex flex-wrap items-center gap-2 ${searchAlign === 'left' && searchInput ? 'sm:ml-auto' : ''}`}>
88
89
  {filters.length > 0 && (
89
- <Button variant="outline" className="h-9" onClick={() => setOpen(true)}>
90
- <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" aria-hidden="true" className="opacity-80"><path d="M3 4h18"/><path d="M6 8h12l-3 8H9L6 8z"/></svg>
90
+ <Button variant="outline" onClick={() => setOpen(true)}>
91
+ <ListFilter aria-hidden="true" className="size-4 opacity-80" />
91
92
  {activeCount
92
93
  ? t('ui.filterBar.filtersWithCount', 'Filters {count}', { count: activeCount })
93
94
  : t('ui.filterBar.filters', 'Filters')
@@ -1,6 +1,7 @@
1
1
  "use client"
2
2
  import * as React from 'react'
3
3
  import { Button } from '../primitives/button'
4
+ import { Checkbox } from '../primitives/checkbox'
4
5
  import { ComboboxInput } from './inputs/ComboboxInput'
5
6
  import { TagsInput, type TagsInputOption } from './inputs/TagsInput'
6
7
  import { useT } from '@open-mercato/shared/lib/i18n/context'
@@ -190,8 +191,8 @@ export function FilterOverlay({
190
191
  return (
191
192
  <>
192
193
  {open && (
193
- <div className="fixed inset-0 z-50">
194
- <div className="absolute inset-0 bg-black/30" onClick={() => onOpenChange(false)} role="presentation" />
194
+ <div className="fixed inset-0 z-modal">
195
+ <div className="absolute inset-0 bg-black/20" onClick={() => onOpenChange(false)} role="presentation" />
195
196
  <div className="absolute left-0 top-0 h-full w-full sm:w-[380px] bg-background shadow-xl border-r flex flex-col">
196
197
  <div className="flex items-center justify-between p-4 border-b">
197
198
  <h2 className="text-base font-semibold">{defaultTitle}</h2>
@@ -249,15 +250,14 @@ export function FilterOverlay({
249
250
  const arr: string[] = Array.isArray(values[f.id]) ? values[f.id] : []
250
251
  const checked = arr.includes(opt.value)
251
252
  return (
252
- <label key={opt.value} className="inline-flex items-center gap-2">
253
- <input
254
- type="checkbox"
253
+ <label key={opt.value} className="inline-flex items-center gap-2 cursor-pointer">
254
+ <Checkbox
255
255
  checked={checked}
256
- onChange={(e) => {
257
- const next = new Set(arr)
258
- if (e.target.checked) next.add(opt.value)
259
- else next.delete(opt.value)
260
- setValue(f.id, Array.from(next))
256
+ onCheckedChange={(next) => {
257
+ const set = new Set(arr)
258
+ if (next === true) set.add(opt.value)
259
+ else set.delete(opt.value)
260
+ setValue(f.id, Array.from(set))
261
261
  }}
262
262
  />
263
263
  <span className="text-sm">{opt.label}</span>
@@ -152,7 +152,7 @@ function FlashMessagesInner() {
152
152
  const color = colorMap[kind]
153
153
 
154
154
  return (
155
- <div className="pointer-events-none fixed left-3 right-3 top-3 z-[1200] sm:left-auto sm:right-4 sm:w-[380px]">
155
+ <div className="pointer-events-none fixed left-3 right-3 top-3 z-toast sm:left-auto sm:right-4 sm:w-[380px]">
156
156
  <div className={`pointer-events-auto rounded px-3 py-2 text-white shadow-md ${color}`}>
157
157
  <div className="flex items-center justify-between gap-2">
158
158
  <div className="text-sm">{msg}</div>
@@ -117,7 +117,7 @@ export function JsonBuilder({
117
117
  } catch { }
118
118
  }}
119
119
  placeholder='{"key": "value"}'
120
- className="w-full rounded border px-3 py-2 min-h-[300px] text-sm font-mono focus:outline-none focus:ring-2 focus:ring-blue-500"
120
+ className="w-full rounded border px-3 py-2 min-h-[300px] text-sm font-mono focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
121
121
  disabled={disabled}
122
122
  />
123
123
  {parseError && (
@@ -242,7 +242,7 @@ function JsonNode({ data, onChange, onDelete, readOnly, label, isRoot }: JsonNod
242
242
  <select
243
243
  value={type}
244
244
  onChange={(e) => handleTypeChange(e.target.value as JsonNodeType)}
245
- className="text-xs border rounded px-1 py-0.5 bg-muted text-foreground focus:ring-1 focus:ring-blue-500"
245
+ className="text-xs border rounded px-1 py-0.5 bg-muted text-foreground focus-visible:ring-1 focus-visible:ring-ring"
246
246
  >
247
247
  <option value="string">String</option>
248
248
  <option value="number">Number</option>
@@ -255,7 +255,7 @@ function JsonNode({ data, onChange, onDelete, readOnly, label, isRoot }: JsonNod
255
255
 
256
256
  {type === 'string' && (
257
257
  <input
258
- className="flex-1 min-w-0 sm:min-w-[120px] text-sm border rounded px-2 py-0.5 focus:outline-none focus:border-blue-500"
258
+ className="flex-1 min-w-0 sm:min-w-[120px] text-sm border rounded px-2 py-0.5 focus-visible:outline-none focus-visible:border-ring"
259
259
  value={data}
260
260
  onChange={e => onChange(e.target.value)}
261
261
  disabled={readOnly}
@@ -264,7 +264,7 @@ function JsonNode({ data, onChange, onDelete, readOnly, label, isRoot }: JsonNod
264
264
  {type === 'number' && (
265
265
  <input
266
266
  type="number"
267
- className="flex-1 w-full sm:w-[100px] text-sm border rounded px-2 py-0.5 focus:outline-none focus:border-blue-500"
267
+ className="flex-1 w-full sm:w-[100px] text-sm border rounded px-2 py-0.5 focus-visible:outline-none focus-visible:border-ring"
268
268
  value={data}
269
269
  onChange={e => onChange(parseFloat(e.target.value) || 0)}
270
270
  disabled={readOnly}
@@ -272,7 +272,7 @@ function JsonNode({ data, onChange, onDelete, readOnly, label, isRoot }: JsonNod
272
272
  )}
273
273
  {type === 'boolean' && (
274
274
  <select
275
- className="flex-1 w-full sm:w-[100px] text-sm border rounded px-2 py-0.5 focus:outline-none focus:border-blue-500"
275
+ className="flex-1 w-full sm:w-[100px] text-sm border rounded px-2 py-0.5 focus-visible:outline-none focus-visible:border-ring"
276
276
  value={String(data)}
277
277
  onChange={e => onChange(e.target.value === 'true')}
278
278
  disabled={readOnly}
@@ -310,7 +310,7 @@ function JsonNode({ data, onChange, onDelete, readOnly, label, isRoot }: JsonNod
310
310
  <div className="pt-2">
311
311
  {/* Key Renamer */}
312
312
  <input
313
- className="w-full sm:w-[100px] text-xs font-mono border-b border-transparent hover:border-gray-300 focus:border-blue-500 bg-transparent focus:outline-none text-right pr-1"
313
+ className="w-full sm:w-[100px] text-xs font-mono border-b border-transparent hover:border-gray-300 focus-visible:border-ring bg-transparent focus-visible:outline-none text-right pr-1"
314
314
  value={key}
315
315
  onChange={(e) => handleKeyRename(key, e.target.value)}
316
316
  disabled={readOnly}
@@ -46,7 +46,7 @@ const STEP_STYLES: Record<NonNullable<NextStepCalloutStep['state']>, string> = {
46
46
  }
47
47
 
48
48
  const STATUS_STYLES: Record<NextStepCalloutStatusTone, string> = {
49
- default: 'border-border bg-background/70 text-foreground',
49
+ default: 'border-border bg-background/80 text-foreground',
50
50
  info: 'border-primary/20 bg-primary/5 text-primary',
51
51
  success: 'border-emerald-500/20 bg-emerald-500/5 text-emerald-200',
52
52
  warning: 'border-amber-500/20 bg-amber-500/5 text-amber-200',
@@ -352,8 +352,8 @@ export function PerspectiveSidebar({
352
352
  const isShare = mode.type === 'share'
353
353
 
354
354
  return (
355
- <div className="fixed inset-0 z-50">
356
- <div className="absolute inset-0 bg-black/30" onClick={() => onOpenChange(false)} role="presentation" />
355
+ <div className="fixed inset-0 z-modal">
356
+ <div className="absolute inset-0 bg-black/20" onClick={() => onOpenChange(false)} role="presentation" />
357
357
  <div className="fixed right-0 top-0 h-full w-full sm:w-80 bg-background shadow-xl border-l flex flex-col">
358
358
  <div className="flex items-center p-4 border-b">
359
359
  <Button
@@ -321,7 +321,7 @@ export function ProfileDropdown({
321
321
  {open && (
322
322
  <div
323
323
  ref={menuRef}
324
- className="absolute right-0 top-full mt-1 w-56 rounded-md border bg-background p-1 shadow-lg z-50"
324
+ className="absolute right-0 top-full mt-1 w-56 rounded-md border bg-background p-1 shadow-lg z-dropdown"
325
325
  role="menu"
326
326
  data-testid="profile-dropdown"
327
327
  >
@@ -109,7 +109,7 @@ export function RowActions({ items = [] }: { items?: RowActionItem[] }) {
109
109
  <div
110
110
  ref={menuRef}
111
111
  role="menu"
112
- className="fixed w-44 max-w-[calc(100vw-1rem)] rounded-md border bg-background p-1 shadow focus:outline-none z-[1000]"
112
+ className="fixed w-44 max-w-[calc(100vw-1rem)] rounded-md border bg-background p-1 shadow focus-visible:outline-none z-dropdown"
113
113
  style={{
114
114
  top: direction === 'down' ? anchorRect.bottom + 8 : anchorRect.top - 8,
115
115
  left: Math.min(anchorRect.right, window.innerWidth - 8),
@@ -88,7 +88,7 @@ export function UserMenu({ email }: { email?: string }) {
88
88
  <div
89
89
  ref={menuRef}
90
90
  id="user-menu-dropdown"
91
- className="absolute right-0 top-full mt-0 w-56 rounded-md border bg-background p-1 shadow z-50"
91
+ className="absolute right-0 top-full mt-0 w-56 rounded-md border bg-background p-1 shadow z-dropdown"
92
92
  role="menu"
93
93
  aria-labelledby="user-menu-button"
94
94
  tabIndex={-1}
@@ -102,7 +102,7 @@ export function UserMenu({ email }: { email?: string }) {
102
102
  <Link
103
103
  ref={profileButtonRef}
104
104
  href="/backend/profile/change-password"
105
- className="w-full text-left text-sm px-2 py-1 rounded hover:bg-accent inline-flex items-center gap-2 outline-none focus:outline-none focus-visible:outline-none ring-0 focus:ring-0 focus-visible:ring-0"
105
+ className="w-full text-left text-sm px-2 py-1 rounded hover:bg-accent inline-flex items-center gap-2 outline-none focus-visible:outline-none focus-visible:outline-none ring-0 focus-visible:ring-0 focus-visible:ring-0"
106
106
  role="menuitem"
107
107
  tabIndex={0}
108
108
  onClick={() => setOpen(false)}
@@ -46,7 +46,7 @@ export function WebhookSetupGuide({
46
46
  </Button>
47
47
 
48
48
  {isOpen ? (
49
- <div className="space-y-4 rounded-lg border bg-muted/20 p-4">
49
+ <div className="space-y-4 rounded-lg border bg-muted/30 p-4">
50
50
  <div className="space-y-1">
51
51
  <div className="flex items-center gap-2">
52
52
  <Webhook className="h-4 w-4 text-muted-foreground" />
@@ -56,16 +56,16 @@ export function WebhookSetupGuide({
56
56
  </div>
57
57
 
58
58
  <div className="space-y-2">
59
- <p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
59
+ <p className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
60
60
  {t('ui.webhookGuide.dashboardPath', 'Dashboard path')}
61
61
  </p>
62
- <div className="rounded-md border bg-background/70 px-3 py-2 text-sm">
62
+ <div className="rounded-md border bg-background/80 px-3 py-2 text-sm">
63
63
  {guide.dashboardPathLabel}
64
64
  </div>
65
65
  </div>
66
66
 
67
67
  <div className="space-y-2">
68
- <p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
68
+ <p className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
69
69
  {t('ui.webhookGuide.steps', 'Setup steps')}
70
70
  </p>
71
71
  <ol className="list-decimal space-y-2 pl-5 text-sm text-muted-foreground">
@@ -76,22 +76,22 @@ export function WebhookSetupGuide({
76
76
  </div>
77
77
 
78
78
  <div className="space-y-2">
79
- <p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
79
+ <p className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
80
80
  {t('ui.webhookGuide.endpointUrl', 'Webhook endpoint URL')}
81
81
  </p>
82
- <div className="rounded-md border bg-background/70 px-3 py-2 font-mono text-xs break-all">
82
+ <div className="rounded-md border bg-background/80 px-3 py-2 font-mono text-xs break-all">
83
83
  {endpointUrl}
84
84
  </div>
85
85
  </div>
86
86
 
87
87
  {guide.events && guide.events.length > 0 ? (
88
88
  <div className="space-y-2">
89
- <p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
89
+ <p className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
90
90
  {t('ui.webhookGuide.recommendedEvents', 'Recommended events')}
91
91
  </p>
92
92
  <div className="flex flex-wrap gap-2">
93
93
  {guide.events.map((eventName) => (
94
- <Badge key={eventName} variant="outline" className="font-mono text-[11px]">
94
+ <Badge key={eventName} variant="outline" className="font-mono text-overline">
95
95
  {eventName}
96
96
  </Badge>
97
97
  ))}
@@ -101,16 +101,16 @@ export function WebhookSetupGuide({
101
101
 
102
102
  {guide.localDevelopment ? (
103
103
  <div className="space-y-3">
104
- <p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
104
+ <p className="text-overline font-medium uppercase tracking-wide text-muted-foreground">
105
105
  {t('ui.webhookGuide.localDevelopment', 'Local development')}
106
106
  </p>
107
107
  {guide.localDevelopment.note ? (
108
108
  <p className="text-sm text-muted-foreground">{guide.localDevelopment.note}</p>
109
109
  ) : null}
110
- <div className="rounded-md border bg-background/70 px-3 py-2 font-mono text-xs">
110
+ <div className="rounded-md border bg-background/80 px-3 py-2 font-mono text-xs">
111
111
  {guide.localDevelopment.tunnelCommand}
112
112
  </div>
113
- <div className="rounded-md border bg-background/70 px-3 py-2 font-mono text-xs break-all">
113
+ <div className="rounded-md border bg-background/80 px-3 py-2 font-mono text-xs break-all">
114
114
  {guide.localDevelopment.publicUrlExample}
115
115
  </div>
116
116
  </div>
@@ -46,9 +46,9 @@ function BadgeDelta({ direction, value }: BadgeDeltaProps) {
46
46
  const baseClasses = 'inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-medium'
47
47
 
48
48
  const directionClasses = {
49
- up: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400',
50
- down: 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-400',
51
- unchanged: 'bg-gray-100 text-gray-700 dark:bg-gray-800 dark:text-gray-400',
49
+ up: 'bg-status-success-bg text-status-success-text',
50
+ down: 'bg-status-error-bg text-status-error-text',
51
+ unchanged: 'bg-status-neutral-bg text-status-neutral-text',
52
52
  }
53
53
 
54
54
  const icons = {
@@ -276,7 +276,7 @@ export function ColumnChooserPanel({
276
276
  }, [open])
277
277
  if (!open) return null
278
278
  return (
279
- <div className="fixed inset-y-0 right-0 z-50 w-80 border-l bg-background shadow-lg flex flex-col">
279
+ <div className="fixed inset-y-0 right-0 z-modal w-80 border-l bg-background shadow-lg flex flex-col">
280
280
  <div className="flex items-center justify-between border-b px-4 py-3">
281
281
  <h3 className="font-semibold text-sm">
282
282
  {t('ui.columnChooser.title', 'Columns')}