@djangocfg/layouts 2.1.226 → 2.1.228

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 (97) hide show
  1. package/README.md +3 -17
  2. package/package.json +18 -18
  3. package/src/components/errors/ErrorLayout.tsx +2 -2
  4. package/src/components/errors/ErrorsTracker/index.ts +1 -0
  5. package/src/components/errors/ErrorsTracker/utils/formatters.ts +23 -1
  6. package/src/hooks/useLogout.ts +9 -12
  7. package/src/layouts/AppLayout/AppLayout.tsx +20 -8
  8. package/src/layouts/AppLayout/BaseApp.tsx +5 -28
  9. package/src/layouts/AuthLayout/AuthLayout.tsx +51 -22
  10. package/src/layouts/AuthLayout/README.md +78 -0
  11. package/src/layouts/AuthLayout/components/shared/AuthDivider.tsx +2 -2
  12. package/src/layouts/AuthLayout/components/shared/AuthError.tsx +10 -2
  13. package/src/layouts/AuthLayout/components/shared/AuthFooter.tsx +2 -2
  14. package/src/layouts/AuthLayout/components/shared/AuthHeader.tsx +3 -2
  15. package/src/layouts/AuthLayout/components/shared/AuthOTPInput.tsx +4 -1
  16. package/src/layouts/AuthLayout/components/shared/TermsCheckbox.tsx +2 -2
  17. package/src/layouts/AuthLayout/components/shared/index.ts +0 -2
  18. package/src/layouts/AuthLayout/components/steps/IdentifierStep.tsx +25 -80
  19. package/src/layouts/AuthLayout/components/steps/OTPStep.tsx +8 -13
  20. package/src/layouts/AuthLayout/components/steps/SetupStep/SetupComplete.tsx +2 -2
  21. package/src/layouts/AuthLayout/components/steps/SetupStep/SetupLoading.tsx +2 -2
  22. package/src/layouts/AuthLayout/components/steps/SetupStep/SetupQRCode.tsx +2 -2
  23. package/src/layouts/AuthLayout/components/steps/TwoFactorStep.tsx +61 -42
  24. package/src/layouts/AuthLayout/context.tsx +0 -2
  25. package/src/layouts/AuthLayout/index.ts +9 -6
  26. package/src/layouts/AuthLayout/styles/auth.css +265 -120
  27. package/src/layouts/AuthLayout/types.ts +60 -7
  28. package/src/layouts/ProfileLayout/.claude/.sidecar/activity.jsonl +2 -0
  29. package/src/layouts/ProfileLayout/.claude/.sidecar/history/2026-03-15.md +35 -0
  30. package/src/layouts/ProfileLayout/.claude/.sidecar/review.md +35 -0
  31. package/src/layouts/ProfileLayout/.claude/.sidecar/scan.log +3 -0
  32. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-001.md +18 -0
  33. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-002.md +19 -0
  34. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-003.md +18 -0
  35. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-004.md +18 -0
  36. package/src/layouts/ProfileLayout/.claude/.sidecar/tasks/T-005.md +18 -0
  37. package/src/layouts/ProfileLayout/.claude/.sidecar/usage.json +5 -0
  38. package/src/layouts/ProfileLayout/ProfileLayout.tsx +52 -403
  39. package/src/layouts/ProfileLayout/components/ActionButton.tsx +38 -0
  40. package/src/layouts/ProfileLayout/components/DeleteAccountSection.tsx +109 -148
  41. package/src/layouts/ProfileLayout/components/EditableField.tsx +119 -0
  42. package/src/layouts/ProfileLayout/components/Section.tsx +22 -0
  43. package/src/layouts/ProfileLayout/components/index.ts +4 -1
  44. package/src/layouts/ProfileLayout/context.tsx +31 -0
  45. package/src/layouts/PublicLayout/components/PublicMobileDrawer.tsx +2 -2
  46. package/src/layouts/PublicLayout/components/PublicNavigation.tsx +2 -2
  47. package/src/layouts/_components/UserMenu.tsx +2 -2
  48. package/src/layouts/types/README.md +0 -20
  49. package/src/layouts/types/index.ts +2 -2
  50. package/src/layouts/types/layout.types.ts +2 -5
  51. package/src/layouts/types/providers.types.ts +0 -27
  52. package/src/snippets/AuthDialog/AuthDialog.tsx +2 -2
  53. package/src/snippets/Breadcrumbs.tsx +2 -2
  54. package/src/snippets/index.ts +0 -67
  55. package/src/layouts/AuthLayout/components/shared/ChannelToggle.tsx +0 -56
  56. package/src/snippets/McpChat/README.md +0 -441
  57. package/src/snippets/McpChat/components/AIChatWidget.tsx +0 -361
  58. package/src/snippets/McpChat/components/AskAIButton.tsx +0 -92
  59. package/src/snippets/McpChat/components/ChatMessages.tsx +0 -138
  60. package/src/snippets/McpChat/components/ChatPanel.tsx +0 -131
  61. package/src/snippets/McpChat/components/ChatSidebar.tsx +0 -156
  62. package/src/snippets/McpChat/components/ChatWidget.tsx +0 -115
  63. package/src/snippets/McpChat/components/MessageBubble.tsx +0 -142
  64. package/src/snippets/McpChat/components/MessageInput.tsx +0 -140
  65. package/src/snippets/McpChat/components/index.ts +0 -24
  66. package/src/snippets/McpChat/config.ts +0 -94
  67. package/src/snippets/McpChat/context/AIChatContext.tsx +0 -327
  68. package/src/snippets/McpChat/context/ChatContext.tsx +0 -361
  69. package/src/snippets/McpChat/context/index.ts +0 -7
  70. package/src/snippets/McpChat/hooks/index.ts +0 -6
  71. package/src/snippets/McpChat/hooks/useAIChat.ts +0 -503
  72. package/src/snippets/McpChat/hooks/useChatLayout.ts +0 -442
  73. package/src/snippets/McpChat/hooks/useMcpChat.ts +0 -90
  74. package/src/snippets/McpChat/index.ts +0 -79
  75. package/src/snippets/McpChat/types.ts +0 -189
  76. package/src/snippets/PWAInstall/@docs/README.md +0 -92
  77. package/src/snippets/PWAInstall/@docs/research/ios-android-install-flows.md +0 -576
  78. package/src/snippets/PWAInstall/README.md +0 -235
  79. package/src/snippets/PWAInstall/components/A2HSHint.tsx +0 -236
  80. package/src/snippets/PWAInstall/components/DesktopGuide.tsx +0 -234
  81. package/src/snippets/PWAInstall/components/IOSGuide.tsx +0 -29
  82. package/src/snippets/PWAInstall/components/IOSGuideDrawer.tsx +0 -103
  83. package/src/snippets/PWAInstall/components/IOSGuideModal.tsx +0 -103
  84. package/src/snippets/PWAInstall/components/PWAPageResumeManager.tsx +0 -33
  85. package/src/snippets/PWAInstall/context/InstallContext.tsx +0 -102
  86. package/src/snippets/PWAInstall/hooks/useInstallPrompt.ts +0 -168
  87. package/src/snippets/PWAInstall/hooks/useIsPWA.ts +0 -116
  88. package/src/snippets/PWAInstall/hooks/usePWAPageResume.ts +0 -163
  89. package/src/snippets/PWAInstall/index.ts +0 -80
  90. package/src/snippets/PWAInstall/types/components.ts +0 -95
  91. package/src/snippets/PWAInstall/types/config.ts +0 -29
  92. package/src/snippets/PWAInstall/types/index.ts +0 -26
  93. package/src/snippets/PWAInstall/types/install.ts +0 -38
  94. package/src/snippets/PWAInstall/types/platform.ts +0 -29
  95. package/src/snippets/PWAInstall/utils/localStorage.ts +0 -181
  96. package/src/snippets/PWAInstall/utils/logger.ts +0 -149
  97. package/src/snippets/PWAInstall/utils/platform.ts +0 -151
