@umituz/web-dashboard 5.0.1 → 6.1.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 (120) hide show
  1. package/package.json +19 -17
  2. package/src/domains/onboarding/calc/calc.test.ts +181 -0
  3. package/src/domains/onboarding/calc/card-stack-motion-curve.ts +33 -0
  4. package/src/domains/onboarding/calc/count-with-locale.ts +16 -0
  5. package/src/domains/onboarding/calc/duration-equal-split.ts +24 -0
  6. package/src/domains/onboarding/calc/elapsed-millis.ts +12 -0
  7. package/src/domains/onboarding/calc/index.ts +36 -0
  8. package/src/domains/onboarding/calc/progress-percentage.ts +37 -0
  9. package/src/domains/onboarding/calc/slider-value-bounds.ts +44 -0
  10. package/src/domains/onboarding/calc/step-index-clamp.ts +28 -0
  11. package/src/domains/onboarding/calc/swipe-gesture-curve.ts +67 -0
  12. package/src/domains/onboarding/components/OnboardingFlow.test.tsx +481 -0
  13. package/src/domains/onboarding/components/OnboardingFlow.tsx +361 -0
  14. package/src/domains/onboarding/components/OnboardingIntl.tsx +108 -0
  15. package/src/domains/onboarding/components/hooks/index.ts +7 -0
  16. package/src/domains/onboarding/components/hooks/useOnboardingAnalytics.test.tsx +74 -0
  17. package/src/domains/onboarding/components/hooks/useOnboardingAnalytics.ts +62 -0
  18. package/src/domains/onboarding/components/hooks/useOnboardingProgress.test.tsx +150 -0
  19. package/src/domains/onboarding/components/hooks/useOnboardingProgress.ts +260 -0
  20. package/src/domains/onboarding/components/hooks/usePermissionPriming.ts +52 -0
  21. package/src/domains/onboarding/components/hooks/useReducedMotion.ts +24 -0
  22. package/src/domains/onboarding/components/screens/AccountGateScreen.tsx +89 -0
  23. package/src/domains/onboarding/components/screens/AppDemoScreen.tsx +39 -0
  24. package/src/domains/onboarding/components/screens/ComparisonScreen.tsx +59 -0
  25. package/src/domains/onboarding/components/screens/GoalQuestionScreen.tsx +56 -0
  26. package/src/domains/onboarding/components/screens/PainPointsScreen.tsx +65 -0
  27. package/src/domains/onboarding/components/screens/PaywallScreen.tsx +138 -0
  28. package/src/domains/onboarding/components/screens/PermissionPrimingScreen.tsx +113 -0
  29. package/src/domains/onboarding/components/screens/PersonalizedSolutionScreen.tsx +53 -0
  30. package/src/domains/onboarding/components/screens/PreferencesScreen.tsx +194 -0
  31. package/src/domains/onboarding/components/screens/ProcessingScreen.tsx +79 -0
  32. package/src/domains/onboarding/components/screens/SocialProofScreen.tsx +116 -0
  33. package/src/domains/onboarding/components/screens/TinderCardsScreen.tsx +108 -0
  34. package/src/domains/onboarding/components/screens/ValueDeliveryScreen.tsx +85 -0
  35. package/src/domains/onboarding/components/screens/WelcomeScreen.tsx +52 -0
  36. package/src/domains/onboarding/components/screens/index.ts +28 -0
  37. package/src/domains/onboarding/components/shared/AnimationWrapper.tsx +73 -0
  38. package/src/domains/onboarding/components/shared/OnboardingErrorBoundary.tsx +81 -0
  39. package/src/domains/onboarding/components/shared/OptionCard.tsx +73 -0
  40. package/src/domains/onboarding/components/shared/PrimaryButton.tsx +58 -0
  41. package/src/domains/onboarding/components/shared/ProgressBar.tsx +51 -0
  42. package/src/domains/onboarding/components/shared/QuestionWrapper.tsx +36 -0
  43. package/src/domains/onboarding/components/shared/ScreenContainer.tsx +29 -0
  44. package/src/domains/onboarding/components/shared/SwipeCard.test.tsx +51 -0
  45. package/src/domains/onboarding/components/shared/SwipeCard.tsx +106 -0
  46. package/src/domains/onboarding/components/shared/index.ts +16 -0
  47. package/src/domains/onboarding/components/shared/renderBundledIcon.tsx +20 -0
  48. package/src/domains/onboarding/index.ts +182 -0
  49. package/src/domains/onboarding/onboarding.css +1 -0
  50. package/src/domains/onboarding/predicates/has-handler.ts +25 -0
  51. package/src/domains/onboarding/predicates/icon-name-resolves.ts +113 -0
  52. package/src/domains/onboarding/predicates/index.ts +26 -0
  53. package/src/domains/onboarding/predicates/permission-granted.ts +26 -0
  54. package/src/domains/onboarding/predicates/permission-supports.ts +66 -0
  55. package/src/domains/onboarding/predicates/predicates.test.ts +202 -0
  56. package/src/domains/onboarding/predicates/screen-emits-data.ts +17 -0
  57. package/src/domains/onboarding/predicates/storage-available.ts +22 -0
  58. package/src/domains/onboarding/templates/TemplateDemoFallback.tsx +112 -0
  59. package/src/domains/onboarding/templates/art-onboarding.ts +81 -0
  60. package/src/domains/onboarding/templates/health-onboarding.ts +97 -0
  61. package/src/domains/onboarding/templates/index.ts +6 -0
  62. package/src/domains/onboarding/templates/platform-onboarding.ts +210 -0
  63. package/src/domains/onboarding/templates/video-onboarding.ts +100 -0
  64. package/src/domains/onboarding/test/setup.ts +30 -0
  65. package/src/domains/onboarding/theme/cn.ts +10 -0
  66. package/src/domains/onboarding/theme/index.css +131 -0
  67. package/src/domains/onboarding/theme/index.ts +12 -0
  68. package/src/domains/onboarding/theme/tokens.ts +122 -0
  69. package/src/domains/onboarding/types/config.ts +68 -0
  70. package/src/domains/onboarding/types/index.ts +10 -0
  71. package/src/domains/onboarding/types/labels.ts +83 -0
  72. package/src/domains/onboarding/types/screens.ts +193 -0
  73. package/src/domains/onboarding/utils/analytics-dispatch.test.ts +93 -0
  74. package/src/domains/onboarding/utils/analytics-dispatch.ts +92 -0
  75. package/src/domains/onboarding/utils/default-storage-key.ts +2 -0
  76. package/src/domains/onboarding/utils/index.ts +13 -0
  77. package/src/domains/onboarding/utils/local-storage-bridge.test.ts +93 -0
  78. package/src/domains/onboarding/utils/local-storage-bridge.ts +104 -0
  79. package/src/domains/onboarding/utils/permission-bridge.test.ts +64 -0
  80. package/src/domains/onboarding/utils/permission-bridge.ts +95 -0
  81. package/src/domains/onboarding/validation/flow-structure-check.ts +28 -0
  82. package/src/domains/onboarding/validation/index.ts +9 -0
  83. package/src/domains/onboarding/validation/permission-status-check.ts +23 -0
  84. package/src/domains/onboarding/validation/screen-config-check.ts +105 -0
  85. package/src/domains/onboarding/validation/stored-progress-check.ts +68 -0
  86. package/src/domains/onboarding/validation/validation.test.ts +175 -0
  87. package/src/index.ts +0 -10
  88. package/src/styles/dashboard.contract.test.ts +1 -0
  89. package/src/styles/dashboard.css +0 -460
  90. package/src/domains/auth/components/AuthLayout.tsx +0 -99
  91. package/src/domains/auth/components/ForgotPasswordForm.tsx +0 -167
  92. package/src/domains/auth/components/LoginForm.tsx +0 -222
  93. package/src/domains/auth/components/RegisterForm.tsx +0 -281
  94. package/src/domains/auth/components/ResetPasswordForm.tsx +0 -173
  95. package/src/domains/auth/components/index.ts +0 -11
  96. package/src/domains/auth/components/shared/AuthErrorBanner.tsx +0 -25
  97. package/src/domains/auth/components/shared/EmailInput.tsx +0 -73
  98. package/src/domains/auth/components/shared/PasswordInput.tsx +0 -100
  99. package/src/domains/auth/components/shared/PasswordStrengthIndicator.tsx +0 -63
  100. package/src/domains/auth/components/shared/SocialLoginButtons.tsx +0 -44
  101. package/src/domains/auth/components/shared/SocialProviderIcons.tsx +0 -48
  102. package/src/domains/auth/components/shared/index.ts +0 -20
  103. package/src/domains/auth/hooks/index.ts +0 -8
  104. package/src/domains/auth/hooks/useAuth.ts +0 -230
  105. package/src/domains/auth/index.ts +0 -62
  106. package/src/domains/auth/types/auth.ts +0 -302
  107. package/src/domains/auth/types/index.ts +0 -25
  108. package/src/domains/auth/utils/auth.test.ts +0 -188
  109. package/src/domains/auth/utils/auth.ts +0 -221
  110. package/src/domains/auth/utils/i18nKeys.ts +0 -109
  111. package/src/domains/auth/utils/index.ts +0 -29
  112. package/src/domains/auth/utils/secureToken.ts +0 -33
  113. package/src/domains/auth/utils/validationKeys.ts +0 -23
  114. package/src/domains/session/DemoLogin.tsx +0 -42
  115. package/src/domains/session/OrgSwitcher.tsx +0 -102
  116. package/src/domains/session/SessionContext.tsx +0 -150
  117. package/src/domains/session/inMemoryAuthAdapter.ts +0 -53
  118. package/src/domains/session/index.ts +0 -18
  119. package/src/domains/session/types.ts +0 -47
  120. package/src/domains/session/utils/i18nKeys.ts +0 -12
