react-unified-auth 1.0.2 → 1.0.3

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.
package/dist/index.css ADDED
@@ -0,0 +1,438 @@
1
+ /* Reset and base styles */
2
+ * {
3
+ box-sizing: border-box;
4
+ margin: 0;
5
+ padding: 0;
6
+ }
7
+
8
+ /* Button component styles */
9
+ .usa-button {
10
+ display: inline-flex;
11
+ align-items: center;
12
+ justify-content: center;
13
+ font-weight: 500;
14
+ border-radius: 8px;
15
+ transition: all 0.2s ease;
16
+ border: none;
17
+ cursor: pointer;
18
+ outline: none;
19
+ }
20
+
21
+ .usa-button:disabled {
22
+ opacity: 0.5;
23
+ cursor: not-allowed;
24
+ }
25
+
26
+ .usa-button:focus {
27
+ outline: none;
28
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.5);
29
+ }
30
+
31
+ /* Button variants */
32
+ .usa-button--primary {
33
+ background-color: #2563eb;
34
+ color: white;
35
+ }
36
+
37
+ .usa-button--primary:hover:not(:disabled) {
38
+ background-color: #1d4ed8;
39
+ }
40
+
41
+ .usa-button--secondary {
42
+ background-color: #6b7280;
43
+ color: white;
44
+ }
45
+
46
+ .usa-button--secondary:hover:not(:disabled) {
47
+ background-color: #4b5563;
48
+ }
49
+
50
+ .usa-button--outline {
51
+ border: 2px solid #2563eb;
52
+ background-color: transparent;
53
+ color: #2563eb;
54
+ }
55
+
56
+ .usa-button--outline:hover:not(:disabled) {
57
+ background-color: rgba(37, 99, 235, 0.1);
58
+ }
59
+
60
+ /* Button sizes */
61
+ .usa-button--sm {
62
+ padding: 0.375rem 0.75rem;
63
+ font-size: 0.875rem;
64
+ }
65
+
66
+ .usa-button--md {
67
+ padding: 0.5rem 1rem;
68
+ font-size: 1rem;
69
+ }
70
+
71
+ .usa-button--lg {
72
+ padding: 0.75rem 1.5rem;
73
+ font-size: 1.125rem;
74
+ }
75
+
76
+ .usa-button--full-width {
77
+ width: 100%;
78
+ }
79
+
80
+ /* Loading spinner */
81
+ .usa-loading-spinner {
82
+ display: inline-block;
83
+ width: 1rem;
84
+ height: 1rem;
85
+ border: 2px solid rgba(255, 255, 255, 0.3);
86
+ border-radius: 50%;
87
+ border-top-color: #fff;
88
+ animation: spin 0.8s linear infinite;
89
+ margin-right: 0.5rem;
90
+ }
91
+
92
+ .usa-button--outline .usa-loading-spinner {
93
+ border-color: rgba(37, 99, 235, 0.3);
94
+ border-top-color: #2563eb;
95
+ }
96
+
97
+ @keyframes spin {
98
+ to { transform: rotate(360deg); }
99
+ }
100
+
101
+ /* DynamicForm component styles */
102
+ .usa-form {
103
+ display: flex;
104
+ flex-direction: column;
105
+ gap: 1rem;
106
+ }
107
+
108
+ .usa-form__field-group {
109
+ display: flex;
110
+ flex-direction: column;
111
+ gap: 0.25rem;
112
+ }
113
+
114
+ .usa-form__label {
115
+ font-size: 0.875rem;
116
+ font-weight: 500;
117
+ color: #374151;
118
+ }
119
+
120
+ .usa-form__label--required::after {
121
+ content: " *";
122
+ color: #dc2626;
123
+ }
124
+
125
+ .usa-form__input {
126
+ width: 100%;
127
+ padding: 0.5rem 0.75rem;
128
+ border: 1px solid #d1d5db;
129
+ border-radius: 8px;
130
+ font-size: 1rem;
131
+ transition: all 0.2s ease;
132
+ }
133
+
134
+ .usa-form__input:focus {
135
+ outline: none;
136
+ border-color: #2563eb;
137
+ box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
138
+ }
139
+
140
+ .usa-form__input--error {
141
+ border-color: #dc2626;
142
+ }
143
+
144
+ .usa-form__input--error:focus {
145
+ border-color: #dc2626;
146
+ box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.1);
147
+ }
148
+
149
+ .usa-form__textarea {
150
+ width: 100%;
151
+ padding: 0.5rem 0.75rem;
152
+ border: 1px solid #d1d5db;
153
+ border-radius: 8px;
154
+ font-size: 1rem;
155
+ font-family: inherit;
156
+ resize: vertical;
157
+ transition: all 0.2s ease;
158
+ }
159
+
160
+ .usa-form__textarea:focus {
161
+ outline: none;
162
+ border-color: #2563eb;
163
+ box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
164
+ }
165
+
166
+ .usa-form__select {
167
+ width: 100%;
168
+ padding: 0.5rem 0.75rem;
169
+ border: 1px solid #d1d5db;
170
+ border-radius: 8px;
171
+ font-size: 1rem;
172
+ background-color: white;
173
+ cursor: pointer;
174
+ transition: all 0.2s ease;
175
+ }
176
+
177
+ .usa-form__select:focus {
178
+ outline: none;
179
+ border-color: #2563eb;
180
+ box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
181
+ }
182
+
183
+ .usa-form__checkbox {
184
+ width: 1rem;
185
+ height: 1rem;
186
+ border: 1px solid #d1d5db;
187
+ border-radius: 4px;
188
+ accent-color: #2563eb;
189
+ cursor: pointer;
190
+ }
191
+
192
+ .usa-form__radio {
193
+ width: 1rem;
194
+ height: 1rem;
195
+ border: 1px solid #d1d5db;
196
+ border-radius: 50%;
197
+ accent-color: #2563eb;
198
+ cursor: pointer;
199
+ }
200
+
201
+ .usa-form__radio-group {
202
+ display: flex;
203
+ flex-direction: column;
204
+ gap: 0.5rem;
205
+ }
206
+
207
+ .usa-form__radio-label {
208
+ display: flex;
209
+ align-items: center;
210
+ gap: 0.5rem;
211
+ cursor: pointer;
212
+ }
213
+
214
+ .usa-form__error {
215
+ font-size: 0.75rem;
216
+ color: #dc2626;
217
+ }
218
+
219
+ /* LoginForm component styles */
220
+ .usa-login-form {
221
+ width: 100%;
222
+ }
223
+
224
+ .usa-login-form__loading {
225
+ display: flex;
226
+ justify-content: center;
227
+ align-items: center;
228
+ padding: 2rem;
229
+ }
230
+
231
+ .usa-login-form__error {
232
+ padding: 1rem;
233
+ background-color: #fee2e2;
234
+ border: 1px solid #fecaca;
235
+ border-radius: 8px;
236
+ color: #b91c1c;
237
+ }
238
+
239
+ /* UserInfoBox component styles */
240
+ .usa-user-info-box {
241
+ background-color: white;
242
+ border-radius: 8px;
243
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
244
+ padding: 1.5rem;
245
+ }
246
+
247
+ .usa-user-info-box__header {
248
+ display: flex;
249
+ align-items: center;
250
+ gap: 1rem;
251
+ margin-bottom: 1rem;
252
+ }
253
+
254
+ .usa-user-info-box__avatar {
255
+ width: 4rem;
256
+ height: 4rem;
257
+ border-radius: 50%;
258
+ object-fit: cover;
259
+ }
260
+
261
+ .usa-user-info-box__details {
262
+ flex: 1;
263
+ }
264
+
265
+ .usa-user-info-box__name {
266
+ font-size: 1.125rem;
267
+ font-weight: 600;
268
+ color: #111827;
269
+ }
270
+
271
+ .usa-user-info-box__email {
272
+ font-size: 0.875rem;
273
+ color: #6b7280;
274
+ }
275
+
276
+ /* SocialLogin component styles */
277
+ .usa-social-login {
278
+ display: flex;
279
+ flex-direction: column;
280
+ gap: 0.75rem;
281
+ }
282
+
283
+ .usa-social-login-button {
284
+ display: flex;
285
+ align-items: center;
286
+ justify-content: center;
287
+ gap: 0.5rem;
288
+ }
289
+
290
+ .usa-social-login-button__icon {
291
+ width: 1.25rem;
292
+ height: 1.25rem;
293
+ }
294
+
295
+ /* Utility classes */
296
+ .usa-text-center {
297
+ text-align: center;
298
+ }
299
+
300
+ .usa-mt-4 {
301
+ margin-top: 1rem;
302
+ }
303
+
304
+ .usa-mb-4 {
305
+ margin-bottom: 1rem;
306
+ }
307
+
308
+ .usa-mb-8 {
309
+ margin-bottom: 2rem;
310
+ }
311
+
312
+ .usa-w-full {
313
+ width: 100%;
314
+ }
315
+
316
+ .usa-flex {
317
+ display: flex;
318
+ }
319
+
320
+ .usa-flex-col {
321
+ flex-direction: column;
322
+ }
323
+
324
+ .usa-items-center {
325
+ align-items: center;
326
+ }
327
+
328
+ .usa-justify-center {
329
+ justify-content: center;
330
+ }
331
+
332
+ .usa-space-x-2 {
333
+ gap: 0.5rem;
334
+ }
335
+
336
+ .usa-space-y-2 {
337
+ gap: 0.5rem;
338
+ }
339
+
340
+ .usa-space-y-3 {
341
+ gap: 0.75rem;
342
+ }
343
+
344
+ .usa-space-y-4 {
345
+ gap: 1rem;
346
+ }
347
+
348
+ .usa-space-y-6 {
349
+ gap: 1.5rem;
350
+ }
351
+
352
+ .usa-space-y-8 {
353
+ gap: 2rem;
354
+ }
355
+
356
+ .usa-p-6 {
357
+ padding: 1.5rem;
358
+ }
359
+
360
+ .usa-pt-6 {
361
+ padding-top: 1.5rem;
362
+ }
363
+
364
+ .usa-bg-white {
365
+ background-color: white;
366
+ }
367
+
368
+ .usa-bg-gray-100 {
369
+ background-color: #f3f4f6;
370
+ }
371
+
372
+ .usa-bg-red-50 {
373
+ background-color: #fee2e2;
374
+ }
375
+
376
+ .usa-text-lg {
377
+ font-size: 1.125rem;
378
+ }
379
+
380
+ .usa-text-xl {
381
+ font-size: 1.25rem;
382
+ }
383
+
384
+ .usa-text-2xl {
385
+ font-size: 1.5rem;
386
+ }
387
+
388
+ .usa-text-3xl {
389
+ font-size: 1.875rem;
390
+ }
391
+
392
+ .usa-font-bold {
393
+ font-weight: 700;
394
+ }
395
+
396
+ .usa-font-semibold {
397
+ font-weight: 600;
398
+ }
399
+
400
+ .usa-text-gray-600 {
401
+ color: #6b7280;
402
+ }
403
+
404
+ .usa-text-gray-900 {
405
+ color: #111827;
406
+ }
407
+
408
+ .usa-text-red-600 {
409
+ color: #dc2626;
410
+ }
411
+
412
+ .usa-border-t {
413
+ border-top: 1px solid #e5e7eb;
414
+ }
415
+
416
+ .usa-border {
417
+ border: 1px solid #e5e7eb;
418
+ }
419
+
420
+ .usa-border-red-200 {
421
+ border-color: #fecaca;
422
+ }
423
+
424
+ .usa-rounded-lg {
425
+ border-radius: 8px;
426
+ }
427
+
428
+ .usa-rounded-full {
429
+ border-radius: 50%;
430
+ }
431
+
432
+ .usa-shadow-md {
433
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
434
+ }
435
+
436
+ .usa-shadow-lg {
437
+ box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
438
+ }
package/dist/index.d.ts CHANGED
@@ -1,158 +1,18 @@
1
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import React, { ReactNode } from 'react';
3
- import { AxiosRequestConfig } from 'axios';
4
-
5
- interface AuthConfig {
6
- apiUrl: string;
7
- clientId?: string;
8
- clientSecret?: string;
9
- redirectUri?: string;
10
- scope?: string[];
11
- headers?: Record<string, string>;
12
- timeout?: number;
13
- }
14
- interface FormField {
15
- name: string;
16
- type: 'text' | 'email' | 'password' | 'number' | 'select' | 'checkbox' | 'radio' | 'textarea';
17
- label: string;
18
- placeholder?: string;
19
- required?: boolean;
20
- options?: Array<{
21
- label: string;
22
- value: string;
23
- }>;
24
- validation?: {
25
- pattern?: string;
26
- minLength?: number;
27
- maxLength?: number;
28
- min?: number;
29
- max?: number;
30
- };
31
- }
32
- interface DynamicFormConfig {
33
- fields: FormField[];
34
- submitUrl: string;
35
- method?: 'POST' | 'PUT' | 'PATCH';
36
- submitButton?: {
37
- text: string;
38
- variant?: 'primary' | 'secondary' | 'outline';
39
- };
40
- }
41
- interface UserInfo {
42
- id: string;
43
- name: string;
44
- email?: string;
45
- avatar?: string;
46
- [key: string]: any;
47
- }
48
- interface AuthResponse {
49
- success: boolean;
50
- data?: {
51
- user?: UserInfo;
52
- token?: string;
53
- refreshToken?: string;
54
- };
55
- error?: string;
56
- }
57
- interface SocialProvider {
58
- id: string;
59
- name: string;
60
- icon?: string;
61
- authUrl: string;
62
- scope?: string[];
63
- }
64
-
65
- interface AuthProviderProps {
66
- config: AuthConfig;
67
- children: ReactNode;
68
- }
69
- declare function AuthProvider({ config, children }: AuthProviderProps): react_jsx_runtime.JSX.Element;
70
- declare function useAuthConfig(): AuthConfig;
71
-
72
- declare function useAuth(): {
73
- user: UserInfo | null;
74
- loading: boolean;
75
- error: string | null;
76
- login: (credentials: Record<string, any>) => Promise<AuthResponse>;
77
- logout: () => Promise<void>;
78
- getUserInfo: () => Promise<UserInfo | null>;
79
- isAuthenticated: boolean;
80
- };
81
-
82
- declare function useDynamicForm(formId: string): {
83
- formConfig: DynamicFormConfig | null;
84
- loading: boolean;
85
- error: string | null;
86
- };
87
-
88
- interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
89
- variant?: 'primary' | 'secondary' | 'outline';
90
- size?: 'sm' | 'md' | 'lg';
91
- loading?: boolean;
92
- fullWidth?: boolean;
93
- }
94
- declare function Button({ variant, size, loading, fullWidth, children, disabled, className, ...props }: ButtonProps): react_jsx_runtime.JSX.Element;
95
-
96
- interface DynamicFormProps {
97
- fields: FormField[];
98
- onSubmit: (values: Record<string, any>) => void;
99
- submitText?: string;
100
- submitVariant?: 'primary' | 'secondary' | 'outline';
101
- loading?: boolean;
102
- }
103
- declare function DynamicForm({ fields, onSubmit, submitText, submitVariant, loading, }: DynamicFormProps): react_jsx_runtime.JSX.Element;
104
-
105
- interface LoginFormProps {
106
- formId: string;
107
- onSuccess?: (data: any) => void;
108
- onError?: (error: string) => void;
109
- }
110
- declare function LoginForm({ formId, onSuccess, onError }: LoginFormProps): react_jsx_runtime.JSX.Element | null;
111
-
112
- interface UserInfoBoxProps {
113
- user: UserInfo;
114
- onLogout?: () => void;
115
- loading?: boolean;
116
- className?: string;
117
- }
118
- declare function UserInfoBox({ user, onLogout, loading, className }: UserInfoBoxProps): react_jsx_runtime.JSX.Element;
119
-
120
- interface SocialLoginButtonProps {
121
- provider: SocialProvider;
122
- onClick: (provider: SocialProvider) => void;
123
- loading?: boolean;
124
- className?: string;
125
- }
126
- declare function SocialLoginButton({ provider, onClick, loading, className }: SocialLoginButtonProps): react_jsx_runtime.JSX.Element;
127
- interface SocialLoginProps {
128
- providers: SocialProvider[];
129
- onLogin: (provider: SocialProvider) => void;
130
- loading?: boolean;
131
- className?: string;
132
- }
133
- declare function SocialLogin({ providers, onLogin, loading, className }: SocialLoginProps): react_jsx_runtime.JSX.Element | null;
134
-
135
- declare class ApiClient {
136
- private client;
137
- constructor(config: {
138
- baseURL: string;
139
- timeout?: number;
140
- headers?: Record<string, string>;
141
- });
142
- get<T>(url: string, config?: AxiosRequestConfig): Promise<T>;
143
- post<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
144
- put<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
145
- patch<T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T>;
146
- delete<T>(url: string, config?: AxiosRequestConfig): Promise<T>;
147
- }
148
-
149
- declare function validateField(field: FormField, value: any): {
150
- valid: boolean;
151
- error?: string;
152
- };
153
- declare function validateForm(fields: FormField[], values: Record<string, any>): {
154
- valid: boolean;
155
- errors: Record<string, string>;
156
- };
157
-
158
- export { ApiClient, AuthConfig, AuthProvider, AuthProviderProps, AuthResponse, Button, ButtonProps, DynamicForm, DynamicFormConfig, DynamicFormProps, FormField, LoginForm, LoginFormProps, SocialLogin, SocialLoginButton, SocialLoginButtonProps, SocialLoginProps, SocialProvider, UserInfo, UserInfoBox, UserInfoBoxProps, useAuth, useAuthConfig, useDynamicForm, validateField, validateForm };
1
+ import './styles/index.css';
2
+ export { AuthProvider, useAuthConfig } from './context/AuthContext';
3
+ export { useAuth } from './hooks/useAuth';
4
+ export { useDynamicForm } from './hooks/useDynamicForm';
5
+ export { Button } from './components/Button';
6
+ export { DynamicForm } from './components/DynamicForm';
7
+ export { LoginForm } from './components/LoginForm';
8
+ export { UserInfoBox } from './components/UserInfoBox';
9
+ export { SocialLogin, SocialLoginButton } from './components/SocialLogin';
10
+ export { ApiClient } from './utils/api-client';
11
+ export { validateField, validateForm } from './utils/validation';
12
+ export type { AuthConfig, FormField, DynamicFormConfig, UserInfo, AuthResponse, SocialProvider, } from './types';
13
+ export type { AuthProviderProps } from './context/AuthContext';
14
+ export type { ButtonProps } from './components/Button';
15
+ export type { DynamicFormProps } from './components/DynamicForm';
16
+ export type { LoginFormProps } from './components/LoginForm';
17
+ export type { UserInfoBoxProps } from './components/UserInfoBox';
18
+ export type { SocialLoginProps, SocialLoginButtonProps } from './components/SocialLogin';
@@ -0,0 +1 @@
1
+ *,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }.-ml-1{margin-left:-.25rem}.mb-1{margin-bottom:.25rem}.ml-1{margin-left:.25rem}.mr-2{margin-right:.5rem}.mt-1{margin-top:.25rem}.mt-4{margin-top:1rem}.block{display:block}.flex{display:flex}.inline-flex{display:inline-flex}.h-16{height:4rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-8{height:2rem}.w-16{width:4rem}.w-4{width:1rem}.w-5{width:1.25rem}.w-8{width:2rem}.w-full{width:100%}.flex-1{flex:1 1 0%}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.items-center{align-items:center}.justify-center{justify-content:center}.space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(.5rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(.5rem*var(--tw-space-x-reverse))}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)));margin-right:calc(1rem*var(--tw-space-x-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.5rem*var(--tw-space-y-reverse));margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(.75rem*var(--tw-space-y-reverse));margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1rem*var(--tw-space-y-reverse));margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)))}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.border{border-width:1px}.border-2{border-width:2px}.border-b-2{border-bottom-width:2px}.border-blue-600{--tw-border-opacity:1;border-color:rgb(37 99 235/var(--tw-border-opacity,1))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity,1))}.border-red-200{--tw-border-opacity:1;border-color:rgb(254 202 202/var(--tw-border-opacity,1))}.border-red-500{--tw-border-opacity:1;border-color:rgb(239 68 68/var(--tw-border-opacity,1))}.bg-blue-600{--tw-bg-opacity:1;background-color:rgb(37 99 235/var(--tw-bg-opacity,1))}.bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.object-cover{-o-object-fit:cover;object-fit:cover}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-1\.5{padding-bottom:.375rem;padding-top:.375rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.font-medium{font-weight:500}.font-semibold{font-weight:600}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity,1))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity,1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-red-600{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline{outline-style:solid}.transition-colors{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1)}.hover\:bg-blue-50:hover{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.hover\:bg-blue-700:hover{--tw-bg-opacity:1;background-color:rgb(29 78 216/var(--tw-bg-opacity,1))}.hover\:bg-gray-700:hover{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity,1))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-blue-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(59 130 246/var(--tw-ring-opacity,1))}.focus\:ring-gray-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(107 114 128/var(--tw-ring-opacity,1))}.focus\:ring-red-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(239 68 68/var(--tw-ring-opacity,1))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}