create-brainerce-store 1.27.5 → 1.28.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 (35) hide show
  1. package/dist/index.js +95 -22
  2. package/messages/en.json +12 -1
  3. package/messages/he.json +12 -1
  4. package/package.json +1 -1
  5. package/templates/nextjs/base/.env.local.ejs +3 -3
  6. package/templates/nextjs/base/next.config.ts +13 -12
  7. package/templates/nextjs/base/package.json.ejs +2 -1
  8. package/templates/nextjs/base/src/app/api/auth/logout/route.ts +15 -14
  9. package/templates/nextjs/base/src/app/api/auth/oauth-callback/route.ts +66 -59
  10. package/templates/nextjs/base/src/app/api/auth/reset-password/route.ts +76 -77
  11. package/templates/nextjs/base/src/app/api/store/[...path]/route.ts +229 -198
  12. package/templates/nextjs/base/src/app/checkout/page.tsx +975 -972
  13. package/templates/nextjs/base/src/app/layout.tsx.ejs +29 -13
  14. package/templates/nextjs/base/src/app/order-confirmation/page.tsx +271 -271
  15. package/templates/nextjs/base/src/app/payment-complete/page.tsx +59 -59
  16. package/templates/nextjs/base/src/app/products/[slug]/product-client-section.tsx +501 -486
  17. package/templates/nextjs/base/src/app/products/page.tsx +475 -475
  18. package/templates/nextjs/base/src/app/reset-password/page.tsx +138 -131
  19. package/templates/nextjs/base/src/components/auth/register-form.tsx +245 -232
  20. package/templates/nextjs/base/src/components/checkout/checkout-form.tsx +416 -415
  21. package/templates/nextjs/base/src/components/checkout/custom-fields-step.tsx +258 -184
  22. package/templates/nextjs/base/src/components/checkout/payment-step.tsx +84 -20
  23. package/templates/nextjs/base/src/components/seo/product-json-ld.tsx +86 -72
  24. package/templates/nextjs/base/src/lib/csrf.ts +11 -0
  25. package/templates/nextjs/base/src/lib/navigation.tsx.ejs +60 -60
  26. package/templates/nextjs/base/src/lib/nonce.ts +10 -0
  27. package/templates/nextjs/base/src/lib/safe-redirect.ts +45 -0
  28. package/templates/nextjs/base/src/lib/sanitize-html.ts +93 -0
  29. package/templates/nextjs/base/src/lib/validation.ts +37 -0
  30. package/templates/nextjs/base/src/middleware.ts.ejs +91 -8
  31. package/templates/nextjs/base/tsconfig.tsbuildinfo +1 -0
  32. package/templates/nextjs/themes/luxury/globals.css +399 -399
  33. package/templates/nextjs/themes/luxury/theme.json +23 -23
  34. package/templates/nextjs/themes/playful/globals.css +400 -400
  35. package/templates/nextjs/themes/playful/theme.json +23 -23