@@ -1,8 +1,9 @@
1
1
  /**
2
- * Auth Layout Styles
2
+ * Auth Layout Styles — Apple HIG
3
3
  *
4
- * Minimal auth-specific styles.
5
- * Uses design system variables from @djangocfg/ui-core.
4
+ * Frameless, centered layout. No visible card/border.
5
+ * Uses system-level typography and spacing rhythm.
6
+ * Design tokens from @djangocfg/ui-core.
6
7
  */
7
8
 
8
9
  /* ===== SPRING EASINGS ===== */
@@ -11,11 +12,15 @@
11
12
  --spring-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
12
13
  --spring-smooth: cubic-bezier(0.16, 1, 0.3, 1);
13
14
  --spring-snappy: cubic-bezier(0.2, 0, 0, 1);
15
+ --auth-radius: 0.75rem;
16
+ --auth-radius-sm: 0.5rem;
17
+ --auth-radius-xs: 0.375rem;
14
18
  }
15
19
 
16
20
  /* ===== LAYOUT ===== */
17
21
 
18
22
  .auth-layout {
23
+ position: relative;
19
24
  min-height: 100vh;
20
25
  min-height: 100dvh;
21
26
  display: flex;
@@ -23,35 +28,43 @@
23
28
  align-items: center;
24
29
  justify-content: center;
25
30
  padding: 1.5rem;
26
- background: hsl(var(--background));
31
+ }
32
+
33
+ /* Glow layer override — force z-index 0 behind auth content */
34
+ .auth-glow-layer {
35
+ z-index: 0;
36
+ pointer-events: none;
37
+ }
38
+
39
+ /* All direct auth content sits above the glow */
40
+ .auth-layout > *:not(.auth-glow-layer) {
41
+ position: relative;
42
+ z-index: 1;
27
43
  }