@@ -0,0 +1,175 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { checkFlowStructure } from './flow-structure-check';
3
+ import { checkScreenConfig, getRecognizedScreenTypes } from './screen-config-check';
4
+ import { checkStoredProgress } from './stored-progress-check';
5
+ import {
6
+ isRecognizedPermissionStatus,
7
+ normalizePermissionStatus,
8
+ } from './permission-status-check';
9
+ import type { OnboardingScreen } from '../types/screens';
10
+
11
+ // TEST_SCENARIOS.md §23
12
+ const welcome = (id = 'a'): OnboardingScreen => ({
13
+ id,
14
+ type: 'welcome',
15
+ title: 'T',
16
+ });
17
+
18
+ describe('flow-structure-check (§23.1)', () => {
19
+ it('rejects empty flows', () => {
20
+ expect(checkFlowStructure([])).toEqual({
21
+ ok: false,
22
+ reason: 'flow must contain at least one screen',
23
+ });
24
+ });
25
+
26
+ it('rejects duplicate step ids', () => {
27
+ const outcome = checkFlowStructure([welcome('dup'), welcome('dup')]);
28
+ expect(outcome.ok).toBe(false);
29
+ if (!outcome.ok) expect(outcome.reason).toMatch(/duplicate step id/);
30
+ });
31
+
32
+ it('accepts a valid flow and propagates per-screen failures', () => {
33
+ expect(checkFlowStructure([welcome('a'), welcome('b')])).toEqual({ ok: true });
34
+ // goal-question without options fails at the flow level
35
+ const bad = checkFlowStructure([
36
+ welcome('a'),
37
+ { id: 'g', type: 'goal-question', question: 'Q', options: [], onChange: () => undefined },
38
+ ]);
39
+ expect(bad.ok).toBe(false);
40
+ });
41
+ });
42
+
43
+ // TEST_SCENARIOS.md §23.2
44
+ describe('screen-config-check (§23.2)', () => {
45
+ it('rejects malformed screens', () => {
46
+ // @ts-expect-error -- deliberately malformed input (null is not a screen)
47
+ expect(checkScreenConfig(null).ok).toBe(false);
48
+ // @ts-expect-error -- deliberately malformed input (missing id)
49
+ expect(checkScreenConfig({ type: 'welcome' }).ok).toBe(false);
50
+ expect(checkScreenConfig({ id: '', type: 'welcome' } as OnboardingScreen).ok).toBe(false);
51
+ expect(
52
+ checkScreenConfig({ id: 'x', type: 'unknown' } as unknown as OnboardingScreen).ok,
53
+ ).toBe(false);
54
+ expect(
55
+ checkScreenConfig({ id: 'x', type: 'goal-question' } as OnboardingScreen).ok,
56
+ ).toBe(false);
57
+ });
58
+
59
+ it('requires content for content-driven screens', () => {
60
+ expect(
61
+ checkScreenConfig({
62
+ id: 'p',
63
+ type: 'pain-points',
64
+ painPoints: [],
65
+ } as unknown as OnboardingScreen).ok,
66
+ ).toBe(false);
67
+ expect(
68
+ checkScreenConfig({
69
+ id: 't',
70
+ type: 'tinder-cards',
71
+ statements: [],
72
+ } as unknown as OnboardingScreen).ok,
73
+ ).toBe(false);
74
+ expect(
75
+ checkScreenConfig({ id: 'pp', type: 'permission-priming' } as unknown as OnboardingScreen)
76
+ .ok,
77
+ ).toBe(false);
78
+ expect(
79
+ checkScreenConfig({ id: 'w', type: 'paywall', price: 9 } as unknown as OnboardingScreen).ok,
80
+ ).toBe(false);
81
+ });
82
+
83
+ it('accepts a well-formed screen', () => {
84
+ expect(checkScreenConfig(welcome('ok'))).toEqual({ ok: true });
85
+ });
86
+
87
+ it('knows every screen type the orchestrator can render', () => {
88
+ expect(getRecognizedScreenTypes().size).toBe(14);
89
+ });
90
+ });
91
+
92
+ // TEST_SCENARIOS.md §23.3
93
+ describe('stored-progress-check (§23.3)', () => {
94
+ const validPayload = JSON.stringify({
95
+ version: 1,
96
+ currentStep: 2,
97
+ completedSteps: ['a', 'b'],
98
+ collected: { a: { selected: ['x'] } },
99
+ startedAt: '2026-01-01T10:00:00.000Z',
100
+ lastUpdated: '2026-01-01T10:01:00.000Z',
101
+ });
102
+
103
+ it('returns not-ok for missing, corrupt, or future-version payloads', () => {
104
+ expect(checkStoredProgress(null)).toEqual({ ok: false, reason: 'no stored progress' });
105
+ expect(checkStoredProgress('{ malformed').ok).toBe(false);
106
+ const v2 = checkStoredProgress(JSON.stringify({ version: 2 }));
107
+ expect(v2.ok).toBe(false);
108
+ if (!v2.ok) expect(v2.reason).toMatch(/unsupported storage version/);
109
+ });
110
+
111
+ it('rejects shape violations inside an otherwise-valid envelope', () => {
112
+ expect(
113
+ checkStoredProgress(
114
+ JSON.stringify({
115
+ version: 1,
116
+ currentStep: -1,
117
+ completedSteps: [],
118
+ collected: {},
119
+ startedAt: '2026-01-01T10:00:00.000Z',
120
+ lastUpdated: '2026-01-01T10:00:00.000Z',
121
+ }),
122
+ ).ok,
123
+ ).toBe(false);
124
+ expect(
125
+ checkStoredProgress(
126
+ JSON.stringify({
127
+ version: 1,
128
+ currentStep: 0,
129
+ completedSteps: 'nope',
130
+ collected: {},
131
+ startedAt: '2026-01-01T10:00:00.000Z',
132
+ lastUpdated: '2026-01-01T10:00:00.000Z',
133
+ }),
134
+ ).ok,
135
+ ).toBe(false);
136
+ expect(
137
+ checkStoredProgress(
138
+ JSON.stringify({
139
+ version: 1,
140
+ currentStep: 0,
141
+ completedSteps: [],
142
+ collected: {},
143
+ startedAt: 'not a date',
144
+ lastUpdated: '2026-01-01T10:00:00.000Z',
145
+ }),
146
+ ).ok,
147
+ ).toBe(false);
148
+ });
149
+
150
+ it('accepts a valid v1 payload and returns it typed', () => {
151
+ const outcome = checkStoredProgress(validPayload);
152
+ expect(outcome.ok).toBe(true);
153
+ if (outcome.ok) {
154
+ expect(outcome.data.currentStep).toBe(2);
155
+ expect(outcome.data.completedSteps).toEqual(['a', 'b']);
156
+ }
157
+ });
158
+ });
159
+
160
+ // TEST_SCENARIOS.md §23.4
161
+ describe('permission-status-check (§23.4)', () => {
162
+ it('normalizes browser-level permission strings', () => {
163
+ expect(normalizePermissionStatus('granted')).toBe('granted');
164
+ expect(normalizePermissionStatus('denied')).toBe('denied');
165
+ expect(normalizePermissionStatus('default')).toBe('prompt');
166
+ expect(normalizePermissionStatus(null)).toBe('unsupported');
167
+ expect(normalizePermissionStatus('whatever')).toBe('unsupported');
168
+ });
169
+
170
+ it('recognizes exactly the four internal statuses', () => {
171
+ expect(isRecognizedPermissionStatus('prompt')).toBe(true);
172
+ expect(isRecognizedPermissionStatus('revoked')).toBe(false);
173
+ expect(isRecognizedPermissionStatus(42)).toBe(false);
174
+ });
175
+ });
package/src/index.ts CHANGED
@@ -1,16 +1,6 @@
1
1
  export * from './domains/layouts';
