metabinaries 1.3.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.
@@ -0,0 +1,1066 @@
1
+ // app-clean.js - FIXED VERSION with NO syntax errors
2
+ export const appTemplates = {
3
+ 'app/layout.tsx': `import './globals.css';
4
+ import { Providers } from '@/lib/providers';
5
+ import type { Viewport } from 'next';
6
+ import { Cairo } from 'next/font/google';
7
+
8
+ const cairo = Cairo({
9
+ subsets: ['arabic', 'latin'],
10
+ display: 'swap',
11
+ variable: '--font-cairo',
12
+ });
13
+
14
+ export const viewport: Viewport = {
15
+ width: 'device-width',
16
+ initialScale: 1,
17
+ maximumScale: 5,
18
+ themeColor: [
19
+ { media: '(prefers-color-scheme: light)', color: '#ffffff' },
20
+ { media: '(prefers-color-scheme: dark)', color: '#0a0a0a' },
21
+ ],
22
+ };
23
+
24
+ export default function RootLayout({
25
+ children,
26
+ }: Readonly<{
27
+ children: React.ReactNode;
28
+ }>) {
29
+ return (
30
+ <html lang='en' suppressHydrationWarning className={cairo.variable}>
31
+ <body className={\`\${cairo.className} antialiased\`}>
32
+ <Providers>
33
+ {children}
34
+ </Providers>
35
+ </body>
36
+ </html>
37
+ );
38
+ }`,
39
+
40
+ 'app/not-found.tsx': `'use client';
41
+
42
+ import { motion } from 'framer-motion';
43
+ import { Button } from '@/components/ui/button';
44
+ import { Home, ArrowLeft } from 'lucide-react';
45
+ import Link from 'next/link';
46
+ import { useRouter } from 'next/navigation';
47
+ import { useCallback, useMemo } from 'react';
48
+
49
+ export default function NotFound() {
50
+ const router = useRouter();
51
+
52
+ const handleGoBack = useCallback(() => {
53
+ router.back();
54
+ }, [router]);
55
+
56
+ const floatingElements = useMemo(() =>
57
+ Array.from({ length: 6 }, (_, i) => ({
58
+ id: i,
59
+ x: \`\${Math.random() * 100}%\`,
60
+ y: \`\${Math.random() * 100}%\`,
61
+ duration: 3 + Math.random() * 2,
62
+ delay: Math.random() * 2
63
+ })), []
64
+ );
65
+
66
+ return (
67
+ <div
68
+ className='relative min-h-screen w-full flex items-center justify-center overflow-hidden bg-white dark:bg-slate-950 px-6'
69
+ role="main"
70
+ aria-labelledby="error-heading"
71
+ >
72
+ <div className='absolute inset-0 overflow-hidden pointer-events-none' aria-hidden="true">
73
+ <div className='absolute top-[-10%] right-[-10%] w-[40%] h-[40%] rounded-full bg-blue-500/10 dark:bg-blue-500/20 blur-[100px] animate-pulse' />
74
+ <div className='absolute bottom-[-10%] left-[-10%] w-[40%] h-[40%] rounded-full bg-indigo-500/10 dark:bg-indigo-500/20 blur-[100px] animate-pulse' />
75
+ </div>
76
+
77
+ <div className='relative z-10 max-w-2xl w-full text-center'>
78
+ <motion.div
79
+ initial={{ opacity: 0, scale: 0.5 }}
80
+ animate={{ opacity: 1, scale: 1 }}
81
+ transition={{ duration: 0.8, ease: "easeOut" }}
82
+ className='relative'
83
+ >
84
+ <h1
85
+ className='text-[12rem] md:text-[16rem] font-black leading-none tracking-tighter text-slate-100 dark:text-slate-900 select-none'
86
+ aria-hidden="true"
87
+ >
88
+ 404
89
+ </h1>
90
+
91
+ <motion.div
92
+ initial={{ y: 20, opacity: 0 }}
93
+ animate={{ y: 0, opacity: 1 }}
94
+ transition={{ delay: 0.5, duration: 0.5 }}
95
+ className='absolute inset-0 flex items-center justify-center'
96
+ >
97
+ <h2
98
+ id="error-heading"
99
+ className='text-4xl md:text-6xl font-bold bg-gradient-to-b from-slate-900 to-slate-600 dark:from-white dark:to-slate-400 bg-clip-text text-transparent'
100
+ >
101
+ Lost in Space
102
+ </h2>
103
+ </motion.div>
104
+ </motion.div>
105
+
106
+ <motion.div
107
+ initial={{ opacity: 0, y: 20 }}
108
+ animate={{ opacity: 1, y: 0 }}
109
+ transition={{ delay: 0.7, duration: 0.5 }}
110
+ className='mt-8 space-y-6'
111
+ >
112
+ <p className='text-lg md:text-xl text-slate-500 dark:text-slate-400 max-w-md mx-auto'>
113
+ The page you are looking for doesn&apos;t exist or has been moved to another quadrant.
114
+ </p>
115
+
116
+ <div className='flex flex-wrap items-center justify-center gap-4 pt-4'>
117
+ <Button
118
+ asChild
119
+ size='lg'
120
+ className='h-12 px-6 rounded-full bg-blue-600 hover:bg-blue-700 text-white font-semibold shadow-lg shadow-blue-500/25 transition-all'
121
+ >
122
+ <Link href='/en' prefetch={true}>
123
+ <Home className='mr-2 w-4 h-4' aria-hidden="true" />
124
+ Back Home
125
+ </Link>
126
+ </Button>
127
+
128
+ <Button
129
+ onClick={handleGoBack}
130
+ variant='outline'
131
+ size='lg'
132
+ className='h-12 px-6 rounded-full border-slate-200 dark:border-slate-800 text-slate-700 dark:text-slate-300 font-semibold hover:bg-slate-50 hover:text-slate-900 dark:hover:bg-slate-900 dark:hover:text-white transition-all'
133
+ >
134
+ <ArrowLeft className='mr-2 w-4 h-4' aria-hidden="true" />
135
+ Go Back
136
+ </Button>
137
+ </div>
138
+ </motion.div>
139
+
140
+ <div className='absolute -z-10 top-0 left-0 w-full h-full pointer-events-none' aria-hidden="true">
141
+ {floatingElements.map((el) => (
142
+ <motion.div
143
+ key={el.id}
144
+ className='absolute w-2 h-2 bg-blue-500/30 rounded-full'
145
+ initial={{
146
+ x: el.x,
147
+ y: el.y,
148
+ opacity: 0
149
+ }}
150
+ animate={{
151
+ y: [null, '-20px', '20px'],
152
+ opacity: [0, 1, 0]
153
+ }}
154
+ transition={{
155
+ duration: el.duration,
156
+ repeat: Infinity,
157
+ delay: el.delay,
158
+ ease: "easeInOut"
159
+ }}
160
+ />
161
+ ))}
162
+ </div>
163
+ </div>
164
+ </div>
165
+ );
166
+ }`,
167
+
168
+ 'app/robots.ts': `import { MetadataRoute } from 'next';
169
+
170
+ /**
171
+ * Robots Configuration - Production Ready
172
+ *
173
+ * Advanced configuration for proper indexing while protecting
174
+ * sensitive routes and managing crawler behavior.
175
+ */
176
+
177
+ const APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://metabinaries.com';
178
+
179
+ const IS_PRODUCTION =
180
+ process.env.NODE_ENV === 'production' &&
181
+ (process.env.VERCEL_ENV === 'production' || !process.env.VERCEL_ENV);
182
+
183
+ export default function robots(): MetadataRoute.Robots {
184
+ // Block all indexing in non-production environments
185
+ if (!IS_PRODUCTION) {
186
+ return {
187
+ rules: {
188
+ userAgent: '*',
189
+ disallow: '/',
190
+ },
191
+ sitemap: \`\${APP_URL}/sitemap.xml\`,
192
+ };
193
+ }
194
+
195
+ return {
196
+ rules: [
197
+ // Main crawlers configuration
198
+ {
199
+ userAgent: '*',
200
+ allow: [
201
+ '/',
202
+ '/api/og', // Allow OG image generation for social sharing
203
+ '/public/', // Allow public assets if needed
204
+ ],
205
+ disallow: [
206
+ // API & System Routes
207
+ '/api/',
208
+ '/_next/',
209
+ '/static/',
210
+
211
+ // Admin & Private Routes
212
+ '/admin*',
213
+ '/dashboard*',
214
+ '/account*',
215
+
216
+ // Dynamic & Utility Routes
217
+ '/*?*', // URLs with query parameters
218
+ '/*/draft', // Draft content
219
+ '/preview*', // Preview pages
220
+ '/**/not-found',
221
+
222
+ // File Types
223
+ '/*.json', // JSON files
224
+ '/*.xml', // XML files (except sitemap)
225
+ '/*.env', // Environment files
226
+ ],
227
+ },
228
+
229
+ // AI Crawlers Management
230
+ {
231
+ userAgent: [
232
+ 'GPTBot', // OpenAI
233
+ 'ChatGPT-User', // ChatGPT Browse
234
+ 'CCBot', // Common Crawl
235
+ 'anthropic-ai', // Anthropic
236
+ 'Claude-Web', // Claude
237
+ 'Google-Extended',// Google AI (Bard)
238
+ ],
239
+ disallow: '/',
240
+ },
241
+
242
+ // Aggressive Scrapers
243
+ {
244
+ userAgent: [
245
+ 'SemrushBot',
246
+ 'AhrefsBot',
247
+ 'DotBot',
248
+ ],
249
+ crawlDelay: 10,
250
+ disallow: '/api/',
251
+ },
252
+ ],
253
+ sitemap: \`\${APP_URL}/sitemap.xml\`,
254
+ host: APP_URL,
255
+ };
256
+ }`,
257
+
258
+ 'app/[locale]/layout.tsx': (projectName, options = {}) => {
259
+ const { includeAIChat = false } = options;
260
+
261
+ return `import type { Metadata } from 'next';
262
+ import { NextIntlClientProvider } from 'next-intl';
263
+ import {
264
+ getMessages,
265
+ getTranslations,
266
+ setRequestLocale
267
+ } from 'next-intl/server';
268
+ import { notFound } from 'next/navigation';
269
+ import { routing } from '@/i18n/routing';
270
+ import { Footer } from '@/components/layout/Footer';
271
+ import { Header } from '@/components/layout/Header';
272
+ ${includeAIChat ? "import { AIChat } from '@/components/layout/AIChat';" : ""}
273
+
274
+ type Locale = (typeof routing.locales)[number];
275
+
276
+ function isValidLocale(locale: string): locale is Locale {
277
+ return routing.locales.includes(locale as Locale);
278
+ }
279
+
280
+ export function generateStaticParams() {
281
+ return routing.locales.map((locale) => ({ locale }));
282
+ }
283
+
284
+ export async function generateMetadata({
285
+ params,
286
+ }: {
287
+ params: Promise<{ locale: string }>;
288
+ }): Promise<Metadata> {
289
+ const { locale } = await params;
290
+
291
+ if (!isValidLocale(locale)) {
292
+ return {};
293
+ }
294
+
295
+ const t = await getTranslations({ locale, namespace: 'Metadata' });
296
+
297
+ return {
298
+ title: {
299
+ default: t('title'),
300
+ template: \`%s | \${t('title')}\`,
301
+ },
302
+ description: t('description'),
303
+ keywords: t('keywords').split(',').map(k => k.trim()),
304
+ authors: [{ name: 'MetaBinaries' }],
305
+ creator: 'MetaBinaries',
306
+ metadataBase: new URL(
307
+ process.env.NEXT_PUBLIC_APP_URL || 'https://metabinaries.com'
308
+ ),
309
+ alternates: {
310
+ canonical: \`/\${locale}\`,
311
+ languages: {
312
+ 'en': '/en',
313
+ 'ar': '/ar',
314
+ 'x-default': '/en',
315
+ },
316
+ },
317
+ openGraph: {
318
+ type: 'website',
319
+ locale: locale === 'ar' ? 'ar_EG' : 'en_US',
320
+ alternateLocale: locale === 'ar' ? 'en_US' : 'ar_EG',
321
+ url: \`/\${locale}\`,
322
+ title: t('title'),
323
+ description: t('description'),
324
+ siteName: t('siteName'),
325
+ images: [
326
+ {
327
+ url: \`/og-\${locale}.jpg\`,
328
+ width: 1200,
329
+ height: 630,
330
+ alt: t('title'),
331
+ },
332
+ ],
333
+ },
334
+ twitter: {
335
+ card: 'summary_large_image',
336
+ title: t('title'),
337
+ description: t('description'),
338
+ images: [\`/og-\${locale}.jpg\`],
339
+ creator: '@metabinaries',
340
+ },
341
+ robots: {
342
+ index: true,
343
+ follow: true,
344
+ },
345
+ };
346
+ }
347
+
348
+ export default async function LocaleLayout({
349
+ children,
350
+ params,
351
+ }: Readonly<{
352
+ children: React.ReactNode;
353
+ params: Promise<{ locale: string }>;
354
+ }>) {
355
+ const { locale } = await params;
356
+
357
+ if (!isValidLocale(locale)) {
358
+ notFound();
359
+ }
360
+
361
+ setRequestLocale(locale);
362
+
363
+ const messages = await getMessages({ locale });
364
+
365
+ const isRTL = locale === 'ar';
366
+
367
+ return (
368
+ <NextIntlClientProvider
369
+ messages={messages}
370
+ locale={locale}
371
+ timeZone="Africa/Cairo"
372
+ >
373
+ <div
374
+ dir={isRTL ? 'rtl' : 'ltr'}
375
+ className="flex min-h-screen flex-col"
376
+ >
377
+ <Header />
378
+ <main className="flex-1">
379
+ {children}
380
+ </main>
381
+ <Footer />
382
+ ${includeAIChat ? "<AIChat />" : ""}
383
+ </div>
384
+ </NextIntlClientProvider>
385
+ );
386
+ }`;
387
+ },
388
+
389
+ 'app/[locale]/sitemap.ts': `import { MetadataRoute } from 'next';
390
+
391
+ /**
392
+ * Sitemap Generator - Production Ready
393
+ *
394
+ * This advanced sitemap configuration implements SEO best practices for
395
+ * multilingual Next.js applications, including hreflang alternates.
396
+ */
397
+
398
+ const APP_URL = process.env.NEXT_PUBLIC_APP_URL || 'https://metabinaries.com';
399
+ const LOCALES = ['en', 'ar'] as const;
400
+
401
+ type Locale = (typeof LOCALES)[number];
402
+ type ChangeFrequency = 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
403
+
404
+ interface RouteConfig {
405
+ path: string;
406
+ changeFrequency: ChangeFrequency;
407
+ priority: number;
408
+ }
409
+
410
+ const STATIC_ROUTES: RouteConfig[] = [
411
+ { path: '', changeFrequency: 'daily', priority: 1.0 },
412
+ { path: '/features', changeFrequency: 'weekly', priority: 0.8 },
413
+ { path: '/about', changeFrequency: 'monthly', priority: 0.8 },
414
+ { path: '/contact', changeFrequency: 'monthly', priority: 0.7 },
415
+ { path: '/blog', changeFrequency: 'daily', priority: 0.9 },
416
+ { path: '/privacy', changeFrequency: 'yearly', priority: 0.3 },
417
+ { path: '/terms', changeFrequency: 'yearly', priority: 0.3 },
418
+ ];
419
+
420
+ export default function sitemap(): MetadataRoute.Sitemap {
421
+ return generateStaticEntries();
422
+ }
423
+
424
+ function generateStaticEntries(): MetadataRoute.Sitemap {
425
+ return STATIC_ROUTES.flatMap((route) =>
426
+ LOCALES.map((locale) => ({
427
+ url: \`\${APP_URL}/\${locale}\${route.path}\`,
428
+ lastModified: new Date(),
429
+ changeFrequency: route.changeFrequency,
430
+ priority: route.priority,
431
+ alternates: {
432
+ languages: Object.fromEntries(
433
+ LOCALES.map((l) => [l, \`\${APP_URL}/\${l}\${route.path}\`])
434
+ ),
435
+ },
436
+ }))
437
+ );
438
+ }`,
439
+
440
+ 'app/[locale]/loading.tsx': `import { Loading } from '@/components/shared/loading-ui';
441
+
442
+ export default function LoadingPage() {
443
+ return <Loading />;
444
+ }`,
445
+
446
+ 'app/[locale]/error.tsx': `'use client';
447
+
448
+ import { useEffect } from 'react';
449
+ import { Button } from '@/components/ui/button';
450
+ import { AlertCircle, RefreshCw, Home } from 'lucide-react';
451
+
452
+ export default function Error({
453
+ error,
454
+ reset,
455
+ }: {
456
+ error: Error & { digest?: string };
457
+ reset: () => void;
458
+ }) {
459
+ useEffect(() => {
460
+ console.error(error);
461
+ }, [error]);
462
+
463
+ return (
464
+ <div
465
+ className="flex min-h-[100dvh] w-full flex-col items-center justify-center bg-background p-6"
466
+ role="alert"
467
+ aria-live="assertive"
468
+ >
469
+ <div className="flex flex-col items-center gap-6 max-w-md text-center">
470
+ <div className="relative">
471
+ <div className="absolute inset-0 rounded-full bg-destructive/20 animate-ping" />
472
+ <div className="relative flex h-20 w-20 items-center justify-center rounded-full bg-destructive/10 border border-destructive/20">
473
+ <AlertCircle className="h-10 w-10 text-destructive" aria-hidden="true" />
474
+ </div>
475
+ </div>
476
+
477
+ <div className="space-y-2">
478
+ <h2 className="text-2xl font-bold tracking-tight text-foreground">
479
+ Something went wrong!
480
+ </h2>
481
+ <p className="text-sm text-muted-foreground leading-relaxed">
482
+ An unexpected error occurred. Please try again or return to the home page.
483
+ </p>
484
+ </div>
485
+
486
+ {error.digest && (
487
+ <p className="text-xs text-muted-foreground/60 font-mono bg-muted px-3 py-1.5 rounded-md">
488
+ Error ID: {error.digest}
489
+ </p>
490
+ )}
491
+
492
+ <div className="flex flex-col sm:flex-row gap-3 w-full sm:w-auto">
493
+ <Button
494
+ onClick={() => reset()}
495
+ variant="default"
496
+ className="gap-2"
497
+ >
498
+ <RefreshCw className="h-4 w-4" aria-hidden="true" />
499
+ Try again
500
+ </Button>
501
+ <Button
502
+ onClick={() => (window.location.href = '/')}
503
+ variant="outline"
504
+ className="gap-2"
505
+ >
506
+ <Home className="h-4 w-4" aria-hidden="true" />
507
+ Go Home
508
+ </Button>
509
+ </div>
510
+
511
+ <span className="sr-only">
512
+ An error has occurred. You can try again or go back to the home page.
513
+ </span>
514
+ </div>
515
+ </div>
516
+ );
517
+ }`,
518
+
519
+ 'app/[locale]/page.tsx': `'use client';
520
+
521
+ import { motion } from 'framer-motion';
522
+ import { Button } from '@/components/ui/button';
523
+ import { Badge } from '@/components/ui/badge';
524
+ import { Shield, Globe, Zap, ArrowRight, Sparkles } from 'lucide-react';
525
+ import Link from 'next/link';
526
+
527
+ export default function HomePage() {
528
+ return (
529
+ <div className='relative min-h-screen overflow-hidden bg-white dark:bg-slate-950 font-sans selection:bg-blue-500/30'>
530
+ <div className='fixed inset-0 overflow-hidden pointer-events-none'>
531
+ <div className='absolute top-[-10%] left-[-10%] w-[50%] h-[50%] rounded-full bg-blue-600/5 dark:bg-blue-600/10 blur-[120px]' />
532
+ <div className='absolute bottom-[-10%] right-[-10%] w-[50%] h-[50%] rounded-full bg-indigo-600/5 dark:bg-indigo-600/10 blur-[120px]' />
533
+ </div>
534
+
535
+ <div className='relative z-10 container mx-auto px-6 py-24 md:py-32 flex flex-col items-center text-center'>
536
+ <motion.div
537
+ initial={{ opacity: 0, scale: 0.9 }}
538
+ animate={{ opacity: 1, scale: 1 }}
539
+ transition={{ duration: 0.5 }}
540
+ className='mb-8'
541
+ >
542
+ <Badge
543
+ variant='outline'
544
+ className='py-1.5 px-4 border-blue-100 dark:border-blue-900 bg-blue-50/50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400 backdrop-blur-sm shadow-sm'
545
+ >
546
+ <Sparkles className='w-3.5 h-3.5 mr-2' />
547
+ Release v1.0 is here
548
+ </Badge>
549
+ </motion.div>
550
+
551
+ <motion.h1
552
+ initial={{ opacity: 0, y: 30 }}
553
+ animate={{ opacity: 1, y: 0 }}
554
+ transition={{ duration: 0.7, delay: 0.1 }}
555
+ className='max-w-4xl text-5xl md:text-8xl font-black tracking-tight text-slate-900 dark:text-white mb-8'
556
+ >
557
+ Build something <br />
558
+ <span className='bg-gradient-to-r from-blue-600 via-indigo-600 to-violet-600 bg-clip-text text-transparent'>
559
+ Extraordinary
560
+ </span>
561
+ </motion.h1>
562
+
563
+ <motion.p
564
+ initial={{ opacity: 0, y: 20 }}
565
+ animate={{ opacity: 1, y: 0 }}
566
+ transition={{ duration: 0.7, delay: 0.2 }}
567
+ className='max-w-2xl text-lg md:text-xl text-slate-500 dark:text-slate-400 mb-12 leading-relaxed'
568
+ >
569
+ The ultimate Next.js starter kit for developers who care about aesthetics, performance, and scalability. Start your journey today.
570
+ </motion.p>
571
+
572
+ <motion.div
573
+ initial={{ opacity: 0, y: 20 }}
574
+ animate={{ opacity: 1, y: 0 }}
575
+ transition={{ duration: 0.7, delay: 0.3 }}
576
+ className='flex flex-wrap items-center justify-center gap-4'
577
+ >
578
+ <Button asChild size='lg' className='h-14 px-8 rounded-full bg-blue-600 hover:bg-blue-700 text-white text-lg font-semibold shadow-xl shadow-blue-500/25'>
579
+ <Link href='#features'>
580
+ Get Started <ArrowRight className='ml-2 w-5 h-5' />
581
+ </Link>
582
+ </Button>
583
+ <Button asChild variant='outline' size='lg' className='h-14 px-8 rounded-full border-slate-200 dark:border-slate-800 text-lg font-semibold hover:bg-slate-50 dark:hover:bg-slate-900'>
584
+ <a href='https://nextjs.org/docs' target='_blank' rel='noopener noreferrer'>Documentation</a>
585
+ </Button>
586
+ </motion.div>
587
+
588
+ <motion.div
589
+ initial={{ opacity: 0, y: 40 }}
590
+ animate={{ opacity: 1, y: 0 }}
591
+ transition={{ duration: 0.8, delay: 0.5 }}
592
+ className='grid md:grid-cols-3 gap-6 mt-32 w-full max-w-5xl'
593
+ id='features'
594
+ >
595
+ {[
596
+ { icon: <Zap className='text-yellow-500' />, title: 'Incredible Speed', desc: 'Optimized for Core Web Vitals and lightning-fast LCP.' },
597
+ { icon: <Globe className='text-blue-500' />, title: 'I18n Built-in', desc: 'Seamless English and Arabic support out of the box.' },
598
+ { icon: <Shield className='text-green-500' />, title: 'Enterprise Ready', desc: 'Scalable architecture using modern React patterns.' }
599
+ ].map((f, i) => (
600
+ <div key={i} className='p-8 rounded-3xl border border-slate-100 dark:border-slate-800 bg-white/50 dark:bg-slate-900/50 backdrop-blur-sm hover:border-blue-500/50 transition-all group'>
601
+ <div className='w-12 h-12 rounded-2xl bg-white dark:bg-slate-800 shadow-sm flex items-center justify-center mb-6 group-hover:scale-110 transition-transform'>
602
+ {f.icon}
603
+ </div>
604
+ <h3 className='text-xl font-bold mb-3 text-slate-900 dark:text-white'>{f.title}</h3>
605
+ <p className='text-slate-500 dark:text-slate-400 text-sm leading-relaxed'>{f.desc}</p>
606
+ </div>
607
+ ))}
608
+ </motion.div>
609
+ </div>
610
+ </div>
611
+ );
612
+ }`,
613
+
614
+ 'app/globals.css': `/**
615
+ * Global Styles - Customization Guide
616
+ *
617
+ * 🎨 WHAT TO CUSTOMIZE:
618
+ *
619
+ * 1. ✅ Colors (Primary, Secondary, etc.)
620
+ * 2. ✅ Border Radius
621
+ * 3. ✅ Typography (Font sizes, weights)
622
+ * 4. ⚠️ Keep everything else as-is
623
+ */
624
+
625
+ @import "tailwindcss";
626
+
627
+ /* ========================================
628
+ 🎨 CUSTOMIZATION SECTION
629
+ Change these values for your brand
630
+ ======================================== */
631
+
632
+ @theme {
633
+ /*
634
+ ⚠️ DON'T TOUCH - These map to CSS variables
635
+ Only change the :root values below
636
+ */
637
+ --color-border: hsl(var(--border));
638
+ --color-input: hsl(var(--input));
639
+ --color-ring: hsl(var(--ring));
640
+ --color-background: hsl(var(--background));
641
+ --color-foreground: hsl(var(--foreground));
642
+ --color-primary: hsl(var(--primary));
643
+ --color-primary-foreground: hsl(var(--primary-foreground));
644
+ --color-secondary: hsl(var(--secondary));
645
+ --color-secondary-foreground: hsl(var(--secondary-foreground));
646
+ --color-destructive: hsl(var(--destructive));
647
+ --color-destructive-foreground: hsl(var(--destructive-foreground));
648
+ --color-muted: hsl(var(--muted));
649
+ --color-muted-foreground: hsl(var(--muted-foreground));
650
+ --color-accent: hsl(var(--accent));
651
+ --color-accent-foreground: hsl(var(--accent-foreground));
652
+ --color-popover: hsl(var(--popover));
653
+ --color-popover-foreground: hsl(var(--popover-foreground));
654
+ --color-card: hsl(var(--card));
655
+ --color-card-foreground: hsl(var(--card-foreground));
656
+
657
+ /*
658
+ ✅ CUSTOMIZE - Border Radius
659
+ Change this to match your design style
660
+ */
661
+ --radius-lg: var(--radius);
662
+ --radius-md: calc(var(--radius) - 2px);
663
+ --radius-sm: calc(var(--radius) - 4px);
664
+
665
+ /* ⚠️ DON'T TOUCH - Animation definitions */
666
+ --animate-accordion-down: accordion-down 0.2s ease-out;
667
+ --animate-accordion-up: accordion-up 0.2s ease-out;
668
+
669
+ @keyframes accordion-down {
670
+ from { height: 0; }
671
+ to { height: var(--radix-accordion-content-height); }
672
+ }
673
+
674
+ @keyframes accordion-up {
675
+ from { height: var(--radix-accordion-content-height); }
676
+ to { height: 0; }
677
+ }
678
+
679
+ @keyframes fade-in {
680
+ from { opacity: 0; }
681
+ to { opacity: 1; }
682
+ }
683
+
684
+ @keyframes slide-in-from-top {
685
+ from { transform: translateY(-100%); }
686
+ to { transform: translateY(0); }
687
+ }
688
+
689
+ @keyframes slide-in-from-bottom {
690
+ from { transform: translateY(100%); }
691
+ to { transform: translateY(0); }
692
+ }
693
+ }
694
+
695
+ /* ========================================
696
+ ✅ CUSTOMIZE THESE VALUES
697
+ ======================================== */
698
+
699
+ @layer base {
700
+ /*
701
+ 🎨 LIGHT MODE COLORS
702
+ Change these HSL values to match your brand
703
+
704
+ Format: HUE SATURATION LIGHTNESS
705
+ Example: 221.2 83.2% 53.3%
706
+
707
+ 🔗 Use this tool: https://hslpicker.com
708
+ */
709
+ :root {
710
+ /* Background Colors */
711
+ --background: 0 0% 100%; /* ✅ White - Change for different bg */
712
+ --foreground: 222.2 84% 4.9%; /* ✅ Near black - Text color */
713
+
714
+ /* Card Colors */
715
+ --card: 0 0% 100%; /* ✅ White cards */
716
+ --card-foreground: 222.2 84% 4.9%; /* ✅ Card text color */
717
+
718
+ /* Popover Colors */
719
+ --popover: 0 0% 100%;
720
+ --popover-foreground: 222.2 84% 4.9%;
721
+
722
+ /* 🎨 PRIMARY COLOR - Your Brand Color */
723
+ --primary: 221.2 83.2% 53.3%; /* ✅ Blue - CHANGE THIS */
724
+ --primary-foreground: 210 40% 98%; /* ✅ White text on primary */
725
+
726
+ /* Examples for different brands:
727
+ Red: 0 84% 60%
728
+ Green: 142 76% 36%
729
+ Purple: 262 83% 58%
730
+ Orange: 25 95% 53%
731
+ */
732
+
733
+ /* Secondary Color */
734
+ --secondary: 210 40% 96.1%; /* ✅ Light gray */
735
+ --secondary-foreground: 222.2 47.4% 11.2%;
736
+
737
+ /* Muted (Subtle backgrounds) */
738
+ --muted: 210 40% 96.1%;
739
+ --muted-foreground: 215.4 16.3% 46.9%;
740
+
741
+ /* Accent */
742
+ --accent: 210 40% 96.1%;
743
+ --accent-foreground: 222.2 47.4% 11.2%;
744
+
745
+ /* Destructive (Error/Delete) */
746
+ --destructive: 0 84.2% 60.2%; /* ⚠️ Red - Usually keep as-is */
747
+ --destructive-foreground: 210 40% 98%;
748
+
749
+ /* Border & Input */
750
+ --border: 214.3 31.8% 91.4%; /* ✅ Light gray borders */
751
+ --input: 214.3 31.8% 91.4%; /* ✅ Input borders */
752
+ --ring: 221.2 83.2% 53.3%; /* ✅ Focus ring (match primary) */
753
+
754
+ /* 🎨 BORDER RADIUS - Your Design Style */
755
+ --radius: 0.5rem; /* ✅ CHANGE THIS
756
+ 0rem = Sharp (No radius)
757
+ 0.25rem = Subtle (4px)
758
+ 0.5rem = Moderate (8px) - Default
759
+ 0.75rem = Rounded (12px)
760
+ 1rem = Very Rounded (16px)
761
+ 9999px = Pills/Fully rounded
762
+ */
763
+ }
764
+
765
+ /*
766
+ 🌙 DARK MODE COLORS
767
+ Change these if you want a custom dark theme
768
+ */
769
+ .dark {
770
+ --background: 222.2 84% 4.9%; /* ✅ Dark blue-gray */
771
+ --foreground: 210 40% 98%; /* ✅ Near white */
772
+
773
+ --card: 222.2 84% 4.9%;
774
+ --card-foreground: 210 40% 98%;
775
+
776
+ --popover: 222.2 84% 4.9%;
777
+ --popover-foreground: 210 40% 98%;
778
+
779
+ /* 🎨 PRIMARY COLOR - Usually brighter in dark mode */
780
+ --primary: 217.2 91.2% 59.8%; /* ✅ Lighter blue */
781
+ --primary-foreground: 222.2 47.4% 11.2%;
782
+
783
+ --secondary: 217.2 32.6% 17.5%;
784
+ --secondary-foreground: 210 40% 98%;
785
+
786
+ --muted: 217.2 32.6% 17.5%;
787
+ --muted-foreground: 215 20.2% 65.1%;
788
+
789
+ --accent: 217.2 32.6% 17.5%;
790
+ --accent-foreground: 210 40% 98%;
791
+
792
+ --destructive: 0 62.8% 30.6%; /* ⚠️ Darker red for dark mode */
793
+ --destructive-foreground: 210 40% 98%;
794
+
795
+ --border: 217.2 32.6% 17.5%; /* ✅ Dark borders */
796
+ --input: 217.2 32.6% 17.5%;
797
+ --ring: 224.3 76.3% 48%; /* ✅ Focus ring */
798
+ }
799
+
800
+ /* ⚠️ DON'T TOUCH - Core resets */
801
+ * {
802
+ border-color: hsl(var(--border));
803
+ }
804
+
805
+ html {
806
+ -webkit-font-smoothing: antialiased;
807
+ -moz-osx-font-smoothing: grayscale;
808
+ text-rendering: optimizeLegibility;
809
+ }
810
+
811
+ body {
812
+ background-color: hsl(var(--background));
813
+ color: hsl(var(--foreground));
814
+ font-feature-settings: "rlig" 1, "calt" 1;
815
+ transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
816
+ }
817
+
818
+ [dir="rtl"] {
819
+ font-feature-settings: "ss01" 1;
820
+ }
821
+ }
822
+
823
+ /* ========================================
824
+ ✅ OPTIONAL: CUSTOMIZE TYPOGRAPHY
825
+ ======================================== */
826
+
827
+ @layer base {
828
+ /*
829
+ 🎨 CUSTOMIZE - Heading sizes
830
+ Change these based on your design system
831
+ */
832
+ h1 {
833
+ font-size: 2.25rem; /* ✅ 36px - Change if needed */
834
+ line-height: 2.5rem;
835
+ font-weight: 700; /* ✅ Bold - Change (300-900) */
836
+ }
837
+
838
+ h2 {
839
+ font-size: 1.875rem; /* ✅ 30px */
840
+ line-height: 2.25rem;
841
+ font-weight: 600;
842
+ }
843
+
844
+ h3 {
845
+ font-size: 1.5rem; /* ✅ 24px */
846
+ line-height: 2rem;
847
+ font-weight: 600;
848
+ }
849
+
850
+ h4 {
851
+ font-size: 1.25rem; /* ✅ 20px */
852
+ line-height: 1.75rem;
853
+ font-weight: 600;
854
+ }
855
+
856
+ /*
857
+ 🎨 CUSTOMIZE - Paragraph spacing
858
+ */
859
+ p {
860
+ line-height: 1.7; /* ✅ Change for tighter/looser text */
861
+ }
862
+
863
+ /*
864
+ 🎨 CUSTOMIZE - Link styles
865
+ */
866
+ a {
867
+ text-decoration: none;
868
+ transition: color 0.15s ease-in-out;
869
+ }
870
+
871
+ a:hover {
872
+ color: hsl(var(--primary)); /* ✅ Links turn primary color on hover */
873
+ }
874
+
875
+ /* ⚠️ DON'T TOUCH - Accessibility */
876
+ *:focus-visible {
877
+ outline: 2px solid hsl(var(--ring));
878
+ outline-offset: 2px;
879
+ }
880
+
881
+ *:focus:not(:focus-visible) {
882
+ outline: none;
883
+ }
884
+ }
885
+
886
+ /* ========================================
887
+ ✅ OPTIONAL: CUSTOMIZE SCROLLBAR
888
+ ======================================== */
889
+
890
+ ::-webkit-scrollbar {
891
+ width: 10px; /* ✅ Change scrollbar width (8px-14px) */
892
+ height: 10px;
893
+ }
894
+
895
+ ::-webkit-scrollbar-track {
896
+ background: transparent; /* ✅ Or use a color */
897
+ }
898
+
899
+ ::-webkit-scrollbar-thumb {
900
+ background: hsl(var(--muted-foreground) / 0.2);
901
+ border-radius: 10px;
902
+ border: 2px solid hsl(var(--background));
903
+ }
904
+
905
+ ::-webkit-scrollbar-thumb:hover {
906
+ background: hsl(var(--muted-foreground) / 0.3); /* ✅ Darker on hover */
907
+ }
908
+
909
+ * {
910
+ scrollbar-width: thin;
911
+ scrollbar-color: hsl(var(--muted-foreground) / 0.2) transparent;
912
+ }
913
+
914
+ /* ========================================
915
+ ✅ OPTIONAL: CUSTOMIZE SELECTION
916
+ ======================================== */
917
+
918
+ ::selection {
919
+ background-color: hsl(var(--primary) / 0.2); /* ✅ Selection highlight */
920
+ color: hsl(var(--foreground));
921
+ }
922
+
923
+ ::-moz-selection {
924
+ background-color: hsl(var(--primary) / 0.2);
925
+ color: hsl(var(--foreground));
926
+ }
927
+
928
+ /* ========================================
929
+ ⚠️ DON'T TOUCH - Utility Classes
930
+ ======================================== */
931
+
932
+ @layer utilities {
933
+ .scrollbar-hide {
934
+ -ms-overflow-style: none;
935
+ scrollbar-width: none;
936
+ }
937
+
938
+ .scrollbar-hide::-webkit-scrollbar {
939
+ display: none;
940
+ }
941
+
942
+ .scroll-smooth {
943
+ scroll-behavior: smooth;
944
+ }
945
+
946
+ [dir="rtl"] .rtl\:rotate-180 {
947
+ transform: rotate(180deg);
948
+ }
949
+
950
+ .animation-delay-200 {
951
+ animation-delay: 200ms;
952
+ }
953
+
954
+ .animation-delay-400 {
955
+ animation-delay: 400ms;
956
+ }
957
+
958
+ .animation-delay-600 {
959
+ animation-delay: 600ms;
960
+ }
961
+ }
962
+
963
+ /* ========================================
964
+ ⚠️ DON'T TOUCH - Accessibility
965
+ ======================================== */
966
+
967
+ .sr-only {
968
+ position: absolute;
969
+ width: 1px;
970
+ height: 1px;
971
+ padding: 0;
972
+ margin: -1px;
973
+ overflow: hidden;
974
+ clip: rect(0, 0, 0, 0);
975
+ white-space: nowrap;
976
+ border-width: 0;
977
+ }
978
+
979
+ .skip-to-content {
980
+ position: absolute;
981
+ top: -100%;
982
+ left: 0;
983
+ z-index: 9999;
984
+ padding: 1rem 2rem;
985
+ background-color: hsl(var(--background));
986
+ color: hsl(var(--foreground));
987
+ border: 2px solid hsl(var(--border));
988
+ border-radius: var(--radius);
989
+ transition: top 0.3s ease-in-out;
990
+ }
991
+
992
+ .skip-to-content:focus {
993
+ top: 1rem;
994
+ }
995
+
996
+ /* ========================================
997
+ ⚠️ DON'T TOUCH - Print Styles
998
+ ======================================== */
999
+
1000
+ @media print {
1001
+ *, *::before, *::after {
1002
+ background: white !important;
1003
+ color: black !important;
1004
+ box-shadow: none !important;
1005
+ text-shadow: none !important;
1006
+ }
1007
+
1008
+ a, a:visited {
1009
+ text-decoration: underline;
1010
+ }
1011
+
1012
+ a[href]::after {
1013
+ content: " (" attr(href) ")";
1014
+ }
1015
+
1016
+ img {
1017
+ max-width: 100% !important;
1018
+ page-break-inside: avoid;
1019
+ }
1020
+
1021
+ p, h2, h3 {
1022
+ orphans: 3;
1023
+ widows: 3;
1024
+ }
1025
+
1026
+ h2, h3 {
1027
+ page-break-after: avoid;
1028
+ }
1029
+ }
1030
+
1031
+ /* ========================================
1032
+ ⚠️ DON'T TOUCH - Performance
1033
+ ======================================== */
1034
+
1035
+ .will-change-transform {
1036
+ will-change: transform;
1037
+ }
1038
+
1039
+ .will-change-opacity {
1040
+ will-change: opacity;
1041
+ }
1042
+
1043
+ img, video {
1044
+ height: auto;
1045
+ max-width: 100%;
1046
+ }
1047
+
1048
+ img[loading="lazy"] {
1049
+ min-height: 100px;
1050
+ }
1051
+
1052
+ /* ========================================
1053
+ ✅ ADD YOUR CUSTOM STYLES HERE
1054
+ ======================================== */
1055
+
1056
+ /*
1057
+ Example: Custom button styles
1058
+
1059
+ .btn-custom {
1060
+ background: hsl(var(--primary));
1061
+ color: hsl(var(--primary-foreground));
1062
+ padding: 0.5rem 1rem;
1063
+ border-radius: var(--radius);
1064
+ }
1065
+ */`,
1066
+ };