28
44
 
29
45
  /* ===== CONTAINER ===== */
46
+ /* Apple HIG: No card chrome on auth screens — frameless, content-first */
30
47
 
31
48
  .auth-container {
32
49
  width: 100%;
33
- max-width: 400px;
50
+ max-width: 380px;
34
51
  display: flex;
35
52
  flex-direction: column;
36
- gap: 2rem;
37
- padding: 2rem;
38
- background: hsl(var(--card));
39
- border: 1px solid hsl(var(--border));
40
- border-radius: 1rem;
53
+ gap: 1.25rem;
41
54
  }
42
55
 
43
56
  .auth-container[data-entering="true"] {
44
- animation: authFadeIn 0.4s var(--spring-smooth) forwards;
57
+ animation: authSlideIn 0.45s var(--spring-smooth) both;
45
58
  }
46
59
 
47
- @keyframes authFadeIn {
60
+ @keyframes authSlideIn {
48
61
  from {
49
62
  opacity: 0;
50
- transform: translateY(20px);
63
+ transform: translateY(12px) scale(0.99);
51
64
  }
52
65
  to {
53
66
  opacity: 1;
54
- transform: translateY(0);
67
+ transform: translateY(0) scale(1);
55
68
  }
56
69
  }
57
70
 
@@ -62,28 +75,43 @@
62
75
  display: flex;
63
76
  flex-direction: column;
64
77
  align-items: center;
65
- gap: 0.5rem;
78
+ gap: 0.375rem;
66
79
  }
67
80
 
68
81
  .auth-logo {
69
- width: 64px;
70
- height: 64px;
71
- margin-bottom: 0.5rem;
82
+ width: 56px;
83
+ height: 56px;
84
+ margin-bottom: 0.75rem;
72
85
  object-fit: contain;
86
+ border-radius: 14px; /* iOS app icon radius */
87
+ animation: authLogoIn 0.5s var(--spring-bounce) both;
88
+ }
89
+
90
+ @keyframes authLogoIn {
91
+ from {
92
+ opacity: 0;
93
+ transform: scale(0.7);
94
+ }
95
+ to {
96
+ opacity: 1;
97
+ transform: scale(1);
98
+ }
73
99
  }
74
100
 
75
101
  .auth-title {
76
- font-size: 1.5rem;
77
- font-weight: 600;
78
- line-height: 1.2;
102
+ font-size: 1.625rem;
103
+ font-weight: 700;
104
+ line-height: 1.15;
105
+ letter-spacing: -0.025em;
79
106
  color: hsl(var(--foreground));
80
107
  margin: 0;
81
108
  }
82
109
 
83
110
  .auth-subtitle {
84
111
  font-size: 0.9375rem;
112
+ line-height: 1.5;
85
113
  color: hsl(var(--muted-foreground));
86
- margin: 0;
114
+ margin: 0.125rem 0 0;
87
115
  }
88
116
 