@@ -1,400 +1,400 @@
1
- @tailwind base;
2
- @tailwind components;
3
- @tailwind utilities;
4
-
5
- @layer base {
6
- :root {
7
- --background: 0 0% 99%;
8
- --foreground: 260 25% 16%;
9
- --primary: 330 75% 56%;
10
- --primary-foreground: 0 0% 100%;
11
- --secondary: 260 50% 94%;
12
- --secondary-foreground: 260 25% 16%;
13
- --muted: 270 30% 95%;
14
- --muted-foreground: 260 10% 45%;
15
- --accent: 280 60% 60%;
16
- --accent-foreground: 0 0% 100%;
17
- --destructive: 0 84% 60%;
18
- --destructive-foreground: 0 0% 100%;
19
- --border: 270 20% 88%;
20
- --radius: 1rem;
21
-
22
- /* Playful-specific tokens */
23
- --pink: 330 75% 56%;
24
- --purple: 280 60% 60%;
25
- --lavender: 260 50% 94%;
26
- --peach: 20 80% 88%;
27
- --mint: 160 50% 88%;
28
- }
29
-
30
- * {
31
- @apply border-border;
32
- }
33
-
34
- body {
35
- @apply bg-background text-foreground antialiased;
36
- line-height: 1.65;
37
- }
38
-
39
- /* Playful typography — friendly, bold, tight */
40
- h1,
41
- h2,
42
- h3,
43
- h4 {
44
- font-weight: 700;
45
- letter-spacing: -0.02em;
46
- line-height: 1.2;
47
- }
48
-
49
- h1 {
50
- font-weight: 800;
51
- letter-spacing: -0.03em;
52
- }
53
-
54
- /* Fun colorful selection */
55
- ::selection {
56
- background: hsl(var(--pink) / 0.25);
57
- color: hsl(260 25% 16%);
58
- }
59
-
60
- /* Colorful focus rings */
61
- :focus-visible {
62
- outline: 2.5px solid hsl(var(--purple));
63
- outline-offset: 3px;
64
- border-radius: var(--radius);
65
- }
66
-
67
- /* Playful scrollbar */
68
- ::-webkit-scrollbar {
69
- width: 8px;
70
- }
71
-
72
- ::-webkit-scrollbar-track {
73
- background: hsl(var(--lavender));
74
- }
75
-
76
- ::-webkit-scrollbar-thumb {
77
- background: linear-gradient(
78
- 180deg,
79
- hsl(var(--pink)),
80
- hsl(var(--purple))
81
- );
82
- border-radius: 999px;
83
- }
84
- }
85
-
86
- @layer components {
87
- /* ─── Buttons ─── */
88
-
89
- /* Primary CTA — gradient with bounce and glow */
90
- button[class*="bg-primary"],
91
- a[class*="bg-primary"] {
92
- font-weight: 700;
93
- letter-spacing: 0.01em;
94
- background: linear-gradient(
95
- 135deg,
96
- hsl(var(--pink)),
97
- hsl(330 80% 52%),
98
- hsl(var(--purple))
99
- ) !important;
100
- background-size: 200% 200%;
101
- box-shadow:
102
- 0 4px 14px hsl(var(--pink) / 0.3),
103
- 0 2px 6px hsl(var(--purple) / 0.15);
104
- transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
105
- border: none;
106
- }
107
-
108
- button[class*="bg-primary"]:hover,
109
- a[class*="bg-primary"]:hover {
110
- transform: translateY(-3px) scale(1.03);
111
- box-shadow:
112
- 0 8px 28px hsl(var(--pink) / 0.4),
113
- 0 4px 12px hsl(var(--purple) / 0.2);
114
- background-position: 100% 0;
115
- opacity: 1 !important;
116
- }
117
-
118
- button[class*="bg-primary"]:active,
119
- a[class*="bg-primary"]:active {
120
- transform: translateY(0) scale(0.97);
121
- box-shadow: 0 2px 8px hsl(var(--pink) / 0.2);
122
- }
123
-
124
- /* Secondary buttons — soft pill with hover pop */
125
- [class*="bg-secondary"] {
126
- border-radius: 999px !important;
127
- font-weight: 600;
128
- transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
129
- }
130
-
131
- [class*="bg-secondary"]:hover {
132
- background: hsl(var(--lavender)) !important;
133
- transform: translateY(-2px);
134
- box-shadow: 0 4px 16px hsl(var(--purple) / 0.12);
135
- }
136
-
137
- /* ─── Product Cards ─── */
138
-
139
- [class*="group"][class*="border"] {
140
- border-radius: var(--radius);
141
- overflow: hidden;
142
- border: 2px solid hsl(var(--border));
143
- background: white;
144
- transition: all 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
145
- }
146
-
147
- [class*="group"][class*="border"]:hover {
148
- transform: translateY(-6px) rotate(-0.5deg);
149
- border-color: hsl(var(--pink) / 0.3);
150
- box-shadow:
151
- 0 16px 40px hsl(var(--purple) / 0.12),
152
- 0 6px 16px hsl(var(--pink) / 0.1);
153
- }
154
-
155
- /* Product image hover — fun overshoot zoom */
156
- [class*="group-hover\\:scale-105"] {
157
- transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) !important;
158
- }
159
-
160
- [class*="group"]:hover [class*="group-hover\\:scale-105"] {
161
- transform: scale(1.08) !important;
162
- }
163
-
164
- /* ─── Form Elements ─── */
165
-
166
- input[class*="border-border"],
167
- select[class*="border-border"],
168
- textarea[class*="border-border"] {
169
- border-radius: var(--radius);
170
- border-width: 2px;
171
- transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
172
- }
173
-
174
- input[class*="border-border"]:focus,
175
- select[class*="border-border"]:focus,
176
- textarea[class*="border-border"]:focus {
177
- border-color: hsl(var(--purple)) !important;
178
- box-shadow: 0 0 0 4px hsl(var(--purple) / 0.1);
179
- transform: scale(1.01);
180
- }
181
-
182
- input::placeholder,
183
- textarea::placeholder {
184
- color: hsl(var(--muted-foreground) / 0.6);
185
- }
186
-
187
- /* ─── Navigation & Header ─── */
188
-
189
- header[class*="sticky"] {
190
- border-bottom: none !important;
191
- box-shadow: 0 4px 20px hsl(var(--purple) / 0.06);
192
- background: hsl(0 0% 99% / 0.9) !important;
193
- backdrop-filter: blur(10px);
194
- }
195
-
196
- /* Nav link hover — colorful underline */
197
- nav a {
198
- position: relative;
199
- font-weight: 600;
200
- transition: color 0.2s ease;
201
- }
202
-
203
- nav a::after {
204
- content: '';
205
- position: absolute;
206
- bottom: -2px;
207
- left: 50%;
208
- width: 0;
209
- height: 3px;
210
- background: linear-gradient(90deg, hsl(var(--pink)), hsl(var(--purple)));
211
- border-radius: 999px;
212
- transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
213
- transform: translateX(-50%);
214
- }
215
-
216
- nav a:hover::after {
217
- width: 100%;
218
- }
219
-
220
- nav a:hover {
221
- color: hsl(var(--pink));
222
- }
223
-
224
- /* ─── Badges & Tags ─── */
225
-
226
- /* Category/filter pills */
227
- [class*="bg-muted"][class*="text-xs"] {
228
- border-radius: 999px;
229
- font-weight: 700;
230
- padding-left: 0.85rem;
231
- padding-right: 0.85rem;
232
- transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
233
- }
234
-
235
- [class*="bg-muted"][class*="text-xs"]:hover {
236
- background: hsl(var(--lavender)) !important;
237
- transform: scale(1.05);
238
- }
239
-
240
- /* Sale/discount badges — fun wiggle + pill */
241
- [class*="bg-destructive"] {
242
- border-radius: 999px;
243
- font-weight: 800;
244
- box-shadow: 0 2px 8px hsl(0 84% 60% / 0.3);
245
- animation: playful-wiggle 3s ease-in-out infinite;
246
- }
247
-
248
- /* ─── Price Display ─── */
249
-
250
- [class*="font-bold"][class*="text-lg"],
251
- [class*="font-bold"][class*="text-xl"],
252
- [class*="font-bold"][class*="text-2xl"] {
253
- color: hsl(var(--pink));
254
- }
255
-
256
- /* Strikethrough — more playful */
257
- [class*="line-through"] {
258
- opacity: 0.4;
259
- text-decoration-color: hsl(var(--purple) / 0.4);
260
- text-decoration-thickness: 2px;
261
- }
262
-
263
- /* ─── Dividers ─── */
264
-
265
- hr {
266
- border: none;
267
- height: 3px;
268
- background: linear-gradient(
269
- 90deg,
270
- transparent,
271
- hsl(var(--lavender)),
272
- hsl(var(--pink) / 0.2),
273
- hsl(var(--lavender)),
274
- transparent
275
- );
276
- border-radius: 999px;
277
- }
278
-
279
- /* ─── Cart & Checkout ─── */
280
-
281
- /* Sticky summary — playful card */
282
- [class*="sticky"][class*="top-"] {
283
- border-radius: var(--radius);
284
- border: 2px solid hsl(var(--border));
285
- box-shadow: 0 4px 20px hsl(var(--purple) / 0.06);
286
- }
287
-
288
- /* Quantity buttons */
289
- button[class*="h-8"][class*="w-8"],
290
- button[class*="h-10"][class*="w-10"] {
291
- border-radius: 999px !important;
292
- transition: all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
293
- }
294
-
295
- button[class*="h-8"][class*="w-8"]:hover,
296
- button[class*="h-10"][class*="w-10"]:hover {
297
- transform: scale(1.1);
298
- background: hsl(var(--lavender)) !important;
299
- }
300
-
301
- /* ─── Images ─── */
302
-
303
- /* Product images — rounded */
304
- [class*="aspect-square"] {
305
- border-radius: calc(var(--radius) - 2px);
306
- overflow: hidden;
307
- }
308
- }
309
-
310
- /* ─── Animations ─── */
311
-
312
- /* Bouncy slide-up entrance */
313
- @keyframes playful-slide-up {
314
- from {
315
- opacity: 0;
316
- transform: translateY(24px) scale(0.96);
317
- }
318
- 50% {
319
- transform: translateY(-6px) scale(1.01);
320
- }
321
- to {
322
- opacity: 1;
323
- transform: translateY(0) scale(1);
324
- }
325
- }
326
-
327
- /* Wiggle for discount badges */
328
- @keyframes playful-wiggle {
329
- 0%,
330
- 85%,
331
- 100% {
332
- transform: rotate(0deg);
333
- }
334
- 90% {
335
- transform: rotate(-3deg);
336
- }
337
- 95% {
338
- transform: rotate(3deg);
339
- }
340
- }
341
-
342
- /* Pop-in for grid items */
343
- @keyframes playful-pop-in {
344
- from {
345
- opacity: 0;
346
- transform: scale(0.9) translateY(16px);
347
- }
348
- 60% {
349
- transform: scale(1.02) translateY(-2px);
350
- }
351
- to {
352
- opacity: 1;
353
- transform: scale(1) translateY(0);
354
- }
355
- }
356
-
357
- main > * {
358
- animation: playful-slide-up 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both;
359
- }
360
-
361
- main > *:nth-child(2) {
362
- animation-delay: 0.06s;
363
- }
364
-
365
- main > *:nth-child(3) {
366
- animation-delay: 0.12s;
367
- }
368
-
369
- /* Staggered grid items — playful pop */
370
- [class*="grid"] > [class*="group"] {
371
- animation: playful-pop-in 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both;
372
- }
373
-
374
- [class*="grid"] > [class*="group"]:nth-child(2) {
375
- animation-delay: 0.06s;
376
- }
377
-
378
- [class*="grid"] > [class*="group"]:nth-child(3) {
379
- animation-delay: 0.12s;
380
- }
381
-
382
- [class*="grid"] > [class*="group"]:nth-child(4) {
383
- animation-delay: 0.18s;
384
- }
385
-
386
- [class*="grid"] > [class*="group"]:nth-child(5) {
387
- animation-delay: 0.24s;
388
- }
389
-
390
- [class*="grid"] > [class*="group"]:nth-child(6) {
391
- animation-delay: 0.3s;
392
- }
393
-
394
- [class*="grid"] > [class*="group"]:nth-child(7) {
395
- animation-delay: 0.36s;
396
- }
397
-
398
- [class*="grid"] > [class*="group"]:nth-child(8) {
399
- animation-delay: 0.42s;
400
- }
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ @layer base {
6
+ :root {
7
+ --background: 0 0% 99%;
8
+ --foreground: 260 25% 16%;
9
+ --primary: 330 75% 56%;
10
+ --primary-foreground: 0 0% 100%;
11
+ --secondary: 260 50% 94%;
12
+ --secondary-foreground: 260 25% 16%;
13
+ --muted: 270 30% 95%;
14
+ --muted-foreground: 260 10% 45%;
15
+ --accent: 280 60% 60%;
16
+ --accent-foreground: 0 0% 100%;
17
+ --destructive: 0 84% 60%;
18
+ --destructive-foreground: 0 0% 100%;
19
+ --border: 270 20% 88%;
20
+ --radius: 1rem;
21
+
22
+ /* Playful-specific tokens */
23
+ --pink: 330 75% 56%;
24
+ --purple: 280 60% 60%;
25
+ --lavender: 260 50% 94%;
26
+ --peach: 20 80% 88%;
27
+ --mint: 160 50% 88%;
28
+ }
29
+
30
+ * {
31
+ @apply border-border;
32
+ }
33
+
34
+ body {
35
+ @apply bg-background text-foreground antialiased;
36
+ line-height: 1.65;
37
+ }
38
+
39
+ /* Playful typography — friendly, bold, tight */
40
+ h1,
41
+ h2,
42
+ h3,
43
+ h4 {
44
+ font-weight: 700;
45
+ letter-spacing: -0.02em;
46
+ line-height: 1.2;
47
+ }
48
+
49
+ h1 {
50
+ font-weight: 800;
51
+ letter-spacing: -0.03em;
52
+ }
53
+
54
+ /* Fun colorful selection */
55
+ ::selection {
56
+ background: hsl(var(--pink) / 0.25);
57
+ color: hsl(260 25% 16%);
58
+ }
59
+
60
+ /* Colorful focus rings */
61
+ :focus-visible {
62
+ outline: 2.5px solid hsl(var(--purple));
63
+ outline-offset: 3px;
64
+ border-radius: var(--radius);
65
+ }
66
+
67
+ /* Playful scrollbar */
68
+ ::-webkit-scrollbar {
69
+ width: 8px;
70
+ }
71
+
72
+ ::-webkit-scrollbar-track {
73
+ background: hsl(var(--lavender));
74
+ }
75
+
76
+ ::-webkit-scrollbar-thumb {
77
+ background: linear-gradient(
78
+ 180deg,
79
+ hsl(var(--pink)),
80
+ hsl(var(--purple))
81
+ );
82
+ border-radius: 999px;
83
+ }
84
+ }
85
+
86
+ @layer components {
87
+ /* ─── Buttons ─── */
88
+
89
+ /* Primary CTA — gradient with bounce and glow */
90
+ button[class*="bg-primary"],
91
+ a[class*="bg-primary"] {
92
+ font-weight: 700;
93
+ letter-spacing: 0.01em;
94
+ background: linear-gradient(
95
+ 135deg,
96
+ hsl(var(--pink)),
97
+ hsl(330 80% 52%),
98
+ hsl(var(--purple))
99
+ ) !important;
100
+ background-size: 200% 200%;
101
+ box-shadow:
102
+ 0 4px 14px hsl(var(--pink) / 0.3),
103
+ 0 2px 6px hsl(var(--purple) / 0.15);
104
+ transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
105
+ border: none;
106
+ }
107
+
108
+ button[class*="bg-primary"]:hover,
109
+ a[class*="bg-primary"]:hover {
110
+ transform: translateY(-3px) scale(1.03);
111
+ box-shadow:
112
+ 0 8px 28px hsl(var(--pink) / 0.4),
113
+ 0 4px 12px hsl(var(--purple) / 0.2);
114
+ background-position: 100% 0;
115
+ opacity: 1 !important;
116
+ }
117
+
118
+ button[class*="bg-primary"]:active,
119
+ a[class*="bg-primary"]:active {
120
+ transform: translateY(0) scale(0.97);
121
+ box-shadow: 0 2px 8px hsl(var(--pink) / 0.2);
122
+ }
123
+
124
+ /* Secondary buttons — soft pill with hover pop */
125
+ [class*="bg-secondary"] {
126
+ border-radius: 999px !important;
127
+ font-weight: 600;
128
+ transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
129
+ }
130
+
131
+ [class*="bg-secondary"]:hover {
132
+ background: hsl(var(--lavender)) !important;
133
+ transform: translateY(-2px);
134
+ box-shadow: 0 4px 16px hsl(var(--purple) / 0.12);
135
+ }
136
+
137
+ /* ─── Product Cards ─── */
138
+
139
+ [class*="group"][class*="border"] {
140
+ border-radius: var(--radius);
141
+ overflow: hidden;
142
+ border: 2px solid hsl(var(--border));
143
+ background: white;
144
+ transition: all 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
145
+ }
146
+
147
+ [class*="group"][class*="border"]:hover {
148
+ transform: translateY(-6px) rotate(-0.5deg);
149
+ border-color: hsl(var(--pink) / 0.3);
150
+ box-shadow:
151
+ 0 16px 40px hsl(var(--purple) / 0.12),
152
+ 0 6px 16px hsl(var(--pink) / 0.1);
153
+ }
154
+
155
+ /* Product image hover — fun overshoot zoom */
156
+ [class*="group-hover\\:scale-105"] {
157
+ transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) !important;
158
+ }
159
+
160
+ [class*="group"]:hover [class*="group-hover\\:scale-105"] {
161
+ transform: scale(1.08) !important;
162
+ }
163
+
164
+ /* ─── Form Elements ─── */
165
+
166
+ input[class*="border-border"],
167
+ select[class*="border-border"],
168
+ textarea[class*="border-border"] {
169
+ border-radius: var(--radius);
170
+ border-width: 2px;
171
+ transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
172
+ }
173
+
174
+ input[class*="border-border"]:focus,
175
+ select[class*="border-border"]:focus,
176
+ textarea[class*="border-border"]:focus {
177
+ border-color: hsl(var(--purple)) !important;
178
+ box-shadow: 0 0 0 4px hsl(var(--purple) / 0.1);
179
+ transform: scale(1.01);
180
+ }
181
+
182
+ input::placeholder,
183
+ textarea::placeholder {
184
+ color: hsl(var(--muted-foreground) / 0.6);
185
+ }
186
+
187
+ /* ─── Navigation & Header ─── */
188
+
189
+ header[class*="sticky"] {
190
+ border-bottom: none !important;
191
+ box-shadow: 0 4px 20px hsl(var(--purple) / 0.06);
192
+ background: hsl(0 0% 99% / 0.9) !important;
193
+ backdrop-filter: blur(10px);
194
+ }
195
+
196
+ /* Nav link hover — colorful underline */
197
+ nav a {
198
+ position: relative;
199
+ font-weight: 600;
200
+ transition: color 0.2s ease;
201
+ }
202
+
203
+ nav a::after {
204
+ content: '';
205
+ position: absolute;
206
+ bottom: -2px;
207
+ left: 50%;
208
+ width: 0;
209
+ height: 3px;
210
+ background: linear-gradient(90deg, hsl(var(--pink)), hsl(var(--purple)));
211
+ border-radius: 999px;
212
+ transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
213
+ transform: translateX(-50%);
214
+ }
215
+
216
+ nav a:hover::after {
217
+ width: 100%;
218
+ }
219
+
220
+ nav a:hover {
221
+ color: hsl(var(--pink));
222
+ }
223
+
224
+ /* ─── Badges & Tags ─── */
225
+
226
+ /* Category/filter pills */
227
+ [class*="bg-muted"][class*="text-xs"] {
228
+ border-radius: 999px;
229
+ font-weight: 700;
230
+ padding-left: 0.85rem;
231
+ padding-right: 0.85rem;
232
+ transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
233
+ }
234
+
235
+ [class*="bg-muted"][class*="text-xs"]:hover {
236
+ background: hsl(var(--lavender)) !important;
237
+ transform: scale(1.05);
238
+ }
239
+
240
+ /* Sale/discount badges — fun wiggle + pill */
241
+ [class*="bg-destructive"] {
242
+ border-radius: 999px;
243
+ font-weight: 800;
244
+ box-shadow: 0 2px 8px hsl(0 84% 60% / 0.3);
245
+ animation: playful-wiggle 3s ease-in-out infinite;
246
+ }
247
+
248
+ /* ─── Price Display ─── */
249
+
250
+ [class*="font-bold"][class*="text-lg"],
251
+ [class*="font-bold"][class*="text-xl"],
252
+ [class*="font-bold"][class*="text-2xl"] {
253
+ color: hsl(var(--pink));
254
+ }
255
+
256
+ /* Strikethrough — more playful */
257
+ [class*="line-through"] {
258
+ opacity: 0.4;
259
+ text-decoration-color: hsl(var(--purple) / 0.4);
260
+ text-decoration-thickness: 2px;
261
+ }
262
+
263
+ /* ─── Dividers ─── */
264
+
265
+ hr {
266
+ border: none;
267
+ height: 3px;
268
+ background: linear-gradient(
269
+ 90deg,
270
+ transparent,
271
+ hsl(var(--lavender)),
272
+ hsl(var(--pink) / 0.2),
273
+ hsl(var(--lavender)),
274
+ transparent
275
+ );
276
+ border-radius: 999px;
277
+ }
278
+
279
+ /* ─── Cart & Checkout ─── */
280
+
281
+ /* Sticky summary — playful card */
282
+ [class*="sticky"][class*="top-"] {
283
+ border-radius: var(--radius);
284
+ border: 2px solid hsl(var(--border));
285
+ box-shadow: 0 4px 20px hsl(var(--purple) / 0.06);
286
+ }
287
+
288
+ /* Quantity buttons */
289
+ button[class*="h-8"][class*="w-8"],
290
+ button[class*="h-10"][class*="w-10"] {
291
+ border-radius: 999px !important;
292
+ transition: all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
293
+ }
294
+
295
+ button[class*="h-8"][class*="w-8"]:hover,
296
+ button[class*="h-10"][class*="w-10"]:hover {
297
+ transform: scale(1.1);
298
+ background: hsl(var(--lavender)) !important;
299
+ }
300
+
301
+ /* ─── Images ─── */
302
+
303
+ /* Product images — rounded */
304
+ [class*="aspect-square"] {
305
+ border-radius: calc(var(--radius) - 2px);
306
+ overflow: hidden;
307
+ }
308
+ }
309
+
310
+ /* ─── Animations ─── */
311
+
312
+ /* Bouncy slide-up entrance */
313
+ @keyframes playful-slide-up {
314
+ from {
315
+ opacity: 0;
316
+ transform: translateY(24px) scale(0.96);
317
+ }
318
+ 50% {
319
+ transform: translateY(-6px) scale(1.01);
320
+ }
321
+ to {
322
+ opacity: 1;
323
+ transform: translateY(0) scale(1);
324
+ }
325
+ }
326
+
327
+ /* Wiggle for discount badges */
328
+ @keyframes playful-wiggle {
329
+ 0%,
330
+ 85%,
331
+ 100% {
332
+ transform: rotate(0deg);
333
+ }
334
+ 90% {
335
+ transform: rotate(-3deg);
336
+ }
337
+ 95% {
338
+ transform: rotate(3deg);
339
+ }
340
+ }
341
+
342
+ /* Pop-in for grid items */
343
+ @keyframes playful-pop-in {
344
+ from {
345
+ opacity: 0;
346
+ transform: scale(0.9) translateY(16px);
347
+ }
348
+ 60% {
349
+ transform: scale(1.02) translateY(-2px);
350
+ }
351
+ to {
352
+ opacity: 1;
353
+ transform: scale(1) translateY(0);
354
+ }
355
+ }
356
+
357
+ main > * {
358
+ animation: playful-slide-up 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both;
359
+ }
360
+
361
+ main > *:nth-child(2) {
362
+ animation-delay: 0.06s;
363
+ }
364
+
365
+ main > *:nth-child(3) {
366
+ animation-delay: 0.12s;
367
+ }
368
+
369
+ /* Staggered grid items — playful pop */
370
+ [class*="grid"] > [class*="group"] {
371
+ animation: playful-pop-in 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both;
372
+ }
373
+
374
+ [class*="grid"] > [class*="group"]:nth-child(2) {
375
+ animation-delay: 0.06s;
376
+ }
377
+
378
+ [class*="grid"] > [class*="group"]:nth-child(3) {
379
+ animation-delay: 0.12s;
380
+ }
381
+
382
+ [class*="grid"] > [class*="group"]:nth-child(4) {
383
+ animation-delay: 0.18s;
384
+ }
385
+
386
+ [class*="grid"] > [class*="group"]:nth-child(5) {
387
+ animation-delay: 0.24s;
388
+ }
389
+
390
+ [class*="grid"] > [class*="group"]:nth-child(6) {
391
+ animation-delay: 0.3s;
392
+ }
393
+
394
+ [class*="grid"] > [class*="group"]:nth-child(7) {
395
+ animation-delay: 0.36s;
396
+ }
397
+
398
+ [class*="grid"] > [class*="group"]:nth-child(8) {
399
+ animation-delay: 0.42s;
400
+ }