kasy-cli 1.31.14 → 1.34.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 (127) hide show
  1. package/bin/kasy.js +42 -0
  2. package/lib/commands/apple-web.js +222 -0
  3. package/lib/commands/configure.js +3 -91
  4. package/lib/commands/doctor.js +20 -0
  5. package/lib/commands/facebook.js +189 -0
  6. package/lib/commands/new.js +65 -3
  7. package/lib/scaffold/CHANGELOG.json +27 -0
  8. package/lib/scaffold/backends/api/patch/README.md +87 -2
  9. package/lib/scaffold/backends/api/patch/lib/features/authentication/api/authentication_api.dart +34 -0
  10. package/lib/scaffold/backends/api/patch/lib/features/subscriptions/api/stripe_backend_api.dart +12 -2
  11. package/lib/scaffold/backends/firebase/setup-from-scratch.js +186 -0
  12. package/lib/scaffold/backends/supabase/deploy.js +92 -0
  13. package/lib/scaffold/backends/supabase/edge-functions/send-push-notification/README.md +26 -22
  14. package/lib/scaffold/backends/supabase/edge-functions/send-push-notification/index.ts +8 -11
  15. package/lib/scaffold/backends/supabase/edge-functions/stripe-create-checkout-session/index.ts +3 -1
  16. package/lib/scaffold/backends/supabase/edge-functions/stripe-create-portal-session/index.ts +60 -3
  17. package/lib/scaffold/backends/supabase/patch/lib/features/authentication/api/authentication_api.dart +22 -0
  18. package/lib/scaffold/backends/supabase/patch/lib/features/subscriptions/api/stripe_backend_api.dart +12 -2
  19. package/lib/scaffold/backends/supabase/pubspec.yaml.tpl +3 -2
  20. package/lib/scaffold/generate.js +1 -1
  21. package/lib/scaffold/shared/generator-utils.js +34 -3
  22. package/lib/utils/apple-web.js +147 -0
  23. package/lib/utils/facebook.js +162 -0
  24. package/lib/utils/i18n/messages-en.js +64 -0
  25. package/lib/utils/i18n/messages-es.js +64 -0
  26. package/lib/utils/i18n/messages-pt.js +64 -0
  27. package/package.json +2 -2
  28. package/templates/firebase/AGENTS.md +87 -0
  29. package/templates/firebase/CLAUDE.md +16 -0
  30. package/templates/firebase/DESIGN_SYSTEM.md +234 -0
  31. package/templates/firebase/docs/auth-setup.en.md +7 -1
  32. package/templates/firebase/docs/auth-setup.es.md +7 -1
  33. package/templates/firebase/docs/auth-setup.pt.md +7 -1
  34. package/templates/firebase/functions/src/subscriptions/stripe_functions.ts +79 -5
  35. package/templates/firebase/lib/components/components.dart +1 -0
  36. package/templates/firebase/lib/components/kasy_accordion.dart +2 -2
  37. package/templates/firebase/lib/components/kasy_alert.dart +1 -1
  38. package/templates/firebase/lib/components/kasy_app_bar.dart +7 -4
  39. package/templates/firebase/lib/components/kasy_bottom_sheet.dart +1 -1
  40. package/templates/firebase/lib/components/kasy_button.dart +8 -8
  41. package/templates/firebase/lib/components/kasy_chip.dart +1 -1
  42. package/templates/firebase/lib/components/kasy_date_picker.dart +26 -21
  43. package/templates/firebase/lib/components/kasy_dialog.dart +2 -2
  44. package/templates/firebase/lib/components/kasy_screen.dart +114 -0
  45. package/templates/firebase/lib/components/kasy_sidebar.dart +2 -2
  46. package/templates/firebase/lib/components/kasy_tabs.dart +2 -2
  47. package/templates/firebase/lib/components/kasy_text_area.dart +37 -5
  48. package/templates/firebase/lib/components/kasy_text_field.dart +77 -16
  49. package/templates/firebase/lib/components/kasy_toast.dart +39 -70
  50. package/templates/firebase/lib/components/kasy_web_header.dart +4 -3
  51. package/templates/firebase/lib/core/chrome/chrome_visibility.dart +22 -0
  52. package/templates/firebase/lib/core/config/features.dart +18 -0
  53. package/templates/firebase/lib/core/dev_inspector/dev_inspector.dart +21 -0
  54. package/templates/firebase/lib/core/rating/widgets/rate_banner.dart +1 -1
  55. package/templates/firebase/lib/core/rating/widgets/review_popup.dart +46 -124
  56. package/templates/firebase/lib/core/theme/icon_sizes.dart +47 -0
  57. package/templates/firebase/lib/core/theme/shadows.dart +13 -0
  58. package/templates/firebase/lib/core/theme/texts.dart +32 -0
  59. package/templates/firebase/lib/core/theme/theme.dart +2 -0
  60. package/templates/firebase/lib/core/web_device_preview/web_device_preview.dart +3 -0
  61. package/templates/firebase/lib/core/web_viewport_scale.dart +23 -4
  62. package/templates/firebase/lib/core/widgets/update_bottom_sheet.dart +29 -126
  63. package/templates/firebase/lib/features/ai_chat/ai_chat_page.dart +11 -7
  64. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_chat_composer.dart +21 -0
  65. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_list.dart +1 -1
  66. package/templates/firebase/lib/features/ai_chat/ui/widgets/ai_conversation_tile.dart +1 -1
  67. package/templates/firebase/lib/features/authentication/api/authentication_api.dart +61 -0
  68. package/templates/firebase/lib/features/authentication/ui/components/otp_verification.dart +1 -1
  69. package/templates/firebase/lib/features/authentication/ui/components/phone_input.dart +2 -1
  70. package/templates/firebase/lib/features/authentication/ui/recover_password_page.dart +3 -1
  71. package/templates/firebase/lib/features/authentication/ui/signin_page.dart +57 -29
  72. package/templates/firebase/lib/features/authentication/ui/signup_page.dart +47 -25
  73. package/templates/firebase/lib/features/authentication/ui/widgets/recover_password_result.dart +1 -1
  74. package/templates/firebase/lib/features/feedbacks/ui/feedback_page.dart +1 -1
  75. package/templates/firebase/lib/features/feedbacks/ui/widgets/add_feature_button.dart +1 -1
  76. package/templates/firebase/lib/features/feedbacks/ui/widgets/feature_card.dart +2 -3
  77. package/templates/firebase/lib/features/home/home_components_page.dart +7 -1
  78. package/templates/firebase/lib/features/home/home_components_preview_registry.dart +54 -3
  79. package/templates/firebase/lib/features/home/home_image_grid.dart +1 -1
  80. package/templates/firebase/lib/features/local_reminders/ui/reminder_page.dart +165 -209
  81. package/templates/firebase/lib/features/notifications/ui/components/notification_settings_sheet.dart +2 -2
  82. package/templates/firebase/lib/features/notifications/ui/components/notification_tile.dart +21 -8
  83. package/templates/firebase/lib/features/notifications/ui/components/push_notification_switcher.dart +2 -2
  84. package/templates/firebase/lib/features/notifications/ui/notifications_page.dart +3 -6
  85. package/templates/firebase/lib/features/notifications/ui/widgets/empty_notifications.dart +6 -1
  86. package/templates/firebase/lib/features/notifications/ui/widgets/notification_tile.dart +104 -156
  87. package/templates/firebase/lib/features/notifications/ui/widgets/permission_request_view.dart +1 -1
  88. package/templates/firebase/lib/features/onboarding/ui/components/onboarding_loader.dart +1 -1
  89. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_illustration_scaffold.dart +3 -4
  90. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_module_mockups.dart +3 -3
  91. package/templates/firebase/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +2 -4
  92. package/templates/firebase/lib/features/onboarding/ui/widgets/selectable_row_tile.dart +3 -2
  93. package/templates/firebase/lib/features/settings/settings_page.dart +264 -307
  94. package/templates/firebase/lib/features/settings/ui/components/admin/admin_page.dart +17 -8
  95. package/templates/firebase/lib/features/settings/ui/components/avatar_component.dart +4 -4
  96. package/templates/firebase/lib/features/settings/ui/components/edit_name_sheet.dart +115 -0
  97. package/templates/firebase/lib/features/settings/ui/components/language_switcher.dart +2 -2
  98. package/templates/firebase/lib/features/settings/ui/widgets/settings_bottom_sheet_option_tile.dart +1 -1
  99. package/templates/firebase/lib/features/settings/ui/widgets/settings_tile.dart +13 -5
  100. package/templates/firebase/lib/features/subscriptions/api/stripe_backend_api.dart +12 -2
  101. package/templates/firebase/lib/features/subscriptions/api/stripe_payment_api.dart +7 -1
  102. package/templates/firebase/lib/features/subscriptions/providers/premium_page_provider.dart +11 -3
  103. package/templates/firebase/lib/features/subscriptions/ui/component/paywall_row.dart +1 -1
  104. package/templates/firebase/lib/features/subscriptions/ui/widgets/comparison_table.dart +1 -1
  105. package/templates/firebase/lib/features/subscriptions/ui/widgets/feature_line.dart +2 -2
  106. package/templates/firebase/lib/features/subscriptions/ui/widgets/premium_close_button.dart +1 -1
  107. package/templates/firebase/lib/features/subscriptions/ui/widgets/premium_feature.dart +1 -1
  108. package/templates/firebase/lib/features/subscriptions/ui/widgets/selectable_col.dart +3 -3
  109. package/templates/firebase/lib/features/subscriptions/ui/widgets/selectable_row.dart +1 -1
  110. package/templates/firebase/lib/i18n/en.i18n.json +13 -4
  111. package/templates/firebase/lib/i18n/es.i18n.json +13 -4
  112. package/templates/firebase/lib/i18n/pt.i18n.json +13 -4
  113. package/templates/firebase/lib/router.dart +2 -0
  114. package/templates/firebase/pubspec.yaml +1 -2
  115. package/templates/firebase/tool/design_check.dart +152 -0
  116. package/templates/firebase/web/stripe_success.html +64 -26
  117. package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/animations/movefade_anim.dart +0 -34
  118. package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +0 -67
  119. package/lib/scaffold/backends/api/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +0 -183
  120. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/animations/movefade_anim.dart +0 -34
  121. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/components/onboarding_att_setup.dart +0 -67
  122. package/lib/scaffold/backends/supabase/patch/lib/features/onboarding/ui/widgets/onboarding_radio_question.dart +0 -183
  123. package/templates/firebase/assets/images/review.png +0 -0
  124. package/templates/firebase/assets/images/update.png +0 -0
  125. package/templates/firebase/lib/features/authentication/ui/components/facebook_signin.dart +0 -19
  126. package/templates/firebase/lib/features/notifications/ui/components/notifications_header.dart +0 -32
  127. package/templates/firebase/login-redesign-preview.png +0 -0