89
117
  .auth-identifier {
@@ -96,25 +124,27 @@
96
124
  .auth-form-group {
97
125
  display: flex;
98
126
  flex-direction: column;
99
- gap: 1rem;
127
+ gap: 0.875rem;
100
128
  }
101
129
 
102
130
  .auth-input {
103
131
  width: 100%;
104
132
  height: 3rem;
105
- padding: 0 1rem;
133
+ padding: 0 0.875rem;
106
134
  font-size: 0.9375rem;
107
135
  background: hsl(var(--input));
108
136
  border: 1px solid hsl(var(--border));
109
- border-radius: 0.5rem;
137
+ border-radius: var(--auth-radius-sm);
110
138
  color: hsl(var(--foreground));
111
- transition: border-color 0.2s, box-shadow 0.2s;
139
+ transition:
140
+ border-color 0.18s var(--spring-snappy),
141
+ box-shadow 0.18s var(--spring-snappy);
112
142
  }
113
143
 
114
144
  .auth-input:focus {
115
145
  outline: none;
116
146
  border-color: hsl(var(--ring));
117
- box-shadow: 0 0 0 3px hsl(var(--ring) / 0.1);
147
+ box-shadow: 0 0 0 3px hsl(var(--ring) / 0.12);
118
148
  }
119
149
 
120
150
  .auth-input:disabled {
@@ -123,24 +153,27 @@
123
153
  }
124
154
 
125
155
  .auth-input::placeholder {
126
- color: hsl(var(--muted-foreground));
156
+ color: hsl(var(--muted-foreground) / 0.6);
127
157
  }
128
158
 
129
159
  /* Phone input */
130
160
  .auth-phone-input .PhoneInputInput {
131
161
  height: 3rem;
132
- padding: 0 1rem;
162
+ padding: 0 0.875rem;
133
163
  font-size: 0.9375rem;
134
164
  background: hsl(var(--input));
135
165
  border: 1px solid hsl(var(--border));
136
- border-radius: 0.5rem;
166
+ border-radius: var(--auth-radius-sm);
137
167
  color: hsl(var(--foreground));
168
+ transition:
169
+ border-color 0.18s var(--spring-snappy),
170
+ box-shadow 0.18s var(--spring-snappy);
138
171
  }
139
172
 
140
173
  .auth-phone-input .PhoneInputInput:focus {
141
174
  outline: none;
142
175
  border-color: hsl(var(--ring));
143
- box-shadow: 0 0 0 3px hsl(var(--ring) / 0.1);
176
+ box-shadow: 0 0 0 3px hsl(var(--ring) / 0.12);
144
177
  }
145
178
 
146
179
  /* ===== BUTTONS ===== */
@@ -153,19 +186,24 @@
153
186
  justify-content: center;
154
187
  gap: 0.5rem;
155
188
  font-size: 0.9375rem;
156
- font-weight: 500;
157
- border-radius: 0.5rem;
189
+ font-weight: 600;
190
+ letter-spacing: -0.01em;
191
+ border-radius: var(--auth-radius-sm);
158
192
  border: none;
159
193
  cursor: pointer;
160
- transition: opacity 0.15s, transform 0.15s;
194
+ transition:
195
+ opacity 0.15s,
196
+ transform 0.12s var(--spring-snappy),
197
+ background-color 0.15s;
198
+ -webkit-tap-highlight-color: transparent;
161
199
  }
162
200
 
163
201
  .auth-button:active:not(:disabled) {
164
- transform: scale(0.98);
202
+ transform: scale(0.975);
165
203
  }
166
204
 
167
205
  .auth-button:disabled {
168
- opacity: 0.5;
206
+ opacity: 0.45;
169
207
  cursor: not-allowed;
170
208
  }
171
209
 
@@ -174,38 +212,36 @@
174
212
  color: hsl(var(--primary-foreground));
175
213
  }
176
214
 
177
- .auth-button-primary:hover:not(:disabled) {
178
- opacity: 0.9;
179
- }
180
-
181
215
  .auth-button-secondary {
182
216
  background: hsl(var(--secondary));
183
217
  color: hsl(var(--secondary-foreground));
218
+ border: none;
184
219
  }
185
220
 