2
2
  export * from './domains/settings';
3
3
  export * from './domains/calendar';
4
- export {
5
- AuthLayout,
6
- LoginForm,
7
- RegisterForm,
8
- useAuth,
9
- type LoginCredentials,
10
- type RegisterData,
11
- type User,
12
- } from './domains/auth';
13
-
14
4
  export {
15
5
  useAnalytics,
16
6
  MetricCard,
@@ -1,3 +1,4 @@
1
+ // @vitest-environment node
1
2
  import { readFileSync } from "node:fs";
2
3
  import { describe, expect, it } from "vitest";
3
4
 
@@ -697,165 +697,6 @@
697
697
  margin: var(--udb-space-2) 0;
698
698
  background: var(--color-border);
699
699
  }
700
- .udb-auth {
701
- display: flex;
702
- flex-direction: column;
703
- min-height: 100dvh;
704
- background: var(--color-background);
705
- }
706
- .udb-auth__header {
707
- display: flex;
708
- align-items: center;
709
- justify-content: space-between;
710
- gap: var(--udb-space-3);
711
- padding: var(--udb-space-4) var(--udb-space-6);
712
- }
713
- .udb-auth__brand {
714
- display: flex;
715
- align-items: center;
716
- gap: var(--udb-space-2);
717
- }
718
- .udb-auth__brand-name {
719
- font-size: var(--udb-font-size-lg);
720
- font-weight: var(--font-weight-bold);
721
- letter-spacing: -0.02em;
722
- color: var(--color-foreground);
723
- }
724
- .udb-auth__home-link {
725
- font-size: var(--udb-font-size-md);
726
- color: var(--color-muted-foreground);
727
- text-decoration: none;
728
- }
729
- .udb-auth__home-link:hover {
730
- color: var(--color-foreground);
731
- text-decoration: underline;
732
- }
733
- .udb-auth__main {
734
- display: flex;
735
- flex: 1;
736
- align-items: center;
737
- justify-content: center;
738
- padding: var(--udb-space-6) var(--udb-space-4);
739
- }
740
- .udb-auth__column {
741
- display: flex;
742
- flex-direction: column;
743
- width: 100%;
744
- max-width: 420px;
745
- }
746
- .udb-auth__card {
747
- background: var(--color-card);
748
- border: 1px solid var(--color-border);
749
- border-radius: var(--radius-xl);
750
- box-shadow: var(--shadow-lg);
751
- padding: var(--udb-space-8) var(--udb-space-7);
752
- }
753
- .udb-auth__tagline {
754
- margin: 0 0 var(--udb-space-5);
755
- text-align: center;
756
- font-size: var(--udb-font-size-xs);
757
- font-weight: var(--font-weight-bold);
758
- text-transform: uppercase;
759
- letter-spacing: 0.1em;
760
- color: var(--color-primary);
761
- }
762
- .udb-auth__social {
763
- margin-top: var(--udb-space-5);
764
- }
765
- .udb-auth__footer {
766
- padding: var(--udb-space-4) var(--udb-space-6);
767
- }
768
- .udb-auth__footer-inner {
769
- display: flex;
770
- flex-direction: column;
771
- align-items: center;
772
- gap: var(--udb-space-2);
773
- text-align: center;
774
- font-size: var(--udb-font-size-xs);
775
- color: var(--color-muted-foreground);
776
- }
777
- .udb-auth__footer-inner > p {
778
- margin: 0;
779
- }
780
- .udb-auth__footer-links {
781
- display: flex;
782
- align-items: center;
783
- justify-content: center;
784
- flex-wrap: wrap;
785
- gap: var(--udb-space-4);
786
- }
787
- .udb-auth__footer-link {
788
- font-size: var(--udb-font-size-xs);
789
- color: var(--color-muted-foreground);
790
- text-decoration: none;
791
- }
792
- .udb-auth__footer-link:hover {
793
- color: var(--color-foreground);
794
- text-decoration: underline;
795
- }
796
- .udb-divider-row {
797
- display: flex;
798
- align-items: center;
799
- gap: var(--udb-space-3);
800
- margin: var(--udb-space-5) 0;
801
- }
802
- .udb-divider-row::before,
803
- .udb-divider-row::after {
804
- content: "";
805
- flex: 1;
806
- height: 1px;
807
- background: var(--color-border);
808
- }
809
- .udb-divider-row__label {
810
- font-size: var(--udb-font-size-xs);
811
- font-weight: var(--font-weight-medium);
812
- text-transform: uppercase;
813
- letter-spacing: 0.06em;
814
- color: var(--color-muted-foreground);
815
- white-space: nowrap;
816
- }
817
- .udb-social-grid {
818
- display: grid;
819
- grid-template-columns: repeat(2, minmax(0, 1fr));
820
- gap: var(--udb-space-3);
821
- }
822
- .udb-social-grid__btn {
823
- width: 100%;
824
- }
825
- .udb-social-grid__icon {
826
- width: 16px;
827
- height: 16px;
828
- flex-shrink: 0;
829
- }
830
- .udb-social-btn {
831
- display: inline-flex;
832
- align-items: center;
833
- justify-content: center;
834
- gap: var(--udb-space-2);
835
- height: 40px;
836
- padding: 0 var(--udb-space-3);
837
- border: 1px solid var(--udb-border-strong);
838
- border-radius: var(--radius-md);
839
- background: var(--color-card);
840
- color: var(--color-foreground);
841
- font-family: inherit;
842
- font-size: var(--udb-font-size-md);
843
- font-weight: var(--font-weight-medium);
844
- cursor: pointer;
845
- }
846
- .udb-social-btn:hover {
847
- background: var(--color-muted);
848
- }
849
- .udb-social-btn__icon {
850
- display: inline-flex;
851
- align-items: center;
852
- justify-content: center;
853
- flex-shrink: 0;
854
- }
855
- .udb-social-btn__icon svg {
856
- width: 16px;
857
- height: 16px;
858
- }
859
700
  @keyframes udb-spin {
860
701
  to {
861
702
  transform: rotate(360deg);
@@ -864,271 +705,6 @@
864
705
  .udb-spin {
865
706
  animation: udb-spin 1s linear infinite;
866
707
  }
867
- .udb-form {
868
- display: flex;
869
- flex-direction: column;
870
- gap: var(--udb-space-4);
871
- width: 100%;
872
- }
873
- .udb-form__header {
874
- display: flex;
875
- flex-direction: column;
876
- gap: var(--udb-space-1);
877
- text-align: center;
878
- }
879
- .udb-form__title {
880
- margin: 0;
881
- font-size: var(--udb-font-size-2xl);
882
- font-weight: var(--font-weight-bold);
883
- letter-spacing: -0.02em;
884
- line-height: 1.2;
885
- color: var(--color-foreground);
886
- }
887
- .udb-form__title--lg {
888
- font-size: var(--udb-font-size-3xl);
889
- }
890
- .udb-form__subtitle {
891
- margin: 0;
892
- font-size: var(--udb-font-size-md);
893
- color: var(--color-muted-foreground);
894
- }
895
- .udb-form__subtitle-strong {
896
- color: var(--color-foreground);
897
- font-weight: var(--font-weight-medium);
898
- }
899
- .udb-form__row {
900
- display: flex;
901
- align-items: center;
902
- justify-content: space-between;
903
- gap: var(--udb-space-3);
904
- font-size: var(--udb-font-size-md);
905
- }
906
- .udb-form__footer-text {
907
- margin: 0;
908
- text-align: center;
909
- font-size: var(--udb-font-size-md);
910
- color: var(--color-muted-foreground);
911
- }
912
- .udb-form__group {
913
- display: flex;
914
- flex-direction: column;
915
- gap: var(--udb-space-3);
916
- }
917
- .udb-field {
918
- display: flex;
919
- flex-direction: column;
920
- gap: 6px;
921
- }
922
- .udb-field__label {
923
- font-size: var(--udb-font-size-md);
924
- font-weight: var(--font-weight-medium);
925
- color: var(--color-foreground);
926
- }
927
- .udb-field__required {
928
- margin-left: 2px;
929
- color: var(--color-destructive);
930
- }
931
- .udb-field__error {
932
- margin: 0;
933
- font-size: var(--udb-font-size-sm);
934
- color: var(--color-destructive);
935
- }
936
- .udb-form-alert {
937
- display: flex;
938
- align-items: flex-start;
939
- gap: var(--udb-space-2);
940
- padding: 10px var(--udb-space-3);
941
- border-radius: var(--radius-md);
942
- background: var(--color-destructive-soft, color-mix(in srgb, var(--color-destructive, #dc2626) 10%, transparent));
943
- color: var(--color-destructive);
944
- font-size: var(--udb-font-size-md);
945
- }
946
- .udb-form-alert__icon {
947
- width: 16px;
948
- height: 16px;
949
- flex-shrink: 0;
950
- margin-top: 2px;
951
- }
952
- .udb-check-label {
953
- display: flex;
954
- align-items: center;
955
- gap: var(--udb-space-2);
956
- font-size: var(--udb-font-size-md);
957
- color: var(--color-muted-foreground);
958
- cursor: pointer;
959
- }
960
- .udb-check-label--multiline {
961
- align-items: flex-start;
962
- }
963
- .udb-check-label__text {
964
- flex: 1;
965
- line-height: 1.45;
966
- }
967
- .udb-link-btn {
968
- display: inline;
969
- border: none;
970
- padding: 0;
971
- background: transparent;
972
- font-family: inherit;
973
- font-size: var(--udb-font-size-md);
974
- color: var(--color-primary);
975
- cursor: pointer;
976
- }
977
- .udb-link-btn:hover {
978
- text-decoration: underline;
979
- }
980
- .udb-link-btn:disabled {
981
- pointer-events: none;
982
- opacity: 0.55;
983
- }
984
- .udb-link-btn--strong {
985
- font-weight: 600;
986
- }
987
- .udb-text-link {
988
- color: var(--color-primary);
989
- text-decoration: none;
990
- }
991
- .udb-text-link:hover {
992
- text-decoration: underline;
993
- }
994
- .udb-submit-btn {
995
- width: 100%;
996
- height: 44px;
997
- }
998
- .udb-submit-btn--pill {
999
- height: 48px;
1000
- border-radius: var(--udb-radius-pill);
1001
- }
1002
- .udb-btn__spinner {
1003
- animation: udb-spin 1s linear infinite;
1004
- }
1005
- .udb-password-wrap {
1006
- position: relative;
1007
- width: 100%;
1008
- }
1009
- .udb-input--with-toggle {
1010
- padding-right: 44px;
1011
- }
1012
- .udb-password-toggle {
1013
- position: absolute;
1014
- right: 2px;
1015
- top: 50%;
1016
- transform: translateY(-50%);
1017
- }
1018
- .udb-password-toggle__icon {
1019
- width: 16px;
1020
- height: 16px;
1021
- color: var(--color-muted-foreground);
1022
- }
1023
- .udb-input--error {
1024
- border-color: var(--color-destructive);
1025
- }
1026
- .udb-input--error:focus-visible {
1027
- border-color: var(--color-destructive);
1028
- box-shadow: 0 0 0 3px var(--color-destructive-soft, color-mix(in srgb, var(--color-destructive, #dc2626) 10%, transparent));
1029
- }
1030
- .udb-strength {
1031
- display: flex;
1032
- flex-direction: column;
1033
- gap: 6px;
1034
- margin-top: var(--udb-space-1);
1035
- }
1036
- .udb-strength__bars {
1037
- display: grid;
1038
- grid-template-columns: repeat(4, minmax(0, 1fr));
1039
- gap: var(--udb-space-2);
1040
- }
1041
- .udb-strength__bar {
1042
- height: 4px;
1043
- border-radius: var(--udb-radius-pill);
1044
- background: var(--udb-border-strong);
1045
- transition: background-color 0.2s ease;
1046
- }
1047
- .udb-strength__bar--weak {
1048
- background: var(--color-destructive);
1049
- }
1050
- .udb-strength__bar--fair {
1051
- background: var(--color-warning);
1052
- }
1053
- .udb-strength__bar--good {
1054
- background: var(--color-primary);
1055
- }
1056
- .udb-strength__bar--strong {
1057
- background: var(--color-success);
1058
- }
1059
- .udb-strength__label {
1060
- margin: 0;
1061
- font-size: var(--udb-font-size-xs);
1062
- color: var(--color-muted-foreground);
1063
- }
1064
- .udb-strength__label--weak {
1065
- color: var(--color-destructive);
1066
- }
1067
- .udb-strength__label--fair {
1068
- color: var(--color-warning);
1069
- }
1070
- .udb-strength__label--good {
1071
- color: var(--color-primary);
1072
- }
1073
- .udb-strength__label--strong {
1074
- color: var(--color-success);
1075
- }
1076
- .udb-success-badge {
1077
- display: flex;
1078
- align-items: center;
1079
- justify-content: center;
1080
- width: 48px;
1081
- height: 48px;
1082
- margin: 0 auto var(--udb-space-4);
1083
- border-radius: 50%;
1084
- background: var(--color-success-soft, color-mix(in srgb, var(--color-success, #16a34a) 12%, transparent));
1085
- }
1086
- .udb-success-badge__icon {
1087
- width: 24px;
1088
- height: 24px;
1089
- color: var(--color-success);
1090
- }
1091
- .udb-steps-list {
1092
- display: flex;
1093
- flex-direction: column;
1094
- gap: var(--udb-space-3);
1095
- margin: var(--udb-space-4) 0 0;
1096
- padding: 0;
1097
- list-style: none;
1098
- }
1099
- .udb-steps-list__item {
1100
- display: flex;
1101
- align-items: flex-start;
1102
- gap: var(--udb-space-2);
1103
- font-size: var(--udb-font-size-md);
1104
- color: var(--color-foreground);
1105
- }
1106
- .udb-steps-list__icon {
1107
- width: 16px;
1108
- height: 16px;
1109
- flex-shrink: 0;
1110
- margin-top: 2px;
1111
- color: var(--color-success);
1112
- }
1113
- .udb-back-link {
1114
- display: inline-flex;
1115
- align-items: center;
1116
- gap: 6px;
1117
- margin-top: var(--udb-space-4);
1118
- border: none;
1119
- padding: 0;
1120
- background: transparent;
1121
- font-family: inherit;
1122
- font-size: var(--udb-font-size-md);
1123
- color: var(--color-muted-foreground);
1124
- cursor: pointer;
1125
- }
1126
- .udb-back-link:hover {
1127
- color: var(--color-foreground);
1128
- }
1129
- .udb-back-link__icon {
1130
- width: 14px;
1131
- height: 14px;
1132
708
  }
1133
709
  .udb-settings {
1134
710
  display: flex;
@@ -1616,42 +1192,6 @@
1616
1192
  .udb-table__td--center {
1617
1193
  text-align: center;
1618
1194
  }
1619
- .udb-org {
1620
- display: flex;
1621
- flex-direction: column;
1622
- align-items: flex-start;
1623
- line-height: 1.2;
1624
- }
1625
- .udb-org__name {
1626
- font-size: var(--udb-font-size-md);
1627
- font-weight: var(--font-weight-medium);
1628
- color: var(--color-foreground);
1629
- }
1630
- .udb-org__meta {
1631
- font-size: 10px;
1632
- text-transform: capitalize;
1633
- color: var(--color-muted-foreground);
1634
- }
1635
- .udb-org-menu {
1636
- padding: var(--udb-space-2);
1637
- }
1638
- .udb-org-menu__label {
1639
- flex: 1;
1640
- min-width: 0;
1641
- overflow: hidden;
1642
- text-overflow: ellipsis;
1643
- white-space: nowrap;
1644
- }
1645
- .udb-org-menu__check {
1646
- width: 14px;
1647
- height: 14px;
1648
- color: var(--color-primary);
1649
- }
1650
- .udb-menu__item--active {
1651
- background: var(--color-primary-soft, color-mix(in srgb, var(--color-primary, #2563eb) 10%, transparent));
1652
- color: var(--color-primary);
1653
- font-weight: var(--font-weight-medium);
1654
- }
1655
1195
  .udb-matrix__cell {
1656
1196
  display: inline-flex;
1657
1197
  align-items: center;