@@ -1,6 +1,6 @@
1
- import 'package:better_skeleton/better_skeleton.dart';
2
1
  import 'package:flutter/material.dart';
3
2
  import 'package:jiffy/jiffy.dart';
3
+ import 'package:kasy_kit/components/kasy_skeleton.dart';
4
4
  import 'package:kasy_kit/core/theme/theme.dart';
5
5
  import 'package:kasy_kit/core/widgets/kasy_focus_ring.dart';
6
6
  import 'package:kasy_kit/features/notifications/providers/models/notification.dart'
@@ -9,8 +9,13 @@ import 'package:kasy_kit/features/notifications/providers/models/notification.da
9
9
  typedef OnTapNotification = void Function(app.Notification notification);
10
10
 
11
11
  /// A tile for the [NotificationsPage] widget.
12
- class NotificationTile extends StatefulWidget {
13
- final double bgOpacity;
12
+ ///
13
+ /// Renders only the row content (icon + title / body / date + unread dot). The
14
+ /// card surface (elevated [KasyCard]) and the tap/hover feedback live in
15
+ /// [NotificationTileComponent], so a notification reads exactly like a Settings
16
+ /// card. Unread vs read is signalled by the trailing dot and text strength, not
17
+ /// by a tinted background.
18
+ class NotificationTile extends StatelessWidget {
14
19
  final double titleOpacity;
15
20
  final Color titleColor;
16
21
  final Color descriptionColor;
@@ -24,7 +29,6 @@ class NotificationTile extends StatefulWidget {
24
29
 
25
30
  const NotificationTile({
26
31
  super.key,
27
- required this.bgOpacity,
28
32
  required this.titleOpacity,
29
33
  required this.icon,
30
34
  required this.date,
@@ -47,7 +51,6 @@ class NotificationTile extends StatefulWidget {
47
51
  Key? key,
48
52
  }) => NotificationTile(
49
53
  key: key,
50
- bgOpacity: .08,
51
54
  titleOpacity: 1,
52
55
  showUnreadDot: true,
53
56
  icon: imageUrl != null
@@ -72,7 +75,6 @@ class NotificationTile extends StatefulWidget {
72
75
  Key? key,
73
76
  }) => NotificationTile(
74
77
  key: key,
75
- bgOpacity: 0,
76
78
  titleOpacity: .6,
77
79
  icon: imageUrl != null
78
80
  ? TileNotificationImage(url: imageUrl)
@@ -111,124 +113,66 @@ class NotificationTile extends StatefulWidget {
111
113
  onTap: onTap,
112
114
  );
113
115
 
114
- @override
115
- State<NotificationTile> createState() => _NotificationTileState();
116
- }
117
-
118
- class _NotificationTileState extends State<NotificationTile>
119
- with SingleTickerProviderStateMixin {
120
- late final AnimationController _controller;
121
- late Animation<double> _opacityAnimation;
122
-
123
- @override
124
- void initState() {
125
- super.initState();
126
- _controller = AnimationController(
127
- duration: const Duration(milliseconds: 500),
128
- vsync: this,
129
- );
130
- _opacityAnimation = Tween(
131
- begin: 0.0,
132
- end: widget.bgOpacity,
133
- ).animate(CurvedAnimation(parent: _controller, curve: Curves.decelerate));
134
- _controller.forward();
135
- }
136
-
137
- @override
138
- void didUpdateWidget(covariant NotificationTile oldWidget) {
139
- super.didUpdateWidget(oldWidget);
140
- if (oldWidget.bgOpacity != widget.bgOpacity) {
141
- _opacityAnimation = Tween(
142
- begin: oldWidget.bgOpacity,
143
- end: widget.bgOpacity,
144
- ).animate(CurvedAnimation(parent: _controller, curve: Curves.ease));
145
- _controller.forward(from: 0);
146
- }
147
- }
148
-
149
- @override
150
- void dispose() {
151
- _controller.dispose();
152
- super.dispose();
153
- }
154
-
155
116
  @override
156
117
  Widget build(BuildContext context) {
157
- return AnimatedBuilder(
158
- animation: _controller,
159
- builder: (context, child) {
160
- return Container(
161
- decoration: BoxDecoration(
162
- color: context.colors.primary.withValues(
163
- alpha: _opacityAnimation.value,
164
- ),
165
- borderRadius: KasyRadius.smBorderRadius,
166
- ),
167
- padding: const EdgeInsets.all(KasySpacing.md),
168
- child: child,
169
- );
170
- },
171
- child: Row(
172
- crossAxisAlignment: CrossAxisAlignment.start,
173
- children: [
174
- widget.icon,
175
- const SizedBox(width: KasySpacing.smd),
176
- Expanded(
177
- child: Column(
178
- crossAxisAlignment: CrossAxisAlignment.start,
179
- children: [
180
- Flexible(
181
- flex: 0,
182
- child: Text(
183
- widget.title,
184
- style: context.textTheme.labelLarge?.copyWith(
185
- color: widget.titleColor,
118
+ return Row(
119
+ crossAxisAlignment: CrossAxisAlignment.start,
120
+ children: [
121
+ icon,
122
+ const SizedBox(width: KasySpacing.sm),
123
+ Expanded(
124
+ child: Column(
125
+ crossAxisAlignment: CrossAxisAlignment.start,
126
+ children: [
127
+ // Headline row: bold title on the left, timestamp (and the
128
+ // unread dot) pinned to the right — the compact, professional
129
+ // notification layout (Linear / Gmail).
130
+ Row(
131
+ children: [
132
+ Expanded(
133
+ child: Text(
134
+ title,
135
+ style: context.textTheme.titleSmall?.copyWith(
136
+ color: titleColor,
137
+ fontWeight: FontWeight.w700,
138
+ ),
139
+ overflow: TextOverflow.ellipsis,
140
+ maxLines: 1,
186
141
  ),
187
- overflow: TextOverflow.clip,
188
- maxLines: 2,
189
142
  ),
190
- ),
191
- const SizedBox(height: KasySpacing.xs),
192
- Flexible(
193
- flex: 0,
194
- child: Text(
195
- widget.description,
196
- style: context.textTheme.bodyMedium?.copyWith(
197
- color: widget.descriptionColor,
198
- ),
199
- overflow: TextOverflow.ellipsis,
200
- maxLines: 3,
201
- ),
202
- ),
203
- const SizedBox(height: KasySpacing.smd),
204
- Flexible(
205
- flex: 0,
206
- child: Text(
207
- Jiffy.parseFromDateTime(widget.date).fromNow(),
143
+ const SizedBox(width: KasySpacing.sm),
144
+ Text(
145
+ Jiffy.parseFromDateTime(date).fromNow(),
208
146
  style: context.textTheme.bodySmall?.copyWith(
209
- color: widget.dateColor,
147
+ color: dateColor,
210
148
  ),
211
149
  ),
150
+ if (showUnreadDot) ...[
151
+ const SizedBox(width: KasySpacing.sm),
152
+ Container(
153
+ width: 6,
154
+ height: 6,
155
+ decoration: BoxDecoration(
156
+ shape: BoxShape.circle,
157
+ color: context.colors.primary,
158
+ ),
159
+ ),
160
+ ],
161
+ ],
162
+ ),
163
+ const SizedBox(height: KasySpacing.xs),
164
+ Text(
165
+ description,
166
+ style: context.textTheme.bodyMedium?.copyWith(
167
+ color: descriptionColor,
212
168
  ),
213
- ],
214
- ),
215
- ),
216
- if (widget.showUnreadDot) ...[
217
- const SizedBox(width: KasySpacing.sm),
218
- Padding(
219
- padding: const EdgeInsets.only(top: 3),
220
- child: Container(
221
- width: 8,
222
- height: 8,
223
- decoration: BoxDecoration(
224
- shape: BoxShape.circle,
225
- color: context.colors.primary,
226
- ),
169
+ overflow: TextOverflow.ellipsis,
170
+ maxLines: 2,
227
171
  ),
228
- ),
229
- ],
230
- ],
231
- ),
172
+ ],
173
+ ),
174
+ ),
175
+ ],
232
176
  );
233
177
  }
234
178
  }
@@ -269,8 +213,8 @@ class TileNotificationImage extends StatelessWidget {
269
213
  borderRadius: BorderRadius.circular(8),
270
214
  child: Image.network(
271
215
  url,
272
- width: 48,
273
- height: 48,
216
+ width: 36,
217
+ height: 36,
274
218
  fit: BoxFit.cover,
275
219
  errorBuilder: (context, error, stack) =>
276
220
  const TileNotificationIcon(active: false),
@@ -297,8 +241,8 @@ class TileNotificationIcon extends StatelessWidget {
297
241
  ? context.colors.primary
298
242
  : context.colors.onSurface.withValues(alpha: 0.35);
299
243
  return Container(
300
- width: 40,
301
- height: 40,
244
+ width: 36,
245
+ height: 36,
302
246
  decoration: BoxDecoration(
303
247
  color: active
304
248
  ? context.colors.primary.withValues(alpha: 0.12)
@@ -307,54 +251,58 @@ class TileNotificationIcon extends StatelessWidget {
307
251
  ),
308
252
  child: Icon(
309
253
  active ? KasyIcons.notificationActive : KasyIcons.notification,
310
- size: 20,
254
+ size: KasyIconSize.sm,
311
255
  color: color,
312
256
  ),
313
257
  );
314
258
  }
315
259
  }
316
260
 
317
- /// A skeleton for the [NotificationTile] widget.
318
- class NotificationSkeletonTile extends StatefulWidget {
261
+ /// Skeleton placeholder for [NotificationTile], built from the design-system
262
+ /// [KasySkeleton] bones so the loading shimmer matches the kit everywhere and
263
+ /// mirrors the real tile's layout (leading badge + title / body / date lines).
264
+ class NotificationSkeletonTile extends StatelessWidget {
319
265
  const NotificationSkeletonTile({super.key});
320
266
 
321
- @override
322
- State<NotificationSkeletonTile> createState() =>
323
- _NotificationSkeletonTileState();
324
- }
325
-
326
- class _NotificationSkeletonTileState extends State<NotificationSkeletonTile>
327
- with SingleTickerProviderStateMixin {
328
- late final AnimationController animationController;
329
-
330
- @override
331
- void initState() {
332
- super.initState();
333
- animationController = AnimationController(
334
- vsync: this,
335
- duration: const Duration(milliseconds: 1000),
336
- )..repeat();
337
- }
338
-
339
- @override
340
- void deactivate() {
341
- animationController.dispose();
342
- super.deactivate();
343
- }
344
-
345
267
  @override
346
268
  Widget build(BuildContext context) {
347
- return Padding(
348
- padding: const EdgeInsets.only(top: KasySpacing.sm),
349
- child: AnimatedSkeleton(
350
- listenable: animationController,
351
- child: Container(
352
- height: 80,
353
- decoration: BoxDecoration(
354
- color: context.colors.primary.withValues(alpha: .1),
355
- borderRadius: KasyRadius.smBorderRadius,
269
+ return const Padding(
270
+ padding: EdgeInsets.only(top: KasySpacing.sm),
271
+ child: KasySkeletonGroup(
272
+ child: Padding(
273
+ padding: EdgeInsets.symmetric(
274
+ horizontal: KasySpacing.md,
275
+ vertical: KasySpacing.smd,
276
+ ),
277
+ child: Row(
278
+ crossAxisAlignment: CrossAxisAlignment.start,
279
+ children: [
280
+ KasySkeleton(
281
+ width: 36,
282
+ height: 36,
283
+ borderRadius: BorderRadius.all(Radius.circular(10)),
284
+ ),
285
+ SizedBox(width: KasySpacing.sm),
286
+ Expanded(
287
+ child: Column(
288
+ crossAxisAlignment: CrossAxisAlignment.start,
289
+ children: [
290
+ Row(
291
+ children: [
292
+ Expanded(child: KasySkeleton(width: 150, height: 13)),
293
+ SizedBox(width: KasySpacing.sm),
294
+ KasySkeleton(width: 44, height: 10),
295
+ ],
296
+ ),
297
+ SizedBox(height: KasySpacing.sm),
298
+ KasySkeleton(width: double.infinity, height: 11),
299
+ SizedBox(height: KasySpacing.xs),
300
+ KasySkeleton(width: 210, height: 11),
301
+ ],
302
+ ),
303
+ ),
304
+ ],
356
305
  ),
357
- padding: const EdgeInsets.all(KasySpacing.md),
358
306
  ),
359
307
  ),
360
308
  );
@@ -76,7 +76,7 @@ class PermissionRequestView extends StatelessWidget {
76
76
  child: Center(
77
77
  child:
78
78
  illustration ??
79
- KasyBrandBadge(icon: icon, size: 76, glyphSize: 36),
79
+ KasyBrandBadge(icon: icon, size: 76, glyphSize: KasyIconSize.display),
80
80
  ),
81
81
  ),
82
82
  const SizedBox(height: KasySpacing.xl),
@@ -102,7 +102,7 @@ class _PulsingOrb extends StatelessWidget {
102
102
  ),
103
103
  ],
104
104
  ),
105
- child: Icon(KasyIcons.flash, color: colors.onPrimary, size: 34),
105
+ child: Icon(KasyIcons.flash, color: colors.onPrimary, size: KasyIconSize.display),
106
106
  )
107
107
  .animate(onPlay: (c) => c.repeat(reverse: true))
108
108
  .scaleXY(
@@ -93,12 +93,11 @@ class OnboardingIllustrationScaffold extends StatelessWidget {
93
93
  child: Text(
94
94
  title,
95
95
  textAlign: TextAlign.start,
96
+ // Design-system page-title scale (headlineMedium = 24/w700).
97
+ // Previously bumped to 28 with custom tracking, which read as
98
+ // oversized next to the rest of the app.
96
99
  style: context.textTheme.headlineMedium?.copyWith(
97
100
  color: colors.onBackground,
98
- fontSize: 28,
99
- fontWeight: FontWeight.w700,
100
- letterSpacing: -0.3,
101
- height: 1.2,
102
101
  ),
103
102
  ),
104
103
  ),
@@ -283,7 +283,7 @@ class _PlanRow extends StatelessWidget {
283
283
  ),
284
284
  ),
285
285
  child: selected
286
- ? Icon(KasyIcons.check, size: 12, color: colors.onPrimary)
286
+ ? Icon(KasyIcons.check, size: KasyIconSize.xxs, color: colors.onPrimary)
287
287
  : null,
288
288
  ),
289
289
  const SizedBox(width: KasySpacing.smd),
@@ -421,7 +421,7 @@ class _FakeField extends StatelessWidget {
421
421
  ),
422
422
  child: Row(
423
423
  children: [
424
- Icon(icon, size: 16, color: colors.muted),
424
+ Icon(icon, size: KasyIconSize.sm, color: colors.muted),
425
425
  const SizedBox(width: KasySpacing.sm),
426
426
  Text(
427
427
  hint,
@@ -452,7 +452,7 @@ class _SocialChip extends StatelessWidget {
452
452
  borderRadius: KasyRadius.mdBorderRadius,
453
453
  border: Border.all(color: colors.outline),
454
454
  ),
455
- child: Icon(icon, size: 18, color: colors.onSurface),
455
+ child: Icon(icon, size: KasyIconSize.md, color: colors.onSurface),
456
456
  );
457
457
  }
458
458
  }
@@ -71,12 +71,10 @@ class _OnboardingRadioQuestionState
71
71
  child: Text(
72
72
  widget.title,
73
73
  textAlign: TextAlign.start,
74
+ // Design-system page-title scale (headlineMedium = 24/w700),
75
+ // matching the illustration steps instead of a bespoke 26px size.
74
76
  style: context.textTheme.headlineMedium?.copyWith(
75
77
  color: context.colors.onBackground,
76
- fontSize: 26,
77
- fontWeight: FontWeight.w700,
78
- letterSpacing: -0.2,
79
- height: 1.2,
80
78
  ),
81
79
  ),
82
80
  ),
@@ -283,7 +283,8 @@ class _SelectableRowTileState extends State<SelectableRowTile>
283
283
  padding: const EdgeInsets.only(right: KasySpacing.md),
284
284
  child: Text(
285
285
  widget.emoj!,
286
- style: context.textTheme.titleMedium?.copyWith(fontSize: 28),
286
+ style: context.textTheme.titleMedium
287
+ ?.copyWith(fontSize: 28), // design-check: ignore — emoji glyph
287
288
  ),
288
289
  ),
289
290
  ),
@@ -391,7 +392,7 @@ class RoundRadioBox extends StatelessWidget {
391
392
  opacity: iconOpacity,
392
393
  child: Transform.scale(
393
394
  scale: iconSize,
394
- child: Icon(icon, color: context.colors.onPrimary, size: 15),
395
+ child: Icon(icon, color: context.colors.onPrimary, size: KasyIconSize.sm),
395
396
  ),
396
397
  )
397
398
  : const SizedBox.shrink(),