186
- .auth-button-secondary:hover:not(:disabled) {
187
- opacity: 0.9;
221
+ .auth-button:hover:not(:disabled) {
222
+ opacity: 0.88;
188
223
  }
189
224
 
190
225
  /* Loading state */
191
226
  .auth-button-loading {
192
227
  color: transparent !important;
193
228
  position: relative;
229
+ pointer-events: none;
194
230
  }
195
231
 
196
- .auth-button-loading::before {
232
+ .auth-button-loading::after {
197
233
  content: "";
198
234
  position: absolute;
199
- width: 1.25rem;
200
- height: 1.25rem;
235
+ width: 1.125rem;
236
+ height: 1.125rem;
201
237
  border: 2px solid currentColor;
202
238
  border-right-color: transparent;
203
239
  border-radius: 50%;
204
- animation: authSpin 0.6s linear infinite;
240
+ animation: authSpin 0.55s linear infinite;
205
241
  }
206
242
 
207
- .auth-button-primary.auth-button-loading::before {
208
- border-color: hsl(var(--primary-foreground));
243
+ .auth-button-primary.auth-button-loading::after {
244
+ border-color: hsl(var(--primary-foreground) / 0.7);
209
245
  border-right-color: transparent;
210
246
  }
211
247
 
@@ -218,9 +254,11 @@
218
254
  .auth-divider {
219
255
  display: flex;
220
256
  align-items: center;
221
- gap: 1rem;
257
+ gap: 0.75rem;
222
258
  color: hsl(var(--muted-foreground));
223
- font-size: 0.8125rem;
259
+ font-size: 0.75rem;
260
+ letter-spacing: 0.02em;
261
+ text-transform: uppercase;
224
262
  }
225
263
 
226
264
  .auth-divider::before,
@@ -238,20 +276,22 @@
238
276
  align-items: center;
239
277
  gap: 0.25rem;
240
278
  font-size: 0.875rem;
279
+ font-weight: 500;
241
280
  color: hsl(var(--primary));
242
281
  background: none;
243
282
  border: none;
244
283
  padding: 0;
245
284
  cursor: pointer;
246
285
  transition: opacity 0.15s;
286
+ -webkit-tap-highlight-color: transparent;
247
287
  }
248
288
 
249
289
  .auth-link:hover {
250
- opacity: 0.8;
290
+ opacity: 0.75;
251
291
  }
252
292
 
253
293
  .auth-link:disabled {
254
- opacity: 0.5;
294
+ opacity: 0.45;
255
295
  cursor: not-allowed;
256
296
  }
257
297
 
@@ -264,21 +304,28 @@
264
304
  /* ===== ERROR ===== */
265
305
 
266
306
  .auth-error {
267
- padding: 0.75rem 1rem;
268
- font-size: 0.875rem;
307
+ display: flex;
308
+ align-items: center;
309
+ gap: 0.375rem;
310
+ font-size: 0.8125rem;
311
+ line-height: 1.4;
269
312
  color: hsl(var(--destructive));
270
- background: hsl(var(--destructive) / 0.1);
271
- border: 1px solid hsl(var(--destructive) / 0.2);
272
- border-radius: 0.5rem;
273
- animation: authShake 0.4s ease;
313
+ animation: authShake 0.38s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
314
+ }
315
+
316
+ .auth-error-icon {
317
+ flex-shrink: 0;
318
+ width: 1rem;
319
+ height: 1rem;
320
+ margin-top: 0.1rem;
321
+ opacity: 0.85;
274
322
  }
275
323
 
276
324
  @keyframes authShake {
277
- 0%, 100% { transform: translateX(0); }
278
- 20% { transform: translateX(-6px); }
279
- 40% { transform: translateX(6px); }
280
- 60% { transform: translateX(-4px); }
281
- 80% { transform: translateX(4px); }
325
+ 10%, 90% { transform: translateX(-2px); }
326
+ 20%, 80% { transform: translateX(4px); }
327
+ 30%, 50%, 70% { transform: translateX(-5px); }
328
+ 40%, 60% { transform: translateX(5px); }
282
329
  }
283
330
 
284
331
  /* ===== FOOTER ===== */
@@ -287,13 +334,14 @@
287
334
  display: flex;
288
335
  justify-content: center;
289
336
  gap: 0.75rem;
290
- font-size: 0.8125rem;
337
+ font-size: 0.75rem;
291
338
  color: hsl(var(--muted-foreground));
292
339
  }
293
340
 
294
341
  .auth-footer a {
295
342
  color: inherit;
296
343
  text-decoration: none;
344
+ transition: color 0.15s;
297
345
  }
298
346
 
299
347
  .auth-footer a:hover {
@@ -301,7 +349,7 @@
301
349
  }
302
350
 
303
351
  .auth-footer-dot {
304
- opacity: 0.3;
352
+ opacity: 0.25;
305
353
  }
306
354
 
307
355
  /* ===== TERMS ===== */
@@ -309,33 +357,57 @@
309
357
  .auth-terms {
310
358
  display: flex;
311
359
  align-items: flex-start;
312
- gap: 0.75rem;
313
- font-size: 0.875rem;
360
+ gap: 0.625rem;
361
+ font-size: 0.8125rem;
362
+ line-height: 1.5;
314
363
  color: hsl(var(--muted-foreground));
315
364
  }
316
365
 
317
366
  .auth-terms-checkbox {
318
- margin-top: 2px;
367
+ margin-top: 0.125rem;
319
368
  flex-shrink: 0;
320
369
  }
321
370
 
322
371
  .auth-terms a {
323
372
  color: hsl(var(--primary));
324
373
  text-decoration: none;
374
+ transition: opacity 0.15s;
325
375
  }
326
376
 
327
377
  .auth-terms a:hover {
328
- opacity: 0.8;
378
+ opacity: 0.75;
379
+ }
380
+
381
+ /* ===== REMEMBER ME ===== */
382
+
383
+ .auth-remember {
384
+ display: flex;
385
+ align-items: center;
386
+ gap: 0.625rem;
387
+ font-size: 0.875rem;
388
+ color: hsl(var(--foreground));
389
+ cursor: pointer;
390
+ user-select: none;
391
+ }
392
+
393
+ .auth-remember-checkbox {
394
+ flex-shrink: 0;
395
+ }
396
+
397
+ .auth-remember-label {
398
+ font-weight: 400;
399
+ cursor: pointer;
329
400
  }
330
401
 
331
402
  /* ===== CHANNEL TOGGLE ===== */
403
+ /* Apple HIG segmented control */
332
404
 
333
405
  .auth-channel-toggle {
334
406
  display: flex;
335
- padding: 4px;
407
+ padding: 3px;
336
408
  background: hsl(var(--muted));
337
- border-radius: 0.5rem;
338
- gap: 4px;
409
+ border-radius: var(--auth-radius-sm);
410
+ gap: 2px;
339
411
  }
340
412
 
341
413
  .auth-channel-option {
@@ -344,26 +416,39 @@
344
416
  align-items: center;
345
417
  justify-content: center;
346
418
  gap: 0.375rem;
347
- padding: 0.5rem 1rem;
348
- font-size: 0.875rem;
419
+ padding: 0.4375rem 1rem;
420
+ font-size: 0.8125rem;
349
421
  font-weight: 500;
422
+ letter-spacing: -0.005em;
350
423
  color: hsl(var(--muted-foreground));
351
424
  background: transparent;
352
425
  border: none;
353
- border-radius: 0.375rem;
426
+ border-radius: calc(var(--auth-radius-sm) - 2px);
354
427
  cursor: pointer;
355
- transition: all 0.2s;
428
+ transition:
429
+ color 0.2s,
430
+ background 0.2s,
431
+ box-shadow 0.2s;
432
+ -webkit-tap-highlight-color: transparent;
356
433
  }
357
434
 
358
435
  .auth-channel-option[data-active="true"] {
359
436
  color: hsl(var(--foreground));
360
- background: hsl(var(--card));
361
- box-shadow: 0 1px 2px hsl(0 0% 0% / 0.05);
437
+ background: hsl(var(--background));
438
+ box-shadow:
439
+ 0 1px 3px hsl(0 0% 0% / 0.08),
440
+ 0 0 0 0.5px hsl(var(--border));
441
+ }
442
+
443
+ .auth-channel-option:disabled {
444
+ opacity: 0.45;
445
+ cursor: not-allowed;
362
446
  }
363
447
 
364
448
  .auth-channel-option svg {
365
- width: 1rem;
366
- height: 1rem;
449
+ width: 0.875rem;
450
+ height: 0.875rem;
451
+ flex-shrink: 0;
367
452
  }
368
453
 
369
454
  /* ===== OTP INPUT ===== */
@@ -371,34 +456,40 @@
371
456
  .auth-otp-container {
372
457
  display: flex;
373
458
  justify-content: center;
459
+ width: 100%;
374
460
  }
375
461
 
376
462
  .auth-otp-wrapper {
377
463
  display: flex;
378
- gap: 0.5rem;
464
+ gap: 0.375rem;
465
+ width: 100%;
379
466
  }
380
467
 
468
+
381
469
  .auth-otp-wrapper input {
382
470
  width: 3rem;
383
471
  height: 3.5rem;
384
- font-size: 1.25rem;
385
- font-weight: 500;
472
+ font-size: 1.375rem;
473
+ font-weight: 600;
386
474
  text-align: center;
475
+ letter-spacing: -0.01em;
387
476
  background: hsl(var(--input));
388
477
  border: 1px solid hsl(var(--border));
389
- border-radius: 0.5rem;
478
+ border-radius: var(--auth-radius-sm);
390
479
  color: hsl(var(--foreground));
391
- transition: border-color 0.2s, box-shadow 0.2s;
480
+ transition:
481
+ border-color 0.18s,
482
+ box-shadow 0.18s;
392
483
  }
393
484
 
394
485
  .auth-otp-wrapper input:focus {
395
486
  outline: none;
396
487
  border-color: hsl(var(--ring));
397
- box-shadow: 0 0 0 3px hsl(var(--ring) / 0.1);
488
+ box-shadow: 0 0 0 3px hsl(var(--ring) / 0.12);
398
489
  }
399
490
 
400
491
  .auth-otp-wrapper input:disabled {
401
- opacity: 0.5;
492
+ opacity: 0.45;
402
493
  }
403
494
 
404
495
  /* ===== QR CODE ===== */
@@ -406,14 +497,14 @@
406
497
  .auth-qr-container {
407
498
  display: flex;
408
499
  justify-content: center;
409
- padding: 1rem 0;
500
+ padding: 0.75rem 0;
410
501
  }
411
502
 
412
503
  .auth-qr {
413
- padding: 1rem;
504
+ padding: 0.875rem;
414
505
  background: white;
415
- border-radius: 0.5rem;
416
- box-shadow: 0 2px 8px hsl(0 0% 0% / 0.08);
506
+ border-radius: var(--auth-radius);
507
+ box-shadow: 0 2px 12px hsl(0 0% 0% / 0.1);
417
508
  }
418
509
 
419
510
  /* ===== SECRET CODE ===== */
@@ -423,16 +514,16 @@
423
514
  flex-direction: column;
424
515
  align-items: center;
425
516
  gap: 0.5rem;
426
- padding: 1rem;
517
+ padding: 0.75rem;
427
518
  }
428
519
 
429
520
  .auth-secret {
430
- padding: 0.5rem 1rem;
431
- font-family: ui-monospace, monospace;
521
+ padding: 0.5rem 0.875rem;
522
+ font-family: ui-monospace, 'SF Mono', monospace;
432
523
  font-size: 0.8125rem;
433
- letter-spacing: 0.05em;
524
+ letter-spacing: 0.08em;
434
525
  background: hsl(var(--muted));
435
- border-radius: 0.375rem;
526
+ border-radius: var(--auth-radius-xs);
436
527
  color: hsl(var(--foreground));
437
528
  word-break: break-all;
438
529
  text-align: center;
@@ -443,18 +534,19 @@
443
534
  .auth-backup-codes {
444
535
  display: grid;
445
536
  grid-template-columns: repeat(2, 1fr);
446
- gap: 0.5rem;
447
- padding: 1rem;
448
- background: hsl(var(--muted) / 0.5);
537
+ gap: 0.375rem;
538
+ padding: 0.875rem;
539
+ background: hsl(var(--muted) / 0.4);
449
540
  border: 1px dashed hsl(var(--border));
450
- border-radius: 0.5rem;
541
+ border-radius: var(--auth-radius-sm);
451
542
  }
452
543
 
453
544
  .auth-backup-code {
454
- font-family: ui-monospace, monospace;
545
+ font-family: ui-monospace, 'SF Mono', monospace;
455
546
  font-size: 0.8125rem;
547
+ letter-spacing: 0.05em;
456
548
  text-align: center;
457
- padding: 0.5rem;
549
+ padding: 0.375rem;
458
550
  color: hsl(var(--foreground));
459
551
  }
460
552
 
@@ -468,39 +560,45 @@
468
560
  justify-content: center;
469
561
  background: hsl(var(--background));
470
562
  z-index: 50;
471
- animation: authFadeIn 0.3s ease-out;
563
+ animation: authFadeIn 0.25s var(--spring-snappy) both;
564
+ }
565
+
566
+ @keyframes authFadeIn {
567
+ from { opacity: 0; }
568
+ to { opacity: 1; }
472
569
  }
473
570
 
474
571
  .auth-success-content {
475
572
  display: flex;
476
573
  flex-direction: column;
477
574
  align-items: center;
478
- gap: 1.5rem;
575
+ gap: 1.25rem;
479
576
  }
480
577
 
481
578
  .auth-success-logo {
482
- width: 80px;
483
- height: 80px;
579
+ width: 72px;
580
+ height: 72px;
484
581
  object-fit: contain;
485
- animation: authSuccessIn 0.5s var(--spring-bounce);
582
+ border-radius: 16px;
583
+ animation: authSuccessIn 0.5s var(--spring-bounce) both;
486
584
  }
487
585
 
488
586
  .auth-success-check {
489
- width: 80px;
490
- height: 80px;
587
+ width: 72px;
588
+ height: 72px;
491
589
  display: flex;
492
590
  align-items: center;
493
591
  justify-content: center;
494
592
  background: hsl(142 76% 36% / 0.1);
495
593
  border-radius: 50%;
496
594
  color: hsl(142 76% 36%);
497
- animation: authSuccessIn 0.5s var(--spring-bounce);
595
+ animation: authSuccessIn 0.5s var(--spring-bounce) both;
498
596
  }
499
597
 
500
598
  @keyframes authSuccessIn {
501
599
  from {
502
600
  opacity: 0;
503
- transform: scale(0.5);
601
+ transform: scale(0.4);
504
602
  }
505
603
  to {
506
604
  opacity: 1;
@@ -509,13 +607,55 @@
509
607
  }
510
608
 
511
609
  .auth-success-check svg {
512
- width: 40px;
513
- height: 40px;
610
+ width: 36px;
611
+ height: 36px;
514
612
  }
515
613
 
516
614
  .auth-success-text {
517
615
  font-size: 0.9375rem;
616
+ font-weight: 500;
518
617
  color: hsl(var(--muted-foreground));
618
+ animation: authFadeIn 0.4s 0.15s var(--spring-smooth) both;
619
+ }
620
+
621
+ /* ===== 2FA BOX ===== */
622
+ /* Visual differentiation for the two-factor step */
623
+
624
+ .auth-2fa-box {
625
+ padding: 1.5rem 1.25rem 1.25rem;
626
+ background: hsl(var(--card, var(--muted) / 0.25));
627
+ border: 1px solid hsl(var(--border));
628
+ border-radius: var(--auth-radius);
629
+ box-shadow:
630
+ 0 2px 12px hsl(0 0% 0% / 0.08),
631
+ 0 0 0 1px hsl(var(--border) / 0.4) inset;
632
+ display: flex;
633
+ flex-direction: column;
634
+ gap: 1.125rem;
635
+ }
636
+
637
+ .auth-2fa-shield {
638
+ display: flex;
639
+ align-items: center;
640
+ justify-content: center;
641
+ width: 2.75rem;
642
+ height: 2.75rem;
643
+ margin: 0 auto;
644
+ border-radius: 50%;
645
+ background: hsl(var(--primary) / 0.1);
646
+ color: hsl(var(--primary));
647
+ animation: authLogoIn 0.5s var(--spring-bounce) both;
648
+ }
649
+
650
+ .auth-2fa-shield svg {
651
+ width: 1.375rem;
652
+ height: 1.375rem;
653
+ }
654
+
655
+ /* Actions row inside 2fa box — allow wrapping on very narrow screens */
656
+ .auth-2fa-box .auth-actions {
657
+ flex-wrap: wrap;
658
+ row-gap: 0.625rem;
519
659
  }
520
660
 
521
661
  /* ===== DEV NOTICE ===== */
@@ -526,7 +666,7 @@
526
666
  text-align: center;
527
667
  color: hsl(38 92% 40%);
528
668
  background: hsl(38 92% 95%);
529
- border-radius: 0.375rem;
669
+ border-radius: var(--auth-radius-xs);
530
670
  border: 1px solid hsl(38 92% 80%);
531
671
  }
532
672
 
@@ -540,6 +680,7 @@
540
680
 
541
681
  .auth-instruction {
542
682
  font-size: 0.875rem;
683
+ line-height: 1.5;
543
684
  color: hsl(var(--muted-foreground));
544
685
  text-align: center;
545
686
  margin: 0;
@@ -548,23 +689,27 @@
548
689
  /* ===== RESPONSIVE ===== */
549
690
 
550
691
  @media (max-width: 480px) {
692
+ /* Apple HIG: auth content anchored to the bottom — action area in thumb reach zone.
693
+ overflow-y: auto allows scrolling when keyboard pushes content up. */
551
694
  .auth-layout {
552
- padding: 1rem;
695
+ padding: 1.25rem 1.25rem;
696
+ padding-bottom: max(2rem, env(safe-area-inset-bottom, 1.5rem));
697
+ justify-content: flex-end;
698
+ overflow-y: auto;
553
699
  }
554
700
 
555
701
  .auth-container {
556
- padding: 1.5rem;
557
702
  gap: 1.5rem;
558
703
  }
559
704
 
560
705
  .auth-title {
561
- font-size: 1.25rem;
706
+ font-size: 1.375rem;
562
707
  }
563
708
 
564
709
  .auth-otp-wrapper input {
565
- width: 2.75rem;
566
- height: 3rem;
567
- font-size: 1rem;
710
+ width: 2.625rem;
711
+ height: 3.25rem;
712
+ font-size: 1.125rem;
568
713
  }
569
714
  }
